Что нужно для ЯП

в 12:33, , рубрики: ненормальное программирование, Программирование, языки программирования

image

Дорогой %username%, если ты решишь сделать свой ЯП(язык программирования), с преферансом и балеринами, или понять некоторые основы работы препроцессора, компилятора и выполнения программы, тебе сюда!

Парадигмы

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

Если читатель собирается проектировать современный язык, то на сегодняшний день, наиболее распространенной будет обьектрно-ориентированая парадигма.
Моя жизненная ситуация сложилась так, что я программировал на С++ и Objective-C, и когда я погуглил тесты производительности Objective-C и чистого С, то нашел только топик на StackOverflow. Я понял, что что-то в этом мире пора менять и по этому нужно написать свой обьектно-ориентированный язык.

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

Размышления

Какие же требования можно привести к обьектно-ориентированому ЯП? Ответ знаю все — это три кита (+-четвертый).

  • Инкапсуляция — механизм языка программирования, предоставляющий возможность обрабатывать несколько единиц данных как одну единицу.
  • Наследование — механизм языка, позволяющий описать новый класс на основе уже существующего (родительского, базового) класса.
  • Полиморфизм — единообразная обработка разнотипных данных.
  • Абстракция — это придание объекту характеристик, которые чётко определяют его концептуальные границы, отличая от всех других объектов.

Также я выбрал пару важных штук для себя:

  • Работа со стеком (аппаратным) — т.е. обьекты должны иметь возможность храниться как в стеке, так и в куче.
  • Отсутствие необходимости писать компилятор под свой язык, и по этому следующий пункт:
  • Основание и полная совместимость с С99 и со всеми его вкусностями.
  • Множественное наследование.
  • Легкий в использовании Foundation (Да, тут с Obj-C мало кто может поспорить)

По своей неопытности думал, что можно взять пару препроцессорных макросов, которые сделали бы новый синтаксис С и сишные структуры — и вот готов новенький ЯП. Каков был мой шок, когда я вспомнил про полиморфизм (Наследование и Инкапсуляцию еще, с горем-пополам, можно реализовать на сишных структурах, а вот для полиморфизма нужно что-то еще). Так я стал разделять два ключевых времени для написанной на высокоуровневом языке программы. Это время компиляции( и процессинга, т.е. выполнения препроцессором своих команд) и время выполнения(runtime).

Компиляция(процессинг)

Что нам может дать С во время компиляции

  • Препроцессорные #define'ы, которыми возможно скрыть разделения пространств имен, вызовы обьектами(структурами) методов(функций)
  • Преобразование любого кода в сишную строку.
  • Статическое(не во время выполнения) определение типов и существование фукций/структур(те самые моменты, когда IDE подчеркивает красным то, что неправильно написано).

А что же нам нужно?

Для полиморфизма:

  • Динамическое(во время выполнения) определение типов
  • Динамическое определение нужной функции(функция родительского класса, или переопределенная) для обьекта

Дополнительные вкусности для себя:

  • Возможность замены фукции(функцией уже скомпилированной) во время выполнения, но одинаковых сигнатур (Сигнатура функции — часть общего объявления функции, позволяющая средствам трансляции идентифицировать функцию среди других. В различных языках программирования существуют разные представления о сигнатуре функции, что также тесно связано с возможностями перегрузки функций в этих языках.)
  • Перегрузка функций
  • Жесткая необходимость спецификаторов доступа

Таким образом, я пришел к выводу, что обьектно-ориентированному языку нужен runtime, в котором он будет определять что это за обьект, и какую функцию вызывать. И у класса должны хранится указатели на методы.

Как реализовать?

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

  • Имя класса
  • Имена родительских классов и их количество
  • Имена дочерних классов и их количество
  • Сигнатуру класса (что, какого типа, и где находится)

Все это можно хранить вместе с обьектом. «О боже, да это же сколько дублировать-то прийдется: к простому классу прийдется добавлять еще дополнительно N-килобайт метаинфы», да, но при определении метода(свой, родительский), это будет очень быстро работать, т.к. мы просто смотрим на элемент обьекта.
Я решил, что это непозволительная роскошь, и поэтому с каждым обьектом я буду хранить идентификатор его класса, которому будет присваиваться уникальный номер. Это будет 64(можно взять и 16-разрядное, я, например, не видел программу, у которой будет больше 65536 классов) разрядное число. Согласно этому числу, в специльных таблицах и можно будет найти метаинформацию об обьекте.

Таблицы метаинформации

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

Таблицу можно разбить на несколько подклассов — она будет наследником класса словаря(map, NSDictionary), который будет наследником динамического массива(vector, NSArray) и будет содержать обьекты пары обьект1 — обьект2, или ключ — значение(идентификатор — имя). Так, как компилятор представляет возможность представления куска кода в виде сишной строки, то и имена обьектов и будут сишными строками. При регистрации имени класса, будет создаваться пара из имени и идентификатора, и добавляться в массив.

Синтаксис

Все то что я придумал как временное решение.

Из интересных моментов:

#define _TOSTRING(x) #x
#define TOSTRING(x) _TOSTRING(x)             // gets c-string from define or some code
#define _splitUp(one, two) one##two
#define splitUp(one, two) _splitUp(one, two) // splits up two words: splitUp(Hello,World) -> HelloWorld

splitUp сделал для «пространств имен», например когда я обьявляю метод

#define $method(returnValue, methodName, className) returnValue splitUp(methodName, className)(className *object

$method(uint64_t , getNumberOfClasses, RClassTable));

То препроцессором генерируеться сишная функция

uint64_t getNumberOfClassesRClassTable(RClassTable *object);

Как вы уже поняли — object это аналог this в C++ и self в Obj-C.
А вот так выглядид реализация этого метода:

$method(uint64_t , getNumberOfClasses, RClassTable)){
    return $master(object, RDynamicArray)->count;
}

И не надо писать никаких

 :: и @implimentation @end 

Вызов метода:

#define m(methodName, className) splitUp(methodName,className)                                      // some method function name
#define $(object, methodName)  methodName(object

$(classTable, m(registerClassWithName, RClassTable)),"Luke");

Постфикс

Язык я назвал Ray — Луч.
Синтаксис еще сырой и не обьектно-ориентированный, потому что рантайм не готов(будет готов — прийдется немного поменять синтаксис),
и все мои попытки open-source и absolute free, никаких лицензий, подписей и т.д.
Ознакомится с проектом на GitHub можно тут

Hello world:

#include "RayFoundation.h"
#include <stdio.h>

$class(HelloWorlder)
    char *word;
$endOfClass(HelloWorlder)

$constructor(HelloWorlder)){
    HelloWorlder object2;
    object2.word = "Hello world";
    return &object2;
}

$printer(HelloWorlder){
    printf(object->word,"n");
}

int main(int argc, const char *argv[]) {
    HelloWorlder helloWorlder = *$(NULL, c(HelloWorlder)) );
    $( &helloWorlder, p(HelloWorlder)) );
    return 0;
}

Синтаксис так-себе, но к нему быстро привыкаешь и показывает больше детерминизма, какого класса метод ты вызываешь, и что это за метод(m — method, sm — static method, p — printer, d — destructor, c — constructor). Вот такой вот вышла моя попытка создать ЯП. Буду работать над ним дальше. Больше примеров можно увидеть на GitHub. Единственное что, там проект под Mac (AppCode, Xcode). Можете просто скопировать исходники себе и развлекатся как хотите. Хорошего дня. Буду очень благодарен за feedback если попробуете что-то написать.

Автор: Kojiba

Источник

Поделиться

* - обязательные к заполнению поля