Интерпретатор языка программирования Mython. Mython (Mini-python) — упрощённое подмножество Python.
Перейти в каталог проекта, выполнить:
mkdir build && cd "$_"
cmake -DCMAKE_BUILD_TYPE=Release \
-DBUILD_TESTING=OFF ..
cmake --build .
После запуска Mython ожидает ввод программы от пользователя. Для завершения ввода необходимо нажать C^D, после этого введенная программа начнет исполняться.
./Mython
Mython version: 1.0.0
class Factorial:
def calc(n):
if n == 0:
return 1
return n * self.calc(n - 1)
fact = Factorial()
x = 10
print "Факториал числа", x, "равен", fact.calc(x)
# Для завершения ввода необходимо нажать C^D
Факториал числа 10 равен 3628800Также при запуске Mython можно передать на вход файл, содержащий скрипт программы на исполнение:
./Mython < script.my
Mython version: 1.0.0
Факториал числа 10 равен 3628800
Число Фибоначи для числа 10 равно 55В языке Mython используются только целые числа. С ними можно выполнять обычные арифметические операции: сложение, вычитание, умножение, целочисленное деление.
Строковая константа в Mython — это последовательность произвольных символов, размещающаяся на одной строке и ограниченная двойными кавычками " или одинарными '. Поддерживается экранирование спецсимволов '\n', '\t', '\'' и '\"'. Примеры строк в Mython:
"hello"'world''long string with a double quote " inside'"another long string with a single quote ' inside""string with a double quote \" inside"'string with a single quote \' inside''',""— пустые строки. Строки в Mython — неизменяемые.
Кроме строковых и целочисленных значений язык Mython поддерживает логические значения True и False. Есть также специальное значение None, аналог nullptr в С++. В отличие от C++, логические константы пишутся с большой буквы.
Mython поддерживает однострочные комментарии, начинающиеся с символа #. Весь следующий текст до конца текущей строки игнорируется. # внутри строк считается обычным символом.
# это комментарий
x = 5 #это тоже комментарий
# в следующей строке # - обычный символ
hashtag = "#природа"Идентификаторы в Mython используются для обозначения имён переменных, классов и методов. Об этом далее. Идентификаторы формируются так же, как в большинстве других языков программирования: начинаются со строчной или заглавной латинской буквы либо с символа подчёркивания. Потом следует произвольная последовательность, состоящая из цифр, букв и символа подчёркивания.
Примеры правильных идентификаторов: x, _42, do_something, int2str. Примеры неправильных идентификаторов:
4four— начинается с цифры;one;two— содержит символ, который не относится к цифрам, буквам или знакам подчёркивания.
Объявление класса начинается с ключевого слова class, за которым следует идентификатор имени и объявление методов класса. Пример класса «Прямоугольник»:
class Rect:
def __init__(w, h):
self.w = w
self.h = h
def area():
return self.w * self.hСпециальный метод __init__ играет роль конструктора — он автоматически вызывается при создании нового объекта класса. Метод __init__ может отсутствовать.
Неявный параметр всех методов — специальный параметр self, аналог указателя this в C++. Параметр self ссылается на текущий объект класса.
Поля не объявляются заранее, а добавляются в объект класса при первом присваивании. Поэтому обращения к полям класса всегда надо начинать с self., чтобы отличать их от локальных переменных.
Все поля объекта — публичные.
r = Rect(10, 5)В этой программе создаётся новый объект класса Rect. При вызове метода __init__ параметр w будет иметь значение 10, а параметр h — 5. Созданный прямоугольник будет доступен в переменной r.
Mython — это язык с динамической типизацией. В нём тип каждой переменной определяется во время исполнения программы и может меняться в ходе её работы. Поэтому вместо «присваивания переменной значения» лучше говорить о «связывании значения с некоторым именем». Благодаря динамической типизации при первом использовании переменной не надо указывать её тип. Пример:
x = 4 # переменная x связывается с целочисленным значением 4
# следующей командой переменная x связывается со значением 'hello'
x = 'hello'
y = True
x = yВ Mython определены:
- Арифметические операции для целых чисел, деление выполняется нацело. Деление на ноль вызывает ошибку времени выполнения.
- Операция конкатенации строк, например:
s = 'hello, ' + 'world'. - Операции сравнения строк и целых чисел
==,!=,<=,>=,<,>; сравнение строк выполняется лексикографически. - Логические операции
and,or,not. - Унарный минус.
Приоритет операций (в порядке убывания приоритета):
- Унарный минус.
- Умножение и деление.
- Сложение и вычитание.
- Операции сравнения.
- Логические операции.
Порядок вычисления выражений может быть изменён скобками:
print 2 + 3 * 4 # выведет 14
print (2 + 3) * 4 # выведет 20В Mython операция сложения кроме чисел и строк применима к объектам классов со специальным методом __add__:
class Fire:
def __init__(obj):
self.obj = obj
def __str__():
return "Burnt " + str(self.obj)
class Tree:
def __str__():
return "tree"
class Matches: # Спички
# операция сложения спичек с другими объектами превращает их в огонь
def __add__(smth):
return Fire(smth)
result = Matches() + Tree()
print result # Выведет Burnt tree
print Matches() + result # Выведет Burnt Burnt treeОперации сравнения применяются не только к числам и строкам, но и к объектам классов, имеющих методы __eq__ (проверка «равно») и __lt__ (проверка «меньше»). Используя эти методы, можно реализовать все операции сравнения.
class Person:
def __init__(name, age):
self.name = name
self.age = age
def __eq__(rhs):
return self.name == rhs.name and self.age == rhs.age
def __lt__(rhs):
if self.name < rhs.name:
return True
return self.name == rhs.name and self.age < rhs.age
print Person("Ivan", 10) <= Person("Sergey", 10) # True
print Person("Ivan", 10) <= Person("Sergey", 9) # FalseФункция str преобразует переданный ей аргумент в строку. Если аргумент — объект класса, она вызывает у него специальный метод __str__ и возвращает результат. Если метода __str__ в классе нет, функция возвращает строковое представление адреса объекта в памяти. Примеры:
str('Hello')вернёт строкуHello;str(100500)вернёт строку100500;str(False)вернёт строкуFalse;str(Rect(3, 4))вернёт адрес объекта в памяти, например0x2056fd0.
Пример класса с методом __str__:
class Rect(Shape):
def __init__(w, h):
self.w = w
self.h = h
def __str__():
return "Rect(" + str(self.w) + 'x' + str(self.h) + ')'Выражение str(Rect(3, 4)) вернёт строку Rect(3x4).
Специальная команда print принимает набор аргументов, разделённых запятой, печатает их в стандартный вывод и дополнительно выводит перевод строки. Посмотрите на этот код:
x = 4
w = 'world'
print x, x + 6, 'Hello, ' + wОн выведет:
4 10 Hello, world
Команда print вставляет пробел между выводимыми значениями. Если ей не передать аргументы, она просто выведет перевод строки.
Чтобы преобразовать каждый свой аргумент в строку, команда print вызывает для него функцию str. Таким образом, команда print Rect(20, 15) выведет в stdout строку Rect(20x15).
В Mython есть условный оператор. Его синтаксис:
if <условие>:
<действие 1>
<действие 2>
...
<действие N>
else:
<действие 1>
<действие 2>
...
<действие M><условие> — это произвольное выражение, за которым следует двоеточие. Если условие истинно, выполняются действия под веткой if, если ложно — действия под веткой else. Наличие ветки else необязательно.
<условие> может содержать сравнения, а также логические операции and, or и not. Условие будет истинным или ложным в зависимости от того, какой тип имеет вычисленное выражение.
Если результат вычисления условия — значение логического типа, для проверки истинности условия используется именно оно. Примеры:
if x > 0:if s != 'Jack' and s != 'Ann':
Если результат вычисления условия — число, условие истинно тогда и только тогда, когда это число не равно нулю, как в C/C++, например, if x + y:.
Если результат вычисления условия — строка, условие истинно тогда и только тогда, когда эта строка имеет ненулевую длину.
Если результат вычисления условия — объект класса, условие истинно.
Если результат вычисления условия — None, условие ложно.
Действия в ветках if и else набраны с отступом в два пробела. В языке Mython команды объединяются в блоки отступами. Один отступ равен двум пробелам. Отступ в нечётное количество пробелов считается некорректным.
В языке Mython у класса может быть один родительский класс. Если он есть, он указывается в скобках после имени класса и до символа двоеточия. В примере ниже класс Rect наследуется от класса Shape:
class Shape:
def __str__():
return "Shape"
def area():
return 'Not implemented'
class Rect(Shape):
def __init__(w, h):
self.w = w
self.h = h
def __str__():
return "Rect(" + str(self.w) + 'x' + str(self.h) + ')'
def area():
return self.w * self.hНаследование в Mython работает так же, как в Python, — все методы родительского класса становятся доступны классу-потомку. При этом все методы публичные и виртуальные. Например, код ниже выведет Hello, John:
class Greeting:
def greet():
return "Hello, " + self.name()
def name():
return 'Noname'
class HelloJohn(Greeting):
def name():
return 'John'
greet_john = HelloJohn()
print greet_john.greet()Методы в Mython имеют синтаксис:
def <имя метода>(<список параметров>):
<действие 1>
<действие 2>
...
<действие N>Ключевое слово def располагается с отступом в два пробела относительно класса. Инструкции, составляющие тело метода, имеют отступ в два пробела относительно ключевого слова def.
Как и в случае полей класса, обращения к полям и методам текущего класса надо начинать с self.:
class Factorial:
def calc(n):
if n == 0:
return 1
return n * self.calc(n - 1)
fact = Factorial()
print fact.calc(4) # Prints 24Этот пример также показывает поддержку рекурсии, которая компенсирует отсутствие циклов в языке.
Команда return завершает выполнение метода и возвращает из него результат вычисления своего аргумента. Если исполнение метода не достигает команды return, метод возвращает None.
Как сказано выше, Mython — это язык с динамической типизацией, поэтому операция присваивания имеет семантику не копирования значения в область памяти, а связывания имени переменной со значением. Как следствие, переменные только ссылаются на значения, а не содержат их копии. Говоря терминологией С++, переменные в Mython — указатели. Аналог nullptr — значение None. Код ниже выведет 2, так как переменные x и y ссылаются на один и тот же объект:
class Counter:
def __init__():
self.value = 0
def add():
self.value = self.value + 1
x = Counter()
y = x
x.add()
y.add()
print x.valueРезультат вызова метода или конструктора в Mython — терминальная операция. Её результат можно присвоить переменной или использовать в виде параметра функции или команды, но обратиться к полям и методам возвращённого объекта напрямую нельзя:
# Так нельзя
print Rect(10, 5).w
# А вот так можно
r = Rect(10, 5)
print r.w