From 17e7f3092a4d29ffe19f6789982901f1d046f5fd Mon Sep 17 00:00:00 2001 From: bialger Date: Fri, 5 Sep 2025 17:01:48 +0300 Subject: [PATCH 01/21] chore: update .gitignore to include additional directories and file types Add matches for build artifacts, IDE configurations, temporary files, and cache directories. --- .gitignore | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/.gitignore b/.gitignore index 50c98fc..ce2ca85 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ # CMake **cmake-build*/ +build/ # All idea files **.idea*/ @@ -10,6 +11,15 @@ # IntelliJ **out/ +# Visual Studio Code +**.vscode/ +**.history/ + +# Clangd +compile_commands.json +compile_flags.txt +.clangd + # mpeltonen/sbt-idea plugin **.idea_modules/ @@ -22,6 +32,18 @@ crashlytics.properties crashlytics-build.properties fabric.properties +# Notepad++ temporary file +*.bak + +# API keys +*.apikey + +# Cache directories +**cache*/ + +# Program settings files +**.config*/compiler/* + # Prerequisites *.d From ac63f0cc3565822a3f7cfea699199d4fb357f5e3 Mon Sep 17 00:00:00 2001 From: bialger Date: Fri, 5 Sep 2025 17:30:05 +0300 Subject: [PATCH 02/21] chore: update CI workflow to use 'ovum' targets Refactor the CI configuration to replace 'cpp_tests' with 'ovum' for building and running the main application and tests. This includes updates to the build commands and executable names in both release and debug configurations. --- .github/workflows/ci_tests.yml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/ci_tests.yml b/.github/workflows/ci_tests.yml index a670a69..b46f230 100644 --- a/.github/workflows/ci_tests.yml +++ b/.github/workflows/ci_tests.yml @@ -18,23 +18,23 @@ jobs: - name: Build main target shell: bash run: | - cmake --build cmake-build-release --target cpp_tests || echo Built with errors + cmake --build cmake-build-release || echo Built with errors - name: Build tests target shell: bash run: | - cmake --build cmake-build-debug --target cpp_tests_tests || echo Built with errors + cmake --build cmake-build-debug --target ovum_tests || echo Built with errors - name: Run program working-directory: .\cmake-build-release run: | - .\cpp_tests.exe --help + .\ovum.exe --help - name: Run tests working-directory: .\cmake-build-debug run: | echo "Currently unable to run tests on Windows Latest MinGW. See https://gitmemories.com/cristianadam/HelloWorld/issues/12 and https://github.com/microsoft/vscode-cmake-tools/issues/2451" - % .\cpp_tests_tests.exe + % .\ovum_tests.exe build-matrix: name: Tests and application run on ${{ matrix.config.name }} @@ -72,22 +72,22 @@ jobs: - name: Build main target shell: bash run: | - cmake --build cmake-build-release --target cpp_tests || echo "Built with errors" + cmake --build cmake-build-release --target ovum || echo "Built with errors" - name: Build tests target shell: bash run: | - cmake --build cmake-build-debug --target cpp_tests_tests || echo "Built with errors" + cmake --build cmake-build-debug --target ovum_tests || echo "Built with errors" - name: Run program shell: bash working-directory: ./cmake-build-release run: | if [ "$RUNNER_OS" == "Windows" ]; then - ./cpp_tests.exe --help + ./ovum.exe --help else cd bin - ./cpp_tests --help + ./ovum --help fi - name: Run tests @@ -95,10 +95,10 @@ jobs: working-directory: ./cmake-build-debug run: | if [ "$RUNNER_OS" == "Windows" ]; then - ./cpp_tests_tests.exe + ./ovum_tests.exe else cd tests - ./cpp_tests_tests + ./ovum_tests fi memory-leaks: @@ -117,9 +117,9 @@ jobs: - name: Build tests target run: | - cmake --build cmake-build --target cpp_tests_tests + cmake --build cmake-build --target ovum_tests - name: Run valgrind working-directory: ./cmake-build/tests run: | - valgrind --leak-check=full --track-origins=yes --error-exitcode=1 ./cpp_tests_tests + valgrind --leak-check=full --track-origins=yes --error-exitcode=1 ./ovum_tests From 4bbd4e46dff0e9e57e1ce1e0aff0366d0cc6e754 Mon Sep 17 00:00:00 2001 From: bialger Date: Sat, 6 Sep 2025 19:22:52 +0300 Subject: [PATCH 03/21] docs: add build instructions, code of conduct, and coding guidelines Introduce comprehensive documentation for the Ovum programming language, including build instructions in BUILD.md, a Code of Conduct in CODE_OF_CONDUCT.md, and coding guidelines in CODING_GUIDELINES.md. Update README.md to reflect the new structure and provide an overview of the language's features and syntax. --- BUILD.md | 58 +++++ CODE_OF_CONDUCT.md | 66 ++++++ CODING_GUIDELINES.md | 338 +++++++++++++++++++++++++++ README.md | 529 ++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 961 insertions(+), 30 deletions(-) create mode 100644 BUILD.md create mode 100644 CODE_OF_CONDUCT.md create mode 100644 CODING_GUIDELINES.md diff --git a/BUILD.md b/BUILD.md new file mode 100644 index 0000000..37e38cd --- /dev/null +++ b/BUILD.md @@ -0,0 +1,58 @@ +# Build instructions for Ovum toolset + +This documents describes build process for Ovum programming language toolset and tests. + +## How to build and run + +Run the following commands from the project directory. + +1. Create CMake cache + +```shell +cmake -S . -B cmake-build +``` + +2. Build all targets + +```shell +cmake --build cmake-build +``` + +4. Run main executable + +* On Windows: + +```shell +.\cmake-build\ovum.exe +``` + +* On *nix: + +```shell +./cmake-build/bin/ovum World +``` + +5. Run tests + +* On Windows: + +```shell +.\cmake-build\ovum_tests.exe +``` + +* On *nix: + +```shell +./cmake-build/tests/ovum_tests +``` + +6. Installation + +Running this script will build and install Ovum main executable at `$HOME/ovum`. +Define `$SAVE_PREV` environment variable to save previous configuration. + +> There is only a shell script, so on Windows one should use Git Bash. + +```shell +./install.sh +``` \ No newline at end of file diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..4f1bc20 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,66 @@ +# Кодекс поведения участников Соглашения + +## Наше обещание + +В интересах создания открытой и доброжелательной среды мы, как участники и сопровождающие, обязуемся сделать участие в +нашем проекте и нашем сообществе свободным от преследований для всех, независимо от возраста, размера тела, +инвалидности, этнической принадлежности, половых характеристик, гендерной идентичности, самовыражение, уровня опыта, +образования, социально-экономического статус, национальности, внешнего вида, расы, религии или сексуальной идентичности +и ориентации. + +## Наши стандарты + +Примеры поведения, которое способствует созданию благоприятной среды, включают: + +- Использование приветливого и инклюзивного языка +- Уважительное отношение к различным точкам зрения и опыту +- Изящно принимаю конструктивную критику +- Сосредоточение внимания на том, что лучше для сообщества +- Проявление сочувствия к другим членам сообщества + +Примеры недопустимого поведения участников включают: + +- Использование сексуализированной лексики или образов и нежелательное сексуальное внимание или заигрывания +- Троллинг, оскорбительные / уничижительные комментарии, а также личные или политические нападки +- Публичное или частное преследование +- Публикация частной информации других лиц, такой как физический или электронный адрес, без явного разрешения +- Другое поведение, которое можно обоснованно считать неуместным в профессиональной среде. + +## Наши обязанности + +Сопровождающие проекта несут ответственность за разъяснение стандартов приемлемого поведения и от них ожидают принятия +соответствующих и справедливых корректирующих действий в ответ на любые случаи неприемлемого поведения. + +Сопровождающие проекта имеют право и обязаны удалять, редактировать или отклонять комментарии, коммиты, код, правки +вики, проблемы и другие материалы, которые не соответствуют настоящему Кодексу поведения, или временно или навсегда +заблокировать любого участника за другое поведение, которое они считают неуместным, угрожающим, оскорбительным или +вредным. + +## Сфера + +Этот Кодекс поведения применяется как в проектных, так и в общественных местах, когда человек представляет проект или +его сообщество. Примеры представления проекта или сообщества включают использование официального адреса электронной +почты проекта, размещение сообщений через официальную учетную запись в социальных сетях или выполнение функций +назначенного представителя на онлайн- или офлайн-мероприятии. Представление проекта может быть дополнительно определено +и уточнено сопровождающими проекта. + +## Исполнение + +О случаях оскорбления, преследования или иного недопустимого поведения можно сообщить, связавшись с командой проекта по +адресу [bigulov.sasha@gmail.com](mailto:bigulov.sasha@gmail.com). Все жалобы будут рассмотрены и исследованы, и в результате будет дан ответ, который будет +сочтен необходимым и соответствующим обстоятельствам. Команда проекта обязана сохранять конфиденциальность в отношении +лица, сообщившего об инциденте. Более подробная информация о конкретных правилах применения может быть опубликована +отдельно. + +Сопровождающие проекта, которые не соблюдают и не соблюдают Кодекс поведения добросовестно, могут столкнуться с +временными или постоянными последствиями, как это определено другими членами руководства проекта. + +## Атрибуция + +Этот Кодекс поведения адаптирован из [Соглашения для авторов], версия 1.4, доступного по +адресу https://www.contributor-covenant.org/version/1/4/code-of-conduct.html. + +Ответы на распространенные вопросы об этом кодексе поведения см. https://www.contributor-covenant.org/faq. + + +[Соглашения для авторов]: https://www.contributor-covenant.org \ No newline at end of file diff --git a/CODING_GUIDELINES.md b/CODING_GUIDELINES.md new file mode 100644 index 0000000..ff68d33 --- /dev/null +++ b/CODING_GUIDELINES.md @@ -0,0 +1,338 @@ +# Style guide + +В этом документе будут собраны все примеры правильного форматирования кода нашего проекта. + +В основном следует придерживаться [Google Code Style](https://google.github.io/styleguide/cppguide.html). +При противоречии стоит придерживаться этого документа. +Есть файл [ClangFormat](.clang-format), который можно использовать для автоматического форматирования кода. + +### 1. Максимальная длина строки кода — 80 символов. + +### 2. Используем пробелы, не табы. Настройте в своей среде разработки на 2 пробела. + +### 3. Пишем названия переменных, используя snake_case, а для названий функций — PascalCase: + +```c++ +int32_t MakingSomeStuff() { + ... +} + +int main() { + int32_t some_value = 144; + std::string person_name = "Alice"; + std::string base = "we_will_rock_you"; +} +``` + +**НО!** Когда речь идёт о названии классов/перечислений/структур/etc, мы используем PascalCase. + +**При этом!** Если мы создаем объект класса, мы используем snake_case. +Если это приватное или защищенное поле — ставим нижнее подчеркивание в конце. +Константы пишем в PascalCase, но с префиксом `k`. + +```c++ +class SomeClass { +public: + SomeClass(); + void DoSomeStuff(); + int32_t some_value; + static const int32_t kSomeFixedValue = 10; +private: + int32_t some_value_; +}; + +enum Role { + kOfficer = 0, + kPostman, + kWaiter, + kBooster +} + +struct UsersData { + std::string name[3]; + uint32_t age; + Role role; +} +``` + +### 4. Используем тип фиксированной длины. Например, `int32_t` вместо `int`, `uint64_t` вместо `unsigned long`. + +### 5. Мы допускаем использование auto только: +* При создании через явный вызов конструктора или ином явном указании типа +* При tuple unpacking + +**В ИНОМ СЛУЧАЕ — ИЗБЕГАЕМ** + +### 6. Стиль скобок: +При создании новых классов/функций/структур/перечислений/лямбд/etc, определение и скобка на одной строке: + +```c++ +struct TypicalExperimentData { + short num_of_experiment; + int32_t weights[10]; + float temperatures[5]; +}; + +void DoSomeGreatStuff() { + if (true) { + std::cout << "Hello, world!"; + } else { + std::cout << "What a wonderful world!"; + } +} + +int main() { + return 0; +} +``` + +### 7. Переводы строк: + +* После каждой функции, класса, структуры, перечисления, лямбды, etc. +* До и после каждого блока кода внутри функции — всего, что обрамлено фигурными скобками, например, `for` или `if`. +* Между переменными, если они не связаны между собой. +* Между `#include` и кодом. +* Перед `return` в функции. +* Перед квалификаторами доступа в классе, кроме первого. + +*GodObject.hpp* +```c++ +class GodObject { // Обратите внимание на порядок квалификаторов доступа +public: + GodObject(); + ~GodObject(); + int32_t GetSomeValue(); + int32_t CalculateSomething(); + int32_t field; + +protected: + int32_t some_value_; + +private: + int32_t another_value_; +} +``` + +*GodObject.cpp* +```c++ +#include "GodObject.hpp" + +GodObject::GodObject() : some_value_(0), another_value_(0) {} + +GodObject::~GodObject() {} + +int32_t GodObject::GetSomeValue() { + return some_value_; +} + +int32_t GodObject::CalculateSomething() { + int32_t sum = 0; + + for (int32_t i = 0; i < 10; ++i) { + sum += i; + } + + return sum * another_value_; +} +``` + +### 8. Образование названий: + +* ***Функции*** называем по их действию — например, если функция что-то "ищет": ```float FindMatrixDeterminant``` + +Иными словами, следует использовать соответствующий глагол. + +Например, если мы делаем игру — допустим, змейку. У нас есть пользователь и счёт. +В данном случае мы можем описать пользователя с помощью класса и сделать как минимум 2 публичные функции: + +```c++ +float Player::CalculateScore() { + ... +} +``` + +Название должно быть, насколько это возможно, **понятным**, **коротким**, и **интуитивным** для любого человека, работающего с проектом. +Следует держать баланс между понятностью и длиной названия: не стоит давать названия более 20 символов и 4 слов. +Аббревиатуры следует применять только если они общеприняты (например, название формата данных), и при использовании писать строчными буквами. + +* Называем переменные **нормально, то есть осмысленно**: + +```c++ +int a = 12; // ПЛОХО! + +int drops_count = 12; // Более ли менее понятно, о чём идёт речь +``` + +Никаких i, j, k, a, fizz, buzz, etc... + +Глобальные переменные не используем. +Если переменная используется в нескольких функциях, то она должна быть передана в качестве аргумента. + + +* Называем классы с помощью существительных. К примеру: + +```c++ +class Engine { + ... +} + +class TableInfo{ + ... +} + +class AbstactMixer { + ... +} +``` + +* Структуры называем так же, как и классы: + +```c++ +struct List { + int8_t item; + float* pf; + List* next; +}; + +struct TypicalExperimentData { + int16_t num_of_experiment; + int32_t weights[10]; + float temperatures[3]; +}; +``` + +* Концепты называем прилагательными: + +```c++ +template +concept Numeric = std::is_arithmetic_v; +``` + +### 9. Делим логику (определение), записанную в `.cpp` и объявление функции записанное в `.hpp` соответственно +Например: + +*main.cpp* +```c++ +#include "my_func.hpp" + +int main() { + Square(10); + return 0; +} +``` +* Используем include guards! + +*my_func.hpp* +```c++ +#ifndef MYFUNC_HPP +#define MYFUNC_HPP + +void Square(int32_t); + +#endif // MYFUNC_HPP +``` + +* Про `include`: + * Все внешние библиотеки подключаем через `#include <...>`, а все наши файлы через `#include "..."`. + * Все `include` пишем в начале файла. + * Все `include` пишем в алфавитном порядке. + * Все `include` пишем в следующем порядке, каждая категория разделяется пустой строкой: + * Сначала стандартная библиотека + * Затем внешние библиотеки + * Затем другие наши библиотеки + * Затем заголовочные файлы текущей библиотеки + +*my_func.cpp* +```c++ +#include + +#include + +#include + +#include "my_func.hpp" + +int Square(int32_t a) { + return a * a; +} +``` + +### 10. Организация хранения исходного кода. + +Для хранения данных, как-либо связанных с определёнными объектами, используются классы. +В классах описывается модель объекта, поля, хранящие данные, и методы для взаимодействия с данным объектом. +При этом сначала описывается структура класса в .hpp файле, а затем описывается реализация методов в .cpp файле. +Исключений нет, даже конструкторы считаются. +Структуры используем только как DTO (Data Transfer Object). + +> В отличие от Google Code Style, мы называем заголовочные файлы так же, как и классы, которые они описывают. +> При этом файлы, которые содержат реализацию методов класса, называем так же, как и заголовочные файлы, но с расширением .cpp. +> А вот файлы, где лежат только функции, называем в snake_case по общему назначению. + +***Правило:*** один класс — один заголовочный файл. + +*IdealGas.hpp* +```c++ +class IdealGas { +public: + IdealGas(double t = 0.0, double n = 0.0, double v = 0.0, double p = 0.0); + double GetP(); + double GetT(); + double GetV(); + double GetN(); + double CalculateR(); + +private: + double t_; + double n_; + double p_; + double v_; +}; +``` + +*IdealGas.cpp* +```c++ +#include "IdealGas.hpp" + +IdealGas::IdealGas(double t, double n, double v, double p) : t_(t), n_(n), v_(v), p_(p) {} + +double IdealGas::GetP() { + return p_; +} + +// Реализация прочих методов класса +``` +При создании экземпляров классов используются smart pointers, где это возможно (чтобы избежать утечек памяти): + +```c++ +#include + +int main() { + std::unique_ptr ideal_gas; + ideal_gas = std::make_unique(10.0, 10.0, 10.0, 10.0); + // Использование ideal_gas + ideal_gas = std::make_unique(20.0, 20.0, 20.0, 20.0); + + return 0; +} +``` + +> Стараемся использовать modern C++, например, почти всегда предпочитаем `std::array` вместо `char[N]`. + +#### О лямбда-функциях + +Используем лямбда-функции, когда это необходимо, но не злоупотребляем ими. +К примеру, когда надо захватить некий контекст, или когда надо сформировать очень краткую функцию, +которую надо куда-то передать. + +### 11. Организация передачи данных. + +Для передачи в функции используются ссылки и указатели на экземпляры классов, описывающих объекты, с которыми происходит взаимодействие: +* Правильно: +```c++ +void SetIdealGas(std::unique_ptr ideal_gas); +``` +* НЕПРАВИЛЬНО +```c++ +void SetIdealGase(double P, double V, double N, double T, double R, double x, double y, double z, double n, double m, double t); +``` diff --git a/README.md b/README.md index 465c79d..c0db241 100644 --- a/README.md +++ b/README.md @@ -1,56 +1,525 @@ -# C++ project template with Google Tests and CI/CD +# Ovum Programming Language -This is a project template. Feel free to use & fork it. It contains all pre-configured -CMakeLists.txt, so to use it, replace project name with your one in -[main CmakeLists.txt](CMakeLists.txt), and all target and executable names in -[CI/CD script](./.github/workflows/ci_tests.yml). Sample program prints a greeting for the first argument. +> This README describes **Ovum**: syntax & semantics, formal EBNF grammar, lexer & parser rules, runtime & VM requirements, unsafe operations, and code examples (snippets + a complete program). -## How to build and run +--- -Run the following commands from the project directory. +## 1) Overview -1. Create CMake cache +**Ovum** is a strongly **statically typed**, **single-threaded** language with modern, Kotlin-like syntax and a focus on safety, clarity, and performance. -```shell -cmake -S . -B cmake-build +Key design points: + +* **Strong static typing** with **immutability by default** (`mut` required for mutation). +* **Pure functions** (no side effects, VM-level result caching). +* **Classes & interfaces** + + * **No class inheritance**; classes only **implement interfaces**. + * **Every class implements `Object`** (root interface) implicitly; **all interfaces extend `Object`**. `Object` has **only a virtual destructor**. + * Interface methods are **virtual by default**; class methods that implement them must be marked `override`. +* **Namespaces** with `::` resolution (e.g., `sys::Print`). +* **Built-in operators**; **no user-defined operators**. +* **Preprocessor**: `#import`, `#define`, `#ifdef`, `#ifndef`, `#else`, `#undef`. +* **Managed runtime**: VM with **JIT** and **GC**; **no manual memory management**. +* **Single-threaded runtime**: no concurrency primitives. +* **Passing semantics**: all user-defined and non-primitive types (including `String` and all arrays) are **passed by reference** (const by default). + +### Standard Interfaces & Object Model + +* **`Object`**: root interface with **only a virtual destructor**. + + * All classes implement `Object` by default. + * All interfaces extend `Object`. + * Enables safe, uniform storage of user-defined types (e.g., in `ObjectArray`). +* Additional standard interfaces: + + * **`StringConvertible`** — `ToString(): String` + * **`Comparable`** — `IsLess(other: Object): Bool` + + * Required when user-defined types appear as parameters to **pure** functions (for stable ordering/keys). + * Implementations must validate and safely downcast `other` before using it. + * **`Hashable`** — `GetHash(): Int` + +> **Naming**: **Classes, functions, and methods use PascalCase** (e.g., `Main`, `ToString`, `IsLess`). Keywords/modifiers are lowercase (`class`, `interface`, `mut`, `override`, `pure`, etc.). + +--- + +## 2) Types + +### Primitive Types + +* `Int` (8 bytes) +* `Float` (8 bytes) +* `Bool` +* `Char` +* `Byte` +* `Pointer` *(only meaningful in `unsafe` code)* + +### Non-Primitive / Reference Types + +* `String` *(reference type; not primitive)* +* **Array classes (no templates / generics)**: + + * For primitives: `IntArray`, `FloatArray`, `BoolArray`, `CharArray`, `ByteArray`, `PointerArray` + * For objects: **`ObjectArray`** (stores elements of type `Object`) + * **Convenience**: `StringArray` (standard library class for arrays of `String`, commonly used for `Main` arguments) +* Containers `List`, `Map` may exist as reference types (non-primitive) in the stdlib (not templated in this version). + +> All non-primitive values are passed by link (reference), **const by default**. To mutate through a parameter, mark the parameter `mut` and ensure the underlying fields are `mut`. + +--- + +## 3) Syntax & Semantics (Description) + +### Declarations + +* **Functions**: `pure fun Name(params): ReturnType { ... }` + + * Pure functions: side-effect free; may be cached by the VM. + * If parameters include user-defined reference types, those types must implement **`Comparable`** (`IsLess`). +* **Variables**: immutable by default. Use `mut` to permit reassignment/mutation. +* **Classes**: `class Name implements IFace1, IFace2 { ... }` + + * No class inheritance. + * **Fields and methods must specify an access modifier** (`private` or `public`). + * **Fields use `let` or `mut`**: + + * `public let X: Int` — immutable field + * `private mut Count: Int` — mutable field + * Implementing interface methods must be marked `override`. + * `static` fields allowed; **`static mut` is unsafe** to write. +* **Interfaces**: `interface Name : Object { ... }` + + * **Methods are public**; access modifiers are not used in interfaces. + * Signatures only (no fields, no bodies); methods are implicitly virtual. + +### Namespaces & Preprocessor + +* Namespace resolution with `::` (e.g., `sys::Print`). +* Preprocessor directives: + + * `#import "path.ovm"` + * `#define NAME [value]` + * `#ifdef NAME` / `#ifndef NAME` / `#else` / `#endif` + * `#undef NAME` + +### Casting & Type Tests + +* **Upcasts** (e.g., `Derived` → `BaseInterface`/`Object`): **safe**. +* **Downcasts** (e.g., `Object`/interface → concrete class): **runtime-checked**. + + * Use explicit cast: `expr as TargetClass`. + * **If the downcast fails, an unhandleable error is raised (program abort).** + * **Before a downcast you must check**: `if (expr is TargetClass) { let v = expr as TargetClass; ... }` +* **ByteArray casts** (view of raw bytes): + + * **Unsafe cast of any value to (const) `ByteArray`**. + * **Unsafe cast of any value to mutable `ByteArray`** (mutable view). + * Both require `unsafe { ... }`, e.g., `unsafe { let bytes: ByteArray = value as ByteArray; }` +* **Explicit cast to `Bool`** is **safe**: + + * For primitives: `0`/`0.0`/`'\0'` → `false`; non-zero → `true`. + * For non-primitives: `true` iff the reference is a **valid** (non-null, live) object. +* **`is` type test**: `expr is Type` → `Bool` (must be used prior to downcasting). + +### Purity Rules (Summary) + +* **Pure** functions cannot: + + * Perform I/O, call impure/system/`unsafe` code. + * Mutate global or external state, return handles to newly allocated mutable state. +* For pure function parameters of user-defined class types, require **`Comparable`** (`IsLess(other: Object): Bool`) to enable stable ordering/keys. + +### Unsafe Blocks + +Operations only allowed in `unsafe { ... }`: + +* Declaring/writing **global `mut`** variables and **`static mut`** fields. +* Casting const → mutable. +* Using **`Pointer`**, address-of and dereference. +* **Manual destructor** calls. +* Any **`sys::Interope`** (FFI) call. +* Casting any type to **(const or mutable) `ByteArray`**. + +--- + +## 4) Formal Grammar (EBNF) + +> Core EBNF; whitespace/comments omitted. Operator precedence is in §5. + +```ebnf +Program ::= { Import | Conditional | GlobalDef } ; + +Import ::= "#import" StringLiteral ; +Define ::= "#define" Identifier [ NumberLiteral ] ; +Undef ::= "#undef" Identifier ; +Conditional ::= "#ifdef" Identifier { GlobalDef | Import | Conditional } + [ "#else" { GlobalDef | Import | Conditional } ] "#endif" + | "#ifndef" Identifier { GlobalDef | Import | Conditional } + [ "#else" { GlobalDef | Import | Conditional } ] "#endif" ; + +GlobalDef ::= FunctionDecl | ClassDecl | InterfaceDecl | GlobalVarDecl ; + +FunctionDecl ::= [ "pure" ] "fun" Identifier "(" [ ParamList ] ")" [ ":" Type ] Block ; + +ParamList ::= Parameter { "," Parameter } ; +Parameter ::= [ "mut" ] Identifier ":" Type ; + +ClassDecl ::= "class" Identifier [ "implements" TypeList ] ClassBody ; +TypeList ::= Type { "," Type } ; +ClassBody ::= "{" { ClassMember } "}" ; +ClassMember ::= FieldDecl | StaticFieldDecl | MethodDecl ; + +FieldDecl ::= ( "private" | "public" ) ( "let" | "mut" ) Identifier ":" Type [ "=" Expression ] ";" ; +StaticFieldDecl ::= "static" ( "private" | "public" ) ( "let" | "mut" ) Identifier ":" Type [ "=" Expression ] ";" ; + +MethodDecl ::= ( "private" | "public" ) [ "override" ] [ "pure" ] + "fun" Identifier "(" [ ParamList ] ")" [ ":" Type ] ( Block | ";" ) ; + +InterfaceDecl ::= "interface" Identifier ":" "Object" InterfaceBody ; +InterfaceBody ::= "{" { InterfaceMethod } "}" ; +InterfaceMethod ::= "fun" Identifier "(" [ ParamList ] ")" [ ":" Type ] ";" ; // public & virtual by default + +GlobalVarDecl ::= [ "mut" ] Identifier ":" Type "=" Expression ";" ; + +Type ::= PrimitiveType + | "String" + | "IntArray" | "FloatArray" | "BoolArray" | "CharArray" | "ByteArray" | "PointerArray" + | "ObjectArray" + | "StringArray" + | Identifier ; // class/interface names (non-primitive) + +PrimitiveType ::= "Int" | "Float" | "Bool" | "Char" | "Byte" | "Pointer" ; + +Block ::= "{" { Statement } "}" ; +Statement ::= VarDeclStmt | ExprStmt | ReturnStmt | IfStmt | WhileStmt | ForStmt | UnsafeStmt | Block ; + +VarDeclStmt ::= [ "mut" ] Identifier ":" Type "=" Expression ";" ; +ExprStmt ::= Expression ";" ; +ReturnStmt ::= "return" [ Expression ] ";" ; +IfStmt ::= "if" "(" Expression ")" Statement [ "else" Statement ] ; +WhileStmt ::= "while" "(" Expression ")" Statement ; +ForStmt ::= "for" "(" Identifier "in" Expression ")" Statement ; +UnsafeStmt ::= "unsafe" Block ; + +Expression ::= Assignment ; +Assignment ::= OrExpr [ "=" Assignment ] ; +OrExpr ::= AndExpr { "||" AndExpr } ; +AndExpr ::= EqualityExpr { "&&" EqualityExpr } ; +EqualityExpr ::= RelExpr { ("==" | "!=") RelExpr } ; +RelExpr ::= AddExpr { ("<" | "<=" | ">" | ">=") AddExpr } ; +AddExpr ::= MulExpr { ("+" | "-") MulExpr } ; +MulExpr ::= UnaryExpr { ("*" | "/" | "%") UnaryExpr } ; + +UnaryExpr ::= ("!" | "-" | "&" | "*") UnaryExpr + | Postfix ; + +Postfix ::= Primary { PostfixOp } ; +PostfixOp ::= "." Identifier + | "." Identifier "(" [ ArgList ] ")" + | "(" [ ArgList ] ")" + | "as" Type // explicit cast + | "is" Type // type test → Bool + ; + +Primary ::= Identifier + | Literal + | "(" Expression ")" + | NamespaceRef ; + +NamespaceRef ::= Identifier "::" Identifier ; +ArgList ::= Expression { "," Expression } ; + +Literal ::= NumberLiteral | StringLiteral | CharLiteral | "true" | "false" ; ``` -2. Build executable target +> Notes +> +> * **No templates**; array types are concrete classes (`IntArray`, `ObjectArray`, etc.). +> * `String`/all arrays are **reference** (non-primitive) types. +> * `is` and `as` are part of expressions (type test & cast). + +--- -```shell -cmake --build cmake-build --target cpp_tests +## 5) Lexer & Parser Rules + +### Tokens + +* **Identifiers**: `[A-Za-z_][A-Za-z0-9_]*` (case-sensitive). Style: **PascalCase** for classes/functions/methods. +* **Literals**: integers, floats, chars (`'A'`, escapes), strings (`"..."`, escapes). +* **Operators/Punct**: `+ - * / %`, `== != < <= > >=`, `&& || !`, `=`, `.`, `::`, `,`, `;`, `:`, `(` `)` `{` `}`. + +### Comments & Whitespace + +* Line: `// ...` +* Block: `/* ... */` (non-nested) +* Whitespace separates tokens; not otherwise significant. + +### Precedence & Associativity (high → low) + +1. Unary: `!` `-` `&` `*` (right; `&`/`*` only in `unsafe`) +2. Multiplicative: `*` `/` `%` (left) +3. Additive: `+` `-` (left) +4. Relational: `<` `<=` `>` `>=` (left) +5. Equality: `==` `!=` (left) +6. Logical AND: `&&` (left) +7. Logical OR: `||` (left) +8. Assignment: `=` (right) + +> **No user-defined operators**. + +--- + +## 6) Runtime, VM & Platform Support + +* **Execution**: Source → bytecode → **Ovum VM**. +* **JIT**: Hot paths compiled to native for performance. +* **GC**: Automatic memory reclamation; **no manual memory management**. +* **Single-threaded**: Execution model and VM are single-threaded. +* **Architectures**: **amd64** and **arm64** supported. +* **Numeric widths**: `Int` **8 bytes**, `Float` **8 bytes**. + +--- + +## 7) System Library & Interop + +* `sys::Print(msg: String): Void` +* `sys::Time(): Int` +* `sys::Sleep(ms: Int): Void` +* `sys::Exit(code: Int): Never` *(terminates the process)* +* **Interop (FFI)**: + + * `sys::Interope(dllName: String, functionName: String, input: ByteArray, output: ByteArray): Int` + * **All interop calls are `unsafe`.** + +> Names use **PascalCase** (e.g., `Print`, `Time`, `Sleep`, `Exit`, `Interope`). Namespace remains `sys`. + +--- + +## 8) Unsafe Operations (Recap) + +Allowed **only** inside `unsafe { ... }`: + +* Declaring/writing **global `mut`** variables and **`static mut`** fields. +* Casting const → mutable. +* Using **`Pointer`**, address-of and dereference. +* **Manual destructor** calls. +* Any **`sys::Interope`** invocation. +* Casting any value to **(const or mutable) `ByteArray`**. + +--- + +## 9) Code Examples + +### 9.1 Entry Point (`StringArray`) + +```ovum +// Standard library provides StringArray (array of String). +fun Main(args: StringArray): Int { + if (args.Length() == 0) { + sys::Print("Hello, Ovum!"); + return 0; + } + + sys::Print("Args count: " + args.Length().ToString()); + // Example access (APIs are illustrative): + // let first: String = args.Get(0); + return 0; +} ``` -3. Build tests target +### 9.2 Variables & Immutability -```shell -cmake --build cmake-build --target cpp_tests_tests +```ovum +fun DemoVariables(): Void { + value: Int = 10; // immutable local + mut counter: Int = 0; // mutable local + + counter = counter + value; + sys::Print("Counter = " + counter.ToString()); +} ``` -4. Run executable target +### 9.3 Interfaces, Classes, Fields, and Overrides + +```ovum +interface Greeter : Object { + fun Greet(name: String): String; // public by default +} + +class FriendlyGreeter implements Greeter { + private let Prefix: String = "Hello"; + public mut Suffix: String = "!"; + + // Constructor pattern (returns this for chaining) + public fun FriendlyGreeter(prefix: String, suffix: String): FriendlyGreeter { + this.Prefix = prefix; + this.Suffix = suffix; + return this; + } -* On Windows: + public override fun Greet(name: String): String { + return Prefix + ", " + name + Suffix; + } -```shell -.\cmake-build\cpp_tests.exe World + public fun CasualGreet(name: String): String { + return "Hi, " + name; + } +} + +fun DemoGreeter(): Void { + let g: Greeter = FriendlyGreeter("Good morning", "!"); + sys::Print(g.Greet("Ovum")); +} ``` -* On *nix: +### 9.4 Standard Interfaces (`StringConvertible`, `Comparable`, `Hashable`) + +```ovum +interface StringConvertible : Object { + fun ToString(): String; +} + +interface Comparable : Object { + fun IsLess(other: Object): Bool; +} -```shell -./cmake-build/bin/cpp_tests World +interface Hashable : Object { + fun GetHash(): Int; +} + +class Point implements StringConvertible, Comparable, Hashable { + public let X: Int + public let Y: Int + + public fun Point(x: Int, y: Int): Point { this.X = x; this.Y = y; return this; } + + public override fun ToString(): String { + return "(" + X.ToString() + ", " + Y.ToString() + ")"; + } + + public override fun IsLess(other: Object): Bool { + if (!(other is Point)) { return false; } // required check before downcast + let p: Point = other as Point; // safe after 'is' + if (this.X != p.X) return this.X < p.X; + return this.Y < p.Y; + } + + public override fun GetHash(): Int { + return (X * 1315423911) ^ (Y * 2654435761); + } +} +``` + +### 9.5 Pure Functions with Caching + +```ovum +pure fun Fib(n: Int): Int { + if (n <= 1) return n; + return Fib(n - 1) + Fib(n - 2); +} +// For user-defined reference types as parameters, ensure they implement Comparable. ``` -5. Run tests +### 9.6 `is`, `as`, and ByteArray Casts -* On Windows: +```ovum +fun DemoCasts(obj: Object): Void { + // Upcast (implicit) and downcast (explicit) + if (obj is Point) { + let p: Point = obj as Point; // safe after 'is' + sys::Print(p.ToString()); + } else { + // obj as Point; // would abort program (unhandleable) if uncommented + } -```shell -.\cmake-build\cpp_tests_tests.exe + // Explicit Bool cast + let b1: Bool = 0 as Bool; // false + let b2: Bool = 42 as Bool; // true + let b3: Bool = obj as Bool; // true if obj is a valid, live reference + + // Unsafe: view any value as bytes + unsafe { + let cview: ByteArray = obj as ByteArray; // const byte view + let mview: ByteArray = (obj as mut ByteArray); // mutable byte view + // ... use cview/mview ... + } +} ``` -* On *nix: +### 9.7 Unsafe + Interop Example + +```ovum +fun DemoInterope(): Void { + let text: String = "Hello"; + let inBytes: ByteArray = text.ToUtf8NullTerminated(); + let outBytes: ByteArray = ByteArray(8); // reserve space if C func writes a 64-bit result + + unsafe { + let status: Int = sys::Interope("libc.so", "puts", inBytes, outBytes); + // Handle status / parse outBytes... + } +} +``` + +### 9.8 Full Example Program + +```ovum +#define GREET_FEATURE + +interface Runner : Object { fun Run(): Int; } -```shell -./cmake-build/tests/cpp_tests_tests +class App implements Runner, StringConvertible { + private let Name: String + + public fun App(name: String): App { this.Name = name; return this; } + + public override fun ToString(): String { return "App(" + Name + ")"; } + + public override fun Run(): Int { + #ifdef GREET_FEATURE + sys::Print("Welcome, " + Name + "!"); + #else + sys::Print("Running..."); + #endif + return 0; + } +} + +pure fun Add(a: Int, b: Int): Int { return a + b; } + +// Entry point with StringArray +fun Main(args: StringArray): Int { + let app: Runner = App("Ovum"); + sys::Print("App info: " + (app as App).ToString()); + + sys::Print("2 + 3 = " + Add(2, 3).ToString()); + return app.Run(); +} ``` + +--- + +## 10) Build & Run (Conceptual) + +1. **Compile** `.ovum` sources → Ovum bytecode (with preprocessing) using Ovum runner. +2. **Execute** on the Ovum VM (single-threaded): + + * Bytecode interpretation → JIT-optimized native where hot. + * GC manages memory automatically. + * Entry function: `Main(args: StringArray): Int`. + +--- + +## 11) Notes & Best Practices + +* Prefer **immutable** data; use `mut` only when necessary. +* Implement **`StringConvertible`** for diagnostics (`ToString`). +* When using **pure functions** with custom types, implement **`Comparable`**. +* Avoid global `mut`; if necessary, **isolate in `unsafe`** with rationale. +* Keep names **PascalCase** for classes/functions/methods; keep **keywords lowercase**. +* `String` and all array classes are **reference (non-primitive)** types. + +--- + +*© Ovum Project. Licensed under GNU GPLv3 (see separate LICENSE).* From 88ff9fa8cf72d53e8b706bd956c1192b1507677e Mon Sep 17 00:00:00 2001 From: bialger Date: Sat, 6 Sep 2025 19:23:02 +0300 Subject: [PATCH 04/21] chore: add .clang-format and .clang-tidy configuration files Introduce .clang-format for consistent C++ code styling based on Google style guidelines, and .clang-tidy for static analysis checks focusing on modern C++ practices, performance, and core guidelines. --- .clang-format | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++ .clang-tidy | 20 ++++++++++++ 2 files changed, 107 insertions(+) create mode 100644 .clang-format create mode 100644 .clang-tidy diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..9b23e67 --- /dev/null +++ b/.clang-format @@ -0,0 +1,87 @@ +--- +Language: Cpp +BasedOnStyle: Google +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignOperands: true +AlignTrailingComments: true +AllowShortBlocksOnASingleLine: Never +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: None +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakTemplateDeclarations: Yes +BinPackArguments: false +BinPackParameters: false +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: false + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + BeforeLambdaBody: false + BeforeWhile: false + SplitEmptyFunction: false + SplitEmptyRecord: false + SplitEmptyNamespace: false + AfterObjCDeclaration: false + IndentBraces: false +BreakBeforeBraces: Custom +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: AfterColon +BreakConstructorInitializersBeforeComma: false +ColumnLimit: 120 +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ContinuationIndentWidth: 4 +EmptyLineAfterAccessModifier: Never +EmptyLineBeforeAccessModifier: LogicalBlock +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^<.*' + Priority: 1 + - Regex: '^".*' + Priority: 2 + - Regex: '.*' + Priority: 3 +IncludeIsMainRegex: ([-_](test|unittest))?$'([-_](test|unittest))?$' +IndentCaseBlocks: false +IndentCaseLabels: true +IndentGotoLabels: true +IndentPPDirectives: None +IndentWidth: 2 +IndentWrappedFunctionNames: false +InsertNewlineAtEOF: true +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +PointerAlignment: Left +SpaceAfterCStyleCast: true +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: true +SpaceBeforeSquareBrackets: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInConditionalStatement: false +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +TabWidth: 4 +UseTab: Never +... diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 0000000..e46b6ed --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,20 @@ +Checks: '-*, + modernize-*, + performance-*, + cppcoreguidelines-*, + bugprone-*, + -modernize-use-trailing-return-type, + -performance-no-int-to-ptr, + -cppcoreguidelines-avoid-const-or-ref-data-members, + -cppcoreguidelines-pro-type-reinterpret-cast, + -cppcoreguidelines-pro-type-union-access, + -cppcoreguidelines-pro-bounds-pointer-arithmetic, + -bugprone-exception-escape, + -bugprone-easily-swappable-parameters' + +WarningsAsErrors: '' +HeaderFilterRegex: '' +FormatStyle: none +CheckOptions: + - key: modernize-use-using.IgnoreMacros + value: 'true' From 62c0cae683570adbf0f1fe56b17f0cd2928cb530 Mon Sep 17 00:00:00 2001 From: bialger Date: Sat, 6 Sep 2025 19:23:23 +0300 Subject: [PATCH 05/21] chore: rename project to 'ovum' and update related configurations Change project name from 'cpp_tests' to 'ovum' across CMakeLists.txt, install script, and related build configurations. Adjust output directories and build types for better organization and clarity. Clean up unnecessary conditions and improve script handling for configuration directories. --- CMakeLists.txt | 22 +++++++++++++--------- bin/CMakeLists.txt | 12 +++++------- install.sh | 27 ++++++++++++++++++++++----- lib/CMakeLists.txt | 8 +------- lib/mylib/CMakeLists.txt | 1 - lib/ui/CMakeLists.txt | 1 - tests/CMakeLists.txt | 8 ++------ 7 files changed, 43 insertions(+), 36 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c03953b..87075f6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,30 +1,34 @@ cmake_minimum_required(VERSION 3.12) project( - cpp_tests # Rename the project here and in ci_tests.yml - VERSION 0.1 - DESCRIPTION "C++ Project with Google tests" - LANGUAGES CXX + ovum + VERSION 0.1 + DESCRIPTION "Ovum programming language toolset" + LANGUAGES CXX ) set(CMAKE_CXX_STANDARD 20) -if (WIN32) # Install dlls in the same directory as the executable on Windows +if(WIN32) # Install dlls in the same directory as the executable on Windows set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR}) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR}) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR}) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR}) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR}) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR}) -endif () +endif() -if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release) +endif() + +if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") set(CMAKE_CXX_FLAGS_DEBUG "/MDd") set(CMAKE_CXX_FLAGS_RELEASE "/O2") -else () +else() set(CMAKE_CXX_FLAGS_DEBUG "-g") set(CMAKE_CXX_FLAGS_RELEASE "-O3") -endif () +endif() add_subdirectory(lib) add_subdirectory(bin) diff --git a/bin/CMakeLists.txt b/bin/CMakeLists.txt index c84570b..e9bb8f8 100644 --- a/bin/CMakeLists.txt +++ b/bin/CMakeLists.txt @@ -1,13 +1,11 @@ -add_executable(${PROJECT_NAME} main.cpp) - -if (NOT CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE Release) # Main executable should be built with Release -endif () +add_executable(${PROJECT_NAME} + main.cpp +) message(STATUS "Main executable build type: ${CMAKE_BUILD_TYPE}") target_link_libraries(${PROJECT_NAME} PUBLIC - ui + ui ) -target_include_directories(${PROJECT_NAME} PUBLIC ${PROJECT_SOURCE_DIR}) \ No newline at end of file +target_include_directories(${PROJECT_NAME} PUBLIC ${PROJECT_SOURCE_DIR}) diff --git a/install.sh b/install.sh index db58cdc..20157b9 100644 --- a/install.sh +++ b/install.sh @@ -1,14 +1,20 @@ #!/bin/sh OS_NAME="$(cmake -P ./PrintOS.cmake 2>&1)" -PROJECT_NAME="cpp_tests" +PROJECT_NAME="ovum" CMAKE_BUILD_DIR="$HOME/CMakeBuilds" CMAKE_PROJECT_DIR="$CMAKE_BUILD_DIR/$PROJECT_NAME" +LOCAL_CONFIG_DIR="./.config" +CONFIG_DIR="$HOME/.config/$PROJECT_NAME" if [ "x$SAVE_PREV" = "x" ]; then if [ -e "$CMAKE_PROJECT_DIR" ]; then rm -rf "$CMAKE_PROJECT_DIR" fi + + if [ -e "$CONFIG_DIR" ]; then + rm -rf "$CONFIG_DIR" + fi fi EXEC_EXTENSION=".exe" @@ -24,7 +30,14 @@ fi EXEC_LINK_PATH="$HOME/$PROJECT_NAME$EXEC_EXTENSION" +git config --replace-all pack.windowMemory 10m +git config --replace-all pack.packSizeLimit 20m + if (cmake -S . -B "$CMAKE_PROJECT_DIR" -DCMAKE_BUILD_TYPE=Release -G "Unix Makefiles" && cmake --build "$CMAKE_PROJECT_DIR" --target "$PROJECT_NAME"); then + if [ "x$SAVE_PREV" = "x" ]; then + cp -rf "$LOCAL_CONFIG_DIR" "$CONFIG_DIR" + fi + rm -f "$EXEC_LINK_PATH" ln -s "$EXEC_PATH" "$EXEC_LINK_PATH" echo '' @@ -38,6 +51,7 @@ if (cmake -S . -B "$CMAKE_PROJECT_DIR" -DCMAKE_BUILD_TYPE=Release -G "Unix Makef if [ "$OS_NAME" = "Linux" ]; then printf 'Do you want to add this utility to /usr/bin (y/n)? ' && read -r CHOISE COMMON_LINK_PATH="/usr/bin/${PROJECT_NAME:?}" + COMMON_CONFIG_DIR="/etc/${PROJECT_NAME:?}" COMMON_PROJECT_DIR="/opt/${PROJECT_NAME:?}" COMMON_EXEC_PATH="$COMMON_PROJECT_DIR/bin/$PROJECT_NAME" @@ -45,12 +59,17 @@ if (cmake -S . -B "$CMAKE_PROJECT_DIR" -DCMAKE_BUILD_TYPE=Release -G "Unix Makef sudo -S rm -f "$COMMON_LINK_PATH" if (sudo ln -s "$EXEC_PATH" "$COMMON_LINK_PATH"); then + if [ -e "$COMMON_CONFIG_DIR" ]; then + sudo rm -rf "$COMMON_CONFIG_DIR" + fi + if [ -e "$COMMON_PROJECT_DIR" ]; then sudo rm -rf "$COMMON_PROJECT_DIR" fi sudo rm -f "$COMMON_LINK_PATH" sudo cp -r "$CMAKE_PROJECT_DIR" "$COMMON_PROJECT_DIR" + sudo cp -r "$LOCAL_CONFIG_DIR" "$COMMON_CONFIG_DIR" sudo ln -s "$COMMON_EXEC_PATH" "$COMMON_LINK_PATH" echo "Accepted, run utility with $PROJECT_NAME" else @@ -72,12 +91,10 @@ if (cmake -S . -B "$CMAKE_PROJECT_DIR" -DCMAKE_BUILD_TYPE=Release -G "Unix Makef echo "Because of Windows-specific limitations, it is not possible to create a link to it." echo "You can run it from $HOME/$PROJECT_NAME as .\\$PROJECT_NAME$EXEC_EXTENSION" echo "Or you can run CMD.EXE with administrative privileges and type: " - echo 'mklink "%userprofile%\cpp_tests.exe" "%userprofile%\cpp_tests\cpp_tests.exe"' + echo 'mklink "%userprofile%\ovum.exe" "%userprofile%\ovum\ovum.exe"' echo '' mkdir "$HOME/$PROJECT_NAME" cp "$CMAKE_PROJECT_DIR/$PROJECT_NAME$EXEC_EXTENSION" "$HOME/$PROJECT_NAME/$PROJECT_NAME$EXEC_EXTENSION" - # ALso copy all *dll files like following: - # cp -r "$CMAKE_PROJECT_DIR/liblib.dll" "$HOME/$PROJECT_NAME/liblib.dll" cd "$HOME/$PROJECT_NAME" && "./$PROJECT_NAME$EXEC_EXTENSION" -h exit 0 else @@ -87,4 +104,4 @@ if (cmake -S . -B "$CMAKE_PROJECT_DIR" -DCMAKE_BUILD_TYPE=Release -G "Unix Makef else echo 'Error occurred during running CMake. Make sure that it is installed and configured properly.' exit 1 -fi +fi \ No newline at end of file diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 4da245d..b55ff1b 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -1,10 +1,4 @@ -cmake_minimum_required(VERSION 3.12) - -if (NOT CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE Debug) # Change this to Release when you're ready to release -endif () - -message(STATUS "Libraries build type: ${CMAKE_BUILD_TYPE}") +cmake_minimum_required(VERSION 3.25) add_subdirectory(mylib) add_subdirectory(ui) diff --git a/lib/mylib/CMakeLists.txt b/lib/mylib/CMakeLists.txt index 8671cd4..cab79c1 100644 --- a/lib/mylib/CMakeLists.txt +++ b/lib/mylib/CMakeLists.txt @@ -1,4 +1,3 @@ add_library(mylib STATIC MyClass.cpp - MyClass.hpp ) diff --git a/lib/ui/CMakeLists.txt b/lib/ui/CMakeLists.txt index 1260da9..f0ae4f7 100644 --- a/lib/ui/CMakeLists.txt +++ b/lib/ui/CMakeLists.txt @@ -1,6 +1,5 @@ add_library(ui STATIC ui_functions.cpp - ui_functions.hpp ) target_link_libraries(ui PUBLIC diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 3edea0a..93fc839 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -23,20 +23,16 @@ add_executable( ) target_link_libraries( - ${PROJECT_NAME}_tests # link used libraries from lib directory + ${PROJECT_NAME}_tests ui mylib GTest::gtest_main ) -if (NOT CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE Debug) # Tests should be built with Debug -endif () - message(STATUS "Tests build type: ${CMAKE_BUILD_TYPE}") target_include_directories(${PROJECT_NAME}_tests PUBLIC ${PROJECT_SOURCE_DIR}) include(GoogleTest) -gtest_discover_tests(${PROJECT_NAME}_tests) \ No newline at end of file +gtest_discover_tests(${PROJECT_NAME}_tests) From 7fdd857e7b6cef58d6a02f6bc6d46fd5a783bb83 Mon Sep 17 00:00:00 2001 From: bialger Date: Sun, 7 Sep 2025 17:26:48 +0300 Subject: [PATCH 06/21] docs: enhance README.md with detailed language features and nullability support Update the README to provide a comprehensive overview of the Ovum programming language, including new sections on nullable types, functional objects, and detailed syntax rules. Clarify naming conventions and access modifiers, and improve examples to illustrate language capabilities. Adjust structure for better readability and understanding of key concepts. --- README.md | 483 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 254 insertions(+), 229 deletions(-) diff --git a/README.md b/README.md index c0db241..89f0dce 100644 --- a/README.md +++ b/README.md @@ -1,46 +1,48 @@ # Ovum Programming Language -> This README describes **Ovum**: syntax & semantics, formal EBNF grammar, lexer & parser rules, runtime & VM requirements, unsafe operations, and code examples (snippets + a complete program). +> This README (for `.ovum` sources) describes **Ovum**: syntax & semantics, nullable types, formal EBNF grammar, lexer & parser rules, runtime & VM requirements, unsafe operations, casting, functional objects, and code examples (snippets + a complete program). --- ## 1) Overview -**Ovum** is a strongly **statically typed**, **single-threaded** language with modern, Kotlin-like syntax and a focus on safety, clarity, and performance. +**Ovum** is a strongly **statically typed**, **single-threaded** language with Kotlin-like syntax and a focus on safety, clarity, and performance. Key design points: * **Strong static typing** with **immutability by default** (`mut` required for mutation). +* **Nullable types** and Kotlin-style null-handling: `Type?`, safe calls `?.`, Elvis `?:`, non-null assertion `!!`. * **Pure functions** (no side effects, VM-level result caching). * **Classes & interfaces** * **No class inheritance**; classes only **implement interfaces**. - * **Every class implements `Object`** (root interface) implicitly; **all interfaces extend `Object`**. `Object` has **only a virtual destructor**. - * Interface methods are **virtual by default**; class methods that implement them must be marked `override`. + * **Root `Object`** is implicit for all classes and interfaces (no need to write `: Object`). It declares only a **virtual destructor**. + * Interfaces are named with **leading `I`** (C# style): e.g., `IGreeter`, `IComparable`. + * Interface methods are **public** and **virtual** by default. + * Class methods implementing interface members must be marked `override`. + * **Access modifiers are mandatory** for all fields and methods in classes (`public`/`private`). + * **Fields use `let` (immutable) or `mut` (mutable)**. * **Namespaces** with `::` resolution (e.g., `sys::Print`). * **Built-in operators**; **no user-defined operators**. * **Preprocessor**: `#import`, `#define`, `#ifdef`, `#ifndef`, `#else`, `#undef`. * **Managed runtime**: VM with **JIT** and **GC**; **no manual memory management**. * **Single-threaded runtime**: no concurrency primitives. * **Passing semantics**: all user-defined and non-primitive types (including `String` and all arrays) are **passed by reference** (const by default). +* **File extension**: `.ovum`. ### Standard Interfaces & Object Model -* **`Object`**: root interface with **only a virtual destructor**. +* **`Object`**: implicit root; has only a **virtual destructor**. + Enables safe, uniform storage (e.g., in `ObjectArray`). +* Standard interfaces (all implicitly extend `Object`): - * All classes implement `Object` by default. - * All interfaces extend `Object`. - * Enables safe, uniform storage of user-defined types (e.g., in `ObjectArray`). -* Additional standard interfaces: + * **`IStringConvertible`** — `ToString(): String` + * **`IComparable`** — `IsLess(other: Object): Bool` - * **`StringConvertible`** — `ToString(): String` - * **`Comparable`** — `IsLess(other: Object): Bool` + * Required for user-defined types used as parameters to **pure** functions (stable ordering/keys). + * **`IHashable`** — `GetHash(): Int` - * Required when user-defined types appear as parameters to **pure** functions (for stable ordering/keys). - * Implementations must validate and safely downcast `other` before using it. - * **`Hashable`** — `GetHash(): Int` - -> **Naming**: **Classes, functions, and methods use PascalCase** (e.g., `Main`, `ToString`, `IsLess`). Keywords/modifiers are lowercase (`class`, `interface`, `mut`, `override`, `pure`, etc.). +> **Naming**: **Classes, functions, methods use PascalCase** (e.g., `Main`, `ToString`, `IsLess`). Keywords/modifiers remain lowercase (`class`, `interface`, `mut`, `override`, `pure`, `unsafe`, etc.). --- @@ -55,97 +57,145 @@ Key design points: * `Byte` * `Pointer` *(only meaningful in `unsafe` code)* +> Any primitive may have a **nullable** counterpart via `?` (e.g., `Int?`). + ### Non-Primitive / Reference Types * `String` *(reference type; not primitive)* -* **Array classes (no templates / generics)**: +* **Array classes (no templates / generics):** * For primitives: `IntArray`, `FloatArray`, `BoolArray`, `CharArray`, `ByteArray`, `PointerArray` - * For objects: **`ObjectArray`** (stores elements of type `Object`) - * **Convenience**: `StringArray` (standard library class for arrays of `String`, commonly used for `Main` arguments) -* Containers `List`, `Map` may exist as reference types (non-primitive) in the stdlib (not templated in this version). + * For objects: **`ObjectArray`** + * **Convenience**: `StringArray` (array of `String`, used for `Main`) -> All non-primitive values are passed by link (reference), **const by default**. To mutate through a parameter, mark the parameter `mut` and ensure the underlying fields are `mut`. +> All non-primitive values are passed by link (reference), **const by default**. --- -## 3) Syntax & Semantics (Description) +## 3) Nullability & Boolean Logic -### Declarations +### Nullability (Kotlin-style) -* **Functions**: `pure fun Name(params): ReturnType { ... }` +* Append `?` to make a type **nullable**: `Int?`, `String?`, `Point?`. +* **Safe call**: `expr?.Method()` calls only if `expr != null`; otherwise yields `null` (if the method returns a reference type) or a sensible default for chaining to Elvis. + Example: `name?.ToString()?.Length() ?: 0` +* **Elvis**: `a ?: b` evaluates to `a` if non-null, else `b`. +* **Non-null assertion**: `x!!` throws an unhandleable error if `x == null`. +* **Cast to Bool**: any value can be explicitly cast to `Bool`. - * Pure functions: side-effect free; may be cached by the VM. - * If parameters include user-defined reference types, those types must implement **`Comparable`** (`IsLess`). -* **Variables**: immutable by default. Use `mut` to permit reassignment/mutation. -* **Classes**: `class Name implements IFace1, IFace2 { ... }` + * Primitives: zero → `false`, non-zero → `true`. + * Non-primitives: `true` iff the reference is a valid (non-null, live) object. - * No class inheritance. - * **Fields and methods must specify an access modifier** (`private` or `public`). - * **Fields use `let` or `mut`**: +### Boolean Logic - * `public let X: Int` — immutable field - * `private mut Count: Int` — mutable field - * Implementing interface methods must be marked `override`. - * `static` fields allowed; **`static mut` is unsafe** to write. -* **Interfaces**: `interface Name : Object { ... }` +* **Short-circuit**: `&&`, `||` (like Kotlin/Java). +* **Negation**: `!cond`. +* **XOR**: `xor` infix on `Bool` (e.g., `a xor b`). + (Also `==`/`!=` for equality/inequality of Booleans.) - * **Methods are public**; access modifiers are not used in interfaces. - * Signatures only (no fields, no bodies); methods are implicitly virtual. +--- -### Namespaces & Preprocessor +## 4) Casting & Type Tests -* Namespace resolution with `::` (e.g., `sys::Print`). -* Preprocessor directives: +* **Upcasts** (to `Object` or an implemented interface): **safe**, non-nullable result. +* **Downcasts** (to a concrete class or more specific interface): **nullable** result. - * `#import "path.ovm"` - * `#define NAME [value]` - * `#ifdef NAME` / `#ifndef NAME` / `#else` / `#endif` - * `#undef NAME` + * `obj as Foo` has type `Foo?`; it yields `null` if `obj` is not a `Foo`. + * Use `!!` to assert non-null (aborts if `null`) or `?:` to handle null. + * **Guideline**: Prefer `if (obj is Foo) { val f = (obj as Foo)!!; ... }`. +* **Type test**: `expr is Type` → `Bool` (use before downcasting). +* **Byte view casts**: -### Casting & Type Tests + * **Unsafe** cast of any value to **(const) `ByteArray`**. + * **Unsafe** cast of any value to **mutable `ByteArray`**. + * Require `unsafe { ... }`. -* **Upcasts** (e.g., `Derived` → `BaseInterface`/`Object`): **safe**. -* **Downcasts** (e.g., `Object`/interface → concrete class): **runtime-checked**. +--- - * Use explicit cast: `expr as TargetClass`. - * **If the downcast fails, an unhandleable error is raised (program abort).** - * **Before a downcast you must check**: `if (expr is TargetClass) { let v = expr as TargetClass; ... }` -* **ByteArray casts** (view of raw bytes): +## 5) Syntax & Semantics (Description) - * **Unsafe cast of any value to (const) `ByteArray`**. - * **Unsafe cast of any value to mutable `ByteArray`** (mutable view). - * Both require `unsafe { ... }`, e.g., `unsafe { let bytes: ByteArray = value as ByteArray; }` -* **Explicit cast to `Bool`** is **safe**: +### Functions - * For primitives: `0`/`0.0`/`'\0'` → `false`; non-zero → `true`. - * For non-primitives: `true` iff the reference is a **valid** (non-null, live) object. -* **`is` type test**: `expr is Type` → `Bool` (must be used prior to downcasting). +* Declared with `fun`, PascalCase names: `fun Compute(a: Int): Int { ... }` +* **Pure** functions: `pure fun Hash(o: Object): Int { ... }` -### Purity Rules (Summary) + * Side-effect free; VM may cache results. + * If parameters include user-defined reference types, those types must implement **`IComparable`**. -* **Pure** functions cannot: +### Classes - * Perform I/O, call impure/system/`unsafe` code. - * Mutate global or external state, return handles to newly allocated mutable state. -* For pure function parameters of user-defined class types, require **`Comparable`** (`IsLess(other: Object): Bool`) to enable stable ordering/keys. +* `class Name implements IFace1, IFace2 { ... }` -### Unsafe Blocks + * **No class inheritance**. + * **Access modifiers are mandatory** on fields and methods. + * **Fields** use `let` (immutable) or `mut` (mutable): -Operations only allowed in `unsafe { ... }`: + * `private let Prefix: String` + * `public mut Count: Int` + * **Methods** must declare access and can be `override`/`pure`: -* Declaring/writing **global `mut`** variables and **`static mut`** fields. -* Casting const → mutable. -* Using **`Pointer`**, address-of and dereference. -* **Manual destructor** calls. -* Any **`sys::Interope`** (FFI) call. -* Casting any type to **(const or mutable) `ByteArray`**. + * `public override fun Run(): Int { ... }` + * **Static** fields supported; **writing `static mut` is unsafe**. + * **Destructor**: optional, overrides the implicit virtual destructor from `Object`. + + * Syntax: `public destructor(): Void { ... }` (no parameters, no return). + * Called automatically by GC finalization; **manual calls are unsafe**. + +### Interfaces + +* `interface IGreeter { fun Greet(name: String): String; }` + + * Methods are **public** and **virtual** by default. + * No fields, no bodies. + +### Namespaces & Preprocessor + +* Namespace resolution with `::` (e.g., `sys::Print`). +* Preprocessor: `#import`, `#define`, `#ifdef`, `#ifndef`, `#else`, `#undef`. + +### Functional Objects (`call`) + +* Classes can declare a **special `call`** member that makes instances **callable** like functions. +* If a class **declares `call`**, it **may have other members**. +* If a class **does not declare `call`**, it **must not have any non-`call` members** (i.e., it must be purely functional). +* A function literal `fun(...) : T { ... }` can be **coerced** to a class type that exposes a compatible `call(...) : T`. + +Example: + +```ovum +class CustomFunctional { + public call(a: Int?, b: Int?): Int +} + +class DefinedFunctional { + public mut Multiplier: Int + + public fun DefinedFunctional(multiplier: Int): DefinedFunctional { + this.Multiplier = multiplier + return this + } + + // Defines the callable behavior; pure body allowed + public call(secondMultiplier: Int): Int = pure fun(secondMultiplier: Int): Int { + return Multiplier * secondMultiplier + } +} + +let AddNullable: CustomFunctional = fun(a: Int?, b: Int?): Int { + return (a ?: 0) + (b ?: 0) +} + +fun Main(args: StringArray): Int { + // Constructor call then functional call via `call` + return AddNullable(2, DefinedFunctional(-1)(2)) +} +``` --- -## 4) Formal Grammar (EBNF) +## 6) Formal Grammar (EBNF) -> Core EBNF; whitespace/comments omitted. Operator precedence is in §5. +> Core EBNF; whitespace/comments omitted. Operator precedence in §7. ```ebnf Program ::= { Import | Conditional | GlobalDef } ; @@ -153,22 +203,21 @@ Program ::= { Import | Conditional | GlobalDef } ; Import ::= "#import" StringLiteral ; Define ::= "#define" Identifier [ NumberLiteral ] ; Undef ::= "#undef" Identifier ; -Conditional ::= "#ifdef" Identifier { GlobalDef | Import | Conditional } +Conditional ::= "#ifdef" Identifier { GlobalDef | Import | Conditional } [ "#else" { GlobalDef | Import | Conditional } ] "#endif" - | "#ifndef" Identifier { GlobalDef | Import | Conditional } + | "#ifndef" Identifier { GlobalDef | Import | Conditional } [ "#else" { GlobalDef | Import | Conditional } ] "#endif" ; GlobalDef ::= FunctionDecl | ClassDecl | InterfaceDecl | GlobalVarDecl ; FunctionDecl ::= [ "pure" ] "fun" Identifier "(" [ ParamList ] ")" [ ":" Type ] Block ; - ParamList ::= Parameter { "," Parameter } ; Parameter ::= [ "mut" ] Identifier ":" Type ; ClassDecl ::= "class" Identifier [ "implements" TypeList ] ClassBody ; TypeList ::= Type { "," Type } ; ClassBody ::= "{" { ClassMember } "}" ; -ClassMember ::= FieldDecl | StaticFieldDecl | MethodDecl ; +ClassMember ::= FieldDecl | StaticFieldDecl | MethodDecl | DestructorDecl ; FieldDecl ::= ( "private" | "public" ) ( "let" | "mut" ) Identifier ":" Type [ "=" Expression ] ";" ; StaticFieldDecl ::= "static" ( "private" | "public" ) ( "let" | "mut" ) Identifier ":" Type [ "=" Expression ] ";" ; @@ -176,13 +225,17 @@ StaticFieldDecl ::= "static" ( "private" | "public" ) ( "let" | "mut" ) Identifi MethodDecl ::= ( "private" | "public" ) [ "override" ] [ "pure" ] "fun" Identifier "(" [ ParamList ] ")" [ ":" Type ] ( Block | ";" ) ; -InterfaceDecl ::= "interface" Identifier ":" "Object" InterfaceBody ; +DestructorDecl ::= ( "private" | "public" ) "destructor" "(" ")" ":" "Void" Block ; + +InterfaceDecl ::= "interface" Identifier InterfaceBody ; // implicitly extends Object InterfaceBody ::= "{" { InterfaceMethod } "}" ; -InterfaceMethod ::= "fun" Identifier "(" [ ParamList ] ")" [ ":" Type ] ";" ; // public & virtual by default +InterfaceMethod ::= "fun" Identifier "(" [ ParamList ] ")" [ ":" Type ] ";" ; // public & virtual GlobalVarDecl ::= [ "mut" ] Identifier ":" Type "=" Expression ";" ; -Type ::= PrimitiveType +Type ::= NullableType | NonNullType ; +NullableType ::= NonNullType "?" ; +NonNullType ::= PrimitiveType | "String" | "IntArray" | "FloatArray" | "BoolArray" | "CharArray" | "ByteArray" | "PointerArray" | "ObjectArray" @@ -203,9 +256,14 @@ ForStmt ::= "for" "(" Identifier "in" Expression ")" Statement ; UnsafeStmt ::= "unsafe" Block ; Expression ::= Assignment ; -Assignment ::= OrExpr [ "=" Assignment ] ; +Assignment ::= ElvisExpr [ "=" Assignment ] ; + +ElvisExpr ::= OrExpr [ "?:" ElvisExpr ] ; // right-assoc + OrExpr ::= AndExpr { "||" AndExpr } ; -AndExpr ::= EqualityExpr { "&&" EqualityExpr } ; +AndExpr ::= XorExpr { "&&" XorExpr } ; +XorExpr ::= EqualityExpr { "xor" EqualityExpr } ; + EqualityExpr ::= RelExpr { ("==" | "!=") RelExpr } ; RelExpr ::= AddExpr { ("<" | "<=" | ">" | ">=") AddExpr } ; AddExpr ::= MulExpr { ("+" | "-") MulExpr } ; @@ -217,15 +275,20 @@ UnaryExpr ::= ("!" | "-" | "&" | "*") UnaryExpr Postfix ::= Primary { PostfixOp } ; PostfixOp ::= "." Identifier | "." Identifier "(" [ ArgList ] ")" - | "(" [ ArgList ] ")" - | "as" Type // explicit cast - | "is" Type // type test → Bool + | "(" [ ArgList ] ")" // function call or callable object + | "as" Type // explicit cast; downcast yields nullable type + | "is" Type // type test → Bool + | "!!" // non-null assertion + | "?." Identifier [ "(" [ ArgList ] ")" ] // safe call chain ; Primary ::= Identifier | Literal | "(" Expression ")" - | NamespaceRef ; + | NamespaceRef + | FunctionLiteral ; + +FunctionLiteral ::= "fun" "(" [ ParamList ] ")" [ ":" Type ] Block ; NamespaceRef ::= Identifier "::" Identifier ; ArgList ::= Expression { "," Expression } ; @@ -233,21 +296,23 @@ ArgList ::= Expression { "," Expression } ; Literal ::= NumberLiteral | StringLiteral | CharLiteral | "true" | "false" ; ``` -> Notes -> -> * **No templates**; array types are concrete classes (`IntArray`, `ObjectArray`, etc.). -> * `String`/all arrays are **reference** (non-primitive) types. -> * `is` and `as` are part of expressions (type test & cast). - --- -## 5) Lexer & Parser Rules +## 7) Lexer & Parser Rules ### Tokens * **Identifiers**: `[A-Za-z_][A-Za-z0-9_]*` (case-sensitive). Style: **PascalCase** for classes/functions/methods. -* **Literals**: integers, floats, chars (`'A'`, escapes), strings (`"..."`, escapes). -* **Operators/Punct**: `+ - * / %`, `== != < <= > >=`, `&& || !`, `=`, `.`, `::`, `,`, `;`, `:`, `(` `)` `{` `}`. +* **Literals**: integers, floats, chars (`'A'`, escapes), strings (`"..."`, escapes), Booleans. +* **Operators/Punct**: + + * Arithmetic: `+ - * / %` + * Comparison: `== != < <= > >=` + * Boolean: `&& || ! xor` + * Nulls: `?. ?: !!` + * Cast/Test: `as is` + * Call/Access: `. ( ) :: , ; : { } [ ]` + * Assignment: `=` ### Comments & Whitespace @@ -255,24 +320,27 @@ Literal ::= NumberLiteral | StringLiteral | CharLiteral | "true" | "fals * Block: `/* ... */` (non-nested) * Whitespace separates tokens; not otherwise significant. -### Precedence & Associativity (high → low) +### Precedence (high → low) -1. Unary: `!` `-` `&` `*` (right; `&`/`*` only in `unsafe`) -2. Multiplicative: `*` `/` `%` (left) -3. Additive: `+` `-` (left) -4. Relational: `<` `<=` `>` `>=` (left) -5. Equality: `==` `!=` (left) -6. Logical AND: `&&` (left) -7. Logical OR: `||` (left) -8. Assignment: `=` (right) +1. Postfix: member calls `.`, calls `()`, safe call `?.`, non-null `!!`, casts `as`, test `is` +2. Unary: `!` `-` `&` `*` (right; `&`/`*` only in `unsafe`) +3. Multiplicative: `*` `/` `%` (left) +4. Additive: `+` `-` (left) +5. Relational: `<` `<=` `>` `>=` (left) +6. Equality: `==` `!=` (left) +7. XOR: `xor` (left) +8. Logical AND: `&&` (left) +9. Logical OR: `||` (left) +10. Elvis: `?:` (right) +11. Assignment: `=` (right) > **No user-defined operators**. --- -## 6) Runtime, VM & Platform Support +## 8) Runtime, VM & Platform Support -* **Execution**: Source → bytecode → **Ovum VM**. +* **Execution**: Source (`.ovum`) → bytecode → **Ovum VM**. * **JIT**: Hot paths compiled to native for performance. * **GC**: Automatic memory reclamation; **no manual memory management**. * **Single-threaded**: Execution model and VM are single-threaded. @@ -281,7 +349,7 @@ Literal ::= NumberLiteral | StringLiteral | CharLiteral | "true" | "fals --- -## 7) System Library & Interop +## 9) System Library & Interop * `sys::Print(msg: String): Void` * `sys::Time(): Int` @@ -296,7 +364,7 @@ Literal ::= NumberLiteral | StringLiteral | CharLiteral | "true" | "fals --- -## 8) Unsafe Operations (Recap) +## 10) Unsafe Operations (Recap) Allowed **only** inside `unsafe { ... }`: @@ -309,217 +377,174 @@ Allowed **only** inside `unsafe { ... }`: --- -## 9) Code Examples +## 11) Code Examples -### 9.1 Entry Point (`StringArray`) +### 11.1 Entry point (`StringArray`) ```ovum -// Standard library provides StringArray (array of String). +// .ovum file fun Main(args: StringArray): Int { - if (args.Length() == 0) { - sys::Print("Hello, Ovum!"); - return 0; - } - - sys::Print("Args count: " + args.Length().ToString()); - // Example access (APIs are illustrative): - // let first: String = args.Get(0); - return 0; + val count: Int = args.Length() ?: 0 + sys::Print("Args count: " + count.ToString()) + return 0 } ``` -### 9.2 Variables & Immutability +### 11.2 Variables, Nulls, Elvis, Safe Calls ```ovum -fun DemoVariables(): Void { - value: Int = 10; // immutable local - mut counter: Int = 0; // mutable local +fun DemoNulls(): Void { + val a: Int? = null + val b: Int? = 5 + + val sum: Int = (a ?: 0) + (b ?: 0) // Elvis + sys::Print("Sum = " + sum.ToString()) - counter = counter + value; - sys::Print("Counter = " + counter.ToString()); + val name: String? = null + sys::Print("Name length = " + (name?.Length() ?: 0).ToString()) + + val mustNotBeNull: Int = (b!!) // ok + // val crash: Int = (a!!) // aborts (unhandleable) } ``` -### 9.3 Interfaces, Classes, Fields, and Overrides +### 11.3 Interfaces, Classes, Fields, Overrides ```ovum -interface Greeter : Object { - fun Greet(name: String): String; // public by default +interface IGreeter { + fun Greet(name: String): String // public + virtual by default } -class FriendlyGreeter implements Greeter { - private let Prefix: String = "Hello"; - public mut Suffix: String = "!"; +class FriendlyGreeter implements IGreeter { + private let Prefix: String = "Hello" + public mut Suffix: String = "!" - // Constructor pattern (returns this for chaining) public fun FriendlyGreeter(prefix: String, suffix: String): FriendlyGreeter { - this.Prefix = prefix; - this.Suffix = suffix; - return this; + this.Prefix = prefix + this.Suffix = suffix + return this } public override fun Greet(name: String): String { - return Prefix + ", " + name + Suffix; + return Prefix + ", " + name + Suffix } - public fun CasualGreet(name: String): String { - return "Hi, " + name; + // Optional destructor (finalization logic) + public destructor(): Void { + // release non-memory resources if any (files, handles, etc.) } } - -fun DemoGreeter(): Void { - let g: Greeter = FriendlyGreeter("Good morning", "!"); - sys::Print(g.Greet("Ovum")); -} ``` -### 9.4 Standard Interfaces (`StringConvertible`, `Comparable`, `Hashable`) +### 11.4 Standard Interfaces (`IStringConvertible`, `IComparable`, `IHashable`) ```ovum -interface StringConvertible : Object { - fun ToString(): String; -} - -interface Comparable : Object { - fun IsLess(other: Object): Bool; -} +interface IStringConvertible { fun ToString(): String } +interface IComparable { fun IsLess(other: Object): Bool } +interface IHashable { fun GetHash(): Int } -interface Hashable : Object { - fun GetHash(): Int; -} - -class Point implements StringConvertible, Comparable, Hashable { +class Point implements IStringConvertible, IComparable, IHashable { public let X: Int public let Y: Int public fun Point(x: Int, y: Int): Point { this.X = x; this.Y = y; return this; } public override fun ToString(): String { - return "(" + X.ToString() + ", " + Y.ToString() + ")"; + return "(" + X.ToString() + ", " + Y.ToString() + ")" } public override fun IsLess(other: Object): Bool { - if (!(other is Point)) { return false; } // required check before downcast - let p: Point = other as Point; // safe after 'is' - if (this.X != p.X) return this.X < p.X; - return this.Y < p.Y; + if (!(other is Point)) return false + val p: Point = (other as Point)!! // safe after is + !! + if (this.X != p.X) return this.X < p.X + return this.Y < p.Y } public override fun GetHash(): Int { - return (X * 1315423911) ^ (Y * 2654435761); + return (X * 1315423911) ^ (Y * 2654435761) } } ``` -### 9.5 Pure Functions with Caching +### 11.5 Pure Functions with Caching ```ovum pure fun Fib(n: Int): Int { - if (n <= 1) return n; - return Fib(n - 1) + Fib(n - 2); + if (n <= 1) return n + return Fib(n - 1) + Fib(n - 2) } -// For user-defined reference types as parameters, ensure they implement Comparable. +// For user-defined reference types as parameters, implement IComparable. ``` -### 9.6 `is`, `as`, and ByteArray Casts +### 11.6 `is`, `as`, `!!`, and ByteArray Casts ```ovum fun DemoCasts(obj: Object): Void { - // Upcast (implicit) and downcast (explicit) if (obj is Point) { - let p: Point = obj as Point; // safe after 'is' - sys::Print(p.ToString()); - } else { - // obj as Point; // would abort program (unhandleable) if uncommented + val p: Point = (obj as Point)!! // nullable cast + assert + sys::Print(p.ToString()) } - // Explicit Bool cast - let b1: Bool = 0 as Bool; // false - let b2: Bool = 42 as Bool; // true - let b3: Bool = obj as Bool; // true if obj is a valid, live reference + // Bool cast + val b1: Bool = (0 as Bool) // false + val b2: Bool = (42 as Bool) // true + val b3: Bool = (obj as Bool) // true if non-null - // Unsafe: view any value as bytes + // Unsafe: raw byte views unsafe { - let cview: ByteArray = obj as ByteArray; // const byte view - let mview: ByteArray = (obj as mut ByteArray); // mutable byte view - // ... use cview/mview ... + val bytesConst: ByteArray = (obj as ByteArray) + val bytesMut : ByteArray = (obj as mut ByteArray) } } ``` -### 9.7 Unsafe + Interop Example +### 11.7 Functional Objects (`call`) & Literals ```ovum -fun DemoInterope(): Void { - let text: String = "Hello"; - let inBytes: ByteArray = text.ToUtf8NullTerminated(); - let outBytes: ByteArray = ByteArray(8); // reserve space if C func writes a 64-bit result - - unsafe { - let status: Int = sys::Interope("libc.so", "puts", inBytes, outBytes); - // Handle status / parse outBytes... - } +class CustomFunctional { + public call(a: Int?, b: Int?): Int } -``` - -### 9.8 Full Example Program - -```ovum -#define GREET_FEATURE -interface Runner : Object { fun Run(): Int; } +class DefinedFunctional { + public mut Multiplier: Int -class App implements Runner, StringConvertible { - private let Name: String - - public fun App(name: String): App { this.Name = name; return this; } - - public override fun ToString(): String { return "App(" + Name + ")"; } + public fun DefinedFunctional(multiplier: Int): DefinedFunctional { + this.Multiplier = multiplier + return this + } - public override fun Run(): Int { - #ifdef GREET_FEATURE - sys::Print("Welcome, " + Name + "!"); - #else - sys::Print("Running..."); - #endif - return 0; + public call(secondMultiplier: Int): Int = pure fun(secondMultiplier: Int): Int { + return Multiplier * secondMultiplier } } -pure fun Add(a: Int, b: Int): Int { return a + b; } +let AddNullable: CustomFunctional = fun(a: Int?, b: Int?): Int { + return (a ?: 0) + (b ?: 0) +} -// Entry point with StringArray fun Main(args: StringArray): Int { - let app: Runner = App("Ovum"); - sys::Print("App info: " + (app as App).ToString()); - - sys::Print("2 + 3 = " + Add(2, 3).ToString()); - return app.Run(); + return AddNullable(2, DefinedFunctional(-1)(2)) } ``` --- -## 10) Build & Run (Conceptual) +## 12) Build & Run (Conceptual) -1. **Compile** `.ovum` sources → Ovum bytecode (with preprocessing) using Ovum runner. +1. **Compile** `.ovum` sources → Ovum bytecode (preprocessor applied). 2. **Execute** on the Ovum VM (single-threaded): - * Bytecode interpretation → JIT-optimized native where hot. + * Bytecode interpretation with JIT for hot paths. * GC manages memory automatically. * Entry function: `Main(args: StringArray): Int`. --- -## 11) Notes & Best Practices +## 13) Notes & Best Practices * Prefer **immutable** data; use `mut` only when necessary. -* Implement **`StringConvertible`** for diagnostics (`ToString`). -* When using **pure functions** with custom types, implement **`Comparable`**. +* Implement **`IStringConvertible`** for diagnostics (`ToString`). +* For **pure** functions with custom types, implement **`IComparable`**. * Avoid global `mut`; if necessary, **isolate in `unsafe`** with rationale. * Keep names **PascalCase** for classes/functions/methods; keep **keywords lowercase**. * `String` and all array classes are **reference (non-primitive)** types. - ---- - -*© Ovum Project. Licensed under GNU GPLv3 (see separate LICENSE).* From 26f3965f4a4e295e8ddd606a9cb5411f6f83e4c3 Mon Sep 17 00:00:00 2001 From: bialger Date: Sun, 7 Sep 2025 18:13:15 +0300 Subject: [PATCH 07/21] docs: add CODEBASE_STRUCTURE.md and CONTRIBUTING.md for project guidelines Introduce CODEBASE_STRUCTURE.md to outline the repository's structure and directory purposes. Add CONTRIBUTING.md to provide clear instructions for contributing to the project, including forking, branching, and commit message guidelines. Update README.md to reference these new documents for better onboarding and contribution clarity. --- CODEBASE_STRUCTURE.md | 52 +++++++++++++++++++++++++++++++++++++++++++ CONTRIBUTING.md | 41 ++++++++++++++++++++++++++++++++++ README.md | 5 ++++- 3 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 CODEBASE_STRUCTURE.md create mode 100644 CONTRIBUTING.md diff --git a/CODEBASE_STRUCTURE.md b/CODEBASE_STRUCTURE.md new file mode 100644 index 0000000..72ed35e --- /dev/null +++ b/CODEBASE_STRUCTURE.md @@ -0,0 +1,52 @@ +# Базовая структура репозитория + +Ниже описана структура репозитория + +``` +./ +├─ CMakeLists.txt # Корневой CMake-проект, подключает подпроекты +├─ PrintOS.cmake # Вспомогательные CMake-функции/макросы +├─ BUILD.md # Инструкции по сборке +├─ README.md # Обзор и быстрый старт +├─ CONTRIBUTING.md # Правила для участников +├─ CODE_OF_CONDUCT.md # Кодекс поведения +├─ CODING_GUIDELINES.md # Рекомендации по стилю кода +├─ CODEBASE_STRUCTURE.md # Этот документ +├─ LICENSE # Лицензия +├─ install.sh # Скрипт установки/подготовки окружения +├─ .clang-format # Настройки форматирования C/C++ +├─ .clang-tidy # Настройки статического анализа +├─ .gitignore # Правила игнорирования Git +├─ .github/ +│ └─ workflows/ +│ └─ ci_tests.yml # CI: сборка и прогон тестов +├─ bin/ +│ ├─ CMakeLists.txt +│ └─ main.cpp # Точка входа исполняемого файла +├─ lib/ +│ ├─ CMakeLists.txt +│ ├─ mylib/ +│ │ ├─ CMakeLists.txt +│ │ ├─ MyClass.hpp # Заголовок основной библиотеки +│ │ └─ MyClass.cpp # Реализация основной библиотеки +│ └─ ui/ +│ ├─ CMakeLists.txt +│ ├─ ui_functions.hpp # Интерфейс UI/CLI-утилит +│ └─ ui_functions.cpp # Реализация UI/CLI-утилит +└─ tests/ + ├─ CMakeLists.txt + ├─ main_test.cpp # Точка входа тестового раннера + ├─ ProjectIntegrationTestSuite.hpp + ├─ ProjectIntegrationTestSuite.cpp + ├─ test_functions.hpp # Вспомогательные функции для тестов + ├─ test_functions.cpp + └─ unit_tests.cpp # Модульные тесты +``` + +## Назначение директорий + +- bin: исполняемые цели приложения (CLI/демо), точка входа `main.cpp`. +- lib: исходники библиотек проекта (`mylib`, `ui`) и их `CMakeLists.txt`. +- tests: тестовые цели и исходники (модульные и интеграционные). +- .github/workflows: конфигурация CI для сборки и тестов. + diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..69493d7 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,41 @@ +# Руководство по участию + +- Пополнить The Documentation Compendium довольно просто. В этом документе показано, как начать работу + +## Общее + +- [Структура кодовой базы ](./CODEBASE_STRUCTURE.md) содержит подробную информацию о том, как структурированы различные файлы в этом проекте +- Пожалуйста, убедитесь, что любые внесенные вами изменения соответствуют [Гайдлайну по написанию кода](./CODING_GUIDELINES.md) этого репозитория + +## Отправка изменений + +- Сделайте форк репозитория (если вы не ключевой разработчик) + - [https://github.com/Ovum-Programming-Language/OvumLanguage/fork](https://github.com/Ovum-Programming-Language/OvumLanguage/fork) +- Проверьте новую ветку и назовите ее в соответствии с тем, что вы собираетесь делать: + - Пример: + ``` + $ git checkout -b BRANCH_NAME + ``` + Если вы получите сообщение об ошибке, вам может потребоваться сначала получить fooBar, используя + ``` + $ git remote update && git fetch + ``` + - Используйте одну ветку для каждого исправления / добавления +- Закоммитьте свои изменения + - Пожалуйста, предоставьте git сообщение, объясняющее, что вы сделали + - Пожалуйста, убедитесь, что ваши коммиты соответствуют [Semantic Commit Messages](https://seesparkbox.com/foundry/semantic_commit_messages) + - Закоммитьте в репозитории + - Пример: + ``` + $ git commit -am 'Add some fooBar' + ``` +- Запуште в ветку + - Пример: + ``` + $ git push origin BRANCH_NAME + ``` +- Сделать пул реквест + - Убедитесь, что вы отправили пул реквест в ветку fooBar + - Travis CI наблюдает за тобой! + +Если вы будете следовать этим инструкциям, ваш пул реквест довольно безопасно попадет в основной репозиторий! \ No newline at end of file diff --git a/README.md b/README.md index 89f0dce..6d5f166 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,9 @@ # Ovum Programming Language -> This README (for `.ovum` sources) describes **Ovum**: syntax & semantics, nullable types, formal EBNF grammar, lexer & parser rules, runtime & VM requirements, unsafe operations, casting, functional objects, and code examples (snippets + a complete program). +This README (for `.ovum` sources) describes **Ovum**: syntax & semantics, nullable types, formal EBNF grammar, lexer & parser rules, runtime & VM requirements, unsafe operations, casting, functional objects, and code examples (snippets + a complete program). + +If you want to contribute to the project, please read the [CONTRIBUTING.md](./CONTRIBUTING.md) file. +If you want to build the project, please read the [BUILD.md](./BUILD.md) file. --- From ba0366dc453b4249515b8c1d5d36a8bbcc13931b Mon Sep 17 00:00:00 2001 From: bialger Date: Sun, 7 Sep 2025 23:06:19 +0300 Subject: [PATCH 08/21] refactor: modularize CMake configuration by separating compiler options and external libraries Extract compiler options and external library configurations into separate CMake files for improved organization and maintainability. Update main CMakeLists.txt to include these new files and remove redundant code from the tests directory related to GoogleTest integration. --- CMakeLists.txt | 24 ++---------------------- cmake/IncludeExternalLibraries.cmake | 13 +++++++++++++ cmake/SetCompilerOptions.cmake | 25 +++++++++++++++++++++++++ tests/CMakeLists.txt | 12 ------------ 4 files changed, 40 insertions(+), 34 deletions(-) create mode 100644 cmake/IncludeExternalLibraries.cmake create mode 100644 cmake/SetCompilerOptions.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 87075f6..a807f1b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,28 +7,8 @@ project( LANGUAGES CXX ) -set(CMAKE_CXX_STANDARD 20) - -if(WIN32) # Install dlls in the same directory as the executable on Windows - set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR}) - set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR}) - set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR}) - set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR}) - set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR}) - set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR}) -endif() - -if(NOT CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE Release) -endif() - -if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") - set(CMAKE_CXX_FLAGS_DEBUG "/MDd") - set(CMAKE_CXX_FLAGS_RELEASE "/O2") -else() - set(CMAKE_CXX_FLAGS_DEBUG "-g") - set(CMAKE_CXX_FLAGS_RELEASE "-O3") -endif() +include(cmake/SetCompilerOptions.cmake) +include(cmake/IncludeExternalLibraries.cmake) add_subdirectory(lib) add_subdirectory(bin) diff --git a/cmake/IncludeExternalLibraries.cmake b/cmake/IncludeExternalLibraries.cmake new file mode 100644 index 0000000..d002ab7 --- /dev/null +++ b/cmake/IncludeExternalLibraries.cmake @@ -0,0 +1,13 @@ +include(FetchContent) + +# GoogleTest +# For Windows: prevent overriding the parent project's compiler/linker settings +set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) + +FetchContent_Declare( + googletest + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG v1.14.0 +) + +FetchContent_MakeAvailable(googletest) diff --git a/cmake/SetCompilerOptions.cmake b/cmake/SetCompilerOptions.cmake new file mode 100644 index 0000000..86de13c --- /dev/null +++ b/cmake/SetCompilerOptions.cmake @@ -0,0 +1,25 @@ +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release) +endif() + +if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + set(CMAKE_CXX_FLAGS_DEBUG "/MDd") + set(CMAKE_CXX_FLAGS_RELEASE "/O2") +else() + set(CMAKE_CXX_FLAGS_DEBUG "-g") + set(CMAKE_CXX_FLAGS_RELEASE "-O3") +endif() + +# Windows: place runtime artifacts next to the executable +if(WIN32) + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR}) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR}) + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR}) + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR}) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR}) + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR}) +endif() diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 93fc839..7d50a70 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,15 +1,3 @@ -include(FetchContent) - -FetchContent_Declare( - googletest - GIT_REPOSITORY https://github.com/google/googletest.git - GIT_TAG v1.15.2 -) - -# For Windows: Prevent overriding the parent project's compiler/linker settings -set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) -FetchContent_MakeAvailable(googletest) - enable_testing() add_executable( From bb80c3510a3bc44a41901739dc56550dca230eb5 Mon Sep 17 00:00:00 2001 From: bialger Date: Sun, 7 Sep 2025 23:20:09 +0300 Subject: [PATCH 09/21] docs: update CODEBASE_STRUCTURE.md to clarify directory purposes and organization Revise CODEBASE_STRUCTURE.md to enhance clarity on the repository's directory structure. Introduce detailed sections for the root directory, bin, lib, tests, and CI/CD configurations, providing clear descriptions of each component's purpose and organization for improved onboarding and understanding. --- CODEBASE_STRUCTURE.md | 70 +++++++++++++++---------------------------- 1 file changed, 24 insertions(+), 46 deletions(-) diff --git a/CODEBASE_STRUCTURE.md b/CODEBASE_STRUCTURE.md index 72ed35e..7cfc619 100644 --- a/CODEBASE_STRUCTURE.md +++ b/CODEBASE_STRUCTURE.md @@ -1,52 +1,30 @@ # Базовая структура репозитория -Ниже описана структура репозитория +## Назначение директорий -``` -./ -├─ CMakeLists.txt # Корневой CMake-проект, подключает подпроекты -├─ PrintOS.cmake # Вспомогательные CMake-функции/макросы -├─ BUILD.md # Инструкции по сборке -├─ README.md # Обзор и быстрый старт -├─ CONTRIBUTING.md # Правила для участников -├─ CODE_OF_CONDUCT.md # Кодекс поведения -├─ CODING_GUIDELINES.md # Рекомендации по стилю кода -├─ CODEBASE_STRUCTURE.md # Этот документ -├─ LICENSE # Лицензия -├─ install.sh # Скрипт установки/подготовки окружения -├─ .clang-format # Настройки форматирования C/C++ -├─ .clang-tidy # Настройки статического анализа -├─ .gitignore # Правила игнорирования Git -├─ .github/ -│ └─ workflows/ -│ └─ ci_tests.yml # CI: сборка и прогон тестов -├─ bin/ -│ ├─ CMakeLists.txt -│ └─ main.cpp # Точка входа исполняемого файла -├─ lib/ -│ ├─ CMakeLists.txt -│ ├─ mylib/ -│ │ ├─ CMakeLists.txt -│ │ ├─ MyClass.hpp # Заголовок основной библиотеки -│ │ └─ MyClass.cpp # Реализация основной библиотеки -│ └─ ui/ -│ ├─ CMakeLists.txt -│ ├─ ui_functions.hpp # Интерфейс UI/CLI-утилит -│ └─ ui_functions.cpp # Реализация UI/CLI-утилит -└─ tests/ - ├─ CMakeLists.txt - ├─ main_test.cpp # Точка входа тестового раннера - ├─ ProjectIntegrationTestSuite.hpp - ├─ ProjectIntegrationTestSuite.cpp - ├─ test_functions.hpp # Вспомогательные функции для тестов - ├─ test_functions.cpp - └─ unit_tests.cpp # Модульные тесты -``` +### Корневая директория +- **Документация проекта** - README, инструкции по сборке, руководства для разработчиков +- **Конфигурация сборки** - CMakeLists.txt, вспомогательные CMake-скрипты +- **Настройки инструментов** - конфигурации для форматирования, линтеров, Git +- **Скрипты автоматизации** - установка зависимостей, подготовка окружения -## Назначение директорий +### bin/ +- **Исполняемые файлы** - точка входа приложения +- **CLI-интерфейс** - командная строка для взаимодействия с пользователем + +### lib/ +- **Основная библиотека** - ядро функциональности проекта +- **UI-модуль** - пользовательский интерфейс и CLI-утилиты +- **Общие компоненты** - переиспользуемые части кода. Добавляйте новые модули только в эту директорию. + +### tests/ +- **Модульные тесты** - тестирование отдельных компонентов +- **Интеграционные тесты** - тестирование взаимодействия между модулями +- **Вспомогательные функции** - утилиты для тестирования +- **Тестовые данные** - примеры и фикстуры для тестов -- bin: исполняемые цели приложения (CLI/демо), точка входа `main.cpp`. -- lib: исходники библиотек проекта (`mylib`, `ui`) и их `CMakeLists.txt`. -- tests: тестовые цели и исходники (модульные и интеграционные). -- .github/workflows: конфигурация CI для сборки и тестов. +### .github/workflows/ +- **CI/CD конфигурация** - автоматическая сборка и тестирование +- **Проверки качества кода** - статический анализ, форматирование +- **Развертывание** - автоматическая публикация релизов From 38d3b5903d311c501c623020809e40e9a655c458 Mon Sep 17 00:00:00 2001 From: bialger Date: Sun, 7 Sep 2025 23:21:06 +0300 Subject: [PATCH 10/21] refactor: reorganize test structure and implement ProjectIntegrationTestSuite Move test files into a dedicated directory for better organization. Introduce ProjectIntegrationTestSuite with setup and teardown methods for managing temporary directories during tests. Update includes in main_test.cpp to reflect the new structure and remove unnecessary includes from test_functions.hpp. --- tests/CMakeLists.txt | 4 +--- tests/main_test.cpp | 7 +++++-- tests/test_functions.cpp | 2 +- tests/test_functions.hpp | 1 - tests/{ => test_suites}/ProjectIntegrationTestSuite.cpp | 2 ++ tests/{ => test_suites}/ProjectIntegrationTestSuite.hpp | 1 - 6 files changed, 9 insertions(+), 8 deletions(-) rename tests/{ => test_suites}/ProjectIntegrationTestSuite.cpp (91%) rename tests/{ => test_suites}/ProjectIntegrationTestSuite.hpp (95%) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 7d50a70..3a5e04c 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -5,9 +5,7 @@ add_executable( main_test.cpp unit_tests.cpp test_functions.cpp - test_functions.hpp - ProjectIntegrationTestSuite.cpp - ProjectIntegrationTestSuite.hpp + test_suites/ProjectIntegrationTestSuite.cpp ) target_link_libraries( diff --git a/tests/main_test.cpp b/tests/main_test.cpp index 10f77b8..235046a 100644 --- a/tests/main_test.cpp +++ b/tests/main_test.cpp @@ -1,10 +1,13 @@ +#include #include #include -#include "ProjectIntegrationTestSuite.hpp" -#include "test_functions.hpp" + #include "lib/ui/ui_functions.hpp" // include your library here +#include "test_functions.hpp" +#include "test_suites/ProjectIntegrationTestSuite.hpp" + TEST_F(ProjectIntegrationTestSuite, InitTest) { ASSERT_TRUE(std::filesystem::is_directory(kTemporaryDirectoryName)); } diff --git a/tests/test_functions.cpp b/tests/test_functions.cpp index 213536c..b40f6d3 100644 --- a/tests/test_functions.cpp +++ b/tests/test_functions.cpp @@ -7,4 +7,4 @@ std::vector SplitString(const std::string& str) { std::istringstream iss(str); return {std::istream_iterator(iss), std::istream_iterator()}; -} \ No newline at end of file +} diff --git a/tests/test_functions.hpp b/tests/test_functions.hpp index 27d8e8b..50a78bd 100644 --- a/tests/test_functions.hpp +++ b/tests/test_functions.hpp @@ -1,7 +1,6 @@ #ifndef TESTFUNCTIONS_HPP_ #define TESTFUNCTIONS_HPP_ -#include #include #include diff --git a/tests/ProjectIntegrationTestSuite.cpp b/tests/test_suites/ProjectIntegrationTestSuite.cpp similarity index 91% rename from tests/ProjectIntegrationTestSuite.cpp rename to tests/test_suites/ProjectIntegrationTestSuite.cpp index 308cfed..2da1d44 100644 --- a/tests/ProjectIntegrationTestSuite.cpp +++ b/tests/test_suites/ProjectIntegrationTestSuite.cpp @@ -1,5 +1,7 @@ #include "ProjectIntegrationTestSuite.hpp" +#include + void ProjectIntegrationTestSuite::SetUp() { std::filesystem::create_directories(kTemporaryDirectoryName); } diff --git a/tests/ProjectIntegrationTestSuite.hpp b/tests/test_suites/ProjectIntegrationTestSuite.hpp similarity index 95% rename from tests/ProjectIntegrationTestSuite.hpp rename to tests/test_suites/ProjectIntegrationTestSuite.hpp index f1be108..1b1d0bf 100644 --- a/tests/ProjectIntegrationTestSuite.hpp +++ b/tests/test_suites/ProjectIntegrationTestSuite.hpp @@ -1,7 +1,6 @@ #ifndef TEMPORARYDIRECTORYTESTSUITE_HPP_ #define TEMPORARYDIRECTORYTESTSUITE_HPP_ -#include #include #include From 7e802dcae3bf57e1118c7522976922c6fb0fcce2 Mon Sep 17 00:00:00 2001 From: bialger Date: Mon, 8 Sep 2025 02:32:32 +0300 Subject: [PATCH 11/21] docs: enhance README.md with comprehensive design philosophy and control flow details Revise the README.md to include a detailed design philosophy section outlining Ovum's core principles such as memory safety, immutability, and pure functions. Expand the control flow section to cover conditional execution and loop constructs, providing clear examples for better understanding. Update type system characteristics and memory management sections for clarity and completeness. --- README.md | 411 +++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 377 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index 6d5f166..17dad56 100644 --- a/README.md +++ b/README.md @@ -9,9 +9,20 @@ If you want to build the project, please read the [BUILD.md](./BUILD.md) file. ## 1) Overview -**Ovum** is a strongly **statically typed**, **single-threaded** language with Kotlin-like syntax and a focus on safety, clarity, and performance. +**Ovum** is a new general-purpose programming language with a design emphasis on safety, purity, and clarity. It is a strongly **statically typed**, **single-threaded** language with Kotlin-like syntax and a focus on safety, clarity, and performance. -Key design points: +### Design Philosophy + +Ovum's core design principles center around: + +* **Memory Safety**: Automatic memory management through garbage collection eliminates whole classes of bugs like dangling pointers, memory leaks, and buffer overruns. +* **Immutability by Default**: Variables, object fields, and function parameters are constant by default, reducing unintended side effects and making code easier to reason about. +* **Pure Functions**: Functions with no side effects whose results can be cached for performance optimization through memoization. +* **Interface-Based Polymorphism**: No class inheritance; polymorphism achieved through interface implementation and composition, avoiding complex inheritance hierarchies. +* **Explicit Unsafe Operations**: Low-level or potentially unsafe operations are isolated within explicit `unsafe { ... }` blocks. +* **Less is More**: The language is designed to be simple and easy to learn, with a focus on clarity and readability. The less ways there are to do the same thing, the better. + +### Key Design Points * **Strong static typing** with **immutability by default** (`mut` required for mutation). * **Nullable types** and Kotlin-style null-handling: `Type?`, safe calls `?.`, Elvis `?:`, non-null assertion `!!`. @@ -51,31 +62,87 @@ Key design points: ## 2) Types +Ovum has a rich type system with primitive types and user-defined types. The type system is static and does not permit implicit type coercions (an `Int` won't automatically become a `Float` without an explicit cast, for example). + ### Primitive Types -* `Int` (8 bytes) -* `Float` (8 bytes) -* `Bool` -* `Char` -* `Byte` -* `Pointer` *(only meaningful in `unsafe` code)* +* `Int` (8 bytes) - 64-bit signed integer +* `Float` (8 bytes) - 64-bit floating-point number +* `Bool` - Boolean value (`true` or `false`) +* `Char` - single character +* `Byte` - 8-bit unsigned integer +* `Pointer` - raw memory address *(only meaningful in `unsafe` code)* > Any primitive may have a **nullable** counterpart via `?` (e.g., `Int?`). ### Non-Primitive / Reference Types -* `String` *(reference type; not primitive)* +* `String` *(reference type; not primitive)* - text data * **Array classes (no templates / generics):** * For primitives: `IntArray`, `FloatArray`, `BoolArray`, `CharArray`, `ByteArray`, `PointerArray` * For objects: **`ObjectArray`** * **Convenience**: `StringArray` (array of `String`, used for `Main`) -> All non-primitive values are passed by link (reference), **const by default**. +### Passing Semantics + +* **Primitive types**: passed by value (copied) +* **Reference types**: all user-defined and non-primitive types (including `String` and all arrays) are **passed by reference** (const by default) +* **Immutability**: By default, references are considered immutable (the function cannot rebind them or mutate the object's content unless allowed via `mut`) + +### Type System Characteristics + +* **Static typing**: Every variable and expression has a type that is checked at compile time +* **No implicit conversions**: Explicit casting required between different types +* **Type safety**: Prevents type errors and provides better documentation of code intent +* **Nullable types**: Any type can be made nullable by appending `?` + +--- + +## 3) Lexical Structure + +Ovum's source code uses a lexical syntax familiar to C-style and Kotlin-style languages: + +### Identifiers + +Names for variables, functions, classes, etc., consist of letters, digits, and underscores, and must not begin with a digit. For example: `myVar`, `compute_sum`, `GraphNode`. Identifiers are case-sensitive. + +**Naming Convention**: Classes, functions, methods use **PascalCase** (e.g., `Main`, `ToString`, `IsLess`). Keywords/modifiers remain lowercase (`class`, `interface`, `mut`, `override`, `pure`, `unsafe`, etc.). + +### Keywords + +Ovum reserves certain words like `fun`, `class`, `interface`, `mut`, `override`, `pure`, `if`, `else`, `for`, `while`, `return`, `unsafe`, `let`, `static`, `public`, `private`, `implements`, `as`, `is`, `null`, `true`, `false`, etc. These cannot be used as identifiers. + +### Literals + +* **Numeric literals**: integers (e.g., `42`, `-17`) and floating-point numbers (e.g., `3.14`, `-2.5`) +* **Boolean literals**: `true`, `false` +* **Character literals**: single characters in single quotes (e.g., `'A'`, `'\n'`, `'\t'`) +* **String literals**: text in double quotes (e.g., `"hello"`, `"world"`) with escape sequences like `"\n"` for newline, `"\t"` for tab, `"\\"` for backslash, `"\""` for quote + +### Operators and Punctuation + +* **Arithmetic**: `+`, `-`, `*`, `/`, `%` +* **Comparison**: `==`, `!=`, `<`, `<=`, `>`, `>=` +* **Boolean logic**: `&&` (logical AND), `||` (logical OR), `!` (negation), `xor` (exclusive OR) +* **Assignment**: `=` +* **Null handling**: `?.` (safe call), `?:` (Elvis), `!!` (non-null assertion) +* **Type operations**: `as` (cast), `is` (type test) +* **Punctuation**: `,` (comma), `;` (semicolon), `:` (colon), `()` (parentheses), `{}` (braces), `[]` (brackets) +* **Namespace resolution**: `::` + +### Comments + +* **Line comments**: start with `//` and continue to the end of the line +* **Block comments**: start with `/*` and end with `*/`, can span multiple lines. Nested comments are not allowed + +### Whitespace + +Spaces, tabs, and newlines are generally ignored outside of separating tokens. Indentation is not significant (Ovum is not whitespace-sensitive except that newlines can terminate statements if no semicolon is present). --- -## 3) Nullability & Boolean Logic +## 4) Nullability & Boolean Logic ### Nullability (Kotlin-style) @@ -115,7 +182,70 @@ Key design points: --- -## 5) Syntax & Semantics (Description) +## 5) Control Flow + +Ovum supports standard control flow constructs following structured programming principles: + +### Conditional Execution + +**If/Else**: Conditional execution with syntax `if (condition) { ... } else { ... }`. The condition must be a Boolean expression (`Bool`). Braces are required for blocks, but for single statements the braces can be omitted (though using braces is encouraged for clarity). + +```ovum +if (x > 0) { + sys::Print("Positive") +} else if (x < 0) { + sys::Print("Negative") +} else { + sys::Print("Zero") +} +``` + +### Loops + +**While Loop**: `while (condition) { ... }` repeats the body while the condition is true. + +```ovum +mut i: Int = 0 +while (i < 10) { + sys::Print(i.ToString()) + i = i + 1 +} +``` + +**For Loop**: `for (item in collection) { ... }` iterates over elements of a collection (arrays, etc.). + +```ovum +for (item in items) { + sys::Print(item.ToString()) +} +``` + +### Flow Control + +**Return**: `return expression;` exits the current function with the given value (or `return;` with no value to exit a void function). In pure functions, a return simply provides the result; in impure, it may terminate early as usual. + +**Break/Continue**: `break` exits a loop immediately, `continue` skips to the next iteration of the loop. + +```ovum +mut i: Int = 0 +while (i < 10) { + if (i == 5) { + break // Exit loop + } + if (i == 3) { + i = i + 1 + continue // Skip to next iteration + } + sys::Print(i.ToString()) + i = i + 1 +} +``` + +All control flow follows structured programming principles (no `goto`). + +--- + +## 6) Syntax & Semantics (Description) ### Functions @@ -158,16 +288,16 @@ Key design points: ### Functional Objects (`call`) -* Classes can declare a **special `call`** member that makes instances **callable** like functions. -* If a class **declares `call`**, it **may have other members**. -* If a class **does not declare `call`**, it **must not have any non-`call` members** (i.e., it must be purely functional). -* A function literal `fun(...) : T { ... }` can be **coerced** to a class type that exposes a compatible `call(...) : T`. +* Classes or interfaces can declare a **special `call`** member that makes instances **callable** like functions. +* Classes **define `call`**, it **may have other members**. +* Interfaces **contain undefined `call` member** (maybe not one, with all interface rules applying). +* A function literal `fun(...) : T { ... }` can be **coerced** to a interface type that exposes a compatible `call(...) : T` (and only this). Example: ```ovum -class CustomFunctional { - public call(a: Int?, b: Int?): Int +interface CustomFunctional { + call(a: Int?, b: Int?): Int } class DefinedFunctional { @@ -301,7 +431,64 @@ Literal ::= NumberLiteral | StringLiteral | CharLiteral | "true" | "fals --- -## 7) Lexer & Parser Rules +## 7) Expressions and Operators + +Expressions in Ovum include literal values, variable references, function calls, method calls, field accesses, and combinations of these with operators. Operator syntax and precedence are designed to be familiar to C/Java/Kotlin developers. + +### Arithmetic Operators + +* `+` (addition) - operates on numeric types and may be overloaded internally for string concatenation +* `-` (subtraction) - operates on numeric types +* `*` (multiplication) - operates on numeric types +* `/` (division) - operates on numeric types +* `%` (modulo) - operates on numeric types + +### Comparison Operators + +* `==` (equality) - most types can be compared for equality +* `!=` (inequality) - opposite of equality +* `<`, `<=`, `>`, `>=` (ordering) - only valid on types that have a defined ordering (numeric types or classes implementing `IComparable`) + +### Logical Operators + +* `&&` (logical AND) - short-circuit evaluation +* `||` (logical OR) - short-circuit evaluation +* `!` (negation) - unary operator +* `xor` (exclusive OR) - infix operator on `Bool` + +### Assignment Operator + +* `=` (assignment) - assigns a value to a mutable variable or field. The left-hand side must be a mutable variable or field. + +### Member Access + +* `object.field` - access a field of an object +* `object.method()` - call a method on an object +* `object?.field` - safe field access (returns null if object is null) +* `object?.method()` - safe method call (returns null if object is null) + +### Type Operations + +* `expr as Type` - explicit cast (downcast yields nullable type) +* `expr is Type` - type test (returns `Bool`) + +### Null Handling + +* `expr?.member` - safe call (calls only if expr is not null) +* `expr ?: default` - Elvis operator (returns expr if not null, otherwise default) +* `expr!!` - non-null assertion (throws error if expr is null) + +### Namespace Resolution + +* `Namespace::Name` - refers to a definition from a specific namespace (e.g., `sys::Print`) + +### No User-Defined Operators + +Programmers cannot create new operator symbols or overload the existing ones for user-defined types. The set of operators and their meanings are fixed by the language. This keeps the language syntax clear and consistent and avoids operator overloading misuse. + +--- + +## 8) Lexer & Parser Rules ### Tokens @@ -341,7 +528,23 @@ Literal ::= NumberLiteral | StringLiteral | CharLiteral | "true" | "fals --- -## 8) Runtime, VM & Platform Support +## 8) Memory Management and Runtime + +One of Ovum's core principles is memory safety. Memory is managed by the runtime's garbage collector (GC), which automatically frees objects that are no longer in use, eliminating whole classes of bugs like dangling pointers, memory leaks, and buffer overruns. + +### Automatic Memory Management + +* **No Manual Memory Management**: There are no language constructs for pointer arithmetic, manual memory allocation (e.g., no `malloc`/`free` or `new`/`delete` outside of what the language runtime provides), nor explicit memory deallocation by the programmer. +* **Garbage Collection**: The runtime includes a garbage collector that runs periodically (or when allocation thresholds are exceeded) to reclaim memory. It finds objects that are no longer reachable from any live variables or object fields and frees them. +* **Modern GC Algorithm**: Ovum's GC is likely a modern algorithm (possibly generational, parallel, or incremental) to minimize pause times, but these are internal implementation details. + +### Just-In-Time Compilation + +* **JIT Compilation**: The VM includes a Just-In-Time compiler (JIT) that can compile frequently executed code paths to native machine code for speed. +* **Hot Path Optimization**: Initially, Ovum bytecode might be interpreted, but as functions or loops become "hot" (executed often), the JIT will optimize them. +* **Hybrid Approach**: This gives the flexibility of an interpreter (fast startup, platform independence of bytecode) with the performance of compiled code in long-running processes. + +### Runtime, VM & Platform Support * **Execution**: Source (`.ovum`) → bytecode → **Ovum VM**. * **JIT**: Hot paths compiled to native for performance. @@ -352,7 +555,42 @@ Literal ::= NumberLiteral | StringLiteral | CharLiteral | "true" | "fals --- -## 9) System Library & Interop +## 9) Runtime and Execution Model + +The Ovum compiler translates Ovum source code into Ovum bytecode or an intermediate representation, which is executed on the Ovum Virtual Machine (OVM). The OVM provides a sandboxed, platform-independent environment for Ovum programs. + +### Development Workflow + +1. **Write Ovum source code** in `.ovum` files +2. **Compile** using the Ovum compiler, which will: + - Parse using the grammar rules + - Type-check (ensure types match and all variables are defined) + - Enforce const/pure rules + - Produce bytecode or an executable +3. **Execute** using the Ovum VM, which will: + - Load the bytecode + - Resolve any imports (linking together modules) + - Start executing (usually beginning with `Main(args: StringArray): Int`) + - Apply JIT optimization to hot code paths + - Manage memory with garbage collection + +### Platform Requirements + +* **Ovum VM**: Required on the target platform (distributed as standalone application or embedded) +* **Architecture Support**: JIT compiler generates code specific to host CPU architecture for performance +* **Portability**: Bytecode is portable across platforms; only the VM's JIT component is platform-specific +* **Dependencies**: Any necessary native libraries if the program uses `sys::Interope` to call external code + +### Execution Characteristics + +* **Single-threaded**: Execution model and VM are single-threaded +* **No Concurrency Primitives**: No built-in threading or concurrency features +* **Structured Programming**: All control flow follows structured programming principles (no `goto`) +* **Entry Point**: Programs start with `Main(args: StringArray): Int` function + +--- + +## 10) System Library & Interop * `sys::Print(msg: String): Void` * `sys::Time(): Int` @@ -367,7 +605,7 @@ Literal ::= NumberLiteral | StringLiteral | CharLiteral | "true" | "fals --- -## 10) Unsafe Operations (Recap) +## 11) Unsafe Operations (Recap) Allowed **only** inside `unsafe { ... }`: @@ -380,9 +618,9 @@ Allowed **only** inside `unsafe { ... }`: --- -## 11) Code Examples +## 12) Code Examples -### 11.1 Entry point (`StringArray`) +### 12.1 Entry point (`StringArray`) ```ovum // .ovum file @@ -393,7 +631,7 @@ fun Main(args: StringArray): Int { } ``` -### 11.2 Variables, Nulls, Elvis, Safe Calls +### 12.2 Variables, Nulls, Elvis, Safe Calls ```ovum fun DemoNulls(): Void { @@ -411,7 +649,7 @@ fun DemoNulls(): Void { } ``` -### 11.3 Interfaces, Classes, Fields, Overrides +### 12.3 Interfaces, Classes, Fields, Overrides ```ovum interface IGreeter { @@ -439,7 +677,7 @@ class FriendlyGreeter implements IGreeter { } ``` -### 11.4 Standard Interfaces (`IStringConvertible`, `IComparable`, `IHashable`) +### 12.4 Standard Interfaces (`IStringConvertible`, `IComparable`, `IHashable`) ```ovum interface IStringConvertible { fun ToString(): String } @@ -469,7 +707,7 @@ class Point implements IStringConvertible, IComparable, IHashable { } ``` -### 11.5 Pure Functions with Caching +### 12.5 Pure Functions with Caching ```ovum pure fun Fib(n: Int): Int { @@ -479,7 +717,7 @@ pure fun Fib(n: Int): Int { // For user-defined reference types as parameters, implement IComparable. ``` -### 11.6 `is`, `as`, `!!`, and ByteArray Casts +### 12.6 `is`, `as`, `!!`, and ByteArray Casts ```ovum fun DemoCasts(obj: Object): Void { @@ -501,11 +739,11 @@ fun DemoCasts(obj: Object): Void { } ``` -### 11.7 Functional Objects (`call`) & Literals +### 12.7 Functional Objects (`call`) & Literals ```ovum -class CustomFunctional { - public call(a: Int?, b: Int?): Int +interface CustomFunctional { + call(a: Int?, b: Int?): Int } class DefinedFunctional { @@ -530,9 +768,114 @@ fun Main(args: StringArray): Int { } ``` +### 12.8 Control Flow Examples + +```ovum +fun DemoControlFlow(): Void { + mut i: Int = 0 + + // While loop with break and continue + while (i < 10) { + if (i == 3) { + i = i + 1 + continue // Skip to next iteration + } + if (i == 7) { + break // Exit loop + } + sys::Print("i = " + i.ToString()) + i = i + 1 + } + + // For loop over array + let numbers: IntArray = IntArray(3) + numbers[0] = 10 + numbers[1] = 20 + numbers[2] = 30 + + for (num in numbers) { + sys::Print("Number: " + num.ToString()) + } +} +``` + +### 12.9 Memory Management and Unsafe Operations + +```ovum +fun DemoUnsafeOperations(): Void { + // Unsafe block for low-level operations + unsafe { + // Global mutable state (unsafe) + static mut globalCounter: Int = 0 + globalCounter = globalCounter + 1 + + // Pointer operations (unsafe) + let obj: Point = Point(10, 20) + let ptr: Pointer = &obj // address-of + let deref: Point = *ptr // dereference + + // ByteArray casting (unsafe) + let bytes: ByteArray = (obj as ByteArray) + let mutableBytes: ByteArray = (obj as mut ByteArray) + + // Foreign function interface (unsafe) + let input: ByteArray = "Hello".ToUtf8Bytes() + let output: ByteArray = ByteArray(4) + let result: Int = sys::Interope("libc.so", "strlen", input, output) + } +} +``` + +### 12.10 Complete Program Example + +```ovum +// Complete Ovum program demonstrating key features +interface ICalculator { + fun Calculate(a: Int, b: Int): Int +} + +class Adder implements ICalculator { + public override fun Calculate(a: Int, b: Int): Int { + return a + b + } +} + +class Multiplier implements ICalculator { + public override fun Calculate(a: Int, b: Int): Int { + return a * b + } +} + +pure fun ProcessNumbers(calc: ICalculator, numbers: IntArray): Int { + mut result: Int = 0 + for (num in numbers) { + result = result + calc.Calculate(num, 2) + } + return result +} + +fun Main(args: StringArray): Int { + let numbers: IntArray = IntArray(3) + numbers[0] = 5 + numbers[1] = 10 + numbers[2] = 15 + + let adder: ICalculator = Adder() + let multiplier: ICalculator = Multiplier() + + let sumResult: Int = ProcessNumbers(adder, numbers) + let productResult: Int = ProcessNumbers(multiplier, numbers) + + sys::Print("Sum result: " + sumResult.ToString()) + sys::Print("Product result: " + productResult.ToString()) + + return 0 +} +``` + --- -## 12) Build & Run (Conceptual) +## 13) Build & Run (Conceptual) 1. **Compile** `.ovum` sources → Ovum bytecode (preprocessor applied). 2. **Execute** on the Ovum VM (single-threaded): @@ -543,7 +886,7 @@ fun Main(args: StringArray): Int { --- -## 13) Notes & Best Practices +## 14) Notes & Best Practices * Prefer **immutable** data; use `mut` only when necessary. * Implement **`IStringConvertible`** for diagnostics (`ToString`). From d39515927ed7f31116b0041ff1cfab2f5ba5d4ea Mon Sep 17 00:00:00 2001 From: bialger Date: Mon, 8 Sep 2025 08:10:04 +0300 Subject: [PATCH 12/21] docs: update README.md to include nullable type support for primitive types --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 17dad56..a7c684e 100644 --- a/README.md +++ b/README.md @@ -78,8 +78,8 @@ Ovum has a rich type system with primitive types and user-defined types. The typ ### Non-Primitive / Reference Types * `String` *(reference type; not primitive)* - text data +* *Nullable* `Int?` (and all other primitive types) - `Int` or `null` - also passed by reference * **Array classes (no templates / generics):** - * For primitives: `IntArray`, `FloatArray`, `BoolArray`, `CharArray`, `ByteArray`, `PointerArray` * For objects: **`ObjectArray`** * **Convenience**: `StringArray` (array of `String`, used for `Main`) From 24957a214b74614edd29c0559318d2cd44a989b2 Mon Sep 17 00:00:00 2001 From: bialger Date: Mon, 8 Sep 2025 10:48:48 +0300 Subject: [PATCH 13/21] docs: update README.md to reflect changes in variable declaration keywords Revise the README.md to replace instances of `mut` with `var` for mutable variables and `let` with `val` for immutable variables, aligning with the updated language syntax. Adjust naming conventions and examples throughout the document to ensure consistency and clarity in the description of Ovum's design principles and features. --- README.md | 137 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 71 insertions(+), 66 deletions(-) diff --git a/README.md b/README.md index a7c684e..fd28499 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ Ovum's core design principles center around: ### Key Design Points -* **Strong static typing** with **immutability by default** (`mut` required for mutation). +* **Strong static typing** with **immutability by default** (`var` required for mutation). * **Nullable types** and Kotlin-style null-handling: `Type?`, safe calls `?.`, Elvis `?:`, non-null assertion `!!`. * **Pure functions** (no side effects, VM-level result caching). * **Classes & interfaces** @@ -35,7 +35,7 @@ Ovum's core design principles center around: * Interface methods are **public** and **virtual** by default. * Class methods implementing interface members must be marked `override`. * **Access modifiers are mandatory** for all fields and methods in classes (`public`/`private`). - * **Fields use `let` (immutable) or `mut` (mutable)**. + * **Fields use `val` (immutable) or `var` (mutable)**. * **Namespaces** with `::` resolution (e.g., `sys::Print`). * **Built-in operators**; **no user-defined operators**. * **Preprocessor**: `#import`, `#define`, `#ifdef`, `#ifndef`, `#else`, `#undef`. @@ -56,7 +56,7 @@ Ovum's core design principles center around: * Required for user-defined types used as parameters to **pure** functions (stable ordering/keys). * **`IHashable`** — `GetHash(): Int` -> **Naming**: **Classes, functions, methods use PascalCase** (e.g., `Main`, `ToString`, `IsLess`). Keywords/modifiers remain lowercase (`class`, `interface`, `mut`, `override`, `pure`, `unsafe`, etc.). +> **Naming**: **Classes, functions, methods use PascalCase** (e.g., `Main`, `ToString`, `IsLess`). Keywords/modifiers remain lowercase (`class`, `interface`, `var`, `override`, `pure`, `unsafe`, etc.). --- @@ -88,7 +88,7 @@ Ovum has a rich type system with primitive types and user-defined types. The typ * **Primitive types**: passed by value (copied) * **Reference types**: all user-defined and non-primitive types (including `String` and all arrays) are **passed by reference** (const by default) -* **Immutability**: By default, references are considered immutable (the function cannot rebind them or mutate the object's content unless allowed via `mut`) +* **Immutability**: By default, references are considered immutable (the function cannot rebind them or mutate the object's content unless allowed via `var`) ### Type System Characteristics @@ -107,11 +107,11 @@ Ovum's source code uses a lexical syntax familiar to C-style and Kotlin-style la Names for variables, functions, classes, etc., consist of letters, digits, and underscores, and must not begin with a digit. For example: `myVar`, `compute_sum`, `GraphNode`. Identifiers are case-sensitive. -**Naming Convention**: Classes, functions, methods use **PascalCase** (e.g., `Main`, `ToString`, `IsLess`). Keywords/modifiers remain lowercase (`class`, `interface`, `mut`, `override`, `pure`, `unsafe`, etc.). +**Naming Convention**: Classes, functions, methods use **PascalCase** (e.g., `Main`, `ToString`, `IsLess`). Keywords/modifiers remain lowercase (`class`, `interface`, `var`, `override`, `pure`, `unsafe`, etc.). ### Keywords -Ovum reserves certain words like `fun`, `class`, `interface`, `mut`, `override`, `pure`, `if`, `else`, `for`, `while`, `return`, `unsafe`, `let`, `static`, `public`, `private`, `implements`, `as`, `is`, `null`, `true`, `false`, etc. These cannot be used as identifiers. +Ovum reserves certain words like `fun`, `class`, `interface`, `var`, `override`, `pure`, `if`, `else`, `for`, `while`, `return`, `unsafe`, `val`, `static`, `public`, `private`, `implements`, `as`, `is`, `null`, `true`, `false`, etc. These cannot be used as identifiers. ### Literals @@ -205,7 +205,7 @@ if (x > 0) { **While Loop**: `while (condition) { ... }` repeats the body while the condition is true. ```ovum -mut i: Int = 0 +var i: Int = 0 while (i < 10) { sys::Print(i.ToString()) i = i + 1 @@ -227,7 +227,7 @@ for (item in items) { **Break/Continue**: `break` exits a loop immediately, `continue` skips to the next iteration of the loop. ```ovum -mut i: Int = 0 +var i: Int = 0 while (i < 10) { if (i == 5) { break // Exit loop @@ -261,14 +261,14 @@ All control flow follows structured programming principles (no `goto`). * **No class inheritance**. * **Access modifiers are mandatory** on fields and methods. - * **Fields** use `let` (immutable) or `mut` (mutable): + * **Fields** use `val` (immutable) or `var` (mutable): - * `private let Prefix: String` - * `public mut Count: Int` + * `private val Prefix: String` + * `public var Count: Int` * **Methods** must declare access and can be `override`/`pure`: * `public override fun Run(): Int { ... }` - * **Static** fields supported; **writing `static mut` is unsafe**. + * **Static** fields supported; **writing `static var` is unsafe**. * **Destructor**: optional, overrides the implicit virtual destructor from `Object`. * Syntax: `public destructor(): Void { ... }` (no parameters, no return). @@ -301,7 +301,7 @@ interface CustomFunctional { } class DefinedFunctional { - public mut Multiplier: Int + public var Multiplier: Int public fun DefinedFunctional(multiplier: Int): DefinedFunctional { this.Multiplier = multiplier @@ -314,7 +314,7 @@ class DefinedFunctional { } } -let AddNullable: CustomFunctional = fun(a: Int?, b: Int?): Int { +val AddNullable: CustomFunctional = fun(a: Int?, b: Int?): Int { return (a ?: 0) + (b ?: 0) } @@ -345,26 +345,30 @@ GlobalDef ::= FunctionDecl | ClassDecl | InterfaceDecl | GlobalVarDecl ; FunctionDecl ::= [ "pure" ] "fun" Identifier "(" [ ParamList ] ")" [ ":" Type ] Block ; ParamList ::= Parameter { "," Parameter } ; -Parameter ::= [ "mut" ] Identifier ":" Type ; +Parameter ::= [ "var" ] Identifier ":" Type ; ClassDecl ::= "class" Identifier [ "implements" TypeList ] ClassBody ; TypeList ::= Type { "," Type } ; ClassBody ::= "{" { ClassMember } "}" ; -ClassMember ::= FieldDecl | StaticFieldDecl | MethodDecl | DestructorDecl ; +ClassMember ::= FieldDecl | StaticFieldDecl | MethodDecl | DestructorDecl | CallDecl ; -FieldDecl ::= ( "private" | "public" ) ( "let" | "mut" ) Identifier ":" Type [ "=" Expression ] ";" ; -StaticFieldDecl ::= "static" ( "private" | "public" ) ( "let" | "mut" ) Identifier ":" Type [ "=" Expression ] ";" ; +FieldDecl ::= ( "private" | "public" ) ( "val" | "var" ) Identifier ":" Type [ "=" Expression ] ";" ; +StaticFieldDecl ::= "static" ( "private" | "public" ) ( "val" | "var" ) Identifier ":" Type [ "=" Expression ] ";" ; MethodDecl ::= ( "private" | "public" ) [ "override" ] [ "pure" ] "fun" Identifier "(" [ ParamList ] ")" [ ":" Type ] ( Block | ";" ) ; +CallDecl ::= ( "private" | "public" ) "call" "(" [ ParamList ] ")" [ ":" Type ] ( Block | ";" ) ; + DestructorDecl ::= ( "private" | "public" ) "destructor" "(" ")" ":" "Void" Block ; InterfaceDecl ::= "interface" Identifier InterfaceBody ; // implicitly extends Object -InterfaceBody ::= "{" { InterfaceMethod } "}" ; +InterfaceBody ::= "{" { InterfaceMember } "}" ; +InterfaceMember ::= InterfaceMethod | InterfaceCall ; InterfaceMethod ::= "fun" Identifier "(" [ ParamList ] ")" [ ":" Type ] ";" ; // public & virtual +InterfaceCall ::= "call" "(" [ ParamList ] ")" [ ":" Type ] ";" ; // public & virtual -GlobalVarDecl ::= [ "mut" ] Identifier ":" Type "=" Expression ";" ; +GlobalVarDecl ::= [ "var" ] Identifier ":" Type "=" Expression ";" ; Type ::= NullableType | NonNullType ; NullableType ::= NonNullType "?" ; @@ -380,7 +384,7 @@ PrimitiveType ::= "Int" | "Float" | "Bool" | "Char" | "Byte" | "Pointer" ; Block ::= "{" { Statement } "}" ; Statement ::= VarDeclStmt | ExprStmt | ReturnStmt | IfStmt | WhileStmt | ForStmt | UnsafeStmt | Block ; -VarDeclStmt ::= [ "mut" ] Identifier ":" Type "=" Expression ";" ; +VarDeclStmt ::= [ "var" ] Identifier ":" Type "=" Expression ";" ; ExprStmt ::= Expression ";" ; ReturnStmt ::= "return" [ Expression ] ";" ; IfStmt ::= "if" "(" Expression ")" Statement [ "else" Statement ] ; @@ -408,11 +412,12 @@ UnaryExpr ::= ("!" | "-" | "&" | "*") UnaryExpr Postfix ::= Primary { PostfixOp } ; PostfixOp ::= "." Identifier | "." Identifier "(" [ ArgList ] ")" - | "(" [ ArgList ] ")" // function call or callable object + | "(" [ ArgList ] ")" // function call or callable object call | "as" Type // explicit cast; downcast yields nullable type | "is" Type // type test → Bool | "!!" // non-null assertion | "?." Identifier [ "(" [ ArgList ] ")" ] // safe call chain + | "?." "(" [ ArgList ] ")" // safe callable object call ; Primary ::= Identifier @@ -528,7 +533,7 @@ Programmers cannot create new operator symbols or overload the existing ones for --- -## 8) Memory Management and Runtime +## 9) Memory Management and Runtime One of Ovum's core principles is memory safety. Memory is managed by the runtime's garbage collector (GC), which automatically frees objects that are no longer in use, eliminating whole classes of bugs like dangling pointers, memory leaks, and buffer overruns. @@ -555,7 +560,7 @@ One of Ovum's core principles is memory safety. Memory is managed by the runtime --- -## 9) Runtime and Execution Model +## 10) Runtime and Execution Model The Ovum compiler translates Ovum source code into Ovum bytecode or an intermediate representation, which is executed on the Ovum Virtual Machine (OVM). The OVM provides a sandboxed, platform-independent environment for Ovum programs. @@ -590,7 +595,7 @@ The Ovum compiler translates Ovum source code into Ovum bytecode or an intermedi --- -## 10) System Library & Interop +## 11) System Library & Interop * `sys::Print(msg: String): Void` * `sys::Time(): Int` @@ -605,11 +610,11 @@ The Ovum compiler translates Ovum source code into Ovum bytecode or an intermedi --- -## 11) Unsafe Operations (Recap) +## 12) Unsafe Operations (Recap) Allowed **only** inside `unsafe { ... }`: -* Declaring/writing **global `mut`** variables and **`static mut`** fields. +* Declaring/writing **global `var`** variables and **`static var`** fields. * Casting const → mutable. * Using **`Pointer`**, address-of and dereference. * **Manual destructor** calls. @@ -618,9 +623,9 @@ Allowed **only** inside `unsafe { ... }`: --- -## 12) Code Examples +## 13) Code Examples -### 12.1 Entry point (`StringArray`) +### 13.1 Entry point (`StringArray`) ```ovum // .ovum file @@ -631,7 +636,7 @@ fun Main(args: StringArray): Int { } ``` -### 12.2 Variables, Nulls, Elvis, Safe Calls +### 13.2 Variables, Nulls, Elvis, Safe Calls ```ovum fun DemoNulls(): Void { @@ -649,7 +654,7 @@ fun DemoNulls(): Void { } ``` -### 12.3 Interfaces, Classes, Fields, Overrides +### 13.3 Interfaces, Classes, Fields, Overrides ```ovum interface IGreeter { @@ -657,8 +662,8 @@ interface IGreeter { } class FriendlyGreeter implements IGreeter { - private let Prefix: String = "Hello" - public mut Suffix: String = "!" + private val Prefix: String = "Hello" + public var Suffix: String = "!" public fun FriendlyGreeter(prefix: String, suffix: String): FriendlyGreeter { this.Prefix = prefix @@ -677,7 +682,7 @@ class FriendlyGreeter implements IGreeter { } ``` -### 12.4 Standard Interfaces (`IStringConvertible`, `IComparable`, `IHashable`) +### 13.4 Standard Interfaces (`IStringConvertible`, `IComparable`, `IHashable`) ```ovum interface IStringConvertible { fun ToString(): String } @@ -685,8 +690,8 @@ interface IComparable { fun IsLess(other: Object): Bool } interface IHashable { fun GetHash(): Int } class Point implements IStringConvertible, IComparable, IHashable { - public let X: Int - public let Y: Int + public val X: Int + public val Y: Int public fun Point(x: Int, y: Int): Point { this.X = x; this.Y = y; return this; } @@ -707,7 +712,7 @@ class Point implements IStringConvertible, IComparable, IHashable { } ``` -### 12.5 Pure Functions with Caching +### 13.5 Pure Functions with Caching ```ovum pure fun Fib(n: Int): Int { @@ -717,7 +722,7 @@ pure fun Fib(n: Int): Int { // For user-defined reference types as parameters, implement IComparable. ``` -### 12.6 `is`, `as`, `!!`, and ByteArray Casts +### 13.6 `is`, `as`, `!!`, and ByteArray Casts ```ovum fun DemoCasts(obj: Object): Void { @@ -734,12 +739,12 @@ fun DemoCasts(obj: Object): Void { // Unsafe: raw byte views unsafe { val bytesConst: ByteArray = (obj as ByteArray) - val bytesMut : ByteArray = (obj as mut ByteArray) + val bytesMut : ByteArray = (obj as var ByteArray) } } ``` -### 12.7 Functional Objects (`call`) & Literals +### 13.7 Functional Objects (`call`) & Literals ```ovum interface CustomFunctional { @@ -747,7 +752,7 @@ interface CustomFunctional { } class DefinedFunctional { - public mut Multiplier: Int + public var Multiplier: Int public fun DefinedFunctional(multiplier: Int): DefinedFunctional { this.Multiplier = multiplier @@ -759,7 +764,7 @@ class DefinedFunctional { } } -let AddNullable: CustomFunctional = fun(a: Int?, b: Int?): Int { +val AddNullable: CustomFunctional = fun(a: Int?, b: Int?): Int { return (a ?: 0) + (b ?: 0) } @@ -768,11 +773,11 @@ fun Main(args: StringArray): Int { } ``` -### 12.8 Control Flow Examples +### 13.8 Control Flow Examples ```ovum fun DemoControlFlow(): Void { - mut i: Int = 0 + var i: Int = 0 // While loop with break and continue while (i < 10) { @@ -788,7 +793,7 @@ fun DemoControlFlow(): Void { } // For loop over array - let numbers: IntArray = IntArray(3) + val numbers: IntArray = IntArray(3) numbers[0] = 10 numbers[1] = 20 numbers[2] = 30 @@ -799,34 +804,34 @@ fun DemoControlFlow(): Void { } ``` -### 12.9 Memory Management and Unsafe Operations +### 13.9 Memory Management and Unsafe Operations ```ovum fun DemoUnsafeOperations(): Void { // Unsafe block for low-level operations unsafe { // Global mutable state (unsafe) - static mut globalCounter: Int = 0 + static var globalCounter: Int = 0 globalCounter = globalCounter + 1 // Pointer operations (unsafe) - let obj: Point = Point(10, 20) - let ptr: Pointer = &obj // address-of - let deref: Point = *ptr // dereference + val obj: Point = Point(10, 20) + val ptr: Pointer = &obj // address-of + val deref: Point = *ptr // dereference // ByteArray casting (unsafe) - let bytes: ByteArray = (obj as ByteArray) - let mutableBytes: ByteArray = (obj as mut ByteArray) + val bytes: ByteArray = (obj as ByteArray) + val mutableBytes: ByteArray = (obj as var ByteArray) // Foreign function interface (unsafe) - let input: ByteArray = "Hello".ToUtf8Bytes() - let output: ByteArray = ByteArray(4) - let result: Int = sys::Interope("libc.so", "strlen", input, output) + val input: ByteArray = "Hello".ToUtf8Bytes() + val output: ByteArray = ByteArray(4) + val result: Int = sys::Interope("libc.so", "strlen", input, output) } } ``` -### 12.10 Complete Program Example +### 13.10 Complete Program Example ```ovum // Complete Ovum program demonstrating key features @@ -847,7 +852,7 @@ class Multiplier implements ICalculator { } pure fun ProcessNumbers(calc: ICalculator, numbers: IntArray): Int { - mut result: Int = 0 + var result: Int = 0 for (num in numbers) { result = result + calc.Calculate(num, 2) } @@ -855,16 +860,16 @@ pure fun ProcessNumbers(calc: ICalculator, numbers: IntArray): Int { } fun Main(args: StringArray): Int { - let numbers: IntArray = IntArray(3) + val numbers: IntArray = IntArray(3) numbers[0] = 5 numbers[1] = 10 numbers[2] = 15 - let adder: ICalculator = Adder() - let multiplier: ICalculator = Multiplier() + val adder: ICalculator = Adder() + val multiplier: ICalculator = Multiplier() - let sumResult: Int = ProcessNumbers(adder, numbers) - let productResult: Int = ProcessNumbers(multiplier, numbers) + val sumResult: Int = ProcessNumbers(adder, numbers) + val productResult: Int = ProcessNumbers(multiplier, numbers) sys::Print("Sum result: " + sumResult.ToString()) sys::Print("Product result: " + productResult.ToString()) @@ -875,7 +880,7 @@ fun Main(args: StringArray): Int { --- -## 13) Build & Run (Conceptual) +## 14) Build & Run (Conceptual) 1. **Compile** `.ovum` sources → Ovum bytecode (preprocessor applied). 2. **Execute** on the Ovum VM (single-threaded): @@ -886,11 +891,11 @@ fun Main(args: StringArray): Int { --- -## 14) Notes & Best Practices +## 15) Notes & Best Practices -* Prefer **immutable** data; use `mut` only when necessary. +* Prefer **immutable** data; use `var` only when necessary. * Implement **`IStringConvertible`** for diagnostics (`ToString`). * For **pure** functions with custom types, implement **`IComparable`**. -* Avoid global `mut`; if necessary, **isolate in `unsafe`** with rationale. +* Avoid global `var`; if necessary, **isolate in `unsafe`** with rationale. * Keep names **PascalCase** for classes/functions/methods; keep **keywords lowercase**. * `String` and all array classes are **reference (non-primitive)** types. From 6125d43bcbb58383b04288b9a62c5bcd9c9e28a9 Mon Sep 17 00:00:00 2001 From: bialger Date: Mon, 8 Sep 2025 11:19:28 +0300 Subject: [PATCH 14/21] docs: expand project documentation with build instructions and reference materials Add a new BUILD.md file detailing the build process for the Ovum toolset. Update README.md to direct users to the new project documentation index and language reference. Introduce multiple reference documents covering various aspects of the Ovum language, enhancing the overall documentation structure for better accessibility and clarity. --- CODEBASE_STRUCTURE.md | 3 +++ README.md | 3 ++- BUILD.md => docs/BUILD.md | 0 docs/README.md | 11 ++++++++ docs/reference/README.md | 29 +++++++++++++++++++++ docs/reference/builtin_types.md | 0 docs/reference/code_examples.md | 0 docs/reference/control_flow.md | 0 docs/reference/design.md | 0 docs/reference/expressions_and_operators.md | 0 docs/reference/lexical_structure.md | 0 docs/reference/nullable.md | 0 docs/reference/object_model.md | 0 docs/reference/primitive_types.md | 0 docs/reference/runtime.md | 0 docs/reference/syntax.md | 0 docs/reference/system_library.md | 0 docs/reference/types.md | 0 docs/reference/unsafe.md | 0 19 files changed, 45 insertions(+), 1 deletion(-) rename BUILD.md => docs/BUILD.md (100%) create mode 100644 docs/README.md create mode 100644 docs/reference/README.md create mode 100644 docs/reference/builtin_types.md create mode 100644 docs/reference/code_examples.md create mode 100644 docs/reference/control_flow.md create mode 100644 docs/reference/design.md create mode 100644 docs/reference/expressions_and_operators.md create mode 100644 docs/reference/lexical_structure.md create mode 100644 docs/reference/nullable.md create mode 100644 docs/reference/object_model.md create mode 100644 docs/reference/primitive_types.md create mode 100644 docs/reference/runtime.md create mode 100644 docs/reference/syntax.md create mode 100644 docs/reference/system_library.md create mode 100644 docs/reference/types.md create mode 100644 docs/reference/unsafe.md diff --git a/CODEBASE_STRUCTURE.md b/CODEBASE_STRUCTURE.md index 7cfc619..2c8ea85 100644 --- a/CODEBASE_STRUCTURE.md +++ b/CODEBASE_STRUCTURE.md @@ -12,6 +12,9 @@ - **Исполняемые файлы** - точка входа приложения - **CLI-интерфейс** - командная строка для взаимодействия с пользователем +### docs/ +- **Документация проекта** - README, инструкции по сборке, руководства для разработчиков + ### lib/ - **Основная библиотека** - ядро функциональности проекта - **UI-модуль** - пользовательский интерфейс и CLI-утилиты diff --git a/README.md b/README.md index fd28499..34951a6 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,8 @@ This README (for `.ovum` sources) describes **Ovum**: syntax & semantics, nullable types, formal EBNF grammar, lexer & parser rules, runtime & VM requirements, unsafe operations, casting, functional objects, and code examples (snippets + a complete program). If you want to contribute to the project, please read the [CONTRIBUTING.md](./CONTRIBUTING.md) file. -If you want to build the project, please read the [BUILD.md](./BUILD.md) file. +For more information, please read the [project documentation](./docs/README.md) index file. +For complete language reference, please read the [language reference](./docs/reference/README.md) index file. --- diff --git a/BUILD.md b/docs/BUILD.md similarity index 100% rename from BUILD.md rename to docs/BUILD.md diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..508f41d --- /dev/null +++ b/docs/README.md @@ -0,0 +1,11 @@ +# Ovum Documentation Page + +This page contains documentation for the Ovum programming language. + +## Build instructions + +If you want to build Ovum from scratch, please read the [BUILD.md](./BUILD.md) file. + +## Ovum Language Reference + +If you want to read the Ovum language reference, please read the [README.md](../README.md) file. diff --git a/docs/reference/README.md b/docs/reference/README.md new file mode 100644 index 0000000..c2132ef --- /dev/null +++ b/docs/reference/README.md @@ -0,0 +1,29 @@ +# Ovum Language Reference + +This page contains the Ovum language reference. + +## About Ovum + +* [Ovum design principles](./design.md) +* [Ovum runtime](./runtime.md) +* [Code examples](./code_examples.md) + +## Language rules + +* [Lexical structure](./lexical_structure.md) +* [Syntax and semantics](./syntax.md) +* [Expressions and operators](./expressions_and_operators.md) +* [Type system](./types.md) +* [Control flow](./control_flow.md) +* [Unsafe operations](./unsafe.md) + +## Type system + +* [Primitive types](./primitive_types.md) +* [Object model](./object_model.md) +* [Nullable types](./nullable.md) + +## Standard functionality + +* [Built-in types](./builtin_types.md) +* [Standard library](./system_library.md) diff --git a/docs/reference/builtin_types.md b/docs/reference/builtin_types.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/reference/code_examples.md b/docs/reference/code_examples.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/reference/control_flow.md b/docs/reference/control_flow.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/reference/design.md b/docs/reference/design.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/reference/expressions_and_operators.md b/docs/reference/expressions_and_operators.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/reference/lexical_structure.md b/docs/reference/lexical_structure.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/reference/nullable.md b/docs/reference/nullable.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/reference/object_model.md b/docs/reference/object_model.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/reference/primitive_types.md b/docs/reference/primitive_types.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/reference/runtime.md b/docs/reference/runtime.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/reference/syntax.md b/docs/reference/syntax.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/reference/system_library.md b/docs/reference/system_library.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/reference/types.md b/docs/reference/types.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/reference/unsafe.md b/docs/reference/unsafe.md new file mode 100644 index 0000000..e69de29 From 3b699553097010ba49621c70ee2d3ff31255e68c Mon Sep 17 00:00:00 2001 From: bialger Date: Mon, 8 Sep 2025 19:16:36 +0300 Subject: [PATCH 15/21] docs: update README.md and reference documents for section renumbering and new content Revise the README.md to reflect updated section numbers for Formal Grammar, Expressions and Operators, Lexer & Parser Rules, and Memory Management. Introduce new documentation files covering built-in reference types, control flow constructs, and the overall design philosophy of the Ovum language. Enhance clarity and organization of the documentation to improve user understanding and accessibility. --- README.md | 11 +- docs/reference/builtin_types.md | 8 + docs/reference/code_examples.md | 254 ++++++++++++++++++++ docs/reference/control_flow.md | 60 +++++ docs/reference/design.md | 36 +++ docs/reference/expressions_and_operators.md | 54 +++++ docs/reference/lexical_structure.md | 148 ++++++++++++ docs/reference/nullable.md | 11 + docs/reference/object_model.md | 28 +++ docs/reference/primitive_types.md | 11 + docs/reference/runtime.md | 55 +++++ docs/reference/syntax.md | 78 ++++++ docs/reference/system_library.md | 12 + docs/reference/types.md | 36 +++ docs/reference/unsafe.md | 10 + 15 files changed, 805 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 34951a6..97e5acc 100644 --- a/README.md +++ b/README.md @@ -327,7 +327,7 @@ fun Main(args: StringArray): Int { --- -## 6) Formal Grammar (EBNF) +## 7) Formal Grammar (EBNF) > Core EBNF; whitespace/comments omitted. Operator precedence in §7. @@ -437,7 +437,7 @@ Literal ::= NumberLiteral | StringLiteral | CharLiteral | "true" | "fals --- -## 7) Expressions and Operators +## 8) Expressions and Operators Expressions in Ovum include literal values, variable references, function calls, method calls, field accesses, and combinations of these with operators. Operator syntax and precedence are designed to be familiar to C/Java/Kotlin developers. @@ -494,7 +494,7 @@ Programmers cannot create new operator symbols or overload the existing ones for --- -## 8) Lexer & Parser Rules +## 9) Lexer & Parser Rules ### Tokens @@ -534,7 +534,7 @@ Programmers cannot create new operator symbols or overload the existing ones for --- -## 9) Memory Management and Runtime +## 10) Memory Management and Runtime, One of Ovum's core principles is memory safety. Memory is managed by the runtime's garbage collector (GC), which automatically frees objects that are no longer in use, eliminating whole classes of bugs like dangling pointers, memory leaks, and buffer overruns. @@ -559,9 +559,6 @@ One of Ovum's core principles is memory safety. Memory is managed by the runtime * **Architectures**: **amd64** and **arm64** supported. * **Numeric widths**: `Int` **8 bytes**, `Float` **8 bytes**. ---- - -## 10) Runtime and Execution Model The Ovum compiler translates Ovum source code into Ovum bytecode or an intermediate representation, which is executed on the Ovum Virtual Machine (OVM). The OVM provides a sandboxed, platform-independent environment for Ovum programs. diff --git a/docs/reference/builtin_types.md b/docs/reference/builtin_types.md index e69de29..397003a 100644 --- a/docs/reference/builtin_types.md +++ b/docs/reference/builtin_types.md @@ -0,0 +1,8 @@ +# Built-in Reference Types + +* `String` *(reference type; not primitive)* - text data +* *Nullable* `Int?` (and all other primitive types) - `Int` or `null` - also passed by reference +* **Array classes (no templates / generics):** + * For primitives: `IntArray`, `FloatArray`, `BoolArray`, `CharArray`, `ByteArray`, `PointerArray` + * For objects: **`ObjectArray`** + * **Convenience**: `StringArray` (array of `String`, used for `Main`) diff --git a/docs/reference/code_examples.md b/docs/reference/code_examples.md index e69de29..e218f61 100644 --- a/docs/reference/code_examples.md +++ b/docs/reference/code_examples.md @@ -0,0 +1,254 @@ +# Code Examples + +## 1) Entry point (`StringArray`) + +```ovum +// .ovum file +fun Main(args: StringArray): Int { + val count: Int = args.Length() ?: 0 + sys::Print("Args count: " + count.ToString()) + return 0 +} +``` + +## 2) Variables, Nulls, Elvis, Safe Calls + +```ovum +fun DemoNulls(): Void { + val a: Int? = null + val b: Int? = 5 + + val sum: Int = (a ?: 0) + (b ?: 0) // Elvis + sys::Print("Sum = " + sum.ToString()) + + val name: String? = null + sys::Print("Name length = " + (name?.Length() ?: 0).ToString()) + + val mustNotBeNull: Int = (b!!) // ok + // val crash: Int = (a!!) // aborts (unhandleable) +} +``` + +## 3) Interfaces, Classes, Fields, Overrides + +```ovum +interface IGreeter { + fun Greet(name: String): String // public + virtual by default +} + +class FriendlyGreeter implements IGreeter { + private val Prefix: String = "Hello" + public var Suffix: String = "!" + + public fun FriendlyGreeter(prefix: String, suffix: String): FriendlyGreeter { + this.Prefix = prefix + this.Suffix = suffix + return this + } + + public override fun Greet(name: String): String { + return Prefix + ", " + name + Suffix + } + + // Optional destructor (finalization logic) + public destructor(): Void { + // release non-memory resources if any (files, handles, etc.) + } +} +``` + +## 4) Standard Interfaces (`IStringConvertible`, `IComparable`, `IHashable`) + +```ovum +interface IStringConvertible { fun ToString(): String } +interface IComparable { fun IsLess(other: Object): Bool } +interface IHashable { fun GetHash(): Int } + +class Point implements IStringConvertible, IComparable, IHashable { + public val X: Int + public val Y: Int + + public fun Point(x: Int, y: Int): Point { this.X = x; this.Y = y; return this; } + + public override fun ToString(): String { + return "(" + X.ToString() + ", " + Y.ToString() + ")" + } + + public override fun IsLess(other: Object): Bool { + if (!(other is Point)) return false + val p: Point = (other as Point)!! // safe after is + !! + if (this.X != p.X) return this.X < p.X + return this.Y < p.Y + } + + public override fun GetHash(): Int { + return (X * 1315423911) ^ (Y * 2654435761) + } +} +``` + +## 5) Pure Functions with Caching + +```ovum +pure fun Fib(n: Int): Int { + if (n <= 1) return n + return Fib(n - 1) + Fib(n - 2) +} +// For user-defined reference types as parameters, implement IComparable. +``` + +## 6) `is`, `as`, `!!`, and ByteArray Casts + +```ovum +fun DemoCasts(obj: Object): Void { + if (obj is Point) { + val p: Point = (obj as Point)!! // nullable cast + assert + sys::Print(p.ToString()) + } + + // Bool cast + val b1: Bool = (0 as Bool) // false + val b2: Bool = (42 as Bool) // true + val b3: Bool = (obj as Bool) // true if non-null + + // Unsafe: raw byte views + unsafe { + val bytesConst: ByteArray = (obj as ByteArray) + val bytesMut : ByteArray = (obj as var ByteArray) + } +} +``` + +## 7) Functional Objects (`call`) & Literals + +```ovum +interface CustomFunctional { + call(a: Int?, b: Int?): Int +} + +class DefinedFunctional { + public var Multiplier: Int + + public fun DefinedFunctional(multiplier: Int): DefinedFunctional { + this.Multiplier = multiplier + return this + } + + public call(secondMultiplier: Int): Int = pure fun(secondMultiplier: Int): Int { + return Multiplier * secondMultiplier + } +} + +val AddNullable: CustomFunctional = fun(a: Int?, b: Int?): Int { + return (a ?: 0) + (b ?: 0) +} + +fun Main(args: StringArray): Int { + return AddNullable(2, DefinedFunctional(-1)(2)) +} +``` + +## 8) Control Flow Examples + +```ovum +fun DemoControlFlow(): Void { + var i: Int = 0 + + // While loop with break and continue + while (i < 10) { + if (i == 3) { + i = i + 1 + continue // Skip to next iteration + } + if (i == 7) { + break // Exit loop + } + sys::Print("i = " + i.ToString()) + i = i + 1 + } + + // For loop over array + val numbers: IntArray = IntArray(3) + numbers[0] = 10 + numbers[1] = 20 + numbers[2] = 30 + + for (num in numbers) { + sys::Print("Number: " + num.ToString()) + } +} +``` + +## 9) Memory Management and Unsafe Operations + +```ovum +fun DemoUnsafeOperations(): Void { + // Unsafe block for low-level operations + unsafe { + // Global mutable state (unsafe) + static var globalCounter: Int = 0 + globalCounter = globalCounter + 1 + + // Pointer operations (unsafe) + val obj: Point = Point(10, 20) + val ptr: Pointer = &obj // address-of + val deref: Point = *ptr // dereference + + // ByteArray casting (unsafe) + val bytes: ByteArray = (obj as ByteArray) + val mutableBytes: ByteArray = (obj as var ByteArray) + + // Foreign function interface (unsafe) + val input: ByteArray = "Hello".ToUtf8Bytes() + val output: ByteArray = ByteArray(4) + val result: Int = sys::Interope("libc.so", "strlen", input, output) + } +} +``` + +## 10) Complete Program Example + +```ovum +// Complete Ovum program demonstrating key features +interface ICalculator { + fun Calculate(a: Int, b: Int): Int +} + +class Adder implements ICalculator { + public override fun Calculate(a: Int, b: Int): Int { + return a + b + } +} + +class Multiplier implements ICalculator { + public override fun Calculate(a: Int, b: Int): Int { + return a * b + } +} + +pure fun ProcessNumbers(calc: ICalculator, numbers: IntArray): Int { + var result: Int = 0 + for (num in numbers) { + result = result + calc.Calculate(num, 2) + } + return result +} + +fun Main(args: StringArray): Int { + val numbers: IntArray = IntArray(3) + numbers[0] = 5 + numbers[1] = 10 + numbers[2] = 15 + + val adder: ICalculator = Adder() + val multiplier: ICalculator = Multiplier() + + val sumResult: Int = ProcessNumbers(adder, numbers) + val productResult: Int = ProcessNumbers(multiplier, numbers) + + sys::Print("Sum result: " + sumResult.ToString()) + sys::Print("Product result: " + productResult.ToString()) + + return 0 +} +``` diff --git a/docs/reference/control_flow.md b/docs/reference/control_flow.md index e69de29..7037c28 100644 --- a/docs/reference/control_flow.md +++ b/docs/reference/control_flow.md @@ -0,0 +1,60 @@ +# Control Flow + +Ovum supports standard control flow constructs following structured programming principles: + +## Conditional Execution + +**If/Else**: Conditional execution with syntax `if (condition) { ... } else { ... }`. The condition must be a Boolean expression (`Bool`). Braces are required for blocks, but for single statements the braces can be omitted (though using braces is encouraged for clarity). + +```ovum +if (x > 0) { + sys::Print("Positive") +} else if (x < 0) { + sys::Print("Negative") +} else { + sys::Print("Zero") +} +``` + +## Loops + +**While Loop**: `while (condition) { ... }` repeats the body while the condition is true. + +```ovum +var i: Int = 0 +while (i < 10) { + sys::Print(i.ToString()) + i = i + 1 +} +``` + +**For Loop**: `for (item in collection) { ... }` iterates over elements of a collection (arrays, etc.). + +```ovum +for (item in items) { + sys::Print(item.ToString()) +} +``` + +## Flow Control + +**Return**: `return expression;` exits the current function with the given value (or `return;` with no value to exit a void function). In pure functions, a return simply provides the result; in impure, it may terminate early as usual. + +**Break/Continue**: `break` exits a loop immediately, `continue` skips to the next iteration of the loop. + +```ovum +var i: Int = 0 +while (i < 10) { + if (i == 5) { + break // Exit loop + } + if (i == 3) { + i = i + 1 + continue // Skip to next iteration + } + sys::Print(i.ToString()) + i = i + 1 +} +``` + +All control flow follows structured programming principles (no `goto`). diff --git a/docs/reference/design.md b/docs/reference/design.md index e69de29..2e4cc75 100644 --- a/docs/reference/design.md +++ b/docs/reference/design.md @@ -0,0 +1,36 @@ +# Overview + +**Ovum** is a new general-purpose programming language with a design emphasis on safety, purity, and clarity. It is a strongly **statically typed**, **single-threaded** language with Kotlin-like syntax and a focus on safety, clarity, and performance. + +## Design Philosophy + +Ovum's core design principles center around: + +* **Memory Safety**: Automatic memory management through garbage collection eliminates whole classes of bugs like dangling pointers, memory leaks, and buffer overruns. +* **Immutability by Default**: Variables, object fields, and function parameters are constant by default, reducing unintended side effects and making code easier to reason about. +* **Pure Functions**: Functions with no side effects whose results can be cached for performance optimization through memoization. +* **Interface-Based Polymorphism**: No class inheritance; polymorphism achieved through interface implementation and composition, avoiding complex inheritance hierarchies. +* **Explicit Unsafe Operations**: Low-level or potentially unsafe operations are isolated within explicit `unsafe { ... }` blocks. +* **Less is More**: The language is designed to be simple and easy to learn, with a focus on clarity and readability. The less ways there are to do the same thing, the better. + +## Key Design Points + +* **Strong static typing** with **immutability by default** (`var` required for mutation). +* **Nullable types** and Kotlin-style null-handling: `Type?`, safe calls `?.`, Elvis `?:`, non-null assertion `!!`. +* **Pure functions** (no side effects, VM-level result caching). +* **Classes & interfaces** + + * **No class inheritance**; classes only **implement interfaces**. + * **Root `Object`** is implicit for all classes and interfaces (no need to write `: Object`). It declares only a **virtual destructor**. + * Interfaces are named with **leading `I`** (C# style): e.g., `IGreeter`, `IComparable`. + * Interface methods are **public** and **virtual** by default. + * Class methods implementing interface members must be marked `override`. + * **Access modifiers are mandatory** for all fields and methods in classes (`public`/`private`). + * **Fields use `val` (immutable) or `var` (mutable)**. +* **Namespaces** with `::` resolution (e.g., `sys::Print`). +* **Built-in operators**; **no user-defined operators**. +* **Preprocessor**: `#import`, `#define`, `#ifdef`, `#ifndef`, `#else`, `#undef`. +* **Managed runtime**: VM with **JIT** and **GC**; **no manual memory management**. +* **Single-threaded runtime**: no concurrency primitives. +* **Passing semantics**: all user-defined and non-primitive types (including `String` and all arrays) are **passed by reference** (const by default). +* **File extension**: `.ovum`. diff --git a/docs/reference/expressions_and_operators.md b/docs/reference/expressions_and_operators.md index e69de29..1c8043c 100644 --- a/docs/reference/expressions_and_operators.md +++ b/docs/reference/expressions_and_operators.md @@ -0,0 +1,54 @@ +# Expressions and Operators + +Expressions in Ovum include literal values, variable references, function calls, method calls, field accesses, and combinations of these with operators. Operator syntax and precedence are designed to be familiar to C/Java/Kotlin developers. + +## Arithmetic Operators + +* `+` (addition) - operates on numeric types and may be overloaded internally for string concatenation +* `-` (subtraction) - operates on numeric types +* `*` (multiplication) - operates on numeric types +* `/` (division) - operates on numeric types +* `%` (modulo) - operates on numeric types + +## Comparison Operators + +* `==` (equality) - most types can be compared for equality +* `!=` (inequality) - opposite of equality +* `<`, `<=`, `>`, `>=` (ordering) - only valid on types that have a defined ordering (numeric types or classes implementing `IComparable`) + +## Logical Operators + +* `&&` (logical AND) - short-circuit evaluation +* `||` (logical OR) - short-circuit evaluation +* `!` (negation) - unary operator +* `xor` (exclusive OR) - infix operator on `Bool` + +## Assignment Operator + +* `=` (assignment) - assigns a value to a mutable variable or field. The left-hand side must be a mutable variable or field. + +## Member Access + +* `object.field` - access a field of an object +* `object.method()` - call a method on an object +* `object?.field` - safe field access (returns null if object is null) +* `object?.method()` - safe method call (returns null if object is null) + +## Type Operations + +* `expr as Type` - explicit cast (downcast yields nullable type) +* `expr is Type` - type test (returns `Bool`) + +## Null Handling + +* `expr?.member` - safe call (calls only if expr is not null) +* `expr ?: default` - Elvis operator (returns expr if not null, otherwise default) +* `expr!!` - non-null assertion (throws error if expr is null) + +## Namespace Resolution + +* `Namespace::Name` - refers to a definition from a specific namespace (e.g., `sys::Print`) + +## No User-Defined Operators + +Programmers cannot create new operator symbols or overload the existing ones for user-defined types. The set of operators and their meanings are fixed by the language. This keeps the language syntax clear and consistent and avoids operator overloading misuse. diff --git a/docs/reference/lexical_structure.md b/docs/reference/lexical_structure.md index e69de29..c634db8 100644 --- a/docs/reference/lexical_structure.md +++ b/docs/reference/lexical_structure.md @@ -0,0 +1,148 @@ +# Lexical Structure + +Ovum's source code uses a lexical syntax familiar to C-style and Kotlin-style languages: + +## Identifiers + +Names for variables, functions, classes, etc., consist of letters, digits, and underscores, and must not begin with a digit. For example: `myVar`, `compute_sum`, `GraphNode`. Identifiers are case-sensitive. + +**Naming Convention**: Classes, functions, methods use **PascalCase** (e.g., `Main`, `ToString`, `IsLess`). Keywords/modifiers remain lowercase (`class`, `interface`, `var`, `override`, `pure`, `unsafe`, etc.). + +## Keywords + +Ovum reserves certain words like `fun`, `class`, `interface`, `var`, `override`, `pure`, `if`, `else`, `for`, `while`, `return`, `unsafe`, `val`, `static`, `public`, `private`, `implements`, `as`, `is`, `null`, `true`, `false`, etc. These cannot be used as identifiers. + +## Literals + +* **Numeric literals**: integers (e.g., `42`, `-17`) and floating-point numbers (e.g., `3.14`, `-2.5`) +* **Boolean literals**: `true`, `false` +* **Character literals**: single characters in single quotes (e.g., `'A'`, `'\n'`, `'\t'`) +* **String literals**: text in double quotes (e.g., `"hello"`, `"world"`) with escape sequences like `"\n"` for newline, `"\t"` for tab, `"\\"` for backslash, `"\""` for quote + +## Operators and Punctuation + +* **Arithmetic**: `+`, `-`, `*`, `/`, `%` +* **Comparison**: `==`, `!=`, `<`, `<=`, `>`, `>=` +* **Boolean logic**: `&&` (logical AND), `||` (logical OR), `!` (negation), `xor` (exclusive OR) +* **Assignment**: `=` +* **Null handling**: `?.` (safe call), `?:` (Elvis), `!!` (non-null assertion) +* **Type operations**: `as` (cast), `is` (type test) +* **Punctuation**: `,` (comma), `;` (semicolon), `:` (colon), `()` (parentheses), `{}` (braces), `[]` (brackets) +* **Namespace resolution**: `::` + +## Comments + +* **Line comments**: start with `//` and continue to the end of the line +* **Block comments**: start with `/*` and end with `*/`, can span multiple lines. Nested comments are not allowed + +## Whitespace + +Spaces, tabs, and newlines are generally ignored outside of separating tokens. Indentation is not significant (Ovum is not whitespace-sensitive except that newlines can terminate statements if no semicolon is present). + +## Formal Grammar (EBNF) + +> Core EBNF; whitespace/comments omitted. Operator precedence in §7. + +```ebnf +Program ::= { Import | Conditional | GlobalDef } ; + +Import ::= "#import" StringLiteral ; +Define ::= "#define" Identifier [ NumberLiteral ] ; +Undef ::= "#undef" Identifier ; +Conditional ::= "#ifdef" Identifier { GlobalDef | Import | Conditional } + [ "#else" { GlobalDef | Import | Conditional } ] "#endif" + | "#ifndef" Identifier { GlobalDef | Import | Conditional } + [ "#else" { GlobalDef | Import | Conditional } ] "#endif" ; + +GlobalDef ::= FunctionDecl | ClassDecl | InterfaceDecl | GlobalVarDecl ; + +FunctionDecl ::= [ "pure" ] "fun" Identifier "(" [ ParamList ] ")" [ ":" Type ] Block ; +ParamList ::= Parameter { "," Parameter } ; +Parameter ::= [ "var" ] Identifier ":" Type ; + +ClassDecl ::= "class" Identifier [ "implements" TypeList ] ClassBody ; +TypeList ::= Type { "," Type } ; +ClassBody ::= "{" { ClassMember } "}" ; +ClassMember ::= FieldDecl | StaticFieldDecl | MethodDecl | DestructorDecl | CallDecl ; + +FieldDecl ::= ( "private" | "public" ) ( "val" | "var" ) Identifier ":" Type [ "=" Expression ] ";" ; +StaticFieldDecl ::= "static" ( "private" | "public" ) ( "val" | "var" ) Identifier ":" Type [ "=" Expression ] ";" ; + +MethodDecl ::= ( "private" | "public" ) [ "override" ] [ "pure" ] + "fun" Identifier "(" [ ParamList ] ")" [ ":" Type ] ( Block | ";" ) ; + +CallDecl ::= ( "private" | "public" ) "call" "(" [ ParamList ] ")" [ ":" Type ] ( Block | ";" ) ; + +DestructorDecl ::= ( "private" | "public" ) "destructor" "(" ")" ":" "Void" Block ; + +InterfaceDecl ::= "interface" Identifier InterfaceBody ; // implicitly extends Object +InterfaceBody ::= "{" { InterfaceMember } "}" ; +InterfaceMember ::= InterfaceMethod | InterfaceCall ; +InterfaceMethod ::= "fun" Identifier "(" [ ParamList ] ")" [ ":" Type ] ";" ; // public & virtual +InterfaceCall ::= "call" "(" [ ParamList ] ")" [ ":" Type ] ";" ; // public & virtual + +GlobalVarDecl ::= [ "var" ] Identifier ":" Type "=" Expression ";" ; + +Type ::= NullableType | NonNullType ; +NullableType ::= NonNullType "?" ; +NonNullType ::= PrimitiveType + | "String" + | "IntArray" | "FloatArray" | "BoolArray" | "CharArray" | "ByteArray" | "PointerArray" + | "ObjectArray" + | "StringArray" + | Identifier ; // class/interface names (non-primitive) + +PrimitiveType ::= "Int" | "Float" | "Bool" | "Char" | "Byte" | "Pointer" ; + +Block ::= "{" { Statement } "}" ; +Statement ::= VarDeclStmt | ExprStmt | ReturnStmt | IfStmt | WhileStmt | ForStmt | UnsafeStmt | Block ; + +VarDeclStmt ::= [ "var" ] Identifier ":" Type "=" Expression ";" ; +ExprStmt ::= Expression ";" ; +ReturnStmt ::= "return" [ Expression ] ";" ; +IfStmt ::= "if" "(" Expression ")" Statement [ "else" Statement ] ; +WhileStmt ::= "while" "(" Expression ")" Statement ; +ForStmt ::= "for" "(" Identifier "in" Expression ")" Statement ; +UnsafeStmt ::= "unsafe" Block ; + +Expression ::= Assignment ; +Assignment ::= ElvisExpr [ "=" Assignment ] ; + +ElvisExpr ::= OrExpr [ "?:" ElvisExpr ] ; // right-assoc + +OrExpr ::= AndExpr { "||" AndExpr } ; +AndExpr ::= XorExpr { "&&" XorExpr } ; +XorExpr ::= EqualityExpr { "xor" EqualityExpr } ; + +EqualityExpr ::= RelExpr { ("==" | "!=") RelExpr } ; +RelExpr ::= AddExpr { ("<" | "<=" | ">" | ">=") AddExpr } ; +AddExpr ::= MulExpr { ("+" | "-") MulExpr } ; +MulExpr ::= UnaryExpr { ("*" | "/" | "%") UnaryExpr } ; + +UnaryExpr ::= ("!" | "-" | "&" | "*") UnaryExpr + | Postfix ; + +Postfix ::= Primary { PostfixOp } ; +PostfixOp ::= "." Identifier + | "." Identifier "(" [ ArgList ] ")" + | "(" [ ArgList ] ")" // function call or callable object call + | "as" Type // explicit cast; downcast yields nullable type + | "is" Type // type test → Bool + | "!!" // non-null assertion + | "?." Identifier [ "(" [ ArgList ] ")" ] // safe call chain + | "?." "(" [ ArgList ] ")" // safe callable object call + ; + +Primary ::= Identifier + | Literal + | "(" Expression ")" + | NamespaceRef + | FunctionLiteral ; + +FunctionLiteral ::= "fun" "(" [ ParamList ] ")" [ ":" Type ] Block ; + +NamespaceRef ::= Identifier "::" Identifier ; +ArgList ::= Expression { "," Expression } ; + +Literal ::= NumberLiteral | StringLiteral | CharLiteral | "true" | "false" ; +``` diff --git a/docs/reference/nullable.md b/docs/reference/nullable.md index e69de29..80e24ba 100644 --- a/docs/reference/nullable.md +++ b/docs/reference/nullable.md @@ -0,0 +1,11 @@ +# Nullability (Kotlin-style) + +* Append `?` to make a type **nullable**: `Int?`, `String?`, `Point?`. +* **Safe call**: `expr?.Method()` calls only if `expr != null`; otherwise yields `null` (if the method returns a reference type) or a sensible default for chaining to Elvis. + Example: `name?.ToString()?.Length() ?: 0` +* **Elvis**: `a ?: b` evaluates to `a` if non-null, else `b`. +* **Non-null assertion**: `x!!` throws an unhandleable error if `x == null`. +* **Cast to Bool**: any value can be explicitly cast to `Bool`. + + * Primitives: zero → `false`, non-zero → `true`. + * Non-primitives: `true` iff the reference is a valid (non-null, live) object. diff --git a/docs/reference/object_model.md b/docs/reference/object_model.md index e69de29..1c8c77a 100644 --- a/docs/reference/object_model.md +++ b/docs/reference/object_model.md @@ -0,0 +1,28 @@ +# Standard Interfaces & Object Model + +* **`Object`**: implicit root; has only a **virtual destructor**. + Enables safe, uniform storage (e.g., in `ObjectArray`). +* Standard interfaces (all implicitly extend `Object`): + + * **`IStringConvertible`** — `ToString(): String` + * **`IComparable`** — `IsLess(other: Object): Bool` + + * Required for user-defined types used as parameters to **pure** functions (stable ordering/keys). + * **`IHashable`** — `GetHash(): Int` + +## Casting & Type Tests + +* **Upcasts** (to `Object` or an implemented interface): **safe**, non-nullable result. +* **Downcasts** (to a concrete class or more specific interface): **nullable** result. + + * `obj as Foo` has type `Foo?`; it yields `null` if `obj` is not a `Foo`. + * Use `!!` to assert non-null (aborts if `null`) or `?:` to handle null. + * **Guideline**: Prefer `if (obj is Foo) { val f = (obj as Foo)!!; ... }`. +* **Type test**: `expr is Type` → `Bool` (use before downcasting). +* **Byte view casts**: + + * **Unsafe** cast of any value to **(const) `ByteArray`**. + * **Unsafe** cast of any value to **mutable `ByteArray`**. + * Require `unsafe { ... }`. + +> **Naming**: **Classes, functions, methods use PascalCase** (e.g., `Main`, `ToString`, `IsLess`). Keywords/modifiers remain lowercase (`class`, `interface`, `var`, `override`, `pure`, `unsafe`, etc.). diff --git a/docs/reference/primitive_types.md b/docs/reference/primitive_types.md index e69de29..5fca850 100644 --- a/docs/reference/primitive_types.md +++ b/docs/reference/primitive_types.md @@ -0,0 +1,11 @@ +# Primitive Types + +* `Int` (8 bytes) - 64-bit signed integer +* `Float` (8 bytes) - 64-bit floating-point number +* `Bool` - Boolean value (`true` or `false`) +* `Char` - single character +* `Byte` - 8-bit unsigned integer +* `Pointer` - raw memory address *(only meaningful in `unsafe` code)* + +> Any primitive may have a **nullable** counterpart via `?` (e.g., `Int?`). +> \ No newline at end of file diff --git a/docs/reference/runtime.md b/docs/reference/runtime.md index e69de29..cdaa2e9 100644 --- a/docs/reference/runtime.md +++ b/docs/reference/runtime.md @@ -0,0 +1,55 @@ +# Memory Management and Runtime + +One of Ovum's core principles is memory safety. Memory is managed by the runtime's garbage collector (GC), which automatically frees objects that are no longer in use, eliminating whole classes of bugs like dangling pointers, memory leaks, and buffer overruns. + +## Automatic Memory Management + +* **No Manual Memory Management**: There are no language constructs for pointer arithmetic, manual memory allocation (e.g., no `malloc`/`free` or `new`/`delete` outside of what the language runtime provides), nor explicit memory deallocation by the programmer. +* **Garbage Collection**: The runtime includes a garbage collector that runs periodically (or when allocation thresholds are exceeded) to reclaim memory. It finds objects that are no longer reachable from any live variables or object fields and frees them. +* **Modern GC Algorithm**: Ovum's GC is likely a modern algorithm (possibly generational, parallel, or incremental) to minimize pause times, but these are internal implementation details. + +## Just-In-Time Compilation + +* **JIT Compilation**: The VM includes a Just-In-Time compiler (JIT) that can compile frequently executed code paths to native machine code for speed. +* **Hot Path Optimization**: Initially, Ovum bytecode might be interpreted, but as functions or loops become "hot" (executed often), the JIT will optimize them. +* **Hybrid Approach**: This gives the flexibility of an interpreter (fast startup, platform independence of bytecode) with the performance of compiled code in long-running processes. + +## Runtime, VM & Platform Support + +* **Execution**: Source (`.ovum`) → bytecode → **Ovum VM**. +* **JIT**: Hot paths compiled to native for performance. +* **GC**: Automatic memory reclamation; **no manual memory management**. +* **Single-threaded**: Execution model and VM are single-threaded. +* **Architectures**: **amd64** and **arm64** supported. +* **Numeric widths**: `Int` **8 bytes**, `Float` **8 bytes**. + +The Ovum compiler translates Ovum source code into Ovum bytecode or an intermediate representation, which is executed on the Ovum Virtual Machine (OVM). The OVM provides a sandboxed, platform-independent environment for Ovum programs. + +## Development Workflow + +1. **Write Ovum source code** in `.ovum` files +2. **Compile** using the Ovum compiler, which will: + - Parse using the grammar rules + - Type-check (ensure types match and all variables are defined) + - Enforce const/pure rules + - Produce bytecode or an executable +3. **Execute** using the Ovum VM, which will: + - Load the bytecode + - Resolve any imports (linking together modules) + - Start executing (usually beginning with `Main(args: StringArray): Int`) + - Apply JIT optimization to hot code paths + - Manage memory with garbage collection + +## Platform Requirements + +* **Ovum VM**: Required on the target platform (distributed as standalone application or embedded) +* **Architecture Support**: JIT compiler generates code specific to host CPU architecture for performance +* **Portability**: Bytecode is portable across platforms; only the VM's JIT component is platform-specific +* **Dependencies**: Any necessary native libraries if the program uses `sys::Interope` to call external code + +## Execution Characteristics + +* **Single-threaded**: Execution model and VM are single-threaded +* **No Concurrency Primitives**: No built-in threading or concurrency features +* **Structured Programming**: All control flow follows structured programming principles (no `goto`) +* **Entry Point**: Programs start with `Main(args: StringArray): Int` function diff --git a/docs/reference/syntax.md b/docs/reference/syntax.md index e69de29..e602889 100644 --- a/docs/reference/syntax.md +++ b/docs/reference/syntax.md @@ -0,0 +1,78 @@ +# Syntax & Semantics (Description) + +## Functions + +* Declared with `fun`, PascalCase names: `fun Compute(a: Int): Int { ... }` +* **Pure** functions: `pure fun Hash(o: Object): Int { ... }` + + * Side-effect free; VM may cache results. + * If parameters include user-defined reference types, those types must implement **`IComparable`**. + +## Classes + +* `class Name implements IFace1, IFace2 { ... }` + + * **No class inheritance**. + * **Access modifiers are mandatory** on fields and methods. + * **Fields** use `val` (immutable) or `var` (mutable): + + * `private val Prefix: String` + * `public var Count: Int` + * **Methods** must declare access and can be `override`/`pure`: + + * `public override fun Run(): Int { ... }` + * **Static** fields supported; **writing `static var` is unsafe**. + * **Destructor**: optional, overrides the implicit virtual destructor from `Object`. + + * Syntax: `public destructor(): Void { ... }` (no parameters, no return). + * Called automatically by GC finalization; **manual calls are unsafe**. + +## Interfaces + +* `interface IGreeter { fun Greet(name: String): String; }` + + * Methods are **public** and **virtual** by default. + * No fields, no bodies. + +## Namespaces & Preprocessor + +* Namespace resolution with `::` (e.g., `sys::Print`). +* Preprocessor: `#import`, `#define`, `#ifdef`, `#ifndef`, `#else`, `#undef`. + +## Functional Objects (`call`) + +* Classes or interfaces can declare a **special `call`** member that makes instances **callable** like functions. +* Classes **define `call`**, it **may have other members**. +* Interfaces **contain undefined `call` member** (maybe not one, with all interface rules applying). +* A function literal `fun(...) : T { ... }` can be **coerced** to a interface type that exposes a compatible `call(...) : T` (and only this). + +Example: + +```ovum +interface CustomFunctional { + call(a: Int?, b: Int?): Int +} + +class DefinedFunctional { + public var Multiplier: Int + + public fun DefinedFunctional(multiplier: Int): DefinedFunctional { + this.Multiplier = multiplier + return this + } + + // Defines the callable behavior; pure body allowed + public call(secondMultiplier: Int): Int = pure fun(secondMultiplier: Int): Int { + return Multiplier * secondMultiplier + } +} + +val AddNullable: CustomFunctional = fun(a: Int?, b: Int?): Int { + return (a ?: 0) + (b ?: 0) +} + +fun Main(args: StringArray): Int { + // Constructor call then functional call via `call` + return AddNullable(2, DefinedFunctional(-1)(2)) +} +``` diff --git a/docs/reference/system_library.md b/docs/reference/system_library.md index e69de29..0a760ab 100644 --- a/docs/reference/system_library.md +++ b/docs/reference/system_library.md @@ -0,0 +1,12 @@ +# System Library & Interop + +* `sys::Print(msg: String): Void` +* `sys::Time(): Int` +* `sys::Sleep(ms: Int): Void` +* `sys::Exit(code: Int): Never` *(terminates the process)* +* **Interop (FFI)**: + + * `sys::Interope(dllName: String, functionName: String, input: ByteArray, output: ByteArray): Int` + * **All interop calls are `unsafe`.** + +> Names use **PascalCase** (e.g., `Print`, `Time`, `Sleep`, `Exit`, `Interope`). Namespace remains `sys`. \ No newline at end of file diff --git a/docs/reference/types.md b/docs/reference/types.md index e69de29..5a56540 100644 --- a/docs/reference/types.md +++ b/docs/reference/types.md @@ -0,0 +1,36 @@ +# Types + +Ovum has a rich type system with primitive types and user-defined types. The type system is static and does not permit implicit type coercions (an `Int` won't automatically become a `Float` without an explicit cast, for example). + +## Primitive Types + +* `Int` (8 bytes) - 64-bit signed integer +* `Float` (8 bytes) - 64-bit floating-point number +* `Bool` - Boolean value (`true` or `false`) +* `Char` - single character +* `Byte` - 8-bit unsigned integer +* `Pointer` - raw memory address *(only meaningful in `unsafe` code)* + +> Any primitive may have a **nullable** counterpart via `?` (e.g., `Int?`). + +## Non-Primitive / Reference Types + +* `String` *(reference type; not primitive)* - text data +* *Nullable* `Int?` (and all other primitive types) - `Int` or `null` - also passed by reference +* **Array classes (no templates / generics):** + * For primitives: `IntArray`, `FloatArray`, `BoolArray`, `CharArray`, `ByteArray`, `PointerArray` + * For objects: **`ObjectArray`** + * **Convenience**: `StringArray` (array of `String`, used for `Main`) + +## Passing Semantics + +* **Primitive types**: passed by value (copied) +* **Reference types**: all user-defined and non-primitive types (including `String` and all arrays) are **passed by reference** (const by default) +* **Immutability**: By default, references are considered immutable (the function cannot rebind them or mutate the object's content unless allowed via `var`) + +## Type System Characteristics + +* **Static typing**: Every variable and expression has a type that is checked at compile time +* **No implicit conversions**: Explicit casting required between different types +* **Type safety**: Prevents type errors and provides better documentation of code intent +* **Nullable types**: Any type can be made nullable by appending `?` \ No newline at end of file diff --git a/docs/reference/unsafe.md b/docs/reference/unsafe.md index e69de29..c78e19a 100644 --- a/docs/reference/unsafe.md +++ b/docs/reference/unsafe.md @@ -0,0 +1,10 @@ +# Unsafe Operations + +Allowed **only** inside `unsafe { ... }`: + +* Declaring/writing **global `var`** variables and **`static var`** fields. +* Casting const → mutable. +* Using **`Pointer`**, address-of and dereference. +* **Manual destructor** calls. +* Any **`sys::Interope`** invocation. +* Casting any value to **(const or mutable) `ByteArray`**. From c0f780f7ca16a6209ba5f0c3d1dcde1b015ed22a Mon Sep 17 00:00:00 2001 From: bialger Date: Mon, 8 Sep 2025 21:50:43 +0300 Subject: [PATCH 16/21] docs: revise README.md and code examples for clarity and consistency Update README.md to enhance the overview of the Ovum programming language, emphasizing its design principles and key features. Revise code examples for better clarity, including adjustments to nullable type handling and function definitions. Ensure consistency in naming conventions and improve the overall structure for better user comprehension. --- README.md | 820 +++----------------------------- docs/reference/code_examples.md | 19 +- 2 files changed, 84 insertions(+), 755 deletions(-) diff --git a/README.md b/README.md index 97e5acc..ae83e72 100644 --- a/README.md +++ b/README.md @@ -1,738 +1,144 @@ # Ovum Programming Language -This README (for `.ovum` sources) describes **Ovum**: syntax & semantics, nullable types, formal EBNF grammar, lexer & parser rules, runtime & VM requirements, unsafe operations, casting, functional objects, and code examples (snippets + a complete program). +Ovum is a strongly statically typed, single-threaded language focused on safety, clarity, and performance. It uses Kotlin-like syntax, immutability by default, a GC + JIT VM, interface-based polymorphism, and support for pure functions and functional objects. -If you want to contribute to the project, please read the [CONTRIBUTING.md](./CONTRIBUTING.md) file. -For more information, please read the [project documentation](./docs/README.md) index file. -For complete language reference, please read the [language reference](./docs/reference/README.md) index file. +- Contribute: see [`CONTRIBUTING.md`](CONTRIBUTING.md). +- Project docs: [`docs/README.md`](docs/README.md). +- Full language reference: [`docs/reference/README.md`](docs/reference/README.md). --- -## 1) Overview +## [Overview](docs/reference/design.md) -**Ovum** is a new general-purpose programming language with a design emphasis on safety, purity, and clarity. It is a strongly **statically typed**, **single-threaded** language with Kotlin-like syntax and a focus on safety, clarity, and performance. - -### Design Philosophy - -Ovum's core design principles center around: - -* **Memory Safety**: Automatic memory management through garbage collection eliminates whole classes of bugs like dangling pointers, memory leaks, and buffer overruns. -* **Immutability by Default**: Variables, object fields, and function parameters are constant by default, reducing unintended side effects and making code easier to reason about. -* **Pure Functions**: Functions with no side effects whose results can be cached for performance optimization through memoization. -* **Interface-Based Polymorphism**: No class inheritance; polymorphism achieved through interface implementation and composition, avoiding complex inheritance hierarchies. -* **Explicit Unsafe Operations**: Low-level or potentially unsafe operations are isolated within explicit `unsafe { ... }` blocks. -* **Less is More**: The language is designed to be simple and easy to learn, with a focus on clarity and readability. The less ways there are to do the same thing, the better. - -### Key Design Points - -* **Strong static typing** with **immutability by default** (`var` required for mutation). -* **Nullable types** and Kotlin-style null-handling: `Type?`, safe calls `?.`, Elvis `?:`, non-null assertion `!!`. -* **Pure functions** (no side effects, VM-level result caching). -* **Classes & interfaces** - - * **No class inheritance**; classes only **implement interfaces**. - * **Root `Object`** is implicit for all classes and interfaces (no need to write `: Object`). It declares only a **virtual destructor**. - * Interfaces are named with **leading `I`** (C# style): e.g., `IGreeter`, `IComparable`. - * Interface methods are **public** and **virtual** by default. - * Class methods implementing interface members must be marked `override`. - * **Access modifiers are mandatory** for all fields and methods in classes (`public`/`private`). - * **Fields use `val` (immutable) or `var` (mutable)**. -* **Namespaces** with `::` resolution (e.g., `sys::Print`). -* **Built-in operators**; **no user-defined operators**. -* **Preprocessor**: `#import`, `#define`, `#ifdef`, `#ifndef`, `#else`, `#undef`. -* **Managed runtime**: VM with **JIT** and **GC**; **no manual memory management**. -* **Single-threaded runtime**: no concurrency primitives. -* **Passing semantics**: all user-defined and non-primitive types (including `String` and all arrays) are **passed by reference** (const by default). -* **File extension**: `.ovum`. - -### Standard Interfaces & Object Model - -* **`Object`**: implicit root; has only a **virtual destructor**. - Enables safe, uniform storage (e.g., in `ObjectArray`). -* Standard interfaces (all implicitly extend `Object`): - - * **`IStringConvertible`** — `ToString(): String` - * **`IComparable`** — `IsLess(other: Object): Bool` - - * Required for user-defined types used as parameters to **pure** functions (stable ordering/keys). - * **`IHashable`** — `GetHash(): Int` - -> **Naming**: **Classes, functions, methods use PascalCase** (e.g., `Main`, `ToString`, `IsLess`). Keywords/modifiers remain lowercase (`class`, `interface`, `var`, `override`, `pure`, `unsafe`, etc.). +- Memory safety via GC; no manual memory management. +- Immutable by default; explicit mutation with `var`. +- Pure functions (`pure`) are side-effect free and may be cached on VM level. +- Interface-based polymorphism; no class inheritance. +- Explicit `unsafe { ... }` for low-level operations. +- Minimal, predictable syntax; no user-defined operators. --- -## 2) Types - -Ovum has a rich type system with primitive types and user-defined types. The type system is static and does not permit implicit type coercions (an `Int` won't automatically become a `Float` without an explicit cast, for example). - -### Primitive Types - -* `Int` (8 bytes) - 64-bit signed integer -* `Float` (8 bytes) - 64-bit floating-point number -* `Bool` - Boolean value (`true` or `false`) -* `Char` - single character -* `Byte` - 8-bit unsigned integer -* `Pointer` - raw memory address *(only meaningful in `unsafe` code)* - -> Any primitive may have a **nullable** counterpart via `?` (e.g., `Int?`). - -### Non-Primitive / Reference Types +## [Syntax at a Glance](docs/reference/syntax.md) -* `String` *(reference type; not primitive)* - text data -* *Nullable* `Int?` (and all other primitive types) - `Int` or `null` - also passed by reference -* **Array classes (no templates / generics):** - * For primitives: `IntArray`, `FloatArray`, `BoolArray`, `CharArray`, `ByteArray`, `PointerArray` - * For objects: **`ObjectArray`** - * **Convenience**: `StringArray` (array of `String`, used for `Main`) - -### Passing Semantics - -* **Primitive types**: passed by value (copied) -* **Reference types**: all user-defined and non-primitive types (including `String` and all arrays) are **passed by reference** (const by default) -* **Immutability**: By default, references are considered immutable (the function cannot rebind them or mutate the object's content unless allowed via `var`) - -### Type System Characteristics - -* **Static typing**: Every variable and expression has a type that is checked at compile time -* **No implicit conversions**: Explicit casting required between different types -* **Type safety**: Prevents type errors and provides better documentation of code intent -* **Nullable types**: Any type can be made nullable by appending `?` +- Files: `.ovum`. Names: PascalCase for types/methods. +- Functions: `fun Name(a: T): U { ... }`; pure: `pure fun ...`. +- Classes: `class Name implements IFace { ... }`; interfaces: `interface IFace { ... }`. +- Fields: `val` (immutable) or `var` (mutable); access modifiers are mandatory. +- Namespaces: `::` (e.g., `sys::Print`). Basic preprocessor: `#import`, `#define`, `#ifdef`… --- -## 3) Lexical Structure - -Ovum's source code uses a lexical syntax familiar to C-style and Kotlin-style languages: - -### Identifiers - -Names for variables, functions, classes, etc., consist of letters, digits, and underscores, and must not begin with a digit. For example: `myVar`, `compute_sum`, `GraphNode`. Identifiers are case-sensitive. - -**Naming Convention**: Classes, functions, methods use **PascalCase** (e.g., `Main`, `ToString`, `IsLess`). Keywords/modifiers remain lowercase (`class`, `interface`, `var`, `override`, `pure`, `unsafe`, etc.). - -### Keywords - -Ovum reserves certain words like `fun`, `class`, `interface`, `var`, `override`, `pure`, `if`, `else`, `for`, `while`, `return`, `unsafe`, `val`, `static`, `public`, `private`, `implements`, `as`, `is`, `null`, `true`, `false`, etc. These cannot be used as identifiers. - -### Literals - -* **Numeric literals**: integers (e.g., `42`, `-17`) and floating-point numbers (e.g., `3.14`, `-2.5`) -* **Boolean literals**: `true`, `false` -* **Character literals**: single characters in single quotes (e.g., `'A'`, `'\n'`, `'\t'`) -* **String literals**: text in double quotes (e.g., `"hello"`, `"world"`) with escape sequences like `"\n"` for newline, `"\t"` for tab, `"\\"` for backslash, `"\""` for quote - -### Operators and Punctuation - -* **Arithmetic**: `+`, `-`, `*`, `/`, `%` -* **Comparison**: `==`, `!=`, `<`, `<=`, `>`, `>=` -* **Boolean logic**: `&&` (logical AND), `||` (logical OR), `!` (negation), `xor` (exclusive OR) -* **Assignment**: `=` -* **Null handling**: `?.` (safe call), `?:` (Elvis), `!!` (non-null assertion) -* **Type operations**: `as` (cast), `is` (type test) -* **Punctuation**: `,` (comma), `;` (semicolon), `:` (colon), `()` (parentheses), `{}` (braces), `[]` (brackets) -* **Namespace resolution**: `::` - -### Comments - -* **Line comments**: start with `//` and continue to the end of the line -* **Block comments**: start with `/*` and end with `*/`, can span multiple lines. Nested comments are not allowed +## [Types and Nullability](docs/reference/types.md) -### Whitespace - -Spaces, tabs, and newlines are generally ignored outside of separating tokens. Indentation is not significant (Ovum is not whitespace-sensitive except that newlines can terminate statements if no semicolon is present). +- Nullable types: append `?` (e.g., `Int?`). +- Safe call `?.`, Elvis `?:`, non‑null `!!`. +- Type test `is`, cast `as` (downcast yields nullable type). +- Explicit cast to `Bool` allowed for any value. --- -## 4) Nullability & Boolean Logic - -### Nullability (Kotlin-style) - -* Append `?` to make a type **nullable**: `Int?`, `String?`, `Point?`. -* **Safe call**: `expr?.Method()` calls only if `expr != null`; otherwise yields `null` (if the method returns a reference type) or a sensible default for chaining to Elvis. - Example: `name?.ToString()?.Length() ?: 0` -* **Elvis**: `a ?: b` evaluates to `a` if non-null, else `b`. -* **Non-null assertion**: `x!!` throws an unhandleable error if `x == null`. -* **Cast to Bool**: any value can be explicitly cast to `Bool`. - - * Primitives: zero → `false`, non-zero → `true`. - * Non-primitives: `true` iff the reference is a valid (non-null, live) object. +## [Control Flow](docs/reference/control_flow.md) -### Boolean Logic - -* **Short-circuit**: `&&`, `||` (like Kotlin/Java). -* **Negation**: `!cond`. -* **XOR**: `xor` infix on `Bool` (e.g., `a xor b`). - (Also `==`/`!=` for equality/inequality of Booleans.) +- `if/else`, `while`, `for (x in xs)`. +- `return`, `break`, `continue`; no `goto`. --- -## 4) Casting & Type Tests - -* **Upcasts** (to `Object` or an implemented interface): **safe**, non-nullable result. -* **Downcasts** (to a concrete class or more specific interface): **nullable** result. +## [Expressions and Operators](docs/reference/expressions_and_operators.md) - * `obj as Foo` has type `Foo?`; it yields `null` if `obj` is not a `Foo`. - * Use `!!` to assert non-null (aborts if `null`) or `?:` to handle null. - * **Guideline**: Prefer `if (obj is Foo) { val f = (obj as Foo)!!; ... }`. -* **Type test**: `expr is Type` → `Bool` (use before downcasting). -* **Byte view casts**: - - * **Unsafe** cast of any value to **(const) `ByteArray`**. - * **Unsafe** cast of any value to **mutable `ByteArray`**. - * Require `unsafe { ... }`. +- Arithmetic: `+ - * / %` +- Comparison: `== != < <= > >=` +- Boolean: `&& || ! xor` (short‑circuit `&&`/`||`). +- Assignment: `=` +- Member/calls: `. ()` and safe `?.` +- Null handling: `?. ?: !!` +- Type ops: `as`, `is` +- Namespace: `::` --- -## 5) Control Flow - -Ovum supports standard control flow constructs following structured programming principles: +## [Object Model](docs/reference/object_model.md) -### Conditional Execution - -**If/Else**: Conditional execution with syntax `if (condition) { ... } else { ... }`. The condition must be a Boolean expression (`Bool`). Braces are required for blocks, but for single statements the braces can be omitted (though using braces is encouraged for clarity). - -```ovum -if (x > 0) { - sys::Print("Positive") -} else if (x < 0) { - sys::Print("Negative") -} else { - sys::Print("Zero") -} -``` - -### Loops - -**While Loop**: `while (condition) { ... }` repeats the body while the condition is true. - -```ovum -var i: Int = 0 -while (i < 10) { - sys::Print(i.ToString()) - i = i + 1 -} -``` - -**For Loop**: `for (item in collection) { ... }` iterates over elements of a collection (arrays, etc.). - -```ovum -for (item in items) { - sys::Print(item.ToString()) -} -``` - -### Flow Control - -**Return**: `return expression;` exits the current function with the given value (or `return;` with no value to exit a void function). In pure functions, a return simply provides the result; in impure, it may terminate early as usual. - -**Break/Continue**: `break` exits a loop immediately, `continue` skips to the next iteration of the loop. - -```ovum -var i: Int = 0 -while (i < 10) { - if (i == 5) { - break // Exit loop - } - if (i == 3) { - i = i + 1 - continue // Skip to next iteration - } - sys::Print(i.ToString()) - i = i + 1 -} -``` - -All control flow follows structured programming principles (no `goto`). - ---- - -## 6) Syntax & Semantics (Description) - -### Functions - -* Declared with `fun`, PascalCase names: `fun Compute(a: Int): Int { ... }` -* **Pure** functions: `pure fun Hash(o: Object): Int { ... }` - - * Side-effect free; VM may cache results. - * If parameters include user-defined reference types, those types must implement **`IComparable`**. - -### Classes - -* `class Name implements IFace1, IFace2 { ... }` - - * **No class inheritance**. - * **Access modifiers are mandatory** on fields and methods. - * **Fields** use `val` (immutable) or `var` (mutable): - - * `private val Prefix: String` - * `public var Count: Int` - * **Methods** must declare access and can be `override`/`pure`: - - * `public override fun Run(): Int { ... }` - * **Static** fields supported; **writing `static var` is unsafe**. - * **Destructor**: optional, overrides the implicit virtual destructor from `Object`. - - * Syntax: `public destructor(): Void { ... }` (no parameters, no return). - * Called automatically by GC finalization; **manual calls are unsafe**. - -### Interfaces - -* `interface IGreeter { fun Greet(name: String): String; }` - - * Methods are **public** and **virtual** by default. - * No fields, no bodies. - -### Namespaces & Preprocessor - -* Namespace resolution with `::` (e.g., `sys::Print`). -* Preprocessor: `#import`, `#define`, `#ifdef`, `#ifndef`, `#else`, `#undef`. +- Classes implement interfaces; no class inheritance. +- Methods declare access; support `override` and `pure`. +- Optional destructor; called by GC (manual calls are unsafe). ### Functional Objects (`call`) -* Classes or interfaces can declare a **special `call`** member that makes instances **callable** like functions. -* Classes **define `call`**, it **may have other members**. -* Interfaces **contain undefined `call` member** (maybe not one, with all interface rules applying). -* A function literal `fun(...) : T { ... }` can be **coerced** to a interface type that exposes a compatible `call(...) : T` (and only this). - -Example: - -```ovum -interface CustomFunctional { - call(a: Int?, b: Int?): Int -} - -class DefinedFunctional { - public var Multiplier: Int - - public fun DefinedFunctional(multiplier: Int): DefinedFunctional { - this.Multiplier = multiplier - return this - } - - // Defines the callable behavior; pure body allowed - public call(secondMultiplier: Int): Int = pure fun(secondMultiplier: Int): Int { - return Multiplier * secondMultiplier - } -} - -val AddNullable: CustomFunctional = fun(a: Int?, b: Int?): Int { - return (a ?: 0) + (b ?: 0) -} - -fun Main(args: StringArray): Int { - // Constructor call then functional call via `call` - return AddNullable(2, DefinedFunctional(-1)(2)) -} -``` - ---- - -## 7) Formal Grammar (EBNF) - -> Core EBNF; whitespace/comments omitted. Operator precedence in §7. - -```ebnf -Program ::= { Import | Conditional | GlobalDef } ; - -Import ::= "#import" StringLiteral ; -Define ::= "#define" Identifier [ NumberLiteral ] ; -Undef ::= "#undef" Identifier ; -Conditional ::= "#ifdef" Identifier { GlobalDef | Import | Conditional } - [ "#else" { GlobalDef | Import | Conditional } ] "#endif" - | "#ifndef" Identifier { GlobalDef | Import | Conditional } - [ "#else" { GlobalDef | Import | Conditional } ] "#endif" ; - -GlobalDef ::= FunctionDecl | ClassDecl | InterfaceDecl | GlobalVarDecl ; - -FunctionDecl ::= [ "pure" ] "fun" Identifier "(" [ ParamList ] ")" [ ":" Type ] Block ; -ParamList ::= Parameter { "," Parameter } ; -Parameter ::= [ "var" ] Identifier ":" Type ; - -ClassDecl ::= "class" Identifier [ "implements" TypeList ] ClassBody ; -TypeList ::= Type { "," Type } ; -ClassBody ::= "{" { ClassMember } "}" ; -ClassMember ::= FieldDecl | StaticFieldDecl | MethodDecl | DestructorDecl | CallDecl ; - -FieldDecl ::= ( "private" | "public" ) ( "val" | "var" ) Identifier ":" Type [ "=" Expression ] ";" ; -StaticFieldDecl ::= "static" ( "private" | "public" ) ( "val" | "var" ) Identifier ":" Type [ "=" Expression ] ";" ; - -MethodDecl ::= ( "private" | "public" ) [ "override" ] [ "pure" ] - "fun" Identifier "(" [ ParamList ] ")" [ ":" Type ] ( Block | ";" ) ; - -CallDecl ::= ( "private" | "public" ) "call" "(" [ ParamList ] ")" [ ":" Type ] ( Block | ";" ) ; - -DestructorDecl ::= ( "private" | "public" ) "destructor" "(" ")" ":" "Void" Block ; - -InterfaceDecl ::= "interface" Identifier InterfaceBody ; // implicitly extends Object -InterfaceBody ::= "{" { InterfaceMember } "}" ; -InterfaceMember ::= InterfaceMethod | InterfaceCall ; -InterfaceMethod ::= "fun" Identifier "(" [ ParamList ] ")" [ ":" Type ] ";" ; // public & virtual -InterfaceCall ::= "call" "(" [ ParamList ] ")" [ ":" Type ] ";" ; // public & virtual - -GlobalVarDecl ::= [ "var" ] Identifier ":" Type "=" Expression ";" ; - -Type ::= NullableType | NonNullType ; -NullableType ::= NonNullType "?" ; -NonNullType ::= PrimitiveType - | "String" - | "IntArray" | "FloatArray" | "BoolArray" | "CharArray" | "ByteArray" | "PointerArray" - | "ObjectArray" - | "StringArray" - | Identifier ; // class/interface names (non-primitive) - -PrimitiveType ::= "Int" | "Float" | "Bool" | "Char" | "Byte" | "Pointer" ; - -Block ::= "{" { Statement } "}" ; -Statement ::= VarDeclStmt | ExprStmt | ReturnStmt | IfStmt | WhileStmt | ForStmt | UnsafeStmt | Block ; - -VarDeclStmt ::= [ "var" ] Identifier ":" Type "=" Expression ";" ; -ExprStmt ::= Expression ";" ; -ReturnStmt ::= "return" [ Expression ] ";" ; -IfStmt ::= "if" "(" Expression ")" Statement [ "else" Statement ] ; -WhileStmt ::= "while" "(" Expression ")" Statement ; -ForStmt ::= "for" "(" Identifier "in" Expression ")" Statement ; -UnsafeStmt ::= "unsafe" Block ; - -Expression ::= Assignment ; -Assignment ::= ElvisExpr [ "=" Assignment ] ; - -ElvisExpr ::= OrExpr [ "?:" ElvisExpr ] ; // right-assoc - -OrExpr ::= AndExpr { "||" AndExpr } ; -AndExpr ::= XorExpr { "&&" XorExpr } ; -XorExpr ::= EqualityExpr { "xor" EqualityExpr } ; - -EqualityExpr ::= RelExpr { ("==" | "!=") RelExpr } ; -RelExpr ::= AddExpr { ("<" | "<=" | ">" | ">=") AddExpr } ; -AddExpr ::= MulExpr { ("+" | "-") MulExpr } ; -MulExpr ::= UnaryExpr { ("*" | "/" | "%") UnaryExpr } ; - -UnaryExpr ::= ("!" | "-" | "&" | "*") UnaryExpr - | Postfix ; - -Postfix ::= Primary { PostfixOp } ; -PostfixOp ::= "." Identifier - | "." Identifier "(" [ ArgList ] ")" - | "(" [ ArgList ] ")" // function call or callable object call - | "as" Type // explicit cast; downcast yields nullable type - | "is" Type // type test → Bool - | "!!" // non-null assertion - | "?." Identifier [ "(" [ ArgList ] ")" ] // safe call chain - | "?." "(" [ ArgList ] ")" // safe callable object call - ; - -Primary ::= Identifier - | Literal - | "(" Expression ")" - | NamespaceRef - | FunctionLiteral ; - -FunctionLiteral ::= "fun" "(" [ ParamList ] ")" [ ":" Type ] Block ; - -NamespaceRef ::= Identifier "::" Identifier ; -ArgList ::= Expression { "," Expression } ; - -Literal ::= NumberLiteral | StringLiteral | CharLiteral | "true" | "false" ; -``` +- Classes or interfaces can define a special `call` member to be callable. +- Function literals can coerce to an interface exposing a compatible `call`. --- -## 8) Expressions and Operators - -Expressions in Ovum include literal values, variable references, function calls, method calls, field accesses, and combinations of these with operators. Operator syntax and precedence are designed to be familiar to C/Java/Kotlin developers. - -### Arithmetic Operators - -* `+` (addition) - operates on numeric types and may be overloaded internally for string concatenation -* `-` (subtraction) - operates on numeric types -* `*` (multiplication) - operates on numeric types -* `/` (division) - operates on numeric types -* `%` (modulo) - operates on numeric types +## [Runtime and Tooling](docs/reference/runtime.md) -### Comparison Operators +- Pipeline: `.ovum` → bytecode → Ovum VM. +- GC for memory safety; JIT compiles hot paths. +- Single‑threaded execution model. +- Architectures: amd64, arm64. Numeric widths: `Int` 8 bytes, `Float` 8 bytes. +- Entry point: `Main(args: StringArray): Int`. -* `==` (equality) - most types can be compared for equality -* `!=` (inequality) - opposite of equality -* `<`, `<=`, `>`, `>=` (ordering) - only valid on types that have a defined ordering (numeric types or classes implementing `IComparable`) - -### Logical Operators - -* `&&` (logical AND) - short-circuit evaluation -* `||` (logical OR) - short-circuit evaluation -* `!` (negation) - unary operator -* `xor` (exclusive OR) - infix operator on `Bool` - -### Assignment Operator - -* `=` (assignment) - assigns a value to a mutable variable or field. The left-hand side must be a mutable variable or field. - -### Member Access - -* `object.field` - access a field of an object -* `object.method()` - call a method on an object -* `object?.field` - safe field access (returns null if object is null) -* `object?.method()` - safe method call (returns null if object is null) - -### Type Operations - -* `expr as Type` - explicit cast (downcast yields nullable type) -* `expr is Type` - type test (returns `Bool`) - -### Null Handling - -* `expr?.member` - safe call (calls only if expr is not null) -* `expr ?: default` - Elvis operator (returns expr if not null, otherwise default) -* `expr!!` - non-null assertion (throws error if expr is null) - -### Namespace Resolution - -* `Namespace::Name` - refers to a definition from a specific namespace (e.g., `sys::Print`) - -### No User-Defined Operators - -Programmers cannot create new operator symbols or overload the existing ones for user-defined types. The set of operators and their meanings are fixed by the language. This keeps the language syntax clear and consistent and avoids operator overloading misuse. +Build & Run (conceptual): write `.ovum`, compile (parse, type‑check, enforce const/pure), run on VM (JIT + GC). --- -## 9) Lexer & Parser Rules - -### Tokens - -* **Identifiers**: `[A-Za-z_][A-Za-z0-9_]*` (case-sensitive). Style: **PascalCase** for classes/functions/methods. -* **Literals**: integers, floats, chars (`'A'`, escapes), strings (`"..."`, escapes), Booleans. -* **Operators/Punct**: +## [System Library and Interop](docs/reference/system_library.md) - * Arithmetic: `+ - * / %` - * Comparison: `== != < <= > >=` - * Boolean: `&& || ! xor` - * Nulls: `?. ?: !!` - * Cast/Test: `as is` - * Call/Access: `. ( ) :: , ; : { } [ ]` - * Assignment: `=` - -### Comments & Whitespace - -* Line: `// ...` -* Block: `/* ... */` (non-nested) -* Whitespace separates tokens; not otherwise significant. - -### Precedence (high → low) - -1. Postfix: member calls `.`, calls `()`, safe call `?.`, non-null `!!`, casts `as`, test `is` -2. Unary: `!` `-` `&` `*` (right; `&`/`*` only in `unsafe`) -3. Multiplicative: `*` `/` `%` (left) -4. Additive: `+` `-` (left) -5. Relational: `<` `<=` `>` `>=` (left) -6. Equality: `==` `!=` (left) -7. XOR: `xor` (left) -8. Logical AND: `&&` (left) -9. Logical OR: `||` (left) -10. Elvis: `?:` (right) -11. Assignment: `=` (right) - -> **No user-defined operators**. +- `sys::Print(msg: String): Void` +- `sys::Time(): Int` +- `sys::Sleep(ms: Int): Void` +- `sys::Exit(code: Int): Never` +- FFI: `sys::Interope(dllName, functionName, input: ByteArray, output: ByteArray): Int` (unsafe) --- -## 10) Memory Management and Runtime, - -One of Ovum's core principles is memory safety. Memory is managed by the runtime's garbage collector (GC), which automatically frees objects that are no longer in use, eliminating whole classes of bugs like dangling pointers, memory leaks, and buffer overruns. - -### Automatic Memory Management - -* **No Manual Memory Management**: There are no language constructs for pointer arithmetic, manual memory allocation (e.g., no `malloc`/`free` or `new`/`delete` outside of what the language runtime provides), nor explicit memory deallocation by the programmer. -* **Garbage Collection**: The runtime includes a garbage collector that runs periodically (or when allocation thresholds are exceeded) to reclaim memory. It finds objects that are no longer reachable from any live variables or object fields and frees them. -* **Modern GC Algorithm**: Ovum's GC is likely a modern algorithm (possibly generational, parallel, or incremental) to minimize pause times, but these are internal implementation details. - -### Just-In-Time Compilation - -* **JIT Compilation**: The VM includes a Just-In-Time compiler (JIT) that can compile frequently executed code paths to native machine code for speed. -* **Hot Path Optimization**: Initially, Ovum bytecode might be interpreted, but as functions or loops become "hot" (executed often), the JIT will optimize them. -* **Hybrid Approach**: This gives the flexibility of an interpreter (fast startup, platform independence of bytecode) with the performance of compiled code in long-running processes. - -### Runtime, VM & Platform Support - -* **Execution**: Source (`.ovum`) → bytecode → **Ovum VM**. -* **JIT**: Hot paths compiled to native for performance. -* **GC**: Automatic memory reclamation; **no manual memory management**. -* **Single-threaded**: Execution model and VM are single-threaded. -* **Architectures**: **amd64** and **arm64** supported. -* **Numeric widths**: `Int` **8 bytes**, `Float` **8 bytes**. - - -The Ovum compiler translates Ovum source code into Ovum bytecode or an intermediate representation, which is executed on the Ovum Virtual Machine (OVM). The OVM provides a sandboxed, platform-independent environment for Ovum programs. - -### Development Workflow - -1. **Write Ovum source code** in `.ovum` files -2. **Compile** using the Ovum compiler, which will: - - Parse using the grammar rules - - Type-check (ensure types match and all variables are defined) - - Enforce const/pure rules - - Produce bytecode or an executable -3. **Execute** using the Ovum VM, which will: - - Load the bytecode - - Resolve any imports (linking together modules) - - Start executing (usually beginning with `Main(args: StringArray): Int`) - - Apply JIT optimization to hot code paths - - Manage memory with garbage collection +## [Unsafe (recap)](docs/reference/unsafe.md) -### Platform Requirements - -* **Ovum VM**: Required on the target platform (distributed as standalone application or embedded) -* **Architecture Support**: JIT compiler generates code specific to host CPU architecture for performance -* **Portability**: Bytecode is portable across platforms; only the VM's JIT component is platform-specific -* **Dependencies**: Any necessary native libraries if the program uses `sys::Interope` to call external code - -### Execution Characteristics - -* **Single-threaded**: Execution model and VM are single-threaded -* **No Concurrency Primitives**: No built-in threading or concurrency features -* **Structured Programming**: All control flow follows structured programming principles (no `goto`) -* **Entry Point**: Programs start with `Main(args: StringArray): Int` function +Only inside `unsafe { ... }`: +- Global `var` and `static var` writes. +- Const/mutable casts; `Pointer`, address‑of, dereference. +- Manual destructor calls. +- `sys::Interope`; casting any value to (const or mutable) `ByteArray`. --- -## 11) System Library & Interop - -* `sys::Print(msg: String): Void` -* `sys::Time(): Int` -* `sys::Sleep(ms: Int): Void` -* `sys::Exit(code: Int): Never` *(terminates the process)* -* **Interop (FFI)**: - - * `sys::Interope(dllName: String, functionName: String, input: ByteArray, output: ByteArray): Int` - * **All interop calls are `unsafe`.** - -> Names use **PascalCase** (e.g., `Print`, `Time`, `Sleep`, `Exit`, `Interope`). Namespace remains `sys`. - ---- +## [Code Examples](docs/reference/code_examples.md) -## 12) Unsafe Operations (Recap) - -Allowed **only** inside `unsafe { ... }`: - -* Declaring/writing **global `var`** variables and **`static var`** fields. -* Casting const → mutable. -* Using **`Pointer`**, address-of and dereference. -* **Manual destructor** calls. -* Any **`sys::Interope`** invocation. -* Casting any value to **(const or mutable) `ByteArray`**. - ---- - -## 13) Code Examples - -### 13.1 Entry point (`StringArray`) +### Entry point (`StringArray`) ```ovum // .ovum file fun Main(args: StringArray): Int { - val count: Int = args.Length() ?: 0 + val count: Int = args.Length() sys::Print("Args count: " + count.ToString()) return 0 } ``` -### 13.2 Variables, Nulls, Elvis, Safe Calls - -```ovum -fun DemoNulls(): Void { - val a: Int? = null - val b: Int? = 5 - - val sum: Int = (a ?: 0) + (b ?: 0) // Elvis - sys::Print("Sum = " + sum.ToString()) - - val name: String? = null - sys::Print("Name length = " + (name?.Length() ?: 0).ToString()) - - val mustNotBeNull: Int = (b!!) // ok - // val crash: Int = (a!!) // aborts (unhandleable) -} -``` - -### 13.3 Interfaces, Classes, Fields, Overrides - -```ovum -interface IGreeter { - fun Greet(name: String): String // public + virtual by default -} - -class FriendlyGreeter implements IGreeter { - private val Prefix: String = "Hello" - public var Suffix: String = "!" - - public fun FriendlyGreeter(prefix: String, suffix: String): FriendlyGreeter { - this.Prefix = prefix - this.Suffix = suffix - return this - } - - public override fun Greet(name: String): String { - return Prefix + ", " + name + Suffix - } - - // Optional destructor (finalization logic) - public destructor(): Void { - // release non-memory resources if any (files, handles, etc.) - } -} -``` - -### 13.4 Standard Interfaces (`IStringConvertible`, `IComparable`, `IHashable`) - -```ovum -interface IStringConvertible { fun ToString(): String } -interface IComparable { fun IsLess(other: Object): Bool } -interface IHashable { fun GetHash(): Int } - -class Point implements IStringConvertible, IComparable, IHashable { - public val X: Int - public val Y: Int - - public fun Point(x: Int, y: Int): Point { this.X = x; this.Y = y; return this; } - - public override fun ToString(): String { - return "(" + X.ToString() + ", " + Y.ToString() + ")" - } - - public override fun IsLess(other: Object): Bool { - if (!(other is Point)) return false - val p: Point = (other as Point)!! // safe after is + !! - if (this.X != p.X) return this.X < p.X - return this.Y < p.Y - } - - public override fun GetHash(): Int { - return (X * 1315423911) ^ (Y * 2654435761) - } -} -``` - -### 13.5 Pure Functions with Caching +### Pure functions with caching ```ovum pure fun Fib(n: Int): Int { if (n <= 1) return n return Fib(n - 1) + Fib(n - 2) } -// For user-defined reference types as parameters, implement IComparable. ``` -### 13.6 `is`, `as`, `!!`, and ByteArray Casts +### `is`, `as`, `!!` and ByteArray casts ```ovum fun DemoCasts(obj: Object): Void { if (obj is Point) { - val p: Point = (obj as Point)!! // nullable cast + assert + val p: Point = (obj as Point)!! // nullable cast + assert sys::Print(p.ToString()) } // Bool cast - val b1: Bool = (0 as Bool) // false - val b2: Bool = (42 as Bool) // true - val b3: Bool = (obj as Bool) // true if non-null + val b1: Bool = (0 as Bool) // false + val b2: Bool = (42 as Bool) // true + val b3: Bool = (obj as Bool) // always true + val b4: Bool = ((obj as Point) as Bool) // true if obj is a Point // Unsafe: raw byte views unsafe { @@ -742,7 +148,7 @@ fun DemoCasts(obj: Object): Void { } ``` -### 13.7 Functional Objects (`call`) & Literals +### Functional objects (`call`) & literals ```ovum interface CustomFunctional { @@ -757,12 +163,12 @@ class DefinedFunctional { return this } - public call(secondMultiplier: Int): Int = pure fun(secondMultiplier: Int): Int { + public call(secondMultiplier: Int): Int = fun(secondMultiplier: Int): Int { return Multiplier * secondMultiplier } } -val AddNullable: CustomFunctional = fun(a: Int?, b: Int?): Int { +val AddNullable: CustomFunctional = pure fun(a: Int?, b: Int?): Int { return (a ?: 0) + (b ?: 0) } @@ -771,65 +177,7 @@ fun Main(args: StringArray): Int { } ``` -### 13.8 Control Flow Examples - -```ovum -fun DemoControlFlow(): Void { - var i: Int = 0 - - // While loop with break and continue - while (i < 10) { - if (i == 3) { - i = i + 1 - continue // Skip to next iteration - } - if (i == 7) { - break // Exit loop - } - sys::Print("i = " + i.ToString()) - i = i + 1 - } - - // For loop over array - val numbers: IntArray = IntArray(3) - numbers[0] = 10 - numbers[1] = 20 - numbers[2] = 30 - - for (num in numbers) { - sys::Print("Number: " + num.ToString()) - } -} -``` - -### 13.9 Memory Management and Unsafe Operations - -```ovum -fun DemoUnsafeOperations(): Void { - // Unsafe block for low-level operations - unsafe { - // Global mutable state (unsafe) - static var globalCounter: Int = 0 - globalCounter = globalCounter + 1 - - // Pointer operations (unsafe) - val obj: Point = Point(10, 20) - val ptr: Pointer = &obj // address-of - val deref: Point = *ptr // dereference - - // ByteArray casting (unsafe) - val bytes: ByteArray = (obj as ByteArray) - val mutableBytes: ByteArray = (obj as var ByteArray) - - // Foreign function interface (unsafe) - val input: ByteArray = "Hello".ToUtf8Bytes() - val output: ByteArray = ByteArray(4) - val result: Int = sys::Interope("libc.so", "strlen", input, output) - } -} -``` - -### 13.10 Complete Program Example +### Complete program example ```ovum // Complete Ovum program demonstrating key features @@ -875,25 +223,3 @@ fun Main(args: StringArray): Int { return 0 } ``` - ---- - -## 14) Build & Run (Conceptual) - -1. **Compile** `.ovum` sources → Ovum bytecode (preprocessor applied). -2. **Execute** on the Ovum VM (single-threaded): - - * Bytecode interpretation with JIT for hot paths. - * GC manages memory automatically. - * Entry function: `Main(args: StringArray): Int`. - ---- - -## 15) Notes & Best Practices - -* Prefer **immutable** data; use `var` only when necessary. -* Implement **`IStringConvertible`** for diagnostics (`ToString`). -* For **pure** functions with custom types, implement **`IComparable`**. -* Avoid global `var`; if necessary, **isolate in `unsafe`** with rationale. -* Keep names **PascalCase** for classes/functions/methods; keep **keywords lowercase**. -* `String` and all array classes are **reference (non-primitive)** types. diff --git a/docs/reference/code_examples.md b/docs/reference/code_examples.md index e218f61..479f8a8 100644 --- a/docs/reference/code_examples.md +++ b/docs/reference/code_examples.md @@ -1,11 +1,13 @@ # Code Examples +Here are some code examples to help you get started with Ovum. + ## 1) Entry point (`StringArray`) ```ovum // .ovum file fun Main(args: StringArray): Int { - val count: Int = args.Length() ?: 0 + val count: Int = args.Length() sys::Print("Args count: " + count.ToString()) return 0 } @@ -102,14 +104,15 @@ pure fun Fib(n: Int): Int { ```ovum fun DemoCasts(obj: Object): Void { if (obj is Point) { - val p: Point = (obj as Point)!! // nullable cast + assert + val p: Point = (obj as Point)!! // nullable cast + assert sys::Print(p.ToString()) } // Bool cast - val b1: Bool = (0 as Bool) // false - val b2: Bool = (42 as Bool) // true - val b3: Bool = (obj as Bool) // true if non-null + val b1: Bool = (0 as Bool) // false + val b2: Bool = (42 as Bool) // true + val b3: Bool = (obj as Bool) // always true + val b4: Bool = ((obj as Point) as Bool) // true if obj is a Point // Unsafe: raw byte views unsafe { @@ -134,12 +137,12 @@ class DefinedFunctional { return this } - public call(secondMultiplier: Int): Int = pure fun(secondMultiplier: Int): Int { + public call(secondMultiplier: Int): Int = fun(secondMultiplier: Int): Int { return Multiplier * secondMultiplier } } -val AddNullable: CustomFunctional = fun(a: Int?, b: Int?): Int { +val AddNullable: CustomFunctional = pure fun(a: Int?, b: Int?): Int { return (a ?: 0) + (b ?: 0) } @@ -192,7 +195,7 @@ fun DemoUnsafeOperations(): Void { // Pointer operations (unsafe) val obj: Point = Point(10, 20) val ptr: Pointer = &obj // address-of - val deref: Point = *ptr // dereference + val deref: Object = *ptr // dereference to Object, Pointer is not typed // ByteArray casting (unsafe) val bytes: ByteArray = (obj as ByteArray) From 0411684c7550913de9c8462fc301046e96ce4c83 Mon Sep 17 00:00:00 2001 From: bialger Date: Mon, 8 Sep 2025 22:09:43 +0300 Subject: [PATCH 17/21] docs: expand built-in types documentation with detailed reference for String, Nullable, and System Library Enhance the documentation for built-in types in Ovum by providing comprehensive details on the String type, including its methods and usage examples. Expand the Nullable types section to clarify their creation, method call restrictions, and null handling operators. Additionally, significantly enrich the System Library documentation with extensive information on I/O operations, time functions, file handling, process control, and system information, ensuring clarity and usability for developers. --- docs/reference/builtin_types.md | 229 ++++++++++++++++++++++++++++++- docs/reference/nullable.md | 124 +++++++++++++++-- docs/reference/system_library.md | 204 ++++++++++++++++++++++++++- 3 files changed, 535 insertions(+), 22 deletions(-) diff --git a/docs/reference/builtin_types.md b/docs/reference/builtin_types.md index 397003a..6565b19 100644 --- a/docs/reference/builtin_types.md +++ b/docs/reference/builtin_types.md @@ -1,8 +1,225 @@ # Built-in Reference Types -* `String` *(reference type; not primitive)* - text data -* *Nullable* `Int?` (and all other primitive types) - `Int` or `null` - also passed by reference -* **Array classes (no templates / generics):** - * For primitives: `IntArray`, `FloatArray`, `BoolArray`, `CharArray`, `ByteArray`, `PointerArray` - * For objects: **`ObjectArray`** - * **Convenience**: `StringArray` (array of `String`, used for `Main`) +This document describes the built-in reference types in Ovum, their methods, and the standard interfaces that all types implement. + +## String Type + +`String` is a reference type (not primitive) for text data. All strings are immutable by default and implement `IStringConvertible`, `IComparable`, and `IHashable`. + +### String Methods + +* `Length(): Int` - Returns the number of characters in the string +* `ToString(): String` - Returns the string itself (implements `IStringConvertible`) +* `IsLess(other: Object): Bool` - Lexicographic comparison (implements `IComparable`) +* `GetHash(): Int` - Returns hash code for the string (implements `IHashable`) +* `+` operator - String concatenation (e.g., `"Hello" + " " + "World"`) + +### String Usage + +```ovum +val greeting: String = "Hello, World!" +val length: Int = greeting.Length() // Returns 13 +val combined: String = "Hello" + ", " + "World!" + +// String comparison +val a: String = "apple" +val b: String = "banana" +val isLess: Bool = a.IsLess(b) // true (lexicographic order) + +// String hashing +val hash: Int = greeting.GetHash() +``` + +## Nullable Types + +> **Note**: For detailed information about nullable types, see [`nullable.md`](nullable.md). This section only covers basic information. + +Any primitive type can be made nullable by appending `?` (e.g., `Int?`, `String?`). Nullable types are passed by reference and can hold either a value or `null`. + +**Important**: You cannot directly call methods on nullable types using `.` - you must use the safe call operator `?.` or non-null assertion `!!`. + +```ovum +val nullableString: String? = "Hello" +// val length: Int = nullableString.Length() // ERROR: Cannot call method directly on nullable +val safeLength: Int = nullableString?.Length() ?: 0 // Correct: Use safe call +val forcedLength: Int = nullableString!!.Length() // Correct: Use non-null assertion +``` + +## Array Types + +Ovum provides specialized array classes for different data types. Arrays are reference types and support indexing, iteration, and length operations. All array types implement `IStringConvertible`, `IComparable`, and `IHashable`. + +### Primitive Arrays + +* `IntArray` - Array of 64-bit signed integers +* `FloatArray` - Array of 64-bit floating-point numbers +* `BoolArray` - Array of Boolean values +* `CharArray` - Array of characters +* `ByteArray` - Array of 8-bit unsigned integers +* `PointerArray` - Array of raw memory addresses (unsafe) + +### Object Arrays + +* `ObjectArray` - Array of any object type (implements `Object`) +* `StringArray` - Convenience array of `String` objects (used for `Main` function) + +## File Type + +`File` is a reference type for file operations. Files are nullable by default (`File?`) since file operations can fail. The `File` type implements `IStringConvertible`, `IComparable`, and `IHashable`. + +### File Methods + +* `ReadAllBytes(): ByteArray?` - Reads all bytes from the file, returns `null` on error +* `ReadAllText(): String?` - Reads all text from the file as UTF-8, returns `null` on error +* `WriteAllBytes(data: ByteArray): Bool` - Writes all bytes to the file, returns `false` on error +* `WriteAllText(text: String): Bool` - Writes all text to the file as UTF-8, returns `false` on error +* `AppendText(text: String): Bool` - Appends text to the file, returns `false` on error +* `Close(): Void` - Closes the file handle +* `IsOpen(): Bool` - Returns `true` if the file is currently open +* `GetSize(): Int?` - Returns file size in bytes, or `null` if error +* `ToString(): String` - Returns file path (implements `IStringConvertible`) +* `IsLess(other: Object): Bool` - Compares file paths lexicographically (implements `IComparable`) +* `GetHash(): Int` - Returns hash of file path (implements `IHashable`) + +### File Usage + +```ovum +// File operations +val file: File? = sys::OpenFile("data.txt", sys::FileMode::Read) +if (file != null) { + val content: String? = file.ReadAllText() + if (content != null) { + sys::Print("File content: " + content) + } + file.Close() +} + +// Writing to file +val outputFile: File? = sys::OpenFile("output.txt", sys::FileMode::Write) +if (outputFile != null) { + val success: Bool = outputFile.WriteAllText("Hello, World!") + if (success) { + sys::Print("File written successfully") + } + outputFile.Close() +} + +// File comparison +val file1: File? = sys::OpenFile("a.txt", sys::FileMode::Read) +val file2: File? = sys::OpenFile("b.txt", sys::FileMode::Read) +if (file1 != null && file2 != null) { + val isLess: Bool = file1.IsLess(file2) // Compares file paths +} +``` + +### Array Methods + +All array types support the following methods: + +* `Length(): Int` - Returns the number of elements in the array +* `[index]: ElementType` - Indexing operator for element access +* `[index] = value` - Assignment operator for mutable arrays +* `ToString(): String` - String representation of the array (implements `IStringConvertible`) +* `IsLess(other: Object): Bool` - Lexicographic comparison of array elements (implements `IComparable`) +* `GetHash(): Int` - Hash code based on array contents (implements `IHashable`) + +### Array Usage + +```ovum +// Creating and using arrays +val numbers: IntArray = IntArray(3) +numbers[0] = 10 +numbers[1] = 20 +numbers[2] = 30 + +val count: Int = numbers.Length() // Returns 3 + +// Iteration +for (num in numbers) { + sys::Print(num.ToString()) +} + +// Array comparison +val arr1: IntArray = IntArray(2) +arr1[0] = 1 +arr1[1] = 2 + +val arr2: IntArray = IntArray(2) +arr2[0] = 1 +arr2[1] = 3 + +val isLess: Bool = arr1.IsLess(arr2) // true (lexicographic comparison) + +// Array hashing +val hash: Int = numbers.GetHash() + +// String array (used in Main) +fun Main(args: StringArray): Int { + for (arg in args) { + sys::Print("Argument: " + arg) + } + return 0 +} +``` + +## Built-in Interfaces + +All types in Ovum implicitly implement certain standard interfaces that provide common functionality. + +### Object (Root Interface) + +The implicit root interface for all types. Provides: +* `destructor(): Void` - Virtual destructor called by GC during finalization + +### IStringConvertible + +Provides string conversion capability: +* `ToString(): String` - Converts the object to its string representation + +All built-in types implement this interface: +```ovum +val num: Int = 42 +val str: String = num.ToString() // "42" + +val flag: Bool = true +val flagStr: String = flag.ToString() // "true" +``` + +### IComparable + +Provides ordering capability for sorting and comparison: +* `IsLess(other: Object): Bool` - Returns true if this object is less than the other + +Required for user-defined types used as parameters to pure functions (ensures stable ordering). + +```ovum +val a: Int = 5 +val b: Int = 10 +val isLess: Bool = a.IsLess(b) // true +``` + +### IHashable + +Provides hashing capability for use in hash tables and caching: +* `GetHash(): Int` - Returns a hash code for the object + +```ovum +val text: String = "Hello" +val hash: Int = text.GetHash() +``` + +## Type Hierarchy + +``` +Object (implicit root) +├── IStringConvertible +├── IComparable +└── IHashable + +Built-in Types: +├── String (implements all interfaces) +├── File (implements all interfaces) +├── IntArray, FloatArray, etc. (implements all interfaces) +├── Int, Float, Bool, Char, Byte (implements all interfaces) +└── Int?, String?, File?, etc. (nullable versions, implements all interfaces) +``` diff --git a/docs/reference/nullable.md b/docs/reference/nullable.md index 80e24ba..da03e80 100644 --- a/docs/reference/nullable.md +++ b/docs/reference/nullable.md @@ -1,11 +1,117 @@ # Nullability (Kotlin-style) -* Append `?` to make a type **nullable**: `Int?`, `String?`, `Point?`. -* **Safe call**: `expr?.Method()` calls only if `expr != null`; otherwise yields `null` (if the method returns a reference type) or a sensible default for chaining to Elvis. - Example: `name?.ToString()?.Length() ?: 0` -* **Elvis**: `a ?: b` evaluates to `a` if non-null, else `b`. -* **Non-null assertion**: `x!!` throws an unhandleable error if `x == null`. -* **Cast to Bool**: any value can be explicitly cast to `Bool`. - - * Primitives: zero → `false`, non-zero → `true`. - * Non-primitives: `true` iff the reference is a valid (non-null, live) object. +This document describes how nullable types work in Ovum, including their restrictions and available operations. + +## Creating Nullable Types + +Append `?` to make a type **nullable**: `Int?`, `String?`, `Point?`. Nullable types are passed by reference and can hold either a value or `null`. + +```ovum +val nullableInt: Int? = null +val nullableString: String? = "Hello" +val nullablePoint: Point? = Point(10, 20) +``` + +## Method Call Restrictions + +**Important**: You cannot directly call methods on nullable types using `.` - you must use the safe call operator `?.` or non-null assertion `!!`. + +```ovum +val nullableString: String? = "Hello" +// val length: Int = nullableString.Length() // ERROR: Cannot call method directly on nullable +val safeLength: Int = nullableString?.Length() ?: 0 // Correct: Use safe call +val forcedLength: Int = nullableString!!.Length() // Correct: Use non-null assertion +``` + +## Null Handling Operators + +### Safe Call (`?.`) + +`expr?.Method()` calls only if `expr != null`; otherwise yields `null` (if the method returns a reference type) or a sensible default for chaining to Elvis. + +```ovum +val name: String? = null +val length: Int = name?.Length() ?: 0 // Returns 0 if name is null +val upper: String? = name?.ToUpper() // Returns null if name is null +``` + +### Elvis Operator (`?:`) + +`a ?: b` evaluates to `a` if non-null, else `b`. + +```ovum +val nullableInt: Int? = null +val defaultValue: Int = nullableInt ?: 42 // Uses 42 if nullableInt is null + +val nullableString: String? = null +val result: String = nullableString ?: "default" // Uses "default" if nullableString is null +``` + +### Non-null Assertion (`!!`) + +`x!!` throws an unhandleable error if `x == null`. Use with caution - only when you're certain the value is not null. + +```ovum +val nullableInt: Int? = 42 +val mustExist: Int = nullableInt!! // Safe - nullableInt is not null + +// val crash: Int = (null as Int?)!! // ERROR: Will abort the program +``` + +## Type Casting + +### Cast to Bool + +Any value can be explicitly cast to `Bool`: + +* **Primitives**: zero → `false`, non-zero → `true` +* **Non-primitives**: `true` iff the reference is a valid (non-null, live) object + +```ovum +val nullableInt: Int? = null +val isNull: Bool = (nullableInt as Bool) // false (null is falsy) + +val someInt: Int? = 42 +val isNotNull: Bool = (someInt as Bool) // true (non-null is truthy) +``` + +## Chaining Operations + +You can chain safe calls and Elvis operators for complex null handling: + +```ovum +val person: Person? = getPerson() +val nameLength: Int = person?.Name?.Length() ?: 0 + +// Equivalent to: +val nameLength: Int = if (person != null && person.Name != null) { + person.Name.Length() +} else { + 0 +} +``` + +## Nullable Type Methods + +All nullable types support the same operators but cannot directly call methods: + +```ovum +val nullableString: String? = "Hello" +val nullableInt: Int? = 42 + +// Safe operations +val safeLength: Int = nullableString?.Length() ?: 0 +val safeToString: String = nullableInt?.ToString() ?: "null" + +// Unsafe operations (will crash if null) +val forcedLength: Int = nullableString!!.Length() +val forcedToString: String = nullableInt!!.ToString() +``` + +## Best Practices + +1. **Prefer safe calls** over non-null assertions when possible +2. **Use Elvis operator** to provide sensible defaults +3. **Avoid non-null assertions** unless you're certain the value exists +4. **Chain operations** for cleaner null handling code +5. **Consider using `if` statements** for complex null checks instead of deeply nested safe calls diff --git a/docs/reference/system_library.md b/docs/reference/system_library.md index 0a760ab..9c6ab50 100644 --- a/docs/reference/system_library.md +++ b/docs/reference/system_library.md @@ -1,12 +1,202 @@ # System Library & Interop -* `sys::Print(msg: String): Void` -* `sys::Time(): Int` -* `sys::Sleep(ms: Int): Void` -* `sys::Exit(code: Int): Never` *(terminates the process)* -* **Interop (FFI)**: +The `sys` namespace provides essential system operations including I/O, time, process control, and foreign function interface capabilities. - * `sys::Interope(dllName: String, functionName: String, input: ByteArray, output: ByteArray): Int` +## Basic I/O + +* `sys::Print(msg: String): Void` - Prints a string to standard output +* `sys::PrintLine(msg: String): Void` - Prints a string followed by a newline +* `sys::ReadLine(): String?` - Reads a line from standard input, returns `null` on EOF +* `sys::ReadChar(): Char?` - Reads a single character from standard input, returns `null` on EOF + +## Time and Date Operations + +### Unix Time Functions + +* `sys::UnixTime(): Int` - Returns current Unix timestamp (seconds since epoch) +* `sys::UnixTimeMs(): Int` - Returns current Unix timestamp in milliseconds +* `sys::UnixTimeNs(): Int` - Returns current Unix timestamp in nanoseconds +* `sys::NanoTime(): Int` - Returns high-resolution monotonic time in nanoseconds + +### Date/Time Formatting + +* `sys::FormatDateTime(timestamp: Int, format: String): String?` - Formats Unix timestamp using format string +* `sys::FormatDateTimeMs(timestampMs: Int, format: String): String?` - Formats millisecond timestamp +* `sys::ParseDateTime(dateString: String, format: String): Int?` - Parses date string to Unix timestamp + +### Common Format Specifiers + +* `%Y` - 4-digit year (e.g., 2024) +* `%m` - Month (01-12) +* `%d` - Day of month (01-31) +* `%H` - Hour (00-23) +* `%M` - Minute (00-59) +* `%S` - Second (00-59) +* `%s` - Unix timestamp +* `%f` - Microseconds (000000-999999) +* `%n` - Nanoseconds (000000000-999999999) + +## File Operations + +### File Opening + +* `sys::OpenFile(path: String, mode: FileMode): File?` - Opens a file with specified mode +* `sys::OpenFile(path: String, mode: FileMode, permissions: Int): File?` - Opens file with custom permissions + +### FileMode Enumeration + +* `sys::FileMode::Read` - Open for reading only +* `sys::FileMode::Write` - Open for writing only (truncates existing file) +* `sys::FileMode::Append` - Open for writing, append to end +* `sys::FileMode::ReadWrite` - Open for both reading and writing +* `sys::FileMode::Create` - Create new file, fail if exists +* `sys::FileMode::CreateNew` - Create new file, fail if exists +* `sys::FileMode::Truncate` - Open and truncate to zero length + +### File System Operations + +* `sys::FileExists(path: String): Bool` - Checks if file exists +* `sys::DirectoryExists(path: String): Bool` - Checks if directory exists +* `sys::CreateDirectory(path: String): Bool` - Creates directory, returns `false` on error +* `sys::DeleteFile(path: String): Bool` - Deletes file, returns `false` on error +* `sys::DeleteDirectory(path: String): Bool` - Deletes empty directory, returns `false` on error +* `sys::MoveFile(source: String, destination: String): Bool` - Moves/renames file +* `sys::CopyFile(source: String, destination: String): Bool` - Copies file +* `sys::GetFileSize(path: String): Int?` - Returns file size in bytes, or `null` on error +* `sys::GetFileModifiedTime(path: String): Int?` - Returns file modification time as Unix timestamp + +### Directory Operations + +* `sys::ListDirectory(path: String): StringArray?` - Lists directory contents, returns `null` on error +* `sys::GetCurrentDirectory(): String?` - Returns current working directory +* `sys::ChangeDirectory(path: String): Bool` - Changes current directory, returns `false` on error +* `sys::GetAbsolutePath(path: String): String?` - Returns absolute path, or `null` on error + +## Process Control + +* `sys::Sleep(ms: Int): Void` - Sleeps for specified milliseconds +* `sys::SleepNs(ns: Int): Void` - Sleeps for specified nanoseconds +* `sys::Exit(code: Int): Never` - Terminates the process with exit code +* `sys::GetProcessId(): Int` - Returns current process ID +* `sys::GetEnvironmentVariable(name: String): String?` - Gets environment variable value +* `sys::SetEnvironmentVariable(name: String, value: String): Bool` - Sets environment variable + +## Random Number Generation + +* `sys::Random(): Int` - Returns random 64-bit integer +* `sys::RandomRange(min: Int, max: Int): Int` - Returns random integer in range [min, max) +* `sys::RandomFloat(): Float` - Returns random float in range [0.0, 1.0) +* `sys::RandomFloatRange(min: Float, max: Float): Float` - Returns random float in range [min, max) +* `sys::SeedRandom(seed: Int): Void` - Seeds the random number generator + +## Memory and Performance + +* `sys::GetMemoryUsage(): Int` - Returns current memory usage in bytes +* `sys::GetPeakMemoryUsage(): Int` - Returns peak memory usage in bytes +* `sys::ForceGarbageCollection(): Void` - Forces garbage collection +* `sys::GetProcessorCount(): Int` - Returns number of available CPU cores + +## Network Operations + +* `sys::ResolveHostname(hostname: String): String?` - Resolves hostname to IP address +* `sys::IsPortOpen(host: String, port: Int): Bool` - Checks if TCP port is open +* `sys::GetLocalIpAddress(): String?` - Returns local machine's IP address + +## System Information + +* `sys::GetOsName(): String` - Returns operating system name +* `sys::GetOsVersion(): String` - Returns operating system version +* `sys::GetArchitecture(): String` - Returns CPU architecture (e.g., "x64", "arm64") +* `sys::GetUserName(): String?` - Returns current username +* `sys::GetHomeDirectory(): String?` - Returns user's home directory + +## Error Handling + +* `sys::GetLastError(): String?` - Returns description of last system error +* `sys::ClearError(): Void` - Clears the last error state + +## Foreign Function Interface (FFI) + +* `sys::Interope(dllName: String, functionName: String, input: ByteArray, output: ByteArray): Int` * **All interop calls are `unsafe`.** + * Returns 0 on success, non-zero error code on failure + * `input` contains parameters to pass to the function + * `output` buffer receives the function's return value + +## Usage Examples + +### Date/Time Operations + +```ovum +// Get current time in different formats +val unixTime: Int = sys::UnixTime() +val unixTimeMs: Int = sys::UnixTimeMs() +val unixTimeNs: Int = sys::UnixTimeNs() + +// Format current time +val formatted: String? = sys::FormatDateTime(unixTime, "%Y-%m-%d %H:%M:%S") +if (formatted != null) { + sys::PrintLine("Current time: " + formatted) +} + +// High-precision timing +val start: Int = sys::NanoTime() +// ... do some work ... +val end: Int = sys::NanoTime() +val duration: Int = end - start +sys::PrintLine("Operation took " + duration.ToString() + " nanoseconds") +``` + +### File Operations + +```ovum +// Read and write files +val file: File? = sys::OpenFile("data.txt", sys::FileMode::Read) +if (file != null) { + val content: String? = file.ReadAllText() + if (content != null) { + sys::PrintLine("File content: " + content) + } + file.Close() +} + +// Write to file +val outputFile: File? = sys::OpenFile("output.txt", sys::FileMode::Write) +if (outputFile != null) { + val success: Bool = outputFile.WriteAllText("Hello, World!") + if (success) { + sys::PrintLine("File written successfully") + } + outputFile.Close() +} + +// Directory operations +if (sys::CreateDirectory("new_folder")) { + sys::PrintLine("Directory created") +} + +val files: StringArray? = sys::ListDirectory(".") +if (files != null) { + for (filename in files) { + sys::PrintLine("File: " + filename) + } +} +``` + +### System Information + +```ovum +// Get system information +sys::PrintLine("OS: " + sys::GetOsName() + " " + sys::GetOsVersion()) +sys::PrintLine("Architecture: " + sys::GetArchitecture()) +sys::PrintLine("CPU cores: " + sys::GetProcessorCount().ToString()) +sys::PrintLine("Memory usage: " + sys::GetMemoryUsage().ToString() + " bytes") + +// Environment variables +val path: String? = sys::GetEnvironmentVariable("PATH") +if (path != null) { + sys::PrintLine("PATH: " + path) +} +``` -> Names use **PascalCase** (e.g., `Print`, `Time`, `Sleep`, `Exit`, `Interope`). Namespace remains `sys`. \ No newline at end of file +> **Note**: All function names use **PascalCase** (e.g., `Print`, `UnixTime`, `OpenFile`). The namespace remains `sys`. From 8817c3b2dcc79e788d621c36f2922c08a2a62838 Mon Sep 17 00:00:00 2001 From: bialger Date: Mon, 8 Sep 2025 22:22:26 +0300 Subject: [PATCH 18/21] docs: update primitive types and syntax documentation for clarity Remove unnecessary newline at the end of the primitive types documentation. Add a note in the syntax documentation clarifying the purpose of the `#define` preprocessor directive, enhancing the overall clarity and usability of the documentation. --- docs/reference/primitive_types.md | 1 - docs/reference/syntax.md | 6 ++++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/reference/primitive_types.md b/docs/reference/primitive_types.md index 5fca850..9e1aa09 100644 --- a/docs/reference/primitive_types.md +++ b/docs/reference/primitive_types.md @@ -8,4 +8,3 @@ * `Pointer` - raw memory address *(only meaningful in `unsafe` code)* > Any primitive may have a **nullable** counterpart via `?` (e.g., `Int?`). -> \ No newline at end of file diff --git a/docs/reference/syntax.md b/docs/reference/syntax.md index e602889..1a7d993 100644 --- a/docs/reference/syntax.md +++ b/docs/reference/syntax.md @@ -39,6 +39,8 @@ * Namespace resolution with `::` (e.g., `sys::Print`). * Preprocessor: `#import`, `#define`, `#ifdef`, `#ifndef`, `#else`, `#undef`. +> **Note**: `#define` cannot be used to really define something, it is a way to control what code will be used. + ## Functional Objects (`call`) * Classes or interfaces can declare a **special `call`** member that makes instances **callable** like functions. @@ -62,12 +64,12 @@ class DefinedFunctional { } // Defines the callable behavior; pure body allowed - public call(secondMultiplier: Int): Int = pure fun(secondMultiplier: Int): Int { + public call(secondMultiplier: Int): Int = fun(secondMultiplier: Int): Int { return Multiplier * secondMultiplier } } -val AddNullable: CustomFunctional = fun(a: Int?, b: Int?): Int { +val AddNullable: CustomFunctional = pure fun(a: Int?, b: Int?): Int { return (a ?: 0) + (b ?: 0) } From 711a7ee52c38578be4a03aac2220fa090352ec28 Mon Sep 17 00:00:00 2001 From: bialger Date: Tue, 9 Sep 2025 09:39:42 +0300 Subject: [PATCH 19/21] docs: update CODE_OF_CONDUCT.md, CODEBASE_STRUCTURE.md, CODING_GUIDELINES.md, CONTRIBUTING.md, and README.md for clarity and consistency Revise the CODE_OF_CONDUCT.md to reflect the Contributor Covenant format, enhancing inclusivity and clarity. Update CODEBASE_STRUCTURE.md to provide clear descriptions of directory purposes in English. Revise CODING_GUIDELINES.md for improved readability and consistency in coding practices. Update CONTRIBUTING.md to streamline the contribution process and ensure clarity in instructions. Enhance README.md by adding details on polymorphism and clarifying language features, improving overall documentation quality. --- CODEBASE_STRUCTURE.md | 65 ++++++++-------- CODE_OF_CONDUCT.md | 104 +++++++++++++------------ CODING_GUIDELINES.md | 174 +++++++++++++++++++++--------------------- CONTRIBUTING.md | 71 +++++++++-------- README.md | 1 + 5 files changed, 214 insertions(+), 201 deletions(-) diff --git a/CODEBASE_STRUCTURE.md b/CODEBASE_STRUCTURE.md index 2c8ea85..7a22c8c 100644 --- a/CODEBASE_STRUCTURE.md +++ b/CODEBASE_STRUCTURE.md @@ -1,33 +1,32 @@ -# Базовая структура репозитория - -## Назначение директорий - -### Корневая директория -- **Документация проекта** - README, инструкции по сборке, руководства для разработчиков -- **Конфигурация сборки** - CMakeLists.txt, вспомогательные CMake-скрипты -- **Настройки инструментов** - конфигурации для форматирования, линтеров, Git -- **Скрипты автоматизации** - установка зависимостей, подготовка окружения - -### bin/ -- **Исполняемые файлы** - точка входа приложения -- **CLI-интерфейс** - командная строка для взаимодействия с пользователем - -### docs/ -- **Документация проекта** - README, инструкции по сборке, руководства для разработчиков - -### lib/ -- **Основная библиотека** - ядро функциональности проекта -- **UI-модуль** - пользовательский интерфейс и CLI-утилиты -- **Общие компоненты** - переиспользуемые части кода. Добавляйте новые модули только в эту директорию. - -### tests/ -- **Модульные тесты** - тестирование отдельных компонентов -- **Интеграционные тесты** - тестирование взаимодействия между модулями -- **Вспомогательные функции** - утилиты для тестирования -- **Тестовые данные** - примеры и фикстуры для тестов - -### .github/workflows/ -- **CI/CD конфигурация** - автоматическая сборка и тестирование -- **Проверки качества кода** - статический анализ, форматирование -- **Развертывание** - автоматическая публикация релизов - +# Base Repository Structure + +## Directory Purposes + +### Root Directory +- **Project documentation** — README, build instructions, developer guides +- **Build configuration** — `CMakeLists.txt`, auxiliary CMake scripts +- **Tooling settings** — configurations for formatting, linters, Git +- **Automation scripts** — dependency installation, environment setup + +### `bin/` +- **Executables** — application entry point +- **CLI interface** — command line for user interaction + +### `docs/` +- **Project documentation** — README, build instructions, developer guides + +### `lib/` +- **Core library** — the project's core functionality +- **UI module** — user interface and CLI utilities +- **Shared components** — reusable code parts. Add new modules only under this directory. + +### `tests/` +- **Unit tests** — testing individual components +- **Integration tests** — testing interactions between modules +- **Helper functions** — utilities for testing +- **Test data** — examples and fixtures for tests + +### `.github/workflows/` +- **CI/CD configuration** — automated build and testing +- **Code quality checks** — static analysis, formatting +- **Deployment** — automated release publishing diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 4f1bc20..c0e1001 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,66 +1,76 @@ -# Кодекс поведения участников Соглашения +# Contributor Covenant Code of Conduct -## Наше обещание +## Our Pledge -В интересах создания открытой и доброжелательной среды мы, как участники и сопровождающие, обязуемся сделать участие в -нашем проекте и нашем сообществе свободным от преследований для всех, независимо от возраста, размера тела, -инвалидности, этнической принадлежности, половых характеристик, гендерной идентичности, самовыражение, уровня опыта, -образования, социально-экономического статус, национальности, внешнего вида, расы, религии или сексуальной идентичности -и ориентации. +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. -## Наши стандарты +## Our Standards -Примеры поведения, которое способствует созданию благоприятной среды, включают: +Examples of behavior that contributes to creating a positive environment +include: -- Использование приветливого и инклюзивного языка -- Уважительное отношение к различным точкам зрения и опыту -- Изящно принимаю конструктивную критику -- Сосредоточение внимания на том, что лучше для сообщества -- Проявление сочувствия к другим членам сообщества +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members -Примеры недопустимого поведения участников включают: +Examples of unacceptable behavior by participants include: -- Использование сексуализированной лексики или образов и нежелательное сексуальное внимание или заигрывания -- Троллинг, оскорбительные / уничижительные комментарии, а также личные или политические нападки -- Публичное или частное преследование -- Публикация частной информации других лиц, такой как физический или электронный адрес, без явного разрешения -- Другое поведение, которое можно обоснованно считать неуместным в профессиональной среде. +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting -## Наши обязанности +## Our Responsibilities -Сопровождающие проекта несут ответственность за разъяснение стандартов приемлемого поведения и от них ожидают принятия -соответствующих и справедливых корректирующих действий в ответ на любые случаи неприемлемого поведения. +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. -Сопровождающие проекта имеют право и обязаны удалять, редактировать или отклонять комментарии, коммиты, код, правки -вики, проблемы и другие материалы, которые не соответствуют настоящему Кодексу поведения, или временно или навсегда -заблокировать любого участника за другое поведение, которое они считают неуместным, угрожающим, оскорбительным или -вредным. +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. -## Сфера +## Scope -Этот Кодекс поведения применяется как в проектных, так и в общественных местах, когда человек представляет проект или -его сообщество. Примеры представления проекта или сообщества включают использование официального адреса электронной -почты проекта, размещение сообщений через официальную учетную запись в социальных сетях или выполнение функций -назначенного представителя на онлайн- или офлайн-мероприятии. Представление проекта может быть дополнительно определено -и уточнено сопровождающими проекта. +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. -## Исполнение +## Enforcement -О случаях оскорбления, преследования или иного недопустимого поведения можно сообщить, связавшись с командой проекта по -адресу [bigulov.sasha@gmail.com](mailto:bigulov.sasha@gmail.com). Все жалобы будут рассмотрены и исследованы, и в результате будет дан ответ, который будет -сочтен необходимым и соответствующим обстоятельствам. Команда проекта обязана сохранять конфиденциальность в отношении -лица, сообщившего об инциденте. Более подробная информация о конкретных правилах применения может быть опубликована -отдельно. +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at kylelobo20@gmail.com. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. -Сопровождающие проекта, которые не соблюдают и не соблюдают Кодекс поведения добросовестно, могут столкнуться с -временными или постоянными последствиями, как это определено другими членами руководства проекта. +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. -## Атрибуция +## Attribution -Этот Кодекс поведения адаптирован из [Соглашения для авторов], версия 1.4, доступного по -адресу https://www.contributor-covenant.org/version/1/4/code-of-conduct.html. +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html -Ответы на распространенные вопросы об этом кодексе поведения см. https://www.contributor-covenant.org/faq. +[homepage]: https://www.contributor-covenant.org - -[Соглашения для авторов]: https://www.contributor-covenant.org \ No newline at end of file +For answers to common questions about this code of conduct, see +https://www.contributor-covenant.org/faq diff --git a/CODING_GUIDELINES.md b/CODING_GUIDELINES.md index ff68d33..1b5dae5 100644 --- a/CODING_GUIDELINES.md +++ b/CODING_GUIDELINES.md @@ -1,16 +1,16 @@ # Style guide -В этом документе будут собраны все примеры правильного форматирования кода нашего проекта. +This document collects all examples of correct code formatting for our project. -В основном следует придерживаться [Google Code Style](https://google.github.io/styleguide/cppguide.html). -При противоречии стоит придерживаться этого документа. -Есть файл [ClangFormat](.clang-format), который можно использовать для автоматического форматирования кода. +Primarily follow the Google Code Style: https://google.github.io/styleguide/cppguide.html. +If there is any conflict, follow this document. +There is a ClangFormat file (.clang-format) you can use for automatic formatting. -### 1. Максимальная длина строки кода — 80 символов. +### 1. Maximum line length — 80 characters. -### 2. Используем пробелы, не табы. Настройте в своей среде разработки на 2 пробела. +### 2. Use spaces, not tabs. Configure your editor for 2 spaces. -### 3. Пишем названия переменных, используя snake_case, а для названий функций — PascalCase: +### 3. Use snake_case for variable names, and PascalCase for function names: ```c++ int32_t MakingSomeStuff() { @@ -24,11 +24,11 @@ int main() { } ``` -**НО!** Когда речь идёт о названии классов/перечислений/структур/etc, мы используем PascalCase. +BUT! When it comes to class/enum/struct/etc names, use PascalCase. -**При этом!** Если мы создаем объект класса, мы используем snake_case. -Если это приватное или защищенное поле — ставим нижнее подчеркивание в конце. -Константы пишем в PascalCase, но с префиксом `k`. +At the same time, when creating an object of a class, use snake_case. +If it’s a private or protected field, append a trailing underscore. +Constants use PascalCase with a `k` prefix. ```c++ class SomeClass { @@ -55,16 +55,16 @@ struct UsersData { } ``` -### 4. Используем тип фиксированной длины. Например, `int32_t` вместо `int`, `uint64_t` вместо `unsigned long`. +### 4. Use fixed-width types. For example, `int32_t` instead of `int`, `uint64_t` instead of `unsigned long`. -### 5. Мы допускаем использование auto только: -* При создании через явный вызов конструктора или ином явном указании типа -* При tuple unpacking +### 5. Allow `auto` only: +- When the type is explicit (e.g., via an explicit constructor call or otherwise clearly specified) +- For tuple unpacking -**В ИНОМ СЛУЧАЕ — ИЗБЕГАЕМ** +IN ALL OTHER CASES — AVOID -### 6. Стиль скобок: -При создании новых классов/функций/структур/перечислений/лямбд/etc, определение и скобка на одной строке: +### 6. Bracing style: +When declaring new classes/functions/structs/enums/lambdas/etc, put the declaration and opening brace on the same line: ```c++ struct TypicalExperimentData { @@ -86,18 +86,18 @@ int main() { } ``` -### 7. Переводы строк: +### 7. Blank lines: -* После каждой функции, класса, структуры, перечисления, лямбды, etc. -* До и после каждого блока кода внутри функции — всего, что обрамлено фигурными скобками, например, `for` или `if`. -* Между переменными, если они не связаны между собой. -* Между `#include` и кодом. -* Перед `return` в функции. -* Перед квалификаторами доступа в классе, кроме первого. +- After each function, class, struct, enum, lambda, etc. +- Before and after each code block inside a function — anything delimited by braces, e.g., `for` or `if`. +- Between variables if they’re unrelated. +- Between `#include` and the code. +- Before `return` in a function. +- Before access specifiers in a class, except the first one. -*GodObject.hpp* +GodObject.hpp ```c++ -class GodObject { // Обратите внимание на порядок квалификаторов доступа +class GodObject { // Note the order of access specifiers public: GodObject(); ~GodObject(); @@ -113,7 +113,7 @@ private: } ``` -*GodObject.cpp* +GodObject.cpp ```c++ #include "GodObject.hpp" @@ -136,14 +136,17 @@ int32_t GodObject::CalculateSomething() { } ``` -### 8. Образование названий: +### 8. Naming: -* ***Функции*** называем по их действию — например, если функция что-то "ищет": ```float FindMatrixDeterminant``` +- Functions are named by what they do — for example, if a function “finds” something: + ```c++ + float FindMatrixDeterminant + ``` -Иными словами, следует использовать соответствующий глагол. +In other words, use an appropriate verb. -Например, если мы делаем игру — допустим, змейку. У нас есть пользователь и счёт. -В данном случае мы можем описать пользователя с помощью класса и сделать как минимум 2 публичные функции: +For example, if we’re making a game — say, Snake. We have the user and the score. +In this case we can describe the user with a class and create at least two public functions: ```c++ float Player::CalculateScore() { @@ -151,25 +154,25 @@ float Player::CalculateScore() { } ``` -Название должно быть, насколько это возможно, **понятным**, **коротким**, и **интуитивным** для любого человека, работающего с проектом. -Следует держать баланс между понятностью и длиной названия: не стоит давать названия более 20 символов и 4 слов. -Аббревиатуры следует применять только если они общеприняты (например, название формата данных), и при использовании писать строчными буквами. +Names should be, as much as possible, **clear**, **short**, and **intuitive** for anyone working on the project. +Maintain a balance between clarity and length: avoid names longer than 20 characters and 4 words. +Use abbreviations only if they are widely accepted (for example, a data format name), and when used, write them in lowercase. -* Называем переменные **нормально, то есть осмысленно**: +- Name variables **meaningfully**: ```c++ -int a = 12; // ПЛОХО! +int a = 12; // BAD! -int drops_count = 12; // Более ли менее понятно, о чём идёт речь +int drops_count = 12; // More or less clear what this is ``` -Никаких i, j, k, a, fizz, buzz, etc... +No i, j, k, a, fizz, buzz, etc. -Глобальные переменные не используем. -Если переменная используется в нескольких функциях, то она должна быть передана в качестве аргумента. +Do not use global variables. +If a variable is used in multiple functions, it must be passed as an argument. -* Называем классы с помощью существительных. К примеру: +- Name classes using nouns. For example: ```c++ class Engine { @@ -185,7 +188,7 @@ class AbstactMixer { } ``` -* Структуры называем так же, как и классы: +- Name structs the same way as classes: ```c++ struct List { @@ -201,17 +204,17 @@ struct TypicalExperimentData { }; ``` -* Концепты называем прилагательными: +- Name concepts with adjectives: ```c++ template concept Numeric = std::is_arithmetic_v; ``` -### 9. Делим логику (определение), записанную в `.cpp` и объявление функции записанное в `.hpp` соответственно -Например: +### 9. Separate the function declaration and its implementation between `.hpp` and `.cpp`, respectively +For example: -*main.cpp* +main.cpp ```c++ #include "my_func.hpp" @@ -220,9 +223,10 @@ int main() { return 0; } ``` -* Используем include guards! -*my_func.hpp* +- Use include guards! + +my_func.hpp ```c++ #ifndef MYFUNC_HPP #define MYFUNC_HPP @@ -232,17 +236,17 @@ void Square(int32_t); #endif // MYFUNC_HPP ``` -* Про `include`: - * Все внешние библиотеки подключаем через `#include <...>`, а все наши файлы через `#include "..."`. - * Все `include` пишем в начале файла. - * Все `include` пишем в алфавитном порядке. - * Все `include` пишем в следующем порядке, каждая категория разделяется пустой строкой: - * Сначала стандартная библиотека - * Затем внешние библиотеки - * Затем другие наши библиотеки - * Затем заголовочные файлы текущей библиотеки - -*my_func.cpp* +- About `include`: + - Include external libraries via `#include <...>`, and our own files via `#include "..."`. + - Put all `include`s at the top of the file. + - Write all `include`s in alphabetical order. + - Write all `include`s in the following sequence, with each category separated by a blank line: + - First the standard library + - Then external libraries + - Then other libraries of ours + - Then header files of the current library + +my_func.cpp ```c++ #include @@ -257,21 +261,21 @@ int Square(int32_t a) { } ``` -### 10. Организация хранения исходного кода. +### 10. Source code organization. -Для хранения данных, как-либо связанных с определёнными объектами, используются классы. -В классах описывается модель объекта, поля, хранящие данные, и методы для взаимодействия с данным объектом. -При этом сначала описывается структура класса в .hpp файле, а затем описывается реализация методов в .cpp файле. -Исключений нет, даже конструкторы считаются. -Структуры используем только как DTO (Data Transfer Object). +Use classes to store data associated with specific objects. +A class describes the object model, fields that store data, and methods to interact with the object. +First describe the class structure in the `.hpp` file, and then describe method implementations in the `.cpp` file. +There are no exceptions — constructors count too. +Use structs only as DTOs (Data Transfer Objects). -> В отличие от Google Code Style, мы называем заголовочные файлы так же, как и классы, которые они описывают. -> При этом файлы, которые содержат реализацию методов класса, называем так же, как и заголовочные файлы, но с расширением .cpp. -> А вот файлы, где лежат только функции, называем в snake_case по общему назначению. +> Unlike Google Code Style, we name header files the same as the classes they describe. +> Files that contain class method implementations are named the same as the headers but with a `.cpp` extension. +> Files that contain only functions are named in snake_case by general purpose. -***Правило:*** один класс — один заголовочный файл. +Rule: one class — one header file. -*IdealGas.hpp* +IdealGas.hpp ```c++ class IdealGas { public: @@ -290,7 +294,7 @@ private: }; ``` -*IdealGas.cpp* +IdealGas.cpp ```c++ #include "IdealGas.hpp" @@ -300,9 +304,10 @@ double IdealGas::GetP() { return p_; } -// Реализация прочих методов класса +// Implementation of the remaining class methods ``` -При создании экземпляров классов используются smart pointers, где это возможно (чтобы избежать утечек памяти): + +When creating class instances, use smart pointers where possible (to avoid memory leaks): ```c++ #include @@ -310,29 +315,28 @@ double IdealGas::GetP() { int main() { std::unique_ptr ideal_gas; ideal_gas = std::make_unique(10.0, 10.0, 10.0, 10.0); - // Использование ideal_gas + // Use ideal_gas ideal_gas = std::make_unique(20.0, 20.0, 20.0, 20.0); return 0; } ``` -> Стараемся использовать modern C++, например, почти всегда предпочитаем `std::array` вместо `char[N]`. +> Aim to use modern C++; for example, almost always prefer `std::array` over `char[N]`. -#### О лямбда-функциях +#### On lambda functions -Используем лямбда-функции, когда это необходимо, но не злоупотребляем ими. -К примеру, когда надо захватить некий контекст, или когда надо сформировать очень краткую функцию, -которую надо куда-то передать. +Use lambda functions when needed, but don’t overuse them. +For example, when you need to capture some context, or to create a very short function to pass somewhere. -### 11. Организация передачи данных. +### 11. Data passing organization. -Для передачи в функции используются ссылки и указатели на экземпляры классов, описывающих объекты, с которыми происходит взаимодействие: -* Правильно: +To pass data to functions, use references and pointers to instances of the classes that describe the objects you interact with: +- Correct: ```c++ void SetIdealGas(std::unique_ptr ideal_gas); ``` -* НЕПРАВИЛЬНО +- INCORRECT ```c++ void SetIdealGase(double P, double V, double N, double T, double R, double x, double y, double z, double n, double m, double t); ``` diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 69493d7..ab40fc1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,41 +1,40 @@ -# Руководство по участию +# Contributing Guide -- Пополнить The Documentation Compendium довольно просто. В этом документе показано, как начать работу +- Contributing to The Ovum Language is fairly easy. This document shows you how to get started -## Общее +## General +- The [Codebase Structure](./CODEBASE_STRUCTURE.md) has detailed information about how the various files in this project are structured +- Please ensure that any changes you make are in accordance with the [Coding Guidelines](./CODING_GUIDELINES.md) of this repo -- [Структура кодовой базы ](./CODEBASE_STRUCTURE.md) содержит подробную информацию о том, как структурированы различные файлы в этом проекте -- Пожалуйста, убедитесь, что любые внесенные вами изменения соответствуют [Гайдлайну по написанию кода](./CODING_GUIDELINES.md) этого репозитория +## Submitting changes -## Отправка изменений +- Fork the repo (if you're not the maintainer) + - +- Check out a new branch based and name it to what you intend to do: + - Example: + ```` + $ git checkout -b BRANCH_NAME + ```` + If you get an error, you may need to fetch fooBar first by using + ```` + $ git remote update && git fetch + ```` + - Use one branch per fix / feature +- Commit your changes + - Please provide a git message that explains what you've done + - Please make sure your commits follow the [Semantic Commit Messages](https://seesparkbox.com/foundry/semantic_commit_messages) + - Commit to the forked repository + - Example: + ```` + $ git commit -am 'Add some fooBar' + ```` +- Push to the branch + - Example: + ```` + $ git push origin BRANCH_NAME + ```` +- Make a pull request + - Make sure you send the PR to the fooBar branch + - CI is watching you! -- Сделайте форк репозитория (если вы не ключевой разработчик) - - [https://github.com/Ovum-Programming-Language/OvumLanguage/fork](https://github.com/Ovum-Programming-Language/OvumLanguage/fork) -- Проверьте новую ветку и назовите ее в соответствии с тем, что вы собираетесь делать: - - Пример: - ``` - $ git checkout -b BRANCH_NAME - ``` - Если вы получите сообщение об ошибке, вам может потребоваться сначала получить fooBar, используя - ``` - $ git remote update && git fetch - ``` - - Используйте одну ветку для каждого исправления / добавления -- Закоммитьте свои изменения - - Пожалуйста, предоставьте git сообщение, объясняющее, что вы сделали - - Пожалуйста, убедитесь, что ваши коммиты соответствуют [Semantic Commit Messages](https://seesparkbox.com/foundry/semantic_commit_messages) - - Закоммитьте в репозитории - - Пример: - ``` - $ git commit -am 'Add some fooBar' - ``` -- Запуште в ветку - - Пример: - ``` - $ git push origin BRANCH_NAME - ``` -- Сделать пул реквест - - Убедитесь, что вы отправили пул реквест в ветку fooBar - - Travis CI наблюдает за тобой! - -Если вы будете следовать этим инструкциям, ваш пул реквест довольно безопасно попадет в основной репозиторий! \ No newline at end of file +If you follow these instructions, your PR will land pretty safely in the main repo! diff --git a/README.md b/README.md index ae83e72..7521dbe 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ Ovum is a strongly statically typed, single-threaded language focused on safety, - Interface-based polymorphism; no class inheritance. - Explicit `unsafe { ... }` for low-level operations. - Minimal, predictable syntax; no user-defined operators. +- No generics/templates, only ad-hoc and subclass polymorphism. --- From 9f679cee44cd9d8623a086c77efede6056d43d98 Mon Sep 17 00:00:00 2001 From: bialger Date: Tue, 9 Sep 2025 10:15:42 +0300 Subject: [PATCH 20/21] docs: update code examples and reference documentation for clarity and new features Revise the code examples section to reflect changes in memory management and unsafe operations, including new examples for type aliases and destructors. Update the reference documentation to include type aliases in the design principles and lexical structure sections, enhancing clarity and usability. Remove the obsolete primitive types documentation and adjust related references accordingly. --- docs/reference/README.md | 1 - docs/reference/code_examples.md | 73 ++++- docs/reference/design.md | 2 + docs/reference/lexical_structure.md | 6 +- docs/reference/object_model.md | 416 ++++++++++++++++++++++++++-- docs/reference/primitive_types.md | 10 - docs/reference/syntax.md | 6 +- docs/reference/types.md | 205 ++++++++++++-- docs/reference/unsafe.md | 127 ++++++++- 9 files changed, 780 insertions(+), 66 deletions(-) delete mode 100644 docs/reference/primitive_types.md diff --git a/docs/reference/README.md b/docs/reference/README.md index c2132ef..1f92c91 100644 --- a/docs/reference/README.md +++ b/docs/reference/README.md @@ -19,7 +19,6 @@ This page contains the Ovum language reference. ## Type system -* [Primitive types](./primitive_types.md) * [Object model](./object_model.md) * [Nullable types](./nullable.md) diff --git a/docs/reference/code_examples.md b/docs/reference/code_examples.md index 479f8a8..711160e 100644 --- a/docs/reference/code_examples.md +++ b/docs/reference/code_examples.md @@ -182,7 +182,7 @@ fun DemoControlFlow(): Void { } ``` -## 9) Memory Management and Unsafe Operations +## 9) Unsafe Operations ```ovum fun DemoUnsafeOperations(): Void { @@ -209,7 +209,74 @@ fun DemoUnsafeOperations(): Void { } ``` -## 10) Complete Program Example +## 10) Type Aliases + +```ovum +// Define type aliases for better readability +typealias UserId = Int +typealias UserName = String +typealias UserList = ObjectArray + +class User { + public val Id: UserId + public val Name: UserName + + public fun User(id: UserId, name: UserName): User { + this.Id = id + this.Name = name + return this + } +} + +fun ProcessUsers(users: UserList): Void { + for (i in 0..users.Length()) { + val user: User = (users[i] as User)!! + sys::Print("User " + user.Id.ToString() + ": " + user.Name) + } +} +``` + + +## 11) Memory Management and Destructors + +```ovum +class DatabaseConnection { + private val ConnectionId: Int + private val IsConnected: Bool + + public fun DatabaseConnection(id: Int): DatabaseConnection { + this.ConnectionId = id + this.IsConnected = true + // Establish database connection + return this + } + + public fun Query(sql: String): String { + if (!IsConnected) return "Not connected" + // Execute query + return "Query result" + } + + // Destructor called automatically by GC + public destructor(): Void { + if (IsConnected) { + // Close database connection + sys::Print("Closing connection " + ConnectionId.ToString()) + } + } +} + +fun DemoMemoryManagement(): Void { + val db: DatabaseConnection = DatabaseConnection(1) + val result: String = db.Query("SELECT * FROM users") + sys::Print("Query result: " + result) + + // db will be garbage collected automatically + // destructor will be called by GC +} +``` + +## 12) Complete Program Example ```ovum // Complete Ovum program demonstrating key features @@ -254,4 +321,4 @@ fun Main(args: StringArray): Int { return 0 } -``` +``` \ No newline at end of file diff --git a/docs/reference/design.md b/docs/reference/design.md index 2e4cc75..9086ba0 100644 --- a/docs/reference/design.md +++ b/docs/reference/design.md @@ -28,6 +28,8 @@ Ovum's core design principles center around: * **Access modifiers are mandatory** for all fields and methods in classes (`public`/`private`). * **Fields use `val` (immutable) or `var` (mutable)**. * **Namespaces** with `::` resolution (e.g., `sys::Print`). +* **Functional objects** (`call` member) for functional programming. +* **Type aliases** (`typealias` keyword) for better readability. * **Built-in operators**; **no user-defined operators**. * **Preprocessor**: `#import`, `#define`, `#ifdef`, `#ifndef`, `#else`, `#undef`. * **Managed runtime**: VM with **JIT** and **GC**; **no manual memory management**. diff --git a/docs/reference/lexical_structure.md b/docs/reference/lexical_structure.md index c634db8..a8c79bf 100644 --- a/docs/reference/lexical_structure.md +++ b/docs/reference/lexical_structure.md @@ -10,7 +10,7 @@ Names for variables, functions, classes, etc., consist of letters, digits, and u ## Keywords -Ovum reserves certain words like `fun`, `class`, `interface`, `var`, `override`, `pure`, `if`, `else`, `for`, `while`, `return`, `unsafe`, `val`, `static`, `public`, `private`, `implements`, `as`, `is`, `null`, `true`, `false`, etc. These cannot be used as identifiers. +Ovum reserves certain words like `fun`, `class`, `interface`, `var`, `override`, `pure`, `if`, `else`, `for`, `while`, `return`, `unsafe`, `val`, `static`, `public`, `private`, `implements`, `as`, `is`, `null`, `true`, `false`, `typealias`, `destructor`, `call`, etc. These cannot be used as identifiers. ## Literals @@ -54,7 +54,7 @@ Conditional ::= "#ifdef" Identifier { GlobalDef | Import | Conditional } | "#ifndef" Identifier { GlobalDef | Import | Conditional } [ "#else" { GlobalDef | Import | Conditional } ] "#endif" ; -GlobalDef ::= FunctionDecl | ClassDecl | InterfaceDecl | GlobalVarDecl ; +GlobalDef ::= FunctionDecl | ClassDecl | InterfaceDecl | GlobalVarDecl | TypeAliasDecl ; FunctionDecl ::= [ "pure" ] "fun" Identifier "(" [ ParamList ] ")" [ ":" Type ] Block ; ParamList ::= Parameter { "," Parameter } ; @@ -83,6 +83,8 @@ InterfaceCall ::= "call" "(" [ ParamList ] ")" [ ":" Type ] ";" ; // public & GlobalVarDecl ::= [ "var" ] Identifier ":" Type "=" Expression ";" ; +TypeAliasDecl ::= "typealias" Identifier "=" Type ";" ; + Type ::= NullableType | NonNullType ; NullableType ::= NonNullType "?" ; NonNullType ::= PrimitiveType diff --git a/docs/reference/object_model.md b/docs/reference/object_model.md index 1c8c77a..75fa1f9 100644 --- a/docs/reference/object_model.md +++ b/docs/reference/object_model.md @@ -1,28 +1,404 @@ -# Standard Interfaces & Object Model +# Object Model -* **`Object`**: implicit root; has only a **virtual destructor**. - Enables safe, uniform storage (e.g., in `ObjectArray`). -* Standard interfaces (all implicitly extend `Object`): +Ovum uses an interface-based object model with no class inheritance. All types derive from `Object`, and polymorphism is achieved through interface implementation. - * **`IStringConvertible`** — `ToString(): String` - * **`IComparable`** — `IsLess(other: Object): Bool` +## Object Hierarchy - * Required for user-defined types used as parameters to **pure** functions (stable ordering/keys). - * **`IHashable`** — `GetHash(): Int` +### Root Type: `Object` -## Casting & Type Tests +* **`Object`** - implicit root of all reference types + * Contains only a virtual destructor + * Enables safe, uniform storage (e.g., in `ObjectArray`) + * All user-defined classes implicitly extend `Object` + * Cannot be instantiated directly -* **Upcasts** (to `Object` or an implemented interface): **safe**, non-nullable result. -* **Downcasts** (to a concrete class or more specific interface): **nullable** result. +```ovum +// Object is the root of all reference types +val obj: Object = Point(10, 20) // Upcast to Object +val point: Point? = (obj as Point) // Downcast to Point (nullable) +``` - * `obj as Foo` has type `Foo?`; it yields `null` if `obj` is not a `Foo`. - * Use `!!` to assert non-null (aborts if `null`) or `?:` to handle null. - * **Guideline**: Prefer `if (obj is Foo) { val f = (obj as Foo)!!; ... }`. -* **Type test**: `expr is Type` → `Bool` (use before downcasting). -* **Byte view casts**: +## Standard Interfaces - * **Unsafe** cast of any value to **(const) `ByteArray`**. - * **Unsafe** cast of any value to **mutable `ByteArray`**. - * Require `unsafe { ... }`. +All standard interfaces implicitly extend `Object` and provide common functionality: -> **Naming**: **Classes, functions, methods use PascalCase** (e.g., `Main`, `ToString`, `IsLess`). Keywords/modifiers remain lowercase (`class`, `interface`, `var`, `override`, `pure`, `unsafe`, etc.). +### `IStringConvertible` + +Provides string representation capability: + +```ovum +interface IStringConvertible { + fun ToString(): String +} + +class Person implements IStringConvertible { + public val Name: String + public val Age: Int + + public fun Person(name: String, age: Int): Person { + this.Name = name + this.Age = age + return this + } + + public override fun ToString(): String { + return Name + " (" + Age.ToString() + ")" + } +} +``` + +### `IComparable` + +Provides ordering capability for sorting and comparison: + +```ovum +interface IComparable { + fun IsLess(other: Object): Bool +} + +class Point implements IComparable { + public val X: Int + public val Y: Int + + public fun Point(x: Int, y: Int): Point { + this.X = x + this.Y = y + return this + } + + public override fun IsLess(other: Object): Bool { + if (!(other is Point)) return false + val p: Point = (other as Point)!! + if (this.X != p.X) return this.X < p.X + return this.Y < p.Y + } +} +``` + +**Required for pure function parameters** (provides stable ordering/keys). + +### `IHashable` + +Provides hash code generation for use in hash tables: + +```ovum +interface IHashable { + fun GetHash(): Int +} + +class Point implements IHashable { + public val X: Int + public val Y: Int + + public override fun GetHash(): Int { + return (X * 1315423911) ^ (Y * 2654435761) + } +} +``` + +## Class Definitions + +### Basic Class Syntax + +```ovum +class ClassName implements Interface1, Interface2 { + // Fields + // Constructor + // Methods + // Destructor (optional) +} +``` + +### Fields + +Fields can be immutable (`val`) or mutable (`var`): + +```ovum +class BankAccount { + public val AccountNumber: String // Immutable field + public var Balance: Float // Mutable field + private val CreatedDate: Int // Private field +} +``` + +### Access Modifiers + +* **`public`** - accessible from anywhere +* **`private`** - accessible only within the same class + +```ovum +class DataContainer { + public val PublicData: String = "Public" + private val PrivateData: String = "Private" + + public fun GetPrivateData(): String { + return PrivateData // OK: accessing private member from within class + } +} +``` + +### Constructors + +Constructors initialize new instances: + +```ovum +class Rectangle { + public val Width: Float + public val Height: Float + + public fun Rectangle(width: Float, height: Float): Rectangle { + this.Width = width + this.Height = height + return this + } + + // Multiple constructors (overloading) + public fun Rectangle(size: Float): Rectangle { + this.Width = size + this.Height = size + return this + } +} +``` + +### Methods + +Methods can be regular, pure, or override: + +```ovum +class Calculator implements IStringConvertible { + public fun Add(a: Int, b: Int): Int { + return a + b + } + + public pure fun Multiply(a: Int, b: Int): Int { + return a * b + } + + public override fun ToString(): String { + return "Calculator" + } +} +``` + +### Destructors + +Optional destructors are called by the garbage collector: + +```ovum +class FileHandler { + private val FilePath: String + + public destructor(): Void { + // Release file handles, network connections, etc. + // Manual calls are unsafe + } +} +``` + +## Interface Definitions + +### Basic Interface Syntax + +```ovum +interface InterfaceName extends BaseInterface { + // Method declarations + // Property declarations +} +``` + +### Method Declarations + +```ovum +interface IShape { + fun GetArea(): Float + fun GetPerimeter(): Float + fun Draw(): Void +} + +interface IColorable { + fun SetColor(color: String): Void + fun GetColor(): String +} +``` + +### Property Declarations + +Interfaces can declare properties that implementing classes must provide: + +```ovum +interface IReadable { + val IsReadable: Bool + val Content: String +} + +class Document implements IReadable { + public val IsReadable: Bool = true + public val Content: String +} +``` + +### Multiple Interface Implementation + +Classes can implement multiple interfaces: + +```ovum +class ColoredRectangle implements IShape, IColorable { + public val Width: Float + public val Height: Float + public var Color: String + + public fun ColoredRectangle(width: Float, height: Float, color: String): ColoredRectangle { + this.Width = width + this.Height = height + this.Color = color + return this + } + + public override fun GetArea(): Float { + return Width * Height + } + + public override fun GetPerimeter(): Float { + return 2 * (Width + Height) + } + + public override fun Draw(): Void { + sys::Print("Drawing " + Color + " rectangle") + } + + public override fun SetColor(color: String): Void { + this.Color = color + } + + public override fun GetColor(): String { + return Color + } +} +``` + +## Type Casting and Tests + +**Upcasting** (to `Object` or interfaces): safe, non-nullable +**Downcasting** (to concrete classes): nullable result + +```ovum +val point: Point = Point(10, 20) +val obj: Object = point // Upcast to Object +val comparable: IComparable = point // Upcast to interface + +// Downcasting with type test +if (obj is Point) { + val p: Point = (obj as Point)!! // Safe after type test + sys::Print("Point: " + p.ToString()) +} + +// Type test operator +if (shape is ColoredRectangle) { + val rect: ColoredRectangle = (shape as ColoredRectangle)!! + sys::Print("Rectangle color: " + rect.GetColor()) +} +``` + +**Unsafe casting** requires `unsafe` blocks: +```ovum +unsafe { + val obj: Object = Point(10, 20) + val bytes: ByteArray = (obj as ByteArray) // Raw byte view + val mutableBytes: ByteArray = (obj as var ByteArray) // Mutable byte view +} +``` + +## Functional Objects + +Classes and interfaces can define a special `call` member to make them callable: + +```ovum +interface IAdder { + call(a: Int, b: Int): Int +} + +class Calculator implements IAdder { + public var Multiplier: Int + + public call(a: Int, b: Int): Int { + return (a + b) * Multiplier + } +} + +val calc: IAdder = Calculator(2) +val result: Int = calc(5, 3) // Calls the call method: (5 + 3) * 2 = 16 +``` + +**Function literals** can be assigned to interfaces with compatible `call` signatures: + +```ovum +interface IBinaryOperation { + call(a: Int, b: Int): Int +} + +val add: IBinaryOperation = pure fun(a: Int, b: Int): Int { + return a + b +} + +val sum: Int = add(5, 3) // 8 +``` + +## Memory Management + +Ovum uses garbage collection for automatic memory management: + +```ovum +fun CreateObjects(): Void { + val point1: Point = Point(10, 20) // Allocated on heap + val point2: Point = Point(30, 40) // Allocated on heap + + // Objects are automatically collected when no longer referenced +} +``` + +**Destructors** are called by the garbage collector, not manually: + +```ovum +class ResourceManager { + public destructor(): Void { + // Release resource - called automatically by GC + } +} + +// Manual destructor calls are unsafe and not recommended +``` + +## Best Practices + +**Interface Design:** +- Keep interfaces focused on single concepts +- Use descriptive names +- Prefer many small interfaces over few large ones + +**Class Design:** +- Implement standard interfaces (`ToString()`, `IsLess()`, `GetHash()`) +- Use appropriate access modifiers (private fields when possible) +- Prefer immutability (`val` over `var`) + +**Type Safety:** +- Use type tests before casting (`is` before `as`) +- Prefer safe operations (`?.` and `?:` over `!!`) +- Handle nullable types properly + +```ovum +// Good: focused interfaces +interface IReadable { fun Read(): String } +interface IWritable { fun Write(content: String): Void } + +// Good: safe type handling +fun SafeProcessObject(obj: Object?): Void { + val result: String = obj?.ToString() ?: "null" + if (obj is Person) { + val person: Person = (obj as Person)!! + sys::Print("Person: " + person.ToString()) + } +} +``` + +> **Naming Conventions**: Classes, functions, methods, and properties use **PascalCase** (e.g., `Main`, `ToString`, `IsLess`). Keywords and modifiers remain lowercase (`class`, `interface`, `var`, `override`, `pure`, `unsafe`, etc.). diff --git a/docs/reference/primitive_types.md b/docs/reference/primitive_types.md deleted file mode 100644 index 9e1aa09..0000000 --- a/docs/reference/primitive_types.md +++ /dev/null @@ -1,10 +0,0 @@ -# Primitive Types - -* `Int` (8 bytes) - 64-bit signed integer -* `Float` (8 bytes) - 64-bit floating-point number -* `Bool` - Boolean value (`true` or `false`) -* `Char` - single character -* `Byte` - 8-bit unsigned integer -* `Pointer` - raw memory address *(only meaningful in `unsafe` code)* - -> Any primitive may have a **nullable** counterpart via `?` (e.g., `Int?`). diff --git a/docs/reference/syntax.md b/docs/reference/syntax.md index 1a7d993..f5a7611 100644 --- a/docs/reference/syntax.md +++ b/docs/reference/syntax.md @@ -4,7 +4,6 @@ * Declared with `fun`, PascalCase names: `fun Compute(a: Int): Int { ... }` * **Pure** functions: `pure fun Hash(o: Object): Int { ... }` - * Side-effect free; VM may cache results. * If parameters include user-defined reference types, those types must implement **`IComparable`**. @@ -34,6 +33,11 @@ * Methods are **public** and **virtual** by default. * No fields, no bodies. +## Type Aliases + +* Create type aliases for better readability: `typealias UserId = Int` +* Can be used anywhere a type is expected: `fun ProcessUser(id: UserId): Void` + ## Namespaces & Preprocessor * Namespace resolution with `::` (e.g., `sys::Print`). diff --git a/docs/reference/types.md b/docs/reference/types.md index 5a56540..d23fe15 100644 --- a/docs/reference/types.md +++ b/docs/reference/types.md @@ -4,33 +4,196 @@ Ovum has a rich type system with primitive types and user-defined types. The typ ## Primitive Types -* `Int` (8 bytes) - 64-bit signed integer -* `Float` (8 bytes) - 64-bit floating-point number -* `Bool` - Boolean value (`true` or `false`) -* `Char` - single character -* `Byte` - 8-bit unsigned integer -* `Pointer` - raw memory address *(only meaningful in `unsafe` code)* +### Numeric Types -> Any primitive may have a **nullable** counterpart via `?` (e.g., `Int?`). +* **`Int`** (8 bytes) - 64-bit signed integer + * Literals: `42`, `-17`, `0x1A` (hex), `0b1010` (binary) + +* **`Float`** (8 bytes) - 64-bit floating-point number (IEEE 754 double precision) + * Literals: `3.14`, `2.0e10`, `1.5E-3`, `.5`, `5.` + * Special values: `Infinity`, `-Infinity`, `NaN` -## Non-Primitive / Reference Types +* **`Byte`** (1 byte) - 8-bit unsigned integer + * Literals: `255`, `0x00`, `0b11111111` -* `String` *(reference type; not primitive)* - text data -* *Nullable* `Int?` (and all other primitive types) - `Int` or `null` - also passed by reference -* **Array classes (no templates / generics):** - * For primitives: `IntArray`, `FloatArray`, `BoolArray`, `CharArray`, `ByteArray`, `PointerArray` - * For objects: **`ObjectArray`** - * **Convenience**: `StringArray` (array of `String`, used for `Main`) +### Character and Boolean Types + +* **`Char`** - single Unicode character (UTF-32) + * Literals: `'A'`, `'中'`, `'\n'`, `'\t'`, `'\0'` + +* **`Bool`** - Boolean value (`true`, `false`) + * Any value can be explicitly cast to `Bool` + +### Low-Level Types + +* **`Pointer`** - raw memory address *(only meaningful in `unsafe` code)* + * Used for FFI and low-level memory operations + +> **Nullable Primitives**: Any primitive type can be made nullable by appending `?` (e.g., `Int?`, `Float?`, `Bool?`). Nullable primitives are reference types. + +## Reference Types + +### Built-in Reference Types + +* **`String`** - immutable text data (UTF-8 encoded) + * Literals: `"Hello"`, `"Multi-line\nstring"`, `""` (empty string) + * Concatenation: `"Hello" + " " + "World"` + +* **`Object`** - root of all reference types + * Implicit base class for all user-defined types + * Contains only a virtual destructor + +### Array Types + +Ovum provides specialized array classes for different element types (no generics/templates): + +**Primitive Arrays:** +* `IntArray` - array of `Int` values +* `FloatArray` - array of `Float` values +* `BoolArray` - array of `Bool` values +* `CharArray` - array of `Char` values +* `ByteArray` - array of `Byte` values +* `PointerArray` - array of `Pointer` values + +**Object Arrays:** +* `ObjectArray` - array of any `Object`-derived types +* `StringArray` - convenience array of `String` (used for `Main` function arguments) + +**Array Creation:** +```ovum +val numbers: IntArray = IntArray(10) // Create array of size 10 +val names: StringArray = StringArray(5) // Create string array of size 5 +val objects: ObjectArray = ObjectArray(3) // Create object array of size 3 +``` + +## Type Aliases + +Create type aliases for better code readability: + +```ovum +typealias UserId = Int +typealias UserName = String + +fun ProcessUser(id: UserId, name: UserName): Void { + // Implementation +} +``` + + +## Type Casting + +### Explicit Casting + +Use the `as` operator for explicit casting: + +```ovum +val intValue: Int = 42 +val floatValue: Float = (intValue as Float) // Int to Float +val stringValue: String = (intValue as String) // Int to String + +val floatNum: Float = 3.14 +val intNum: Int = (floatNum as Int) // Float to Int (truncates) +``` + +### Boolean Casting + +Any value can be explicitly cast to `Bool`: + +```ovum +val intVal: Int = 42 +val boolVal: Bool = (intVal as Bool) // true (non-zero) + +val zeroInt: Int = 0 +val falseBool: Bool = (zeroInt as Bool) // false (zero) + +val nullString: String? = null +val nullBool: Bool = (nullString as Bool) // false (null) +``` + +**Rules:** Primitives: zero → `false`, non-zero → `true`. References: `null` → `false`, non-null → `true` + +### Unsafe Casting + +Some casts require `unsafe` blocks: + +```ovum +unsafe { + val obj: Object = Point(10, 20) + val bytes: ByteArray = (obj as ByteArray) // Raw byte view + val mutableBytes: ByteArray = (obj as var ByteArray) // Mutable byte view +} +``` ## Passing Semantics -* **Primitive types**: passed by value (copied) -* **Reference types**: all user-defined and non-primitive types (including `String` and all arrays) are **passed by reference** (const by default) -* **Immutability**: By default, references are considered immutable (the function cannot rebind them or mutate the object's content unless allowed via `var`) +**Primitive types** are passed by value (copied): +```ovum +fun ModifyInt(x: Int): Void { + x = x + 1 // Only modifies the local copy +} +``` + +**Reference types** are passed by reference: +```ovum +fun ModifyArray(arr: IntArray): Void { + arr[0] = 999 // Modifies the original array +} +``` + +**Immutability:** References are immutable by default - use `var` for mutable references: +```ovum +fun CannotReassign(str: String): Void { + // str = "New value" // ERROR: Cannot reassign immutable reference +} + +fun CanReassign(var str: String): Void { + str = "New value" // OK: str is mutable +} +``` ## Type System Characteristics -* **Static typing**: Every variable and expression has a type that is checked at compile time -* **No implicit conversions**: Explicit casting required between different types -* **Type safety**: Prevents type errors and provides better documentation of code intent -* **Nullable types**: Any type can be made nullable by appending `?` \ No newline at end of file +**Static typing:** Every variable and expression has a type checked at compile time +**No implicit conversions:** Explicit casting required between different types +**Type safety:** Prevents many common errors +**Nullable types:** Any type can be made nullable by appending `?` + +```ovum +val x: Int = 42 +val y: String = "Hello" +// val z: Int = x + y // ERROR: Cannot add Int and String + +val intVal: Int = 42 +val floatVal: Float = 3.14 +val result: Float = (intVal as Float) + floatVal // OK: Explicit conversion + +val nullableInt: Int? = null +val nullableString: String? = "Hello" +``` + +## Pure Function Constraints + +Types used as parameters in pure functions must implement `IComparable` for stable ordering: + +```ovum +pure fun ProcessData(data: IComparable): Int { + // data must implement IComparable for stable ordering + return data.GetHash() +} +``` + +## Runtime Behavior + +Type information is preserved at runtime for reference types: + +```ovum +fun ProcessObject(obj: Object): Void { + if (obj is String) { + val str: String = (obj as String)!! + sys::Print("String length: " + str.Length().ToString()) + } else if (obj is IntArray) { + val arr: IntArray = (obj as IntArray)!! + sys::Print("Array size: " + arr.Length().ToString()) + } +} +``` diff --git a/docs/reference/unsafe.md b/docs/reference/unsafe.md index c78e19a..50bfa57 100644 --- a/docs/reference/unsafe.md +++ b/docs/reference/unsafe.md @@ -1,10 +1,121 @@ # Unsafe Operations -Allowed **only** inside `unsafe { ... }`: - -* Declaring/writing **global `var`** variables and **`static var`** fields. -* Casting const → mutable. -* Using **`Pointer`**, address-of and dereference. -* **Manual destructor** calls. -* Any **`sys::Interope`** invocation. -* Casting any value to **(const or mutable) `ByteArray`**. +Unsafe operations bypass Ovum's safety guarantees and are allowed **only** inside `unsafe { ... }` blocks. These operations can lead to undefined behavior, memory corruption, or crashes if used incorrectly. + +## Global and Static Variables + +Global mutable state is unsafe because it can be accessed from anywhere: + +```ovum +unsafe { + global var globalCounter: Int = 0 + globalCounter = globalCounter + 1 + + static var staticValue: String = "initial" + staticValue = "modified" +} +``` + +## Const to Mutable Casting + +Converting immutable references to mutable bypasses immutability guarantees: + +```ovum +unsafe { + val immutable: String = "Hello" + val mutable: var String = (immutable as var String) + // mutable can now be modified, breaking immutability +} +``` + +## Pointer Operations + +Raw memory operations are inherently unsafe: + +```ovum +unsafe { + val obj: Point = Point(10, 20) + val ptr: Pointer = &obj // Address-of operator + val deref: Object = *ptr // Dereference to Object + + // Pointer arithmetic and manipulation + val nextPtr: Pointer = ptr + 8 // Assuming 8-byte alignment +} +``` + +## Manual Destructor Calls + +Destructors should only be called by the garbage collector: + +```ovum +unsafe { + val resource: FileHandler = FileHandler("file.txt") + resource.destructor() // Unsafe: manual destructor call +} +``` + +## Foreign Function Interface + +Calling external native code is unsafe: + +```ovum +unsafe { + val input: ByteArray = "Hello".ToUtf8Bytes() + val output: ByteArray = ByteArray(4) + val result: Int = sys::Interope("libc.so", "strlen", input, output) +} +``` + +## ByteArray Casting + +Raw byte access bypasses type safety: + +```ovum +unsafe { + val point: Point = Point(10, 20) + val bytes: ByteArray = (point as ByteArray) // Const byte view + val mutableBytes: ByteArray = (point as var ByteArray) // Mutable byte view + + // Direct memory manipulation + mutableBytes[0] = 0xFF +} +``` + +## Safety Guidelines + +When using unsafe operations: + +1. **Minimize scope** - Keep unsafe blocks as small as possible +2. **Validate assumptions** - Ensure pointers and casts are valid +3. **Document invariants** - Clearly document what makes the code safe +4. **Test thoroughly** - Unsafe code requires extensive testing +5. **Consider alternatives** - Use safe APIs when possible + +## Common Unsafe Patterns + +**Memory layout inspection:** +```ovum +unsafe { + val obj: MyClass = MyClass() + val bytes: ByteArray = (obj as ByteArray) + // Inspect object's memory layout +} +``` + +**Low-level data conversion:** +```ovum +unsafe { + val intValue: Int = 42 + val bytes: ByteArray = (intValue as ByteArray) + // Convert Int to raw bytes +} +``` + +**Performance-critical operations:** +```ovum +unsafe { + val largeArray: IntArray = IntArray(1000000) + val bytes: ByteArray = (largeArray as ByteArray) + // Direct memory operations for performance +} +``` From ab13611b700f712b114cb5cc331729724035439d Mon Sep 17 00:00:00 2001 From: bialger Date: Tue, 9 Sep 2025 10:47:39 +0300 Subject: [PATCH 21/21] fix: update contact email in CODE_OF_CONDUCT.md for reporting incidents Change the contact email for reporting abusive or unacceptable behavior to ensure proper communication with the project team. --- CODE_OF_CONDUCT.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index c0e1001..359586c 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -55,7 +55,7 @@ further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the project team at kylelobo20@gmail.com. All +reported by contacting the project team at [bigulov.sasha@gmail.com](mailto:bigulov.sasha@gmail.com). All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident.