Skip to content

IGags/plamp

Repository files navigation

Язык plamp - parasitic language for mapping

Язык предназначен для встраивания его как языка сценариев в программы на языке c#. Поставляется в форме отдельного компилятора plpc или в форме набора подключаемых библиотек.

Основной идеей языка является простота синтаксиса и выразительность синтаксиса в сочетании со скоростью и безопасностью.

Программирование на языке выполняется в процедурной парадигме. Это значит, что код разбит на набор процедур, которые вызывают друг друга. Язык средствами синтаксиса явно отделяет поведение от данных.

  1. Сборка
  2. Запуск
  3. Базовые типы данных
  4. Арифметика
  5. Переменные
  6. Массивы
  7. Управляющие конструкции
  8. Процедуры
  9. Пользовательские типы
  10. Что дальше

Сборка

Для сборки требуется .net8 на устройстве, которое выполняет сборку проекта. Другие внешние зависимости отсутствуют.

Сборка происходит через вызов одной команды (пример для bash)

cd plamp.Cli && dotnet publish -c Release -r linux-x64 --self-contained true -p:PublishReadyToRun=false -p:Pu
blishSingleFile=true

Запуск

Компилятор запускается как консольная утилита

plamp.Cli <имя кодового файла>

Создание бинарных файлов пока не реализовано. Компилятор выплёвывает код в динамическую сборку внутри себя.

Базовые типы данных

Все данные в языке выражаются комбинацией следующих базовых типов данных.

Целые числа

  • int - 4 байтовое целое число со знаком -2.1B - ~2.1B постфикс после числа i
  • uint - 4 байтовое целое число без знака 0 - ~4.3B постфикс после числа ui
  • long - 8 байтовое целое число со знаком -9.2e18 - ~9.2e18 постфикс после числа l
  • ulong - 8 байтовое целое число без знака 0 - ~1.8e19 постфикс после числа ul
  • short - 2 байтовое целое число со знаком -32,768 - 32,767 постфикс после числа s
  • ushort - 2 байтовое целое число без знака 0 - 65,535 постфикс после числа us
  • byte - 1 байтовое целое число без знака 0 - 255 постфикс после числа b
  • sbyte - 1 байтовое целое число со знаком -128 - 127 постфикс после числа sb

Дробные числа

  • float - 4 байтовое дробное число со знаком ±1.5e-45 - ±3.4e38 точность 6-9 цифр после запятой постфикс после числа f
  • double - 8 байтовое дробное число со знаком ±5.0e-324 - ±1.7e308 точность 15-17 цифр после запятой постфикс после числа d

Постфиксы после чисел означают указание типов этих чисел. Например, 14f запишет число типа float. Число без точки и постфикса воспринимается как int, а число с точкой и без постфикса - double

Логика

  • bool - логический тип данных true или false

Строки

  • string - неизменяемый строковый тип данных. Записывается в двойных кавычках. "Привет" - валидная строка. Внутри строк есть спец. символы, они начинаются с обратного слэша.

  • \" - Кавычка

  • \\ - Обратный слэш

  • \n - Перенос строки

  • \t - Символ tab

Символы

  • char - тип данных, хранящий единственный символ. Объявляется как единственный символ в одиночных кавычках (пока не реализовано)

Абстрактные типы

  • any - что угодно(любой тип)
  • array - какой угодно массив

Арифметика

В языке поддерживаются все базовые арифметические операции.

  • + - сложение
  • - - вычитание
  • * - умножение
  • / - деление
  • % - остаток от деления нацело
  • -- - декремент(префиксный и постфиксный)
  • ++ - инкремент(префиксный и постфиксный)

Также поддерживаются базовые логические операции

  • ! - Логическое НЕ
  • || - Логическое ИЛИ
  • && - Логическое и

Также есть арифметико - логические операции

  • > - Больше
  • < - Меньше
  • = - Равно
  • != - Не равно
  • >= - Больше или равно
  • <= - Меньше или равно

В приоритете сначала арифметические операции, потом арифметико-логические, потом логические. Также приоритет можно изменять с помощью заключения части выражения в круглые скобки

(2 + 2) * 2 = 8 - выдаст true

Попробуй разделить на 0

Переменные

Объявить переменную в языке можно 2мя способами.

Первый - записать переменную, а за ней через двоеточие тип.
a: int;

Второй - записать переменную и присвоить ей сразу значение. Через оператор :=
a := 31;

Если переменная была объявлена выше в коде, то при повторном присваивании новая переменная объявлена не будет.

Переменная не может менять тип. Это значит, что если объявлена переменная одного типа, то в неё нельзя положить значение другого.

Этот код не сработает.

a: string;
a := 31;

Значение переменных можно передавать друг в друга.

a := 1;
b := a;

b будет равен 1

Также есть компактные формы записи для объявления и присваивания множества переменных.

a, b, c: float; - создаст 3 переменные типа float

d, e, f, g := "Привет", "дорогой", "друг", true; - создаст и запишет 3 строки и одну логическую переменную.

Также есть интересная хитрость.

a, b := b, a; - поменяет значения местами

Массивы

Для группировки нескольких однотипных значений существуют массивы. Записать массив можно как a: []int; - Пустой массив целых чисел

a := [10]int; - Массив целых числе длинной 10

Индексация массива происходит с нуля.

Для записи элемента массива к нему можно обратиться через квадратные скобки

a[9] := 4; - запишет в 10 элемент массива.

Синтаксис для получения похожий

b := a[3]; - получит 4 элемент из массива.

Если выйти за границы массива, то программа завершится с ошибкой.
Массив может содержать в себе массивы, тогда это записывается как [][]int - массив массивов интов(кстати это пока сломается)

Управляющие конструкции

Есть 2 способа управлять потоком выполнения кода.

Условия

Синтаксис записи условий следующий if(<условие>) {действия если true} [опционально else { действия если false }]

Пример простейшего условия

if(a > 5) {
    b := a;
}

Пример условия с блоком else

if(a = 3){
    b := -1;
} else {
    b := 22;
}

Приятная полезность. Условия можно комбинировать.

if(a = 2){
    Делай первое
} else if(a < 2){
    Делай второе
} else {
    Иначе делай 3-e
}

Циклы

В язке реализован 1 тип цикла - while (это не конечный вариант всё может поменяться)

Синтаксис цикла while(<условие>) { действия цикла }

Пример цикла

i := 0;
while(i < 10){
    i++;
}

Совершит 10 повторений

Для циклов есть специальные операторы, которые могут быть использованы только внутри них. break и continue

Первый прерывает выполение и выходит из цикла.
Второй пропускает итерацию и идёт на следующее повторение цикла.

Пример.

i := 0;
while(i++ < 100){
    if(i < 50){
        continue;
    }
    print("exit");
    break;
}

Данный цикл прокрутит 50 итераций, потом напечатает exit и завершится, хотя в условии написана цифра 100.

Процедуры

Процедура объявляется следующим образом:

fn <Имя процедуры>([Список аргументов]) <Возвращаемый тип> {
	тело процедуры
}

Возврат из процедуры происходит по средством вызова return с возвращаемым значением. Каждое выражение в теле процедуры отделяется символом ;

Пример корректной процедуры:

fn Echo(a: string) string {
	return a;
}

Процедура может не возрващать ничего, тогда тип возвращаемого значения писать не надо.

fn Say(a: string) {
	println(a);
}

Если процедура не возвращает ничего, то можно написать return без значения и когда код выполнится до этой инструкции произойдёт выход из процедуры

fn Interrupt(){
	println("Это я напишу");
	return;
	println("A это нет");
}

Чтобы начать выполнение кода в файле должна быть обязательно процедура main и указание имени модуля.

Пример процедуры main:

module hello;
fn main() { }

Процедура может вызывать другую процедуру Делается это с помощью указания имени процедуры и списка значений её аргументов в скобках следом за ней.

Пример программы, которая здоровается.

module hello;

fn say_hello(name: string) {
	print("Hello, ");
	println(name);
}

fn main() {
	say_hello("Vasya");
	say_hello("Petya");
}

Аргументы одного типа можно группировать.

fn Add(first, second: int) int {
	return first + second;
}

А можно не группировать

fn Add(first: int, second: int) int {
	return first + second;
}

Поддерживается рекурсия

fn fib(n: int) int {
    if(n <= 1) return 0;
    if(n = 2 || n = 3) return 1;
    else return fib(n - 1) + fib(n - 2);
}

Данный код выполнит вычисление n-го числа Фибоначчи

Пользовательские типы

Для удобной передачи типов из функции и в функцию добавлены пользовательские типы. Тип группирует в себе несколько полей.

Тип в программе объявляется следующим образом.

type <Имя типа>{
    поля типа
}

Пример объявления типа.

type Point {
    X: int;
    Y: int;
}

Также поля можно группировать

type Point{
    X, Y: int;
}

Чтобы создать тип в коде следует записать его имя и фигурные скобки следом.

a := Point{};

Данный пример запишет в переменную пустой тип Point(пустой значит, что у всех полей будут значения по умолчанию).

Для обращения к полю типа следует указать его через точку после переменной этого типа.

a := Point{};
x := a.X;
a.Y := 3;

На примере чтение и запись в поля типа.

Все типы в языке ведут себя как структуры, это значит, что тип не может иметь в себе поле того же типа, что и он сам. А также как временное искусственное ограничение - тип не может иметь в себе поле с типом массива элементом которого является он сам.

Для всех типов в языке не существует понятия null. Строки и массивы имеют значение "" и ARRAY[0] по умолчанию.

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

Текущий набор функций крайне мал и служит лишь для целей отладки. Набор будет только расти.

  • pirnt(any) - выводит значение на экран
  • println(any) - выводит значение на экран и переносит строку
  • length(array) int - возвращает длину массива
  • length(string) int - возвращает длину строки
  • read() char - читает один символ
  • readln() string - читает одну строку до переноса
  • concat(string, string) string - соединяет строки воедино
  • concat([]string) string - соединяет массив строк воедино

Для ветки builtins был реализован демонстративный набор функций и типов. Функции и типы, которые будут перенесены в будущих версиях в отдельные модули

Типы

  • interval - Временной промежуток
  • date - Дата
  • AnyList - Список нетипизированных элементов

Функции для списков

  • length(AnyList) int - Длина списка
  • append(AnyList, any) - Добавляет элемент в список
  • get(AnyList, int) any - Возвращает элемент списка по индексу
  • removeAt(AnyList, int) - Удаляет элемент списка по индексу
  • reverse(AnyList) - Разворачивает список
  • concat(AnyList, AnyList) AnyList - соединение двух списков

Функции для конверсии типов

  • toInt(any) int - пытается перевести что угодно в число
  • toInt(string) int - парсит строку в число
  • toUint(any) uint - пытается перевести что угодно в число
  • toUint(string) uint - парсит строку в число
  • toLong(any) long - пытается перевести что угодно в число
  • toLong(string) long - парсит строку в число
  • toUlong(any) ulong - пытается перевести что угодно в число
  • toUlong(string) ulong - парсит строку в число
  • toChar(any) char - пытается перевести что угодно в число
  • toChar(string) char - парсит строку в число
  • toShort(any) short - пытается перевести что угодно в число
  • toShort(string) short - парсит строку в число
  • toUshort(any) ushort - пытается перевести что угодно в число
  • toUshort(string) ushort - парсит строку в число
  • toFloat(any) float - пытается перевести что угодно в число
  • toFloat(string) float - парсит строку в число
  • toByte(any) byte - пытается перевести что угодно в число
  • toByte(string) byte - парсит строку в число
  • toSbyte(any) sbyte - пытается перевести что угодно в число
  • toSbyte(string) sbyte - парсит строку в число
  • toDouble(any) double - пытается перевести что угодно в число
  • toDouble(string) double - парсит строку в число

Функции для работы с датами

  • fromMilliseconds(double) interval - Создаёт интервал из миллисекунд
  • fromSeconds(double) interval - Создаёт интервал из секунд
  • fromMinutes(double) interval - Создаёт интервал из минут
  • fromHours(double) interval - Создаёт интервал из часов
  • fromDays(double) interval - Создаёт интервал из дней
  • totalDays(interval) double - Сколько всего дней в интервале
  • totalMilliseconds(interval) double - Сколько всего миллисекунд в интервале
  • totalHours(interval) double - Сколько всего часов в интервале
  • totalSeconds(interval) double - Сколько всего секунд в интервале
  • totalMinutes(interval) double - Сколько всего минут в интервале
  • days(interval) int - Число только дней в интервале
  • hours(interval) int - Число только часов в интервале
  • minutes(interval) int - Число только минут в интервале
  • seconds(interval) int - Число только секунд в интервале
  • milliseconds(interval) int - Число только миллисекунд в интервале
  • add(interval, interval) interval - Суммирует 2 временных промежутка
  • add(date, interval) date - Добавляет интервал к дате
  • sub(interval, interval) interval - Вычитает временной промежуток один из другого
  • sub(date, interval) date - Вычитает временной промежуток из даты
  • sub(date, date) interval - Находит разницу между датами
  • toDate(string) date - Парсит строку в дату
  • second(date) int - Получает секунды из даты
  • minute(date) int - Получает минуты из даты
  • hour(date) int - Получает часы из даты
  • day(date) int - Получает дни из даты
  • month(date) int - Получает месяца из даты
  • year(date) int - Получает года из даты
  • dayOfYear(date) int - Получает порядковый номер дня из года
  • dayOfWeek(date) int - Получает порядковый номер дня в неделе. Дни нумеруются с нуля и нумерация начинается с воскресения
  • timeOfDay(date) interval - Получает время
  • now() int - Получает текущую дату со временем
  • utcNow() int - Получает текущую дату со временем по поясу GMT+0
  • date(date) date - Получает дату без времени из даты со временем

Функции для конверсии в строку

  • toString(date, string) string - Превращает дату в строку с определённым форматированием
  • toString(date) string - Превращает дату в строку
  • toString(interval, string) string - Превращает интервал в строку с определённым форматированием
  • toString(interval) string - Превращает интервал в строку
  • toString(any) string - Превращает что угодно в строку

Функции для работы со строками

  • substring(string, int, int) string - Получает подстроку начиная с определённого индекса определённой длины
  • substring(string, int) string - Получает подстроку начиная с определённого до конца
  • get(string, int) char - Получает символ строки по определённому индексу
  • strcmp(string, string) bool - Посимвольное сравнение двух строк.

Что дальше

Текущий набор возможностей кажется мне как разработчику недостаточным, поэтому уже сформирован бэклог дальнейших нововведений.

  • Возврат нескольких значений из функции за раз
  • Generic типы
  • Union типы
  • Делегаты и closure
  • Механизмы паники(panic) и восстановления(recover)
  • typeclasses (см. haskell)
  • Система подключаемых библиотек
  • Стандартная библиотека.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages