diff --git a/.gitignore b/.gitignore index a8a92d86..65af3250 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ contrib/* **/newlang-unit-tests.exe **/nlc **/nlc.exe +**/**tar.xz **/DartConfiguration.tcl Makefile diff --git a/docs/index.md b/docs/index.md index 79d6cb94..579e7f49 100644 --- a/docs/index.md +++ b/docs/index.md @@ -4,7 +4,7 @@ Основной особенностью языка является простой, логичный и не противоречивый синтаксис, который основан не на использовании зарезервированных ключевых слов, а на строгой системе грамматических правил с использованием знаков препинания (в которые входят и операторы языка). -Текущая версия 0.2 от ????????????.08.2022 ([Новое в текущей версии и история выпусков](https://newlang.net/version.html)) +Текущая версия 0.2 от 11.08.2022 ([Новое в текущей версии и история выпусков](https://newlang.net/versions.html)) ## Основные свойства и особенности языка: - Возможность работы как в режиме интерпретатора, так и компилятора* @@ -56,8 +56,8 @@ ``` Вывод (первая строка выводится с помощью printf, а вторая - возвращаемое значение функции hello): ``` -Привет, мир! -Привет, мир! + Привет, мир! + Привет, мир! ``` **Пример скрипта для вычисления факториала 1000 на NewLang** @@ -72,26 +72,61 @@ fact # Вывести итоговый результат ``` -Вывод: `402387260077093773543702433923003985719374864210714632543799910429938512398629020592044208486969404800479988610197196058631666872994808558901323829669944590997424504087073759918823627727188732519779505950995276120874975462497043601418278094646496291056393887437886487337119181045825783647849977012476632889835955735432513185323958463075557409114262417474349347553428646576611667797396668820291207379143853719588249808126867838374559731746136085379534524221586593201928090878297308431392844403281231558611036976801357304216168747609675871348312025478589320767169132448426236131412508780208000261683151027341827977704784635868170164365024153691398281264810213092761244896359928705114964975419909342221566832572080821333186116811553615836546984046708975602900950537616475847728421889679646244945160765353408198901385442487984959953319101723355556602139450399736280750137837615307127761926849034352625200015888535147331611702103968175921510907788019393178114194545257223865541461062892187960223838971476088506276862967146674697562911234082439208160153780889893964518263243671616762179168909779911903754031274622289988005195444414282012187361745992642956581746628302955570299024324153181617210465832036786906117260158783520751516284225540265170483304226143974286933061690897968482590125458327168226458066526769958652682272807075781391858178889652208164348344825993266043367660176999612831860788386150279465955131156552036093988180612138558600301435694527224206344631797460594682573103790084024432438465657245014402821885252470935190620929023136493273497565513958720559654228749774011413346962715422845862377387538230483865688976461927383814900140767310446640259899490222221765904339901886018566526485061799702356193897017860040811889729918311021171229845901641921068884387121855646124960798722908519296819372388642614839657382291123125024186649353143970137428531926649875337218940694281434118520158014123344828015051399694290153483077644569099073152433278288269864602789864321139083506217095002597389863554277196742822248757586765752344220207573630569498825087968928162753848863396909959826280956121450994871701244516461260379029309120889086942028510640182154399457156805941872748998094254742173582401063677404595741785160829230135358081840096996372524230560855903700624271243416909004153690105933983835777939410970027753472000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\1` - +Вывод: +``` +402387260077093773543702433923003985719374864210714632543799910429938512398629 +020592044208486969404800479988610197196058631666872994808558901323829669944590 +997424504087073759918823627727188732519779505950995276120874975462497043601418 +278094646496291056393887437886487337119181045825783647849977012476632889835955 +735432513185323958463075557409114262417474349347553428646576611667797396668820 +291207379143853719588249808126867838374559731746136085379534524221586593201928 +090878297308431392844403281231558611036976801357304216168747609675871348312025 +478589320767169132448426236131412508780208000261683151027341827977704784635868 +170164365024153691398281264810213092761244896359928705114964975419909342221566 +832572080821333186116811553615836546984046708975602900950537616475847728421889 +679646244945160765353408198901385442487984959953319101723355556602139450399736 +280750137837615307127761926849034352625200015888535147331611702103968175921510 +907788019393178114194545257223865541461062892187960223838971476088506276862967 +146674697562911234082439208160153780889893964518263243671616762179168909779911 +903754031274622289988005195444414282012187361745992642956581746628302955570299 +024324153181617210465832036786906117260158783520751516284225540265170483304226 +143974286933061690897968482590125458327168226458066526769958652682272807075781 +391858178889652208164348344825993266043367660176999612831860788386150279465955 +131156552036093988180612138558600301435694527224206344631797460594682573103790 +084024432438465657245014402821885252470935190620929023136493273497565513958720 +559654228749774011413346962715422845862377387538230483865688976461927383814900 +140767310446640259899490222221765904339901886018566526485061799702356193897017 +860040811889729918311021171229845901641921068884387121855646124960798722908519 +296819372388642614839657382291123125024186649353143970137428531926649875337218 +940694281434118520158014123344828015051399694290153483077644569099073152433278 +288269864602789864321139083506217095002597389863554277196742822248757586765752 +344220207573630569498825087968928162753848863396909959826280956121450994871701 +244516461260379029309120889086942028510640182154399457156805941872748998094254 +742173582401063677404595741785160829230135358081840096996372524230560855903700 +624271243416909004153690105933983835777939410970027753472000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000\1 +``` -### Загрузки -[Бинарная сборка REPL (пока только под Ubuntu)](https://newlang.net/nlc) -[Архив с необходимыми разделяемыми библиотеками](https://newlang.net/env) +### Загрузка бинарных сборок +[Бинарная сборка и тесты (пока только под Ubuntu)](https://github.com/rsashka/newlang/releases/download/v0.2.0/nlc_bin.tar.xz) +Для запуска бинарных сборок потребуются разделяемые библиотеки libLLVM-13 и libtorch: [Архив с библиотеками](https://github.com/rsashka/newlang/releases/download/v0.2.0/nlc_so.tar.xz) -## Так же можно собрать из исходников +## Сборка из исходников ### Подготовка репозитория - Скачать исходники [https://github.com/rsashka/newlang](https://github.com/rsashka/newlang) -- Скачать и развернуть архив [libtorch](https://pytorch.org/) в каталоге *contrib* (PyTorch Build: Stable (1.10.*) -> Your OS: Linux -> Package: LibTorch -> Language: C++ / Java -> Compute Platform: CPU -> Download here (cxx11 ABI): -[libtorch-cxx11-abi-shared-with-deps-1.10.2+cpu.zip](https://download.pytorch.org/libtorch/cpu/libtorch-cxx11-abi-shared-with-deps-1.10.2%2Bcpu.zip)) +- Скачать и развернуть архив [libtorch](https://pytorch.org/) в каталоге *contrib* (PyTorch Build: Stable (1.12.*) -> Your OS: Linux -> Package: LibTorch -> Language: C++ / Java -> Compute Platform: CPU -> Download here (cxx11 ABI): +[libtorch-shared-with-deps-1.12.1+cpu.zip](https://download.pytorch.org/libtorch/cpu/libtorch-shared-with-deps-1.12.1%2Bcpu.zip) - Активировать и скачать исходники субмодулей (`git submodule init && git submodule update`) - В каталоге *contrib* запустить файл `build.sh` -- В каталоге *src* запустить файл `compile_syntax.sh` для генерации файлов парсера и лексического анализатора. Также может потребоваться установка утилит *flex* и *bison*. Если что, у меня установлены flex 2.6.4 и bison (GNU Bison) 3.7.4 +- В каталоге *src* запустить файл `compile_syntax.sh` для генерации файлов парсера и лексического анализатора. Также может потребоваться установка утилит *flex* и *bison* (flex 2.6.4 и bison (GNU Bison) 3.7.4) ### Сборка -- Юнит-тесты (nlc_test): в каталоге *src* выполнить команду **`make CONF=UnitTest_LLVM`** * -- Интерпретатор (nlc): в каталоге *src* выполнить команду **`make CONF=Debug_LLVM`** * +- Юнит-тесты (nlc_test): в каталоге *src* выполнить команду `make CONF=UnitTest_LLVM` +- Интерпретатор (nlc): в каталоге *src* выполнить команду `make CONF=Debug_LLVM` + --- -*) - Сборка проекта выполняется обычной утилитой make, но сборочные файлы генерируются автоматически в давно устаревшей версии NetBeans 8.2, т.к. это единственная универсальная среда разработки с поддержкой Makefile "из коробки", тогда как в текущей версии Apache NetBeans полноценная поддержка разработки на С/С++ вообще отсутствует. Начал постепеный переход на использование редактора VSCodium (аналога VSCode, в котором вычищена телеметрия от Microsoft) и генерацию скиптов сборки с помощью сmake, но этот процесс пока не завершен. +*) - Сборка проекта выполняется обычной утилитой make, но сборочные файлы генерируются автоматически в давно устаревшей версии NetBeans 8.2, т.к. это единственная универсальная среда разработки с поддержкой Makefile "из коробки", тогда как в текущей версии Apache NetBeans полноценная поддержка разработки на С/С++ вообще отсутствует. Уже начал постепеный переход на использование редактора VSCodium (аналога VSCode, в котором вычищена телеметрия от Microsoft) и генерацию скиптов сборки с помощью сmake, но этот процесс пока не завершен. diff --git a/docs/iterators.md b/docs/iterators.md index 9544acef..19d3e7d9 100644 --- a/docs/iterators.md +++ b/docs/iterators.md @@ -1,245 +1,3 @@ # Итераторы -Итератор в С++ — это объект, который может перебирать элементы в контейнере и предоставлять доступ к отдельным элементам. Все контейнеры стандартной библиотеки С++ предоставляют итераторы, чтобы алгоритмы могли получить доступ к их элементам стандартным способом, независимо от типа контейнера, в котором сохранены элементы. что итератор C++ это интерфес у которого перегружены некоторые операции, такие как инкремент, обращение по ссылки и пр., но сам итератор концептуяально является указателем и для контроля завершения итератора требуется сравнивать текущий элемент в последей позицией в контейнере (т.е. для сравнения текущего элемента с end()). - -Итераторы в NewLang и итераторы в C++ очень сильно отличаются. - - -Требуется разделять конейнеры с данными и итераторы по данным. -В С++ контейнеры данных предоставялют итераторы, для работы с которыми требуются сами контейнеры непосредствено. -Это удобно для использования в рукописном коде, но сложно контроллировать в генерируемом исходнике, - * т.к. требуется использовать и итертор и сам контейнер с данными (для сравнения текущего элемента с end()). - * - * Итератор - отдельный объект, которому для создания требуется контейнер с данными. - * Итератор реализует два интерфейса перебора данных: - * 1. - первый интерфейс итератора как в С++ - * 2. - второй интерфейс для использования в генерируемом коде с логикой NewLang - * - * template Iterator - Обертка над классическим С++ итератором с добавлением возможности отбора - * элементов по имени поля или с помощь функции обратного вызова для пользовательской фильтрации. - * - * Программынй интерфейс итераторов для NewLang следующий: - * - * ObjPtr IteratorMake(const std::string filter) - создать итератор с возможностью фильтрации по имени поля (данные на начало) - * ObjPtr IteratorMake(Obj * args) - создать итератор с фильтрации с помощью пользовательской функции (данные на начало) - * ObjPtr IteratorReset() - Сбросить итератор на начало данных (возвращает сам итератор) - * ObjPtr IteratorData() - прочитать текущий элемент без смещения указателя. Если данных нет возвращается "конец итератора" - * ObjPtr IteratorNext(int64_t count)- прочитать заданное кол-во элементов и переместить итератор на следующий элемент. - * При не нулевом кол-ве, данные возвращаются как элементы словаря. Если указан кол-во элеметов 0 - возвращается текущий элемент. - * - * Реализаиця итераторов NewLang с помощью данного интерфейса: - * - * Создание итератора - * ?, ?("Фильтр"), ?(func), ?(func, args...) - IteratorMake - * - * Перебор элементов итератора - * !, !(0), !(3), !(-3) - * - * dict! и dict!(0) <НЕ> эквивалентны, т.к. по разному обработывают конец данных - * dict! -> 1, dict! -> 2, dict! -> 3, dict! -> 4, dict! -> 5, dict! -> исключение "конец итератора" - * dict!(0) -> 1, dict!(0) -> 2, ... dict!(0) -> 5, dict!(0) -> :IteratorEnd (может :Empty - пустое значение ?? ) - * dict!(1) -> (1,), dict!(1) -> (2,), ... dict!(1) -> (5,), dict!(1) -> (,) - * - * Различия отрицательного размера возвращаемого словаря для итератора - * (Для отрцетельного размера всегда зозвращается словарь указанного размера) - * dict!(-1) -> (1,), ... dict!(-1) -> (5,), dict!(-1) -> (:IteratorEnd,), - * dict!(1) -> (1,), ... dict!(1) -> (5,), dict!(1) -> (,), - * dict!(-3) -> (1, 2, 3,), dict!(-3) -> (4, 5, :IteratorEnd,) - * dict!(3) -> (1, 2, 3,), dict!(3) -> (4, 5,) - * - * Операторы ?! и !? эквивалентны и возвращают текущие данные без перемещения указателя итератора (IteratorData) и не принимают аргументов. - * Остальные итераторы можно вызвать либо без скобок, либо с аргментами в скобрках. Вызов без аргументов зарпрешщен - * (чтобы не пересекаться с логикой копирования объектов и не делать для итераторов аругменты по умолчанию) - * - * Оператор ?? создает итератор и сразу его выполняет, возвращая все значения - * в виде элементов словаря, т.е. аналог последовательности ?(LINQ); !(:Int64.__max__); - * - * Оператор !! без аргументов - сбрасывает итератор в начальное состояние (IteratorReset), - * Обператор !! с аргументами выполняется как ! с аругментами, но с начла коллекции. - - - -``` -dict := (1,2,3,); # Словарь с тремя элемнтами -iter := dict?; # Итератор по всем элементам словаря -iter!; # Вернется 1 -iter!; # Вернется 2 -iter!; # Вернется 3 -iter!; # Произойдет исключение "конец итератора" - -iter?!; # Произойдет исключение "конец итератора" - - ``` - - - * Перебор элементов итератора - * !, !(0), !(3), !(-3) - * - * dict! и dict!(0) <НЕ> эквивалентны, т.к. по разному обработывают конец данных - * dict! -> 1, dict! -> 2, dict! -> 3, dict! -> 4, dict! -> 5, dict! -> исключение "конец итератора" - * dict!(0) -> 1, dict!(0) -> 2, ... dict!(0) -> 5, dict!(0) -> :IteratorEnd (может :Empty - пустое значение ?? ) - * dict!(1) -> (1,), dict!(1) -> (2,), ... dict!(1) -> (5,), dict!(1) -> (,) - * - * Различия отрицательного размера возвращаемого словаря для итератора - * (Для отрцетельного размера всегда зозвращается словарь указанного размера) - * dict!(-1) -> (1,), ... dict!(-1) -> (5,), dict!(-1) -> (:IteratorEnd,), - * dict!(1) -> (1,), ... dict!(1) -> (5,), dict!(1) -> (,), - * dict!(-3) -> (1, 2, 3,), dict!(-3) -> (4, 5, :IteratorEnd,) - * dict!(3) -> (1, 2, 3,), dict!(3) -> (4, 5,) - * - * Операторы ?! и !? эквивалентны и возвращают текущие данные без перемещения указателя итератора (IteratorData) и не принимают аргументов. - * Остальные итераторы можно вызвать либо без скобок, либо с аргментами в скобрках. Вызов без аргументов зарпрешщен - * (чтобы не пересекаться с логикой копирования объектов и не делать для итераторов аругменты по умолчанию) - * - * Оператор ?? создает итератор и сразу его выполняет, возвращая все значения - * в виде элементов словаря, т.е. аналог последовательности ?(LINQ); !(:Int64.__max__); - * - * Оператор !! без аргументов - сбрасывает итератор в начальное состояние (IteratorReset), - * Обператор !! с аргументами выполняется как ! с аругментами, но с начла коллекции. - * - * [ ] - оператор приведения данных в логический тип. Испольуется в алгоритмических конструкциях (проверка условий и циклы) - * Правила преобразования в логический тип: - * Словарь или класс - нет элементов - false, есть элементы - true - * Число - ноль или нулевой тензо - false, иначе true - * Строка - пустая строка false, иначе true - * Итератор - конец данных false, иначе true - * :IteratorEnd (:Empty ?) - всегда false - * None - true (Это объекст со значением пусто) - * Empty - false (Не инициализированный объект) - * - * - * Логика обработки ссылок - * term1 := term; # Объект term1 - копия term. - * term2 := &term; # Объект term2 - ссылка на term (одни и те же данные, т.е. shared_ptr ссылаются на один и тот же объект) - * &term3 := term; # Создать объект term3 и вернуть ссылку на него (сахар для term3 := term; &term3;) - * - * - * copy(arg) := {}; # Обычная функция принимает любой аргумент как <КОПИЮ> значения - * copy(term1); # ОК - передается <КОПИЯ> term1 - * copy(term2); # ОК - передается <КОПИЯ> term2 - * copy(&term1); # ОК - передается ссылка на term1 (На самом деле копия ссылки, которая указывает на те же данные) - * copy(&term2); # ОК- передается ссылка на term2 (На самом деле копия ссылки, которая указывает на те же данные) - * - * ptr(&arg) := {}; # Функция, которая принимает только аргумент - <ссылку> - * ptr(term1); # Ошибка при компиляции - нужно передавать ссылку !!!!!!!! - * ptr(&term1); # ОК - * ptr(&term2); # ОК - * ptr(term2); # Ошибка при компиляции - нужно передавать ссылку, несмотря на то что term2 УЖЕ содержит ссылку !!!!!!!! - - - - - -Итераторы в NewLang и итераторы в C++ очень сильно отличаются. - - -Требуется разделять конейнеры с данными и итераторы по данным. -В С++ контейнеры данных предоставялют итераторы, для работы с которыми требуются сами контейнеры непосредствено. -Это удобно для использования в рукописном коде, но сложно контроллировать в генерируемом исходнике, - * т.к. требуется использовать и итертор и сам контейнер с данными (для сравнения текущего элемента с end()). - * - * Итератор - отдельный объект, которому для создания требуется контейнер с данными. - * Итератор реализует два интерфейса перебора данных: - * 1. - первый интерфейс итератора как в С++ - * 2. - второй интерфейс для использования в генерируемом коде с логикой NewLang - * - * template Iterator - Обертка над классическим С++ итератором с добавлением возможности отбора - * элементов по имени поля или с помощь функции обратного вызова для пользовательской фильтрации. - * - * Программынй интерфейс итераторов для NewLang следующий: - * - * ObjPtr IteratorMake(const std::string filter) - создать итератор с возможностью фильтрации по имени поля (данные на начало) - * ObjPtr IteratorMake(Obj * args) - создать итератор с фильтрации с помощью пользовательской функции (данные на начало) - * ObjPtr IteratorReset() - Сбросить итератор на начало данных (возвращает сам итератор) - * ObjPtr IteratorData() - прочитать текущий элемент без смещения указателя. Если данных нет возвращается "конец итератора" - * ObjPtr IteratorNext(int64_t count)- прочитать заданное кол-во элементов и переместить итератор на следующий элемент. - * При не нулевом кол-ве, данные возвращаются как элементы словаря. Если указан кол-во элеметов 0 - возвращается текущий элемент. - * - * Реализаиця итераторов NewLang с помощью данного интерфейса: - * - * Создание итератора - * ?, ?("Фильтр"), ?(func), ?(func, args...) - IteratorMake - * - * Перебор элементов итератора - * !, !(0), !(3), !(-3) - * - * dict! и dict!(0) <НЕ> эквивалентны, т.к. по разному обработывают конец данных - * dict! -> 1, dict! -> 2, dict! -> 3, dict! -> 4, dict! -> 5, dict! -> исключение "конец итератора" - * dict!(0) -> 1, dict!(0) -> 2, ... dict!(0) -> 5, dict!(0) -> :IteratorEnd (может :Empty - пустое значение ?? ) - * dict!(1) -> (1,), dict!(1) -> (2,), ... dict!(1) -> (5,), dict!(1) -> (,) - * - * Различия отрицательного размера возвращаемого словаря для итератора - * (Для отрцетельного размера всегда зозвращается словарь указанного размера) - * dict!(-1) -> (1,), ... dict!(-1) -> (5,), dict!(-1) -> (:IteratorEnd,), - * dict!(1) -> (1,), ... dict!(1) -> (5,), dict!(1) -> (,), - * dict!(-3) -> (1, 2, 3,), dict!(-3) -> (4, 5, :IteratorEnd,) - * dict!(3) -> (1, 2, 3,), dict!(3) -> (4, 5,) - * - * Операторы ?! и !? эквивалентны и возвращают текущие данные без перемещения указателя итератора (IteratorData) и не принимают аргументов. - * Остальные итераторы можно вызвать либо без скобок, либо с аргментами в скобрках. Вызов без аргументов зарпрешщен - * (чтобы не пересекаться с логикой копирования объектов и не делать для итераторов аругменты по умолчанию) - * - * Оператор ?? создает итератор и сразу его выполняет, возвращая все значения - * в виде элементов словаря, т.е. аналог последовательности ?(LINQ); !(:Int64.__max__); - * - * Оператор !! без аргументов - сбрасывает итератор в начальное состояние (IteratorReset), - * Обператор !! с аргументами выполняется как ! с аругментами, но с начла коллекции. - - - - рах и итераторы в C++ очень сильно отличаются. - - -Требуется разделять конейнеры с данными и итераторы по данным. -В С++ контейнеры данных предоставялют итераторы, для работы с которыми требуются сами контейнеры непосредствено. -Это удобно для использования в рукописном коде, но сложно контроллировать в генерируемом исходнике, - * т.к. требуется использовать и итертор и сам контейнер с данными (для сравнения текущего элемента с end()). - * - * Итератор - отдельный объект, которому для создания требуется контейнер с данными. - * Итератор реализует два интерфейса перебора данных: - * 1. - первый интерфейс итератора как в С++ - * 2. - второй интерфейс для использования в генерируемом коде с логикой NewLang - * - * template Iterator - Обертка над классическим С++ итератором с добавлением возможности отбора - * элементов по имени поля или с помощь функции обратного вызова для пользовательской фильтрации. - * - * Программынй интерфейс итераторов для NewLang следующий: - * - * ObjPtr IteratorMake(const std::string filter) - создать итератор с возможностью фильтрации по имени поля (данные на начало) - * ObjPtr IteratorMake(Obj * args) - создать итератор с фильтрации с помощью пользовательской функции (данные на начало) - * ObjPtr IteratorReset() - Сбросить итератор на начало данных (возвращает сам итератор) - * ObjPtr IteratorData() - прочитать текущий элемент без смещения указателя. Если данных нет возвращается "конец итератора" - * ObjPtr IteratorNext(int64_t count)- прочитать заданное кол-во элементов и переместить итератор на следующий элемент. - * При не нулевом кол-ве, данные возвращаются как элементы словаря. Если указан кол-во элеметов 0 - возвращается текущий элемент. - * - * Реализаиця итераторов NewLang с помощью данного интерфейса: - * - * Создание итератора - * ?, ?("Фильтр"), ?(func), ?(func, args...) - IteratorMake - * - * Перебор элементов итератора - * !, !(0), !(3), !(-3) - * - * dict! и dict!(0) <НЕ> эквивалентны, т.к. по разному обработывают конец данных - * dict! -> 1, dict! -> 2, dict! -> 3, dict! -> 4, dict! -> 5, dict! -> исключение "конец итератора" - * dict!(0) -> 1, dict!(0) -> 2, ... dict!(0) -> 5, dict!(0) -> :IteratorEnd (может :Empty - пустое значение ?? ) - * dict!(1) -> (1,), dict!(1) -> (2,), ... dict!(1) -> (5,), dict!(1) -> (,) - * - * Различия отрицательного размера возвращаемого словаря для итератора - * (Для отрцетельного размера всегда зозвращается словарь указанного размера) - * dict!(-1) -> (1,), ... dict!(-1) -> (5,), dict!(-1) -> (:IteratorEnd,), - * dict!(1) -> (1,), ... dict!(1) -> (5,), dict!(1) -> (,), - * dict!(-3) -> (1, 2, 3,), dict!(-3) -> (4, 5, :IteratorEnd,) - * dict!(3) -> (1, 2, 3,), dict!(3) -> (4, 5,) - * - * Операторы ?! и !? эквивалентны и возвращают текущие данные без перемещения указателя итератора (IteratorData) и не принимают аргументов. - * Остальные итераторы можно вызвать либо без скобок, либо с аргментами в скобрках. Вызов без аргументов зарпрешщен - * (чтобы не пересекаться с логикой копирования объектов и не делать для итераторов аругменты по умолчанию) - * - * Оператор ?? создает итератор и сразу его выполняет, возвращая все значения - * в виде элементов словаря, т.е. аналог последовательности ?(LINQ); !(:Int64.__max__); - * - * Оператор !! без аргументов - сбрасывает итератор в начальное состояние (IteratorReset), - * Обператор !! с аргументами выполняется как ! с аругментами, но с начла коллекции. - - +Тут будет описание работы с итераторами (перенесу статью с Хабра ) \ No newline at end of file diff --git a/docs/ops.md b/docs/ops.md index fa5d3989..f295a071 100644 --- a/docs/ops.md +++ b/docs/ops.md @@ -20,6 +20,7 @@ printf := :Pointer('printf(format:FmtChar, ...):Int32'); /* Создать но Причем словарь может быть указан и с левой стороны от оператора присвоения и таким образом можно записать самый простой способ перебора всех его элементов: `item, dict := ... dict;`, т.е. когда цикле первый элемент словаря сохраняется в переменую item, а из самого словаря удалется. + ## Арифметические операторы Все операторы имеют парный аналог с присвоением значения: diff --git a/docs/syntax.md b/docs/syntax.md index 02ddc2d4..4ef20855 100644 --- a/docs/syntax.md +++ b/docs/syntax.md @@ -32,405 +32,6 @@ Так же следует иметь в виду, что компилятор может генерировать код для прямого обращения к локальным объектам уже на этапе компиляции, тогда как для обращения к глобальным объектам, или если модификатор области видимости отсутствует, компилятор вынужден каждый раз встраивать в код runtime вызов функции поиска объекта в глобальной таблице символов по его имени. +## Макросы - - - - - -# Система типов - -Так как система типов языка динамическая, то явное указание типа не влияет на размер переменной и является только своего рода логическим ограничением на возможность присвоения переменной значения другого типа. - -Информация о типах используется при проверке их совместимости, когда существующему объекту присваивается значение другого типа. Такая операция возможна только когда типы совместимы между собой и допускают автоматическое приведение. Это справедливо как во время парсинга/компиляции исходного теста, так и во время выполнения в режимах интерпретатора и/или скомпилированного файла. - -## Простые типы - -### Арифметические значения - -Арифметические типы данных являются тензорами — массивами чисел одного типа с произвольным количеством измерений и одинаковым размером столбцов в каждом. Единичное число тоже тензор нулевого размера. - -Поддерживаются только знаковые целые числа, т. к. в беззнаковых числах особая нужда отсутствует, а проблем с ними можно найти очень много на ровном месте. - -Проблемы беззнаковых чисел (из интернета): -> Во-первых, вычитание двух беззнаковых чисел, например 3 и 5. 3 минус 5 равно 4294967294, т.к. -2 не может быть представлено как беззнаковое число. Во-вторых, непредвиденное поведение может возникнуть при смешивании целочисленных значений со знаком и без знака. С++ может свободно преобразовывать числа со знаком и без знака, но не проверяет диапазон, чтобы убедиться, что вы не переполняете свой тип данных. -> В C++ всё же есть несколько случаев, когда можно (или необходимо) использовать беззнаковые числа. Во-первых, числа без знака предпочтительнее при работе с битами. Во-вторых, использование беззнаковых чисел связаных с индексацией массивов. - -Но это не мой случай, так как индекс может быть отрицательным и даже не числом, а диапазоном или многоточием. -З.Ы. И даже зная об этом, все равно умудрился недавно словить баг с отрицательными индексами у словарей! - - -Имена встроенных арифметических типов говорят сами за себя: Int8, Int16, Int32, Int64, Float32, Float64, Complex32, Complex64. Отдельным типом идет логический тип Bool, который может принимать значения только 0 или 1 (false/true соответственно), и в зависимости от выполняемой операции может быть отнесен к целочисленным типам, так и не входить в их состав (данный подход интерпретации логического типа данных был взят из библиотеки Torch). -``` -// Treat bool as a distinct "category," to be consistent with type promotion -// rules (e.g. `bool_tensor + 5 -> int64_tensor`). If `5` was in the same -// category as `bool_tensor`, we would not promote. Differing categories -// implies `bool_tensor += 5` is disallowed. -// -// NB: numpy distinguishes "unsigned" as a category to get the desired -// `bool_tensor + 5 -> int64_tensor` behavior. We don't, because: -// * We don't want the performance hit of checking the runtime sign of Scalars. -// * `uint8_tensor + 5 -> int64_tensor` would be undesirable. -``` - -В будущем планируется добавить классы чисел для длинной арифметики и дробей, для чего зарезервированы названия типов BigNum, Currency и Rational. - -Доступ к элементам тензора происходит по целочисленному индексу, который начинается с 0. Для многомерного тензора, индексы элемента перечисляются в квадратных скобках через запятую. Поддерживается доступ к элементам через отрицательный индекс, который обрабатывается точно так же, как в Python (-1 последний элемент, -2 предпоследний и т.д.). - -Литерал тензор в тексте программы записывается в квадратных скобках с обязательной завершающей запятой, т.е. [1, 2,] — это литерал одномерный тензор из двух чисел. После закрывающей скобки тип тензора может быть указан в явном виде. Если тип не указан, то он выводится автоматически на основании указанных данных и выбирается минимально возможный байтовый размер, который позволяет сохранить все значения без потери точности. - -*Примеры:* -``` -$var_char := 123; # Тип Int8 выводится автоматически -$var_short := 1000; # Тип Int16 выводится автоматически -$var_bool := [0, 1, 0, 1,]; # Тензор из 4 элементов. Тип Bool выводится автоматически -$tensor[10,10]:Int32 := 1; # Тензор Int32 размером 2x2 инициализированный 1 -$scalar := $tensor[5,5]; # Присвоить скаляру значение указанного элемента тензора -``` - - -## Строки - -Поддерживаются два типа строк, StrWide — символьные (широкие) и StrChar — байтовые. Различия между ними заключается в типе единичного элемента. У символьных строк единичным элементом является широкий символ *wchar_t*, а у байтовой строки единичным элементом является один байт (точнее *char*, т.е. байт со знаком). Символьные строки литералы в исходном тексте записывается в «двойных кавычках», а байтовые строки в 'одинарных кавычках'. - -Количество элементов символьной строки возвращается в широких символах, а размер байтовой строки в байтах, поэтому и обращение к элементу строки по индексу происходит соответственно либо к символу, либо к байту. - -Важный момент. К любой переменной можно обратиться так же, как к функции (записав после её имени круглые скобки). Результатом этой операции будет создание копии/клона объекта. Причем некоторые типы (словари, классы и символьные строки) можно использовать в качестве шаблона при создании копии объекта с модифицированными свойствами, если новые и/или изменяемые значения указать в скобках, как аргументы при вызовах функций. Так, если при создании копии в скобках указать набор новых данных, то результирующая копия будет содержать уже измененные данные. - -*Например:* -``` -$template := "${name} $1"; # Обычная строка -$result := $template("шаблон", name = "Строка"); # result = "Строка шаблон" -``` - -## Системные - -## :Pointer - указатель на системную область памяти -Так как любомй программе приходится взаимодействиовать с внешним миром, то по неволе приходится закладывать возможность использования других библиотек и системын типов данных и для этих целей служит тип *Pointer*. Он создается при импорте функций из внешних библиотек и вручную его создать нельзя. Но можно вывести его значение, например для отладки. - -## :Plain - указатель на представление данных в бинарном виде -Для взаимодействия с внешними библиотеками требуется еще и обмен данными. И для этих целей служит тип данных *Plain* - который также является указателем, но на двоичное представление данных в единой области памяти. Конечно, если их можно представить в виде единого фрагмента. - -## Составные типы данных: - -## Словарь -Словарь (:Dictionary) — набор данных произвольного типа с доступом к отдельным элементам по целочисленному индексу или по имени элемента при его наличии (он похож и на tuple и на структуру одновременно). Словари от тензоров отличаются тем, что являются только одномерными массивами, но каждый элемент может содержать произвольное количество элементов любого типа, в том числе и другие словари. - -Доступ к элементам словарей происходит по имени элемента, которое записывается через точку от имени переменной, либо по целочисленному индексу. Индекс также начинается с 0 и как у тензоров и тоже может быть отрицательным. - -Литерал с типом «словарь» в тексте программы записывается в круглых скобках с обязательной завершающей запятой, т. е. (,) — пустой словарь, (1, 2= «2», name=3,). - -## Перечисление, структура и объединение -*:Enum*, *:Struct* и *:Union* — это такие же словари, только на их элементы накладываются определнные ограничения. Каждый эелемент должен иметь уникальное имя, а его тип данных должен быть простым, т.е. числом или строкой фиксированного размера. - -, соотвествующие типах имеют уникальные имена и целочисленные значение, которое явно указывается при определении или вычисляется автоматически (на единицу больше предыдущего элемента). У перечислений тип значения указывается сразу после закрывающей скобки через двоеточие (ONE=1, TWO=, THREE=): Int32. - -## Классы - -Класс (реализован частично) — тип данных, с помощью которого реализуется один из принципов ООП — наследование. При создании экземпляра класса создается новая переменная, у которой сохраняется информацию о своем родителе и которая наследует от него свойства и методы. Тип данных *:Class* аналогичен словарю, но все свойства обязаны иметь имена (хотя доступ к свойствам класса по индексу так же возможен). - -## Функции - -Синтаксис NewLang поддерживать несколько типов функций (а в будущем и методов классов): обычные функции, чистые функции и простые чистые функции. - -Для всех типов функций поддерживаются аргументы по умолчанию. При создании функции, её аргументы указываются как в Питоне, т.е. вначале идут обязательные аргументы, потом аргументы со значениями по умолчанию, где имя аргумента отделяется от его значения по умолчанию знаком равно **=**. Если функция допускает обработку произвольного количества аргументов, то последним в списке параметров указывается многоточие **...** (три точки подряд) . - -### Обычная функция - -Обычная функция — такие функции являются именно обычными функциями в понимании С/С++. Внутри них можно писать совершенно любой код, включая проверки условий, циклы, вызовы других функций и т.д. - -Внутри обычной функции можно обращаться к локальным и глобальным объектам, и они могут содержаться вставки на языке реализации*, например, для вызова функций из внешних библиотек. - -Вставки на языке реализации оформляются в виде %{ %} и могут содержать любой текст на С/С++, а прямо из него можно обращаться к локальным и глобальным объектам NewLang так же, как и в обычном синтаксисе, указывая первым символом имени соответствующий модификатор (*$* для локальных объектов и *@* для глобальных). - -Технически, такая программная вставка просто переносится трансплайтером непосредственно в исходный текст генерируемого файла, а все идентификаторы NewLang специальным образом декорируются (добавляются специальные маркеры для их идентификации), после этого исходный текст подается на вход обычному компилятору С++. Для локальных объектов трансплайтер может генерировать код для прямого доступа к объекту на этапе компиляции, а для работы с глобальными объектами вынужден использовать runtime вызовы функции поиска в таблице символов. - ---- -*) - Программные вставки на языке реализации обрабатываются только во время компиляции - -*Например:* -``` -print(str) := { - %{ - printf("%s", static_cast($str)); /* Прямой вызов С функции */ - %} -}; -``` - -### Чистые функции - -Чистая функция — это тоже обычная функция, только в том смысле, какой в него вкладывает функциональное программирование. Создания чистой функции происходит с помощью оператора **:-**, а сам оператор заимствован из языка Пролог. У чистой функции отсутствует доступ к контексту и глобальным переменным, поэтому она может обрабатывать только те данные, которые были ей переданы в качестве аргументов. - -Программные вставки на языке реализации внутри чистых функций не запрещены и могут использоваться, например, для отладки. Но делается это на страх и риск разработчика. Именно он отвечает за их «чистоту», например при вызове функций из внешних библиотек. -``` -Sum(arg1, arg2) :- {$arg1+$arg2;}; # Вернуть сумму аргументов -``` - - -### Простые чистые функции - -Простые чистые функции — отдельный класс чистых функций, которые предназначены только для вычисления логического результата (т.е. они являются предикатами) и их отличает упрощенная формой записи. Тело простой чистой функции состоит из последовательности операторов, которые разделяются запятыми и заканчиваются, как и любое выражение, точкой с запятой. Все операторы простой чистой функции всегда приводятся к булевому значению, а итоговый результат функции вычисляется по одной из возможных логических операций: И, ИЛИ и исключающее ИЛИ. - -*Например:* -``` -func_and(arg1, arg2) :&&= arg1==3, arg2 > 0; # Простая чистая функция Логическое И -func_or(arg1, arg2) :||= arg1==3, arg2 > 0; # Простая чистая функция Логическое ИЛИ -func_xor(arg1, arg2) :^^= arg1==3, arg2 > 0; # Простая чистая функция Исключающее ИЛИ -``` - - -## Специальные типы данных: - -### Пусто (:None) - -**:None** (пусто) — не содержит значения (точнее имеет одно значение None) и совместим с любым другим типом данных. Указывается в тексте программы как один подчерк «_». None имеют не инициализированные переменные и при попытке чтения из такой переменной возникает ошибка. - -Тип переменной может быть явно указан или выведен автоматически из присваиваемого значения. Присвоить новое значение уже инициализированной переменной можно только для совместимого типа, так как неявное преобразование типов не допускаются. - -``` -$var := _; # Создать не инициализированную переменную -$var2 := var; # Ошибка!!! Нельзя прочитать неинициализированную переменную var -$var = 1000; # У переменной будет тип Int16 (минимальный размер для хранения значения) -$var = 0,5; # Ошибка!!! Int16 ← Float32 не совместимы -$var = _; # Очистить значение переменной -$var = 0,5; # Теперь можно, т. к. None совместим с любым типом -``` - - -### Диапазон (:Range) - -Диапазон — специальный тип данных, являющейся приблизительным аналогом типа «генератор» в Python. К диапазону можно обращаться как к итератору и он будет поочередно выдавать элементы в указанном интервале с заданным шагом. Диапазон в тексте программы указывается как два или три элемента через две точки, например 1..5 — диапазон от единицы до пяти с шагом по умолчанию 1. В качестве параметров диапазона можно указывать не только литералы, но и имена переменных. Например, *0,1..$stop..0,1* — диапазон от 0,1 до значения, указанного в переменной $stop с шагом 0,1. - -Диапазон для целых чисел можно использовать в качестве индекса у тензоров (точнее, у любых объектов, которые допускают доступ к своим элементам по индексу, т.е. тензоры, словари и текстовые строки). Фактический, это поведение аналогично *slice* в языке Python и *array[1:5]* в Python означает тоже самое, что и *array[1..5]* в NewLang. - -В качестве индекса у тензоров еще можно указать произвольное количество измерений с помощью многоточия, т.е. -``` -$tensor[…, 0] = 0; # Обнулить все первые элементы в каждом измерении. -``` - - - -## Преобразование типов - -### Явное приведение типов -Несмотря на динамическую типизацию языка, если тип переменной указан явно, то автоматическое приведение типов не выполняется, и чтобы присвоить переменой значение не совместимого типа, требуется явное преобразование. - -Так как символьные названия типов относятся к деталям реализации, то явное преобразование в конкретный тип данных производится с помощью вызова функции с именем типа, т.е. :Bool(), :StrWide(), :Int64() и т.д. - -Для преобразования любого типа данных в строку ещё можно использовать оператор конкатенации строк, которой преобразует любой тип данных в строковое представление. Но, так как строковых типов два (байтовые и широкие строки), то тип строки определяется первым аргументом в операторе конкатенации/сцепления **++**. Также преобразовать любое значение в строковое можно с помощью строки-шаблона. - -``` -"" ++ 123; # "123" - Строка широких символов -'' ++ 123; # '123' - Байтовая строка - -val := 12345; # Число -"$1"(val); # Будет строка "12345" -``` - -Так как тензоры могут иметь больше одного значения, то и в качестве аргументов могут принимать их произвольное количество, а итоговым результатом будет тензор, в котором все переданные данные преобразованы к требуемому типу автоматически. - -*Примеры:* - -``` -> tstr := :Tensor("Тест"); # Создать тензор из строки широких символов -[1058, 1077, 1089, 1090,]:Int32 - -> t2 := :Tensor[2,2]("Тест"); # Тоже самое, но тензор указанной размерности -[ - [1058, 1077,], [1089, 1090,], -]:Int32 - -> :StrWide(tstr) # Создать символьную строку из тензора -Тест - -> :Float64(t2) # Изменить тип данных тезора без изменения размерности -[ - [1058, 1077,], [1089, 1090,], -]:Float64 - -> t3 := :Int8[4]( t2 ) # Изменить размерность тензора и его тип (в данном случае с частичной потерей данных) -[34, 53, 65, 66,]:Int8 - - ->:Tensor( (1,2,3,) ); # Тензор из словаря -[1, 2, 3,]:Int8 - ->:Tensor( 'first second' ) # Байтовая строка в тензор -[102, 105, 114, 115, 116, 32, 115, 101, 99, 111, 110, 100,]:Int8 - ->:Tensor( (first='first', space=32, second='second',) ) # Получаем тензор из словаря с такими же данными -[102, 105, 114, 115, 116, 32, 115, 101, 99, 111, 110, 100,]:Int8 - ->:Float64[10,2]( 0, ...) # Тензор заданного формата с нулями, где многоточие повторяет последние указанные данные до получения тензора требуемого размера -[ - [0, 0,], [0, 0,], [0, 0,], [0, 0,], [0, 0,], [0, 0,], [0, 0,], [0, 0,], [0, 0,], [0, 0,], -]:Float64 - ->:Int32[3,2]( ... rand() ...) # Тензор со случайными данными, где между многоточиями указана функция, которую следуюет вызывать каждый раз при получении нового элеменета тензора -# Пришлось придумывать новую конструкцию, т.к. многоточие перед именем, это оператор раскрытия словаря, а многоточие после имени, это повторение последнего значения до конца заданной размерности. -[ - [1804289383, 846930886,], [1681692777, 1714636915,], [1957747793, 424238335,], -]:Int32 - ->:Int32[5,2]( 0..10 ); # Создание тензора из диапзона -[ - [0, 1,], [2, 3,], [4, 5,], [6, 7,], [8, 9,], -]:Int32 - ->:Tensor( 0..0.99..0.1 ); # Или даже так -[0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9,]:Float64 -``` - - -# Операторы и управляющие конструкции - -## Операторы: - -Все операторы имеют парный аналог с присвоением значения. - -- **+** и **+=** - сложение арифметических типов данных -- **-** и **-=** - вычитание арифметических типов данных -- **/** и **/=** - деление (результат число с плавающей точкой) -- **//** и **//=** - целочисленное деление с округлением к меньшему числу (как в Python) -- * и *= - умножение -- ** и **= - возведение в степень (он же используется и для повторения текстовых строк) -- **++** и **++=** - конкатенация строк с автоматическим приведением аргументов к стоковому типу (символ инкремента специально используется вместо одиночного плюса для того, чтобы в явном виде разделить конкатенацию строк и операторы арифметического сложения) - - -## Операторы сравнения: -- **<**, **>**, **<=**, **>=** - классические для сравнения скаляров -- **==** и **!=** - операторы сравнения с автоматическим приведением совместимых типов для любых объектов -- **===** и **!==** - оператор точного сравнения для любых объектов (автоматического приведения типов не выполняется) - - -## Проверки типа (имени класса объекта): -Для оператора проверки имени класса объекта используется символ тильда **~**. Он немного похож на оператор *instanceof* в Java. Левым операндом должен быть проверяемый объект, а правым — проверяемый тип, который можно указать строкой литералом, переменной строкового типа или именем проверяемого класса непосредственно. Результатом операции будет истина, если правый операнд содержит название класса проверяемого объекта или он присутствует в иерархии наследования. -``` -name := "class"; # Строковая переменная с именем класса -var ~ name; -var ~ :class; # Имя типа -var ~ "class"; # Строка литерал с именем типа -``` - -## Утиная типизация -Оператор утиной типизации, два символа тильны **~~** — приблизительный аналог функции isinstance() в Python, который для простых типов сравнивает непосредственную совместимость типа левого операнда по отношению к правому. А для словарей и классов в левом операнде проверяется наличие всех имен полей, присутствующих у правого операнда, т.е.: - -``` -(field1=«value», field2=2,) ~~ (); # Истина (т. е. левый операнд словарь) -(field1=«value», field2=2,) ~~ (field1=_); # Тоже истина (т. к. поле field1 присутствует у левого операнда) -(field1=«value», field2=2,) ~~ (not_found=_); # Ложь, т.к. поле not_found у левого операнда отсутсвует -``` - -Строгая утиная типизация **~~~** — для простых типов сравнивается идентичности типов без учета совместимости, а для составных типов происходит сравнение всех свойств с помощью оператора строгого равенства. Для данной операции, пустой тип совместим только с другим пустим типом. - - -# Управляющие конструкции -К управляющим конструкциям языка NewLang относятся условный оператор, два вида циклов, оператор оценки выражения, оператор прерывания последовательности выполнения команд и перехват прерывания. Операторы проверки условий всегда указываются в квадратных скобках, а последовательность команд для выполнения - в фигурных. - -## Условный оператор -В качестве оператора проверки условия используется синтаксическая конструкция, соответствующая по смыслу термину «следует», т.е. тире и угловая скобка **->** или с двумя тире для большей наглядности **-->**. Такая запись условного оператора очень похожа на математическую и легко объединяется в последовательности для проверки множественных условий вида «else if». - -В общем случае условный оператор имеет вид: `[ условие ] -> действие;` или `[ условие ] -> {действие};` -или `[ условие1 || условие2 ] --> {действие}, [_] --> {действие иначе};` - -Для наглядности записанный с отступами: -``` -[ условие1 ] -> { действие1 }, - [ условие2 ] -> действие2, - [ условие3 ] -> действие3, - [_] -> {действие_иначе}; -``` - - -## Оценка выражения -Синтаксическая конструкция с помощью которой реализуется аналог оператора switch выглядит следующим образом: -``` -[ $var ] ==> { - [1] -> { code }; # Выполнется проверка условия $var == 1 - [1, 2] -> { code }; # Выполнется проверка условия ($var == 1 || $var == 2) - [_] -> { code default }; # Ветка условия иначе -}; -``` - -Причем в качестве оператора для оценки могут быть использован любые имеющиеся операторы сравнения на равенство: -- **==>** - проверка на равенство с приведением типов - - **===>** - проверка на точное равенство - - **~>** - проверка типа (имени класса) - - **~~>** - утиная типизация - - **~~~>** - строгая утиная типизация - -И если в качестве оператора сравнения использовать оператор утиной типизации, то оценка выражения превращается в классический Pattern Matching: -``` -$value := (f1=1, f2="2",); -[ $value ] ~~~> { - [ (f1=_, ), (f1=_, f2=0, ) ] -> { code }; # Поле f2 отсутствует или число - [(f1=_, f2="",), (f1=_, f2='',)] -> { code }; # Поле f2 строка - [_] -> { code default }; # Код по умолчанию -}; -``` - - -## Операторы циклов - -Для указания операторов циклов используются управлялюящие **<<->>** или **<<-->>** (с двумя стрелками по направлению от проверки условия к телу цикла). И в заисимости от расположения условия и тела цикла, он может быть с предусловием (*while*) или постусловием (*do while*). Хотя пока эти синтаксические конструкции не "отлежались" и их можно считать временными из-за того, что их легко перепутать с условным оператором, и, возможно, имеет смысл заменить разные операторы цикла одной единственной конструкцией вида: **<-->** или **<<->>**, котрая сильнее отличается от оператора следования. - -Но в настоящий момент циклы реализованы вот так: -``` -[условие while] <<->> { - тело цикла while -}; - -{ - тело цикла do while -} <<-->> [условие do while]; -``` - -Реализация цикла foreach на примере суммирования всех элементов словаря (или одномерного тензора) - -``` -summa := 0; -dict := (1,2,3,4,5,); -[ dict ] <<-->> { # Условие цикла, пока есть данные - item, dict := ... dict; # Результат оператора раскрытия словаря - первый его элемент перемещается в item - summa += item; # Вычисление суммы всех элементов словаря -}; - -``` - - -## Операторы прерывания (возврата) -В качестве оператора прерывания/возврата используется два символа минус **--**. Опреатор позволяет прервать выполнение последоватльности команд и/или вернуть данные из текущей функции/блока кода и является самым близким аналогом оператора **return** и **throw** одновременно. Для того, чтобы вернуть данные, их необходимо указать между двумя операторами прерывания, т.е. `--100--; # Вернуть указанное значение`. Если возвращаемое значение не указано явно, то будет возвращено значение *None*. - - -## Следование (блок кода/лямбда функция) -Алгоритмическая конструкция, которая отвечает последовательное выполнение нескольких команд/операторов и возвращающая результат выполнения последнего из них. Также, результатом выполнения может быть значение, которое возвращается с помощью оператора прерывания(возврата). Это очень похоже на классическую лямбда функцию, только она выполняется сразу во время определения, а в переменную сохраняется уже результат её выполнения. - -Следование без перехвата прерывания оформляется в виде последовательности обычных и фигурны скобок, т.е. `(){ run code };` или тоже самое, но сохраняет результата выполения в переменной: `$result := (){ run(); code() };`. Но если внутри такой функции будет выполнен оператор прерывания, то она никогда вернет управления и не сохранит возвращаемое значение в переменой *$result*! - -Чтобы перехватывать прерывания, в том числе и возвращаемые значения, необходимо использовать конструкция следования с перехватом прерываний, которая оформляется в виде последовательности обычных и **двойных** фигурны скобок, т.е. `$error := (){{ run(); error();code() }};`. Такая конструкция перехватывает все возвраты и прерывания, если они возникают во время выполнения последовательности команд. В этом случае любой результат будет сохранен в перемнной *$error* как при нормальном завершении, так и в случае возникновения ошибки. - -Для более тонкой настройки перехвата прерываний следует использовать типизированную конструкцию, когда в явном виде указывается, какие типы прерываний следует перехватывать. `$runtime := (){{ run(); error(); code() }}:ErrorRuntime;`. Такая конструкция вернет результат только в случае успешного завершения (когда с помощью оператора прерывания возвращается не типизированное значение, например, `--"Строка"--;`), или при создании прерывания с указанием конкретного типа **--:ErrorRuntime("Описание ошибки")--;**. А вот при возникновении любого другого типизированного прерывания, значение перехвачено не будет и все отработает как самый первый вариант, т.е. без перехвата прерывания и без сохранения возвращаемого значения в переменную. - - -## Стратегия обработки ошибок -Обработка ошибок состоит из комбинации двух элементов: оператора прерывания выполнения с указанием типа возвращаемого значения и алгоритмической конструкции следование с возможностью перехвата прерывания заданного типа. - -Это немного отличается от классического варианта обработки исключений, который в обычных языках программирования обычно оформляется ключевыми словами try… catch… finally с различными вариациями. Ведь основная цель подобных синтаксических конструкций — выделить участок кода где возможно возникновение ошибки, перехватить и обработать правильный тип данных (исключений), т.к. **NewLang** не делает различний между операторами возврата и генерации исключения. - -### Подход к обработке исключений следующий: -Программный код, который может привести к ошибке, заключается в двойные фигурные скобки, а результат выполнения такого блока кода присваивается переменной. После этого анализируется возвращенное значение, например, оператором сравнения по образцу: -``` -$result := (){ { # начало аналога блока try - $value := call_or_exception1(); - [условие1] -> { -- :Error -- }; - [условие2] -> { -- $value -- }; - $value := call_or_exception2(); -} }; # конец аналога блока try - -[$result] ~> { # Для сравнения по образцу использовать оператор проверки типа (имени класса) - [:ErrorParser] -> {Код обработки ошибок парсера}; - [:ErrorRunTime] -> {Код обработки ошибок времени выполнения}; - [:Error] -> { Код обработки остальных ошибок }; - [_] -> { Обработка нормальных данных $value без ошибок }; -}; -``` +Тут будет описание синтаксиса макросов и примеры их использования (перенесу статью с Хабра) diff --git a/docs/versions.md b/docs/versions.md new file mode 100644 index 00000000..cabc1a3e --- /dev/null +++ b/docs/versions.md @@ -0,0 +1,19 @@ +# История версий языка NewLang + +## Релиз 0.2 (11.08.2022) - текущая версия +### Новые возможности и изменения в синтаксисе NewLang +- Добавылены макросы (появилась возможность использовать более привычный синтаксис на основе ключевых слов) +- Реализованы итераторы +- Добавлен новый тип данных - рациональные числа не ограниченной точности +- Многострочные комментарии стали вложенными +- Имена встроенных типов переименованы с указанием размерности + +### Другие важные изменения +- Вместо использования gcc перешел на clang, а libffi заменена на JIT компиляцию вызова нативных функций +- В релиз добавленые бинарные сборки для Linux +- Начало портирования кода на Windows + + +## Релиз 0.1 (24.06.2022) - первая публичная версия +- Представление общей концепции языка +- Сборка тестов и примеров под Linux из исходников diff --git a/src/nbproject/Makefile-Debug.mk b/src/nbproject/Makefile-Debug.mk index 734317f4..202c4892 100644 --- a/src/nbproject/Makefile-Debug.mk +++ b/src/nbproject/Makefile-Debug.mk @@ -89,21 +89,11 @@ ${OBJECTDIR}/_ext/e16507f5/logger.o: ../contrib/logger/logger.cpp ${RM} "$@.d" $(COMPILE.cc) -g -DDEBUG -DLOG_LEVEL_NORMAL=LOG_LEVEL_DEBUG -DPDC_WIDE -I. -I.. -I../contrib/googletest/googletest -I../contrib/googletest/googletest/include -I../contrib/Lyra/include -I../contrib/libtorch/include/torch/csrc/api/include -I../contrib/libtorch/include -I../contrib/tensorboard_logger/include -std=c++14 -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/_ext/e16507f5/logger.o ../contrib/logger/logger.cpp -temp/syntax.temp.txt: ../docs/op_iterator.md ../docs/syntax.md - ${MKDIR} -p temp - @echo Выполнение шага пользовательского сборки - mkdir temp || pandoc -t plain ../docs/syntax.md > temp/syntax.temp.txt - temp/syntax.temp.txt: ../docs/syntax.md ../docs/syntax.md ${MKDIR} -p temp @echo Выполнение шага пользовательского сборки mkdir temp || pandoc -t plain ../docs/syntax.md > temp/syntax.temp.txt -temp/syntax.temp.txt: ../docs/version.md ../docs/syntax.md - ${MKDIR} -p temp - @echo Выполнение шага пользовательского сборки - mkdir temp || pandoc -t plain ../docs/syntax.md > temp/syntax.temp.txt - ${OBJECTDIR}/builtin.o: builtin.cpp parser.h parser.yy.h pch.h.gch location.hh ${MKDIR} -p ${OBJECTDIR} ${RM} "$@.d" @@ -287,8 +277,6 @@ ${OBJECTDIR}/version.o: version.cpp .clean-conf: ${CLEAN_SUBPROJECTS} ${RM} -r ${CND_BUILDDIR}/${CND_CONF} ${RM} temp/syntax.temp.txt - ${RM} temp/syntax.temp.txt - ${RM} temp/syntax.temp.txt ${RM} ${RM} ${RM} diff --git a/src/nbproject/Makefile-Debug_LLVM.mk b/src/nbproject/Makefile-Debug_LLVM.mk index d6152f08..21ece6b6 100644 --- a/src/nbproject/Makefile-Debug_LLVM.mk +++ b/src/nbproject/Makefile-Debug_LLVM.mk @@ -74,7 +74,7 @@ FFLAGS= ASFLAGS= # Link Libraries and Options -LDLIBSOPTIONS=-L../contrib/libtorch/lib -Wl,-rpath,'../contrib/libtorch/lib' -lc10 -ltorch_cpu -lcrypto +LDLIBSOPTIONS=-L../contrib/libtorch/lib -Wl,-rpath,'.' -Wl,-rpath,'../contrib/libtorch/lib' -lc10 -ltorch_cpu -lcrypto # Build Targets .build-conf: ${BUILD_SUBPROJECTS} diff --git a/src/nbproject/Makefile-UnitTest_LLVM.mk b/src/nbproject/Makefile-UnitTest_LLVM.mk index 88f764d9..666de0a8 100644 --- a/src/nbproject/Makefile-UnitTest_LLVM.mk +++ b/src/nbproject/Makefile-UnitTest_LLVM.mk @@ -75,7 +75,7 @@ FFLAGS= ASFLAGS= # Link Libraries and Options -LDLIBSOPTIONS=-L../contrib/libtorch/lib -L/usr/lib/x86_64-linux-gnu -Wl,-rpath,'../contrib/libtorch/lib' -Wl,-rpath,'/usr/lib/x86_64-linux-gnu' -lpthread -lc10 -ltorch -ltorch_cpu -lcrypto +LDLIBSOPTIONS=-L../contrib/libtorch/lib -L/usr/lib/x86_64-linux-gnu -Wl,-rpath,'.' -Wl,-rpath,'../contrib/libtorch/lib' -Wl,-rpath,'/usr/lib/x86_64-linux-gnu' -lpthread -lc10 -ltorch -ltorch_cpu -lcrypto # Build Targets .build-conf: ${BUILD_SUBPROJECTS} diff --git a/src/nbproject/configurations.xml b/src/nbproject/configurations.xml index a038f1de..1961dae2 100644 --- a/src/nbproject/configurations.xml +++ b/src/nbproject/configurations.xml @@ -5,9 +5,11 @@ ../docs/CNAME ../docs/_config.yml ../docs/index.md - ../docs/op_iterator.md + ../docs/iterators.md + ../docs/ops.md ../docs/syntax.md - ../docs/version.md + ../docs/types.md + ../docs/versions.md - - - mkdir temp || pandoc -t plain ../docs/syntax.md > temp/syntax.temp.txt - temp/syntax.temp.txt - ../docs/syntax.md - + + + @@ -217,12 +216,9 @@ - - - mkdir temp || pandoc -t plain ../docs/syntax.md > temp/syntax.temp.txt - temp/syntax.temp.txt - ../docs/syntax.md - + + + @@ -498,6 +494,7 @@ ../contrib/libtorch/lib + . ../contrib/libtorch/lib @@ -528,13 +525,17 @@ - + + + - + + + @@ -781,13 +782,17 @@ - + + + - + + + @@ -991,7 +996,9 @@ - + + + @@ -1001,7 +1008,9 @@ syntax_help.cpp - + + + @@ -1279,6 +1288,7 @@ /usr/lib/x86_64-linux-gnu + . ../contrib/libtorch/lib /usr/lib/x86_64-linux-gnu @@ -1312,13 +1322,17 @@ - + + + - + + + @@ -1607,13 +1621,17 @@ - + + + - + + + @@ -1869,13 +1887,17 @@ - + + + - + + + @@ -2127,13 +2149,17 @@ - + + + - + + + @@ -2374,13 +2400,17 @@ - + + + - + + + @@ -2685,13 +2715,17 @@ - + + + - + + +