Продолжаю свои эксперименты с языками программирования.
Вот плод моего больного воображения:
printf: (fmt: @(char const), ...) no_mangle;
main: (argc: int, argv: @(@(char))) -> int {
i: int = 0;
while (i < argc) {
printf("%s\n", argv[i]);
i += 1;
}
return 0;
};
ООП как-то так:
SomeClass: class {
someFunc: (a: int) public {
return a * 2;
};
};
instanceOfSomeClass1: SomeClass;
Ну и массивы:
m: int[100];
Две основные идеи:
1) Обычно программист сначала придумывает название для сущности и только потом окончательно определяется с типом. Си заставляет писать сначала имя типа, а потом уже только потом название, что плохо. А уж всякие модификаторы (public, private, static, extern и т. д.) и подавно можно подобрать уже в самом конце определения.
2) Всякие фигурные скобочки придают коду наглядность куда лучше, чем паскалевский begin-end.
Но есть дополнительные вопросы:
1) Указатели. Как они должны определяться? В примере выше используется конструкция @(базовый тип). В том числе к ней можно применить модификаторы. Например, @(char const) volatile - изменчивый указатель на константный символ. Но можно было бы сделать что-то вроде Pointer(базовый тип), что было бы более наглядно, но и более многословно.
2) Опять указатели. Как следует выполнять разыменовывание указателей? C-style с помощью унарного *? Или может быть Pascal-style с помощью постфиксного ^? А может вообще считать указатели структурами с единственным полем value и делать разыменовывание как ptr->value (допустим, к полям структуры мы обращаемся через указатель через ->)?
3) И снова указатели. Как следует выполнять взятие адреса? C-style &? Или Pascal-style @? Или может неявно при присваивании указателю объекта?
4) Циклы. Классический сишный набор for-do-while с сишным же синтаксисом? Для for можно добавить for-each семантику. Какую? for (переменная: коллекция) или же for (переменная in коллекция)?
5) Шаблоны? Нужно ли? Если да, то какой синтаксис.
6) Алиасы для типов. Следуя основному стилю языка лучше сделать что-то вроде MyIntType: TypeAlias(int);, но это выглядит как введение ещё одного ключевого слова в язык. Может использовать какой-то символ? Какой?
7) ++ и --. Из-за этих операций возможны всякие странные вещи типа ++i + ++i. Так ли это плохо?
8) Преобразования типов. Варианты: сишный вариант (тип)значение. Паскалевский вариант тип(значение), C++ вариант reintepret_cast<тип>(значение). Что лучше?
Да, сам язык будет использовать концепцию модулей. Опрережающие определения не нужны - компилятор будет двухпроходным. Таким образом все определения из текущего модуля будут считаться объявленными в любой момент времени. Разумеется, циклы в иерархии наследования классов допускаться не будут. Подключение других модулей выполняется с помощью ключевого слова import some.module; Импорт возможен только до первой декларации. Взаимный импорт модулей должен корректно разруливаться компилятором (а не как в Python).
Весь код транслируется в Си. Причём язык позволяет закодировать любую сишную конструкцию (в том числе всякие грязные преобразования типов и т. д.). Более того, можно сделать что-то типа import «stdio.h». При этом компилятор с помощью libclang по-быстрому парсит подключенные заголовочные файлы, таким образом видит все сишные определения как свои (разве что с макросами печалька, но можно и этот момент частично разрулить).
Разумеется, помимо ООП и шаблонов должны быть лямбда-функции и асинхронное программирование.
UPD: Про псевдонимы типов придумал вариант синтаксиса получше.
NewType := OldType;
Логика простая - если вместо имени типа сразу идёт =, то это не обычное определение, а псевдоним типа (таким образом чисто технически между : и = может быть пробел).