Предисловие
Данный язык был разработан мной в учебных целях. Я не считаю его (на данный момент) идеально проработанным языком, но возможно в будущем он сможет потягаться с конкурентами.
Если у вас есть желание попробовать его в действии самому — скачивайте репозиторий проекта, в нем вы сможете найти собранную версию проекта или же собрать её самостоятельно, для своей ОС.
В данной статье будет описан небольшой мануал по проекту и рассмотрен синтаксис языка.
Переменные и неявные указатели
В Mash каждая переменная хранит указатель на объект в памяти. При передаче переменных в методы, получении результата или же при простых манипуляциях с ними — работа идет с объектами в памяти по указателям на них.
Т.е. в следующем коде в метод p(arr) будет передан массив в виде указателя на уже созданный ранее объект.
proc p(arr):
...
end
proc main():
arr ?= [1, 2, 3, 4, 5]
p(arr)
end
Присутствие указателей в языке, как явных, так и неявных на мой взгляд придает ему дополнительную гибкость и функциональность, хотя в некоторых случаях и способствует порождению ошибок.
Временные переменные и сборщик мусора
В отличии от подобных ему языков программирования, в Mash полуавтоматический сборщик мусора, в основе которого лежит механизм меток временных значений, а не подсчета указателей.
Т.е. разработчик сам решает когда следует очистить память от мусора и также может делать это вручную, для определенных случаев.
Сборка мусора вызывается с помощью gc() и освобождает память из под всех временных объектов.
Многие простые действия с переменными сопровождаются созданием временных объектов в памяти.
Разработчик может явно объявлять выделение памяти, для дальнейшей работы с ней, т.е. объявлять переменные для длительного использования.
Примеры создания временной переменной:
x ?= 10
И переменных, не помеченных для сборщика мусора:
x ?= new(10)
var x2 = 20
Пример использования gc():
while a > b:
doSomething(a, b)
gc()
end
Память также можно освобождать вручную:
var a = 10, b = 20, c = 30
...
Free(a, b, c)
Зоны видимости переменных
Переменные в Mash могут быть объявлены как локально, так и глобально.
Глобальные переменные объявляются между методов, через оператор var. Локальные — внутри методов любым способом.
Типы данных
В Mash динамическая типизация. Поддерживается автоматическое определение/переопределение типов данных для чисел без знака и со знаком, дробных чисел и строк. Помимо этого из простых типов данных поддерживаются массивы (в т.ч. многоуровневые), enum типы (почти тоже самое, что и массивы), методы, присутствует логический тип данных и пожалуй все.
Примеры кода:
x ?= 10
x += 3.14
x *= "3"
x /= "2,45"
x ?= [1, 2, 3.33, func1(1, 2, 3), "String", ["Enum type", 1, 2, 3], "3,14"]
Интроспекция позволяет определять тип нужной переменной:
if typeof(x) == TypeInt:
...
end
Массивы & перечисления
Редкие задачи не заставляют разработчика объявлять очередной массив в коде.
Mash поддерживает массивы, состоящие из произвольного количества уровней, + массивы могут быть чем-то вроде деревьев, т.е. размеры подуровней могут различаться на одном подуровне.
Примеры объявлений массивов и перечислений:
a ?= new[10][20]
var b = new[10][20]
c ?= [1, [], 3, 3.14, "Test", [1, 2, 3, 4, 5], 7.7, a, b, ["77", func1()]]
var d = [1, 2, 3]
Любые объекты, объявляемые через оператор new не помечаются для сборщика мусора.Такая работа с перечислениями довольно удобна.
Массивы также как и обычные объекты в памяти освобождаются вызовом Free()
Например, можно передавать в методы или возвращать из них множество значений одной переменной:
func doSomething(a, b, c):
return [a+c, b+c]
end
Операторы присваивания
В Mash целых 3 оператора присваивания.
- ?=
Присваивает переменной указатель на какой-либо объект (если переменная объявлена но не хранит указатель на объект в памяти, то нужно использовать именно этот оператор, для присваивания ей значения). - =
Обычное присваивание. Присваивает объекту по указателю в переменной значение другого объекта. - @=
Присваивает значение объекту по явному указателю на этот объект (об этом будет сказано позже).
Математические и логические операции
Список поддерживаемых на данный момент математических и логических операций:
- +, -, *, /
В комментариях не нуждаются. - \
Деление нацело. - %
Остаток от деления. - &
Логическое «и». - |
Логическое «или». - ^
Логическое «исключающее или». - ~
Логическое «не». - ++, --
Инкремент и декремент. - <<, >>
Побитовые сдвиги влево и вправо. - ==, <>, >=, <=
Логические операторы сравнения. - in
Проверяет принадлежность объекта к перечислению или к массиву.
Пример:if Flag in [1, 3, 5, 8]: ...
Явные указатели
Казалось бы, зачем они нужны, если есть не явные указатели? Например для проверки, хранят ли переменные A и B указатели на один и тот же объект в памяти.
- @ — получить указатель на объект и положить его в переменную, как объект.
- ? — получить объект по указателю из объекта в переменной.
Пример:a ?= ?b
Процедуры и функции
Я решил сделать в языке разделение методов по возврату значений на процедуры и функции (как в Pascal).
Объявления методов производятся подобно следующим примерам:
proc SayHello(arg1, arg2, argN):
println("Hello, ", arg1, arg2, argN)
end
func SummIt(a, b):
return a + b
end
Языковые конструкции
Пример конструкции if..else..end.
if <условие>:
...
else:
...
end
Цикл for.
for([инициализация]; <условие>; [операции с переменными]):
...
end
While. Условие проверяется перед итерацией.
whilst <условие>:
...
end
Whilst. Цикл, отличающийся от while тем, что проверка условия выполняется после итерации.
until <условие>:
...
end
switch..case..end..else..end… — всем знакомая конструкция для создания логических ветвлений.
switch <переменная>:
case <значение 1>:
...
end
case <значение 2>:
...
end
else:
...
end
Классы и элементы ООП языка
В Mash реализована поддержка классов, наследования, динамической интроспекции и рефлексии, полиморфизм. Т.е. стандартный набор скриптового языка поддерживается.
Рассмотрим объявление простого класса:
class MyClass:
var a, b
proc Create, Free
func SomeFunction
end
Объявление класса не содержит реализаций методов, которые в нем объявлены.
В качестве конструктора класса выступает метод Create. В качестве деструктора — Free.
После объявления класса можно описать реализацию его методов:
proc MyClass::Create(a, b):
$a ?= new(a)
$b ?= new(b)
end
proc MyClass::Free():
Free($a, $b, $)
end
func MyClass::SomeFunction(x):
return ($a + $b) / x
end
Вы могли заметить символ $ в некоторых местах кода — этим символом я просто сократил длинное this->. Т.е. код:
return ($a + $b) / x
...
Free($a, $b, $)
Эквивалентен этому коду:
return (this->a + this->b) / x
...
Free(this->a, this->b, this)
В this находится указатель на экземпляр класса, от лица которого вызывается метод этого класса.
Для того, чтобы унаследовать функционал какого-либо класса, нужно описать объявление нового класса таким вот образом:
class MySecondClass(MyClass):
func SomeFunction
end
func MySecondClass::SomeFunction(x):
return ($a - $b) / x
end
MySecondClass — будет иметь конструктор и деструктор от своего предка + функция SomeFunction, которая имеется у класса-предка перезаписывается функцией из нового класса.
Для создания экземпляров классов существует оператор new.
Примеры кода:
a ?= new MyClass //выделение памяти под структуру класса
b ?= new MyClass(10, 20) //выделение памяти под структуру класса и последующий вызов конструктора
Тип экземпляра класса можно определить при создании этого экземпляра, соответственно в языке отсутствует приведение типов.
Интроспекция позволяет определить тип экземпляра класса, пример кода:
x ?= new MyClass(10, 20)
...
if x->type == MyClass:
//делаем что-нибудь...
end
Иногда нужно обратиться к классовой функции и перезаписать её новой. Пример кода:
func class::NewSomeFunction(x):
return $x * $y * x
end
...
x ?= new MyClass(10, 20)
x->SomeFunction ?= class::NewSomeFunction
x->SomeFunction(33) //Вызывается NewSomeFunction, будто это оригинальная функция класса.
Заключение
В данной статье я постарался познакомить возможных заинтересованных людей с моим творением.
Спасибо за прочтение. Жду комментариев.
Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Была ли эта статья вам интересна?
25% Да.15
33.33% Да, но ничего особенного нового я не узнал.20
41.67% Нет.25
Проголосовали 60 пользователей. Воздержались 25 пользователей.