Проект

Общее

Профиль

TEGU Littlelang интерпретатор

Начиная с версии 1.52.5 TEGU Enterprise поддерживает Littlelang интерпретатор. Язык программирования Littlelang - это маленький язык разработанный Беном Хойтом (Ben Hoyt).

Спецификация языка

Синтаксис Littlelang представляет собой нечто среднее между Go и Python. Как и Go, он использует func для определения функций (именованных или анонимных), требует { и } для блоков и не нуждается в точках с запятой. Но, как и в Python, в нем используются ключевые слова для and и or и in. Как и в обоих этих языках, он различает выражения и инструкции. Он динамически типизирован и использует сборку мусора с обычными типами данных: nil, bool, int, str, list, map и func. Также есть несколько встроенных функций.

Программы

Программа на littlelang - это просто ноль или более операторов. Операторы на самом деле не обязательно должны разделяться символами новой строки, только пробелами. Ниже приведена допустимая программа (но в реальной жизни вы, вероятно, использовали бы символы новой строки в блоке if).:

s = "медвед" 
print("Превед, " + s)
if s != "" { t = "The end"  print(t) }
// Превед, медвед
// The end

Между токенами игнорируются пробелы и комментарии (// до конца строки).

Типы

В Littlelang есть следующие типы данных: nil, bool, int, str, list, map и func. Тип int - это 64-разрядное целое число со знаком, строки - это неизменяемые массивы байт, списки - это расширяемые массивы (используйте встроенную функцию append()), а карты - это неупорядоченные хэш-таблицы. После последнего элемента в списке или карте допустимы запятые:

Type Syntax Comments
nil nil
bool true false
int 0 42 1234 -5 -5 is actually 5 with unary -
str "" "foo" "\"quotes\" and a\nline break" Escapes: \" \\ \t \r \n
list [] [1, 2,] [1, 2, 3]
map {} {"a": 1,} {"a": 1, "b": 2}

Операторы If

В Littlelang поддерживаются if, else if и else else. Вы должны использовать { ... } фигурные скобки вокруг блоков:

a = 10
if a > 5 {
    print("large")
} else if a < 0 {
    print("negative")
} else {
    print("small")
}
// large

Циклы While

Циклы While стандартны:

i = 3
while i > 0 {
    print(i)
    i = i - 1
}
// 3
// 2
// 1

В Littlelang нет функции break или continue, но вы можете вернуть значение как один из способов раннего выхода из цикла.

Циклы For

Циклы For аналогичны циклам for в Python и циклам Go для range. Вы можете выполнять итерацию по символам (Unicode) в строке, элементам в списке (встроенная функция range() возвращает список) и ключам в карте.

Обратите внимание, что порядок итераций карты не определен - создайте список ключей и выполните сортировку(), если вам это нужно.

for c in "foo" {
    print(c)
}
// f
// o
// o

for x in [nil, 3, "z"] {
    print(x)
}
// nil
// 3
// z

for i in range(5) {
    print(i, i*i)
}
// 0 0
// 1 1
// 2 4
// 3 9
// 4 16

map = {"a": 1, "b": 2}
for k in map {
    print(k, map[k])
}
// a 1
// b 2

Функции и возвращаемые значения

Вы можете определять именованные или анонимные функции, включая функции внутри функций, которые ссылаются на внешние переменные (замыкания). Поддерживаются функции Vararg... синтаксис такой же, как в Go.

func add(a, b) {
    return a + b
}
print(add(3, 4))
// 7

func make_adder(n) {
    func adder(x) {
        return x + n
    }
    return adder
}
add5 = make_adder(5)
print(add5(7))
// 12

// Anonymous function, equivalent to "func plus(nums...)" 
plus = func(nums...) {
    sum = 0
    for n in nums {
        sum = sum + n
    }
    return sum
}
print(plus(1, 2, 3))
lst = [4, 5, 6]
print(plus(lst...))
// 6
// 15

Грамматическое замечание: у вас не может быть "простого возврата" - для этого требуется возвращаемое значение. Поэтому, если вы не хотите ничего возвращать (функции в любом случае всегда возвращают как минимум nil), просто скажите return nil.

Назначение

Назначение может быть присвоено имени, элементу списка по индексу или значению карты по ключу. При присвоении имени (переменной) оно всегда присваивается локальной области действия функции (как в Python). Вы не можете назначить внешнюю область видимости без использования изменяемого списка или карты (здесь нет глобального или нелокального ключевого слова).

Для облегчения объектно-ориентированного программирования obj.foo = bar является синтаксическим дополнением к obj["foo"] = bar. Они в точности эквивалентны.

i = 1
func nochange() {
    i = 2
    print(i)
}
print(i)
nochange()
print(i)
// 1
// 2
// 1

map = {"a": 1}
func change() {
    map.a = 2
    print(map.a)
}
print(map.a)
change()
print(map.a)
// 1
// 2
// 2

lst = [0, 1, 2]
lst[1] = "one" 
print(lst)
// [0, "one", 2]

map = {"a": 1, "b": 2}
map["a"] = 3
map.c = 4
print(map)
// {"a": 3, "b": 2, "c": 4}

Бинарные и унарные операторы

Littlelang поддерживает довольно стандартные бинарные и унарные операторы. Здесь они представлены с указанием их приоритета, от самого высокого к самому низкому (операторы с одинаковым приоритетом вычисляются слева направо).:

Operators Description
[] Subscript
- Unary minus
* / % Multiplication
+ - Addition
< <= > >= in Comparison
== != Equality
not Logical not
and Logical and (short-circuit)
or Logical or (short-circuit)

Некоторые операторы изменены. Вот типы, с которыми они могут работать:

Operator Types Action
[] str[int] fetch nth byte of str (0-based)
[] list[int] fetch nth element of list (0-based)
[] map[str] fetch map value by key str
- int negate int
* int * int multiply ints
* str * int repeat str n times
* int * str repeat str n times
* list * int repeat list n times, give new list
* int * list repeat list n times, give new list
/ int / int divide ints, truncated
% int % int divide ints, give remainder
+ int + int add ints
+ str + str concatenate strs, give new string
+ list + list concatenate lists, give new list
+ map + map merge maps into new map, keys in right map win
- int - int subtract ints
< int < int true iff left < right
< str < str true iff left < right (lexicographical)
< list < list true iff left < right (lexicographical, recursive)
<= > >= same as < similar to <
in str in str true iff left is substr of right
in any in list true iff one of list elements left
in str in map true iff key in map
any any deep equality (always false if different type)
!= any != any same as not
not not bool inverse of bool
and bool and bool true iff both true, right not evaluated if left false
or bool or bool true iff either true, right not evaluated if left true

Встроенные функции

append(list, values...) добавляют заданные элементы в list, изменяя список на месте. Вместо возврата списка возвращается значение nil, что подтверждает тот факт, что у него есть побочные эффекты.

функция args() возвращает список аргументов командной строки, переданных интерпретатору (после имени исходного файла на littlelang).

char(int) возвращает односимвольную строку с заданным значением кода в Юникоде.

exit([int]) немедленно завершает работу программы с заданным кодом состояния (0, если не задан).

find(haystack, needle) возвращает индекс позиции needle в haystack str или индекс элемента needle в списке haystack. Возвращает значение -1, если он не найден.

int(str_or_int) преобразует десятичную строку str в int (возвращает значение nil, если оно недействительно). Если аргумент уже имеет значение int, верните его напрямую.

join(list, sep) объединяет строки в списке в единую строку с разделителем str между каждым элементом.

len(iterable) возвращает длину str (количество байт), list (количество элементов) или map (количество пар ключ/значение).

lower(str) возвращает версию str в нижнем регистре.

print(values...) выводит все значения, разделенные пробелом, за которыми следует новая строка. Для каждого значения вызывается эквивалент str(v), преобразующий его в str.

range(int) возвращает список чисел от 0 до int-1.

read([имя файла]) считывает стандартный ввод или заданный файл и возвращает содержимое в виде str.

rune(str) возвращает кодовую точку Unicode для заданного 1-символьного str.

slice(str_or_list, start, end) возвращает вложенный фрагмент заданного str или списка от начала индекса до конца-1. При разделении списка на части входной список не изменяется.

sort(list[, func]) сортирует список на месте, используя стабильную сортировку, и возвращает значение nil. Элементы в списке должны быть упорядочены с помощью < (int, str или список из них). Если предусмотрена функция key, она должна принимать элемент в качестве аргумента и возвращать упорядочиваемое значение для использования в качестве ключа сортировки.

split(str[, sep]) разбивает строку str с использованием заданного разделителя и возвращает части (за исключением разделителя) в виде списка. Если значение sep не задано или равно нулю, оно разбивается на пробелы.

str(value) возвращает строковое представление значения: nil для nil, true или false для bool, decimal для int (например: 1234), сам str для str (без кавычек), представление littlelang для списка и карты (например: [1, 2] и {"a").: 1} с отсортированными ключами), и что-то вроде <имя функции> для func.

type(значение) возвращает строку, обозначающую тип значения: nil, bool, int, str, list, map или func.

upper(str) возвращает версию str в верхнем регистре.

Грамматика

Ниже приведена полная грамматика littlelang в формате псевдо-BNF. Правила пишутся строчными буквами, например "statement", а отдельные токены - заглавными, например "COMMA" и "NAME" (полный список токенов смотрите в разделе tokenizer/токенизатор.перейти).

program    = statement*
statement  = if | while | for | return | func | assign | expression
if         = IF expression block |
             IF expression block ELSE block |
             IF expression block ELSE if
block      = LBRACE statement* RBRACE
while      = WHILE expression block
for        = FOR NAME IN expression block
return     = RETURN expression
func       = FUNC NAME params block |
             FUNC params block
params     = LPAREN RPAREN |
             LPAREN NAME (COMMA NAME)* ELLIPSIS? COMMA? RPAREN |
assign     = NAME ASSIGN expression |
             call subscript ASSIGN expression |
             call dot ASSIGN expression

expression = and (OR and)*
and        = not (AND not)*
not        = NOT not | equality
equality   = comparison ((EQUAL | NOTEQUAL) comparison)*
comparison = addition ((LT | LTE | GT | GTE | IN) addition)*
addition   = multiply ((PLUS | MINUS) multiply)*
multiply   = negative ((TIMES | DIVIDE | MODULO) negative)*
negative   = MINUS negative | call
call       = primary (args | subscript | dot)*
args       = LPAREN RPAREN |
             LPAREN expression (COMMA expression)* ELLIPSIS? COMMA? RPAREN)
subscript  = LBRACKET expression RBRACKET
dot        = DOT NAME
primary    = NAME | INT | STR | TRUE | FALSE | NIL | list | map |
             FUNC params block |
             LPAREN expression RPAREN
list       = LBRACKET RBRACKET |
             LBRACKET expression (COMMA expression)* COMMA? RBRACKET
map        = LBRACE RBRACE |
             LBRACE expression COLON expression
                    (COMMA expression COLON expression)* COMMA? RBRACE

Доступные глобальные переменные TEGU

В контексте TEGU доступны следующие переменные:

EVENT_START_UNIX = 1746428400
EVENT_START_DATE = "2025-05-05" 
EVENT_START_TIME = "07:00:00" 
EVENT_FINISH_UNIX = 1746432000
EVENT_FINISH_DATE = "2025-05-05" 
EVENT_FINISH_TIME = "08:00:00" 
EVENT_SUBJECT = "Тема ивента" 
EVENT_MESSAGE = "Сообщение ивента" 
EVENT_PARTICIPANTS = ["user1@tegu.online,  user2@tegu.online"]
EVENT_CREATOR = "user1@tegu.online" 
EVENT_ACTION = "create" // Может принимать значения 'create','update','cancel'