История изменений
Исправление
geekless,
(текущая версия)
:
Я тут нашел описание грамматики выражений какого-то своего черновика ЯП, который набросал лет 5 назад. В общем, я просто оставлю это здесь. (Я не знаю, чем я упарывался.)
Приоритет и ассоциативность операций.
left `
left or
left and
right =, bin_op=
left ? :?
left ||
left &&
left |
left ~
left &
non-associative ==, !=
non-associative <, <=, >, >=
non-associative in
left shl, shr, rol, ror
left +, -,
left *, /, -/
left \r
right \b, \rd
left :...
left :., операции объединения
left ::, :*, операции поиска и выборки
left as
right !, ~(унарная), +(унарная), -(унарная), new, %..., <>...
right ++ --
left ^
left ., ->, [], (), of
Простые операции.
Арифметические:
+(унарная) пустая операция
-(унарная) смена знака
+ сложение
- вычитание
* умножение
/ деление
-/ взятие остатка
Для взятия остатка выбрана такая операция, поскольку -/ можно воспринимать
как сокращение a - a / b. По аналогии с конструкциями вида a += b логичнее
было бы /-, но это конфликтует с унарным минусом: a/-b.
Побитовые:
shr сдвиг вправо
shl сдвиг влево
ror вращение вправо
rol вращение влево
~ побитовое исключающее или
| обитовое или
& побитовое и
~(унарная) побитовое отрицание
Равенства:
== равно
!= не равно
Сравнения:
< меньше
<= меньше или равно
> больше
>= больше или равно
Логические:
&& логическое и
|| логическое или
!(унарная) логическое отрицание
and, or, not - аналогично, но с иным приоритетом.
Выборки:
:: выборка элемента из контейнера по ключу
:* выборка элементов из контейнера по ключам
vec::i // i-й элемент в vec, аналогично vec[i]
vec:*[1...10, 4] // выбрать с 1-го по 10-й, а затем 4-й (повторно)
Поиска и выборки:
Данные операции конструируются по следующему шаблону:
":" "!"? (">" | "<" | "*") ("<" | "<=" | ">" | ">=" | "!=" | "==" | "/")
Если имеется "!", результатом служит ключ(ключи) найденного
элемента(элементов), иначе - значение элемента.
Если далее идёт ">", поиск осуществляется от начала к концу,
если "<" - от конца к началу, если "*" - поиск осуществляется
по всему контейнеру и тип результата - контейнер с выбранными
элементами. Далее указывается либо:
1) либо одна из операций "<", "<=", ">", ">=", "!=", "==",
в этом случае осуществляется поиск элемента, для которого
данная операция истинна (при сравнении со вторым операндом),
2) либо символ "/", в этом случае второй операнд - функция-фильтр.
Примеры:
vec:!<==' ' // возвращает ключ элемента со значением ' ', поиск с конца
vec:>/filter // возвращает значение элемента, для которого filter вернул true, поиск с начала
vec:*/filter // выбрать все элементы, для которых функция filter вернула true
in имеется ли в контейнере (второй операнд) элемент, равный первому операнду
' ' in vec
Конкатенации:
:. конкатенация
vec = ['a', 'b', ' ', '0'];
vec:.['q', 'w'] // ['a', 'b', ' ', '0', 'q', 'w']
Объединения:
Данные операции конструируются по следующему шаблону:
":" операция_для_уникальных_ключей операция_для_неуникальных_ключей.
Два контейнера объединяются по ключам.
Ключи, которые имеются только в одном контейнере:
* включать элементы из обоих контейнеров
1 включать элементы из левого контейнера
2 включать элементы из правого контейнера
0 не включать эти элементы
Ключи, которые имеются в обоих контейнерах:
1 включать значения элементов из левого контейнера
2 включать значения элементов из правого контейнера
== включить только совпадающие в обоих контейнерах значения
!= включить только не совпадающие в обоих контейнерах значения
> включать большее значение
< включать меньшее значение
0 не включать эти элементы
Примечание. Сочетания :11, :22, :00 разрешены. Результат, соотвественно,
левый контейнер, правый контейнер и пустой контейнер.
Примеры:
v1:0==v2 // найти пары ключ-значение, общие для обоих контейнеров
v1:20 v2 // найти пары элементы с уникальным ключём в правом контейнере
Приведения типа:
as - привести к указанному типу
a as integer // привести a к типу integer
Присваивания:
= присваивание
Выражения-операции.
Инверсия.
bin_op : "\" bin_op;
Значение: a "\" bin_op b === b bin_op a
Сложное присваивание.
bin_op : bin_op "=";
Значение: a bin_op "=" b === a "=" a bin_op b
Выбор.
bin_op : "??" bin_op;
Значение: a "??" bin_op b === a bin_op b "?" a ":" b
Примеры:
a ??> b // большее из a и b
Свёртка. (Reduce)
un_op : "\r" bin_op;
Значение: "\r" bin_op a === {if %len a == 0, raise Exc; auto i = %iterator a; __result = i++^; foreach auto v in i, __result bin_op= v;}
Свёртка со значением по умолчанию. (Reduce with Default)
bin_op : "\rd" bin_op;
Значение: b "\rd" bin_op a === {__result = b; auto i = %iterator a; foreach auto v in i, __result bin_op= v;}
Примеры:
\r+[1, 2, 3] // 1 + 2 + 3
5 \rd+[1, 2, 3] // 5 + 1 + 2 + 3
a\rd??>=vec; // Среди значения a и всех значений
контейнера vec выбрать максимальное при присвоить a.
Разветвление. (Branch)
un_op : "\b" un_op*(1) "{" bin_op "}" un_op*(2) ;
Значение: "\b" un_op*(1) "{" bin_op "}" un_op*(2) a === (un_op*(1) a) bin_op (un_op*(2) a)
Примеры:
\b\r+{/}%len v // то же самое, что (\r+ v) / (%len v), т.е. вычисление среднего арифметического элементов v
Понижение до унарной операции.
(Объединение последовательности бинарных операций в унарную.)
un_op : "%" "{" bin_op expression { "," bin_op expression} "}" ;
Значение: "%" "{" bin_op expression { "," bin_op expression} "}" a === алгоритм:
1) __result(0) = a;
2) для каждого i-го фрагмента вида bin_op expression,
__result(i) = __result(i-1) bin_op(i) expression(i);
Следует обратить внимание, что переменные __result(0),
__result(1), __result(2) и т.п. - это разные переменные, могущие иметь разные типы.
\b \r+%{:/filter1} {/} \r+%{:/filter2} v
// Выбирает из v элементы по фильтру filter1, ищет их сумму;
// выбирает из v элементы по фильтру filter2, ищет их сумму;
// находит частное от сумм.
Векторизация бинарной операции.
bin_op: "bin_op" "<" a1 a2 ">"
Значение: бинарная операция применяется к парам значений
(с совпадающими ключами) из двух контейнеров. Параметры a1 и a1
указывают, как поступать с элементами (соотвественно, в левом и
правом контейнере), которые не имеют пары:
"e" - иницировать исключение при встрече такого элемента
"i" - игнорировать такие элементы и не включать в контейнер-результат
"r" помещать такие элементы в контейнер результат без выполнения над ним вычислений
"{" expression "}" использовать в качестве пары
значение expression (значение вычисляет один раз в начале
выполнения векторизованной операции)
"!{" expression "}" использовать в качестве пары
значение expression (значение вычисляет для каждой пары
заново)
"l" использовать в качестве пары значение, свойства last
другого контейнера
"f" использовать в качестве пары значение, свойства first
другого контейнера
Если a2 отсуствует, подразумевается "i".
Если и a1, и a2 отсутствуют, подразумевается "i" "i".
Частичная (левая) векторизация бинарной операции.
bin_op: "!" "bin_op"
Значение: a "!" "bin_op" b.
Аналогично векторизации, но в качестве второго аргумента
выступают не значения из b, а само значение b.
Частичная (правая) векторизация бинарной операции.
bin_op: "bin_op" "*"
Значение: a "bin_op" "*" b.
Аналогично векторизации, но в качестве первого аргумента
выступают не значения из a, а само значение a.
Векторизация унарной префиксной операции.
un_op: "un_op" "*"
Векторизация унарной постфиксной операции.
un_op: "!" "un_op"
Примеры:
%{/2}* (a +<> b) // Среднее арифметическое для каждой пары элементов
(a +<> b) !/ 2 // аналогично предыдущему
(vec:*<16)!++ //Инкрементировать все элементы, меньшие 16.
stream :write* v // Записать в stream элементы v.
Исходная версия
geekless,
:
Я тут нашел описание грамматики выражений какого-то своего черновика ЯП, который набросал лет 5 назад. В общем, я просто оставлю это здесь. (Я не знаю, чем я упарывался.)
Приоритет и ассоциативность операций.
left `
left or
left and
right =, bin_op=
left ? :?
left ||
left &&
left |
left ~
left &
non-associative ==, !=
non-associative <, <=, >, >=
non-associative in
left shl, shr, rol, ror
left +, -,
left *, /, -/
left \r
right \b, \rd
left :...
left :., операции объединения
left ::, :*, операции поиска и выборки
left as
right !, ~(унарная), +(унарная), -(унарная), new, %..., <>...
right ++ --
left ^
left ., ->, [], (), of
Простые операции.
Арифметические:
+(унарная) пустая операция
-(унарная) смена знака
+ сложение
- вычитание
* умножение
/ деление
-/ взятие остатка
Для взятия остатка выбрана такая операция, поскольку -/ можно воспринимать
как сокращение a - a / b. По аналогии с конструкциями вида a += b логичнее
было бы /-, но это конфликтует с унарным минусом: a/-b.
Побитовые:
shr сдвиг вправо
shl сдвиг влево
ror вращение вправо
rol вращение влево
~ побитовое исключающее или
| обитовое или
& побитовое и
~(унарная) побитовое отрицание
Равенства:
== равно
!= не равно
Сравнения:
< меньше
<= меньше или равно
> больше
>= больше или равно
Логические:
&& логическое и
|| логическое или
!(унарная) логическое отрицание
and, or, not - аналогично, но с иным приоритетом.
Выборки:
:: выборка элемента из контейнера по ключу
:* выборка элементов из контейнера по ключам
vec::i // i-й элемент в vec, аналогично vec[i]
vec:*[1...10, 4] // выбрать с 1-го по 10-й, а затем 4-й (повторно)
Поиска и выборки:
Данные операции конструируются по следующему шаблону:
":" "!"? (">" | "<" | "*") ("<" | "<=" | ">" | ">=" | "!=" | "==" | "/")
Если имеется "!", результатом служит ключ(ключи) найденного
элемента(элементов), иначе - значение элемента.
Если далее идёт ">", поиск осуществляется от начала к концу,
если "<" - от конца к началу, если "*" - поиск осуществляется
по всему контейнеру и тип результата - контейнер с выбранными
элементами. Далее указывается либо:
1) либо одна из операций "<", "<=", ">", ">=", "!=", "==",
в этом случае осуществляется поиск элемента, для которого
данная операция истинна (при сравнении со вторым операндом),
2) либо символ "/", в этом случае второй операнд - функция-фильтр.
Примеры:
vec:!<==' ' // возвращает ключ элемента со значением ' ', поиск с конца
vec:>/filter // возвращает значение элемента, для которого filter вернул true, поиск с начала
vec:*/filter // выбрать все элементы, для которых функция filter вернула true
in имеется ли в контейнере (второй операнд) элемент, равный первому операнду
' ' in vec
Конкатенации:
:. конкатенация
vec = ['a', 'b', ' ', '0'];
vec:.['q', 'w'] // ['a', 'b', ' ', '0', 'q', 'w']
Объединения:
Данные операции конструируются по следующему шаблону:
":" операция_для_уникальных_ключей операция_для_неуникальных_ключей.
Два контейнера объединяются по ключам.
Ключи, которые имеются только в одном контейнере:
* включать элементы из обоих контейнеров
1 включать элементы из левого контейнера
2 включать элементы из правого контейнера
0 не включать эти элементы
Ключи, которые имеются в обоих контейнерах:
1 включать значения элементов из левого контейнера
2 включать значения элементов из правого контейнера
== включить только совпадающие в обоих контейнерах значения
!= включить только не совпадающие в обоих контейнерах значения
> включать большее значение
< включать меньшее значение
0 не включать эти элементы
Примечание. Сочетания :11, :22, :00 разрешены. Результат, соотвественно,
левый контейнер, правый контейнер и пустой контейнер.
Примеры:
v1:0==v2 // найти пары ключ-значение, общие для обоих контейнеров
v1:20 v2 // найти пары элементы с уникальным ключём в правом контейнере
Приведения типа:
as - привести к указанному типу
a as integer // привести a к типу integer
Присваивания:
= присваивание
Выражения-операции.
Инверсия.
bin_op : "\" bin_op;
Значение: a "\" bin_op b === b bin_op a
Сложное присваивание.
bin_op : bin_op "=";
Значение: a bin_op "=" b === a "=" a bin_op b
Выбор.
bin_op : "??" bin_op;
Значение: a "??" bin_op b === a bin_op b "?" a ":" b
Примеры:
a ??> b // большее из a и b
Свёртка. (Reduce)
un_op : "\r" bin_op;
Значение: "\r" bin_op a === {if %len a == 0, raise Exc; auto i = %iterator a; __result = i++^; foreach auto v in i, __result bin_op= v;}
Свёртка со значением по умолчанию. (Reduce with Default)
bin_op : "\rd" bin_op;
Значение: b "\rd" bin_op a === {__result = b; auto i = %iterator a; foreach auto v in i, __result bin_op= v;}
Примеры:
\r+[1, 2, 3] // 1 + 2 + 3
5 \rd+[1, 2, 3] // 5 + 1 + 2 + 3
a\rd??>=vec; // Среди значения a и всех значений
контейнера vec выбрать максимальное при присвоить a.
Разветвление. (Branch)
un_op : "\b" un_op*(1) "{" bin_op "}" un_op*(2) ;
Значение: "\b" un_op*(1) "{" bin_op "}" un_op*(2) a === (un_op*(1) a) bin_op (un_op*(2) a)
Примеры:
\b\r+{/}%len v // (\r+ v) / (%len v); вычисление среднего арифметического элементов v
Понижение до унарной операции.
(Объединение последовательности бинарных операций в унарную.)
un_op : "%" "{" bin_op expression { "," bin_op expression} "}" ;
Значение: "%" "{" bin_op expression { "," bin_op expression} "}" a === алгоритм:
1) __result(0) = a;
2) для каждого i-го фрагмента вида bin_op expression,
__result(i) = __result(i-1) bin_op(i) expression(i);
Следует обратить внимание, что переменные __result(0),
__result(1), __result(2) и т.п. - это разные переменные, могущие иметь разные типы.
\b \r+%{:/filter1} {/} \r+%{:/filter2} v
// Выбирает из v элементы по фильтру filter1, ищет их сумму;
// выбирает из v элементы по фильтру filter2, ищет их сумму;
// находит частное от сумм.
Векторизация бинарной операции.
bin_op: "bin_op" "<" a1 a2 ">"
Значение: бинарная операция применяется к парам значений
(с совпадающими ключами) из двух контейнеров. Параметры a1 и a1
указывают, как поступать с элементами (соотвественно, в левом и
правом контейнере), которые не имеют пары:
"e" - иницировать исключение при встрече такого элемента
"i" - игнорировать такие элементы и не включать в контейнер-результат
"r" помещать такие элементы в контейнер результат без выполнения над ним вычислений
"{" expression "}" использовать в качестве пары
значение expression (значение вычисляет один раз в начале
выполнения векторизованной операции)
"!{" expression "}" использовать в качестве пары
значение expression (значение вычисляет для каждой пары
заново)
"l" использовать в качестве пары значение, свойства last
другого контейнера
"f" использовать в качестве пары значение, свойства first
другого контейнера
Если a2 отсуствует, подразумевается "i".
Если и a1, и a2 отсутствуют, подразумевается "i" "i".
Частичная (левая) векторизация бинарной операции.
bin_op: "!" "bin_op"
Значение: a "!" "bin_op" b.
Аналогично векторизации, но в качестве второго аргумента
выступают не значения из b, а само значение b.
Частичная (правая) векторизация бинарной операции.
bin_op: "bin_op" "*"
Значение: a "bin_op" "*" b.
Аналогично векторизации, но в качестве первого аргумента
выступают не значения из a, а само значение a.
Векторизация унарной префиксной операции.
un_op: "un_op" "*"
Векторизация унарной постфиксной операции.
un_op: "!" "un_op"
Примеры:
%{/2}* (a +<> b) // Среднее арифметическое для каждой пары элементов
(a +<> b) !/ 2 // аналогично предыдущему
(vec:*<16)!++ //Инкрементировать все элементы, меньшие 16.
stream :write* v // Записать в stream элементы v.