На протяжении нескольких лет я пробовал свои силы в разработке своего языка программирования. Мне хотелось создать на мой взгляд максимально простой, полнофункциональный и удобный язык.

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

Заранее скажу, что писал весь проект на Free Pascal, т.к. проги на нем можно собрать под огромное число платформ, да и сам компилятор выдает очень даже оптимизированные бинарники (собираю все составляющие проекта с O2 флагом).

Среда выполнения языка


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

Реализация стека


Очевидно, во главе ВМ лежит стек. В моей реализации он работает блоками. По сути это простой массив указателей и переменная для хранения индекса вершины стека.
При его инициализации, создается массив на 256 элементов. Если в стек закидывается большее число указателей, то его размер увеличивается на следующие 256 элементов. Соответственно, при удалении элементов из стека — его размер регулируется.

В ВМ используется несколько стеков:

  1. Основной стек.
  2. Стек для хранения точек возврата.
  3. Стек сборщика мусора.
  4. Стек обработчика try/catch/finally блоков.

Константы и переменные


С этим все просто. Константы обрабатываются отдельным небольшим куском кода и доступны в приложениях в будущем по статическим адресам. Переменные представляют собой массив указателей определенного размера, доступ к его ячейкам осуществляется по индексу — т.е. статическому адресу. Переменные можно помещать в вершину стека или читать её оттуда. Собственно, т.к. у нас переменные по сути хранят указатели на значения в памяти ВМ, то в языке преобладает работа с неявными указателями.

Сборщик мусора


В моей ВМ он полуавтоматический. Т.е. разработчик сам решает когда нужно вызвать сборщик мусора. Работает он не по обычному счетчику указателей, как в тех же Python, Perl, Ruby, Lua и т.д. Он реализован через систему маркеров. Т.е. когда подразумевается, что переменной присваивается временное значение — указатель на это значение добавляется в стек сборщика мусора. В дальнейшем сборщик быстро пробегается по уже готовому списку указателей.

Обработка try/catch/finally блоков


Как и в любом современном языке, обработка исключений — важная его составляющая. Ядро ВМ обернуто в try..catch блок, который может вернуться к исполнению кода, после поимки исключения, поместив в стек немного информации о нем. В коде приложений можно задавать try/catch/finally блоки кода, указывая точки входа на catch (обработчик исключения) и на finally/end (конец блока).

Многопоточность


Она поддерживается на уровне ВМ. Это просто и удобно для использования. Работает без системы прерываний, так что код должен выполняться в нескольких потоках в несколько раз быстрее соответственно.

Внешние библиотеки для ВМ


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

Транслятор с высокоуровневого языка Mash в байткод для ВМ


Промежуточный язык


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

Архитектура транслятора


Выбрал я не самую хорошую архитектуру для реализации. Транслятор не строит дерево кода, как подобает прочим трансляторам. Он смотрит на начало конструкции. Т.е. если разбираемый кусок кода имеет вид «while <условие>:», то очевидно, что это конструкция while цикла и обрабатывать её нужно как конструкцию while цикла. Что-то вроде сложного switch-case.

Благодаря такому архитектурному решению транслятор получился не очень уж быстрым. Однако простота его доработки возросла в разы. Нужные конструкции я добавлял быстрее, чем мог остыть мой кофе. Полная поддержка ООП и вовсе была реализована менее чем за неделю.

Оптимизация кода


Тут конечно можно было реализовать и лучше (и будет реализовано, но позже, как руки дойдут). Пока что оптимизатор только умеет отсекать неиспользуемый код, константы и импорты от сборки. Также несколько констант с одинаковым значением заменяются одной. Вот и все.

Язык Mash


Основная концепция языка


Основной идеей было разработать максимально функциональный и простой язык. Считаю, что со своей задачей разработка справляется на ура.

Блоки кода, процедуры и функции


Все конструкции в языке открываются двоеточием : и закрываются оператором end.

Процедуры и функции объявляются как proc и func соответственно. В скобках перечисляются аргументы. Все как у большинства других языков.

Оператором return можно вернуть из функции значение, оператор break позволяет выйти из процедуры/функции (если он стоит вне циклов).

Пример кода:

...

func summ(a, b):
  return a + b
end

proc main():
  println(summ(inputln(), inputln()))
end

Поддерживаемые конструкции


  • Циклы: for..end, while..end, until..end
  • Условия: if..[else..]end, switch..[case..end..][else..]end
  • Методы: proc <имя>():… end, func <имя>():… end
  • Label & goto: <имя>:, jump <имя>
  • Enum перечисления и константные массивы.

Переменные


Транслятор их может определять автоматически, либо если разработчик пишет var перед их определением.

Примеры кода:

a ?= 10
b ?= a + 20

var a = 10, b = a + 20

Поддерживаются глобальные и локальные переменные.

ООП


Ну вот и подобрались мы к самой вкусной теме. В языке Mash поддерживаются все парадигмы объектно-ориентированного программирования. Т.е. классы, наследования, полиморфизм (в т.ч. динамический), динамические автоматические рефлексия и интроспекция (полная).

Без лишних слов, лучше просто приведу примеры кода.

Простой класс и работа с ним:

uses <bf>
uses <crt>

class MyClass:
  var a, b
  proc Create, Free
  func Summ
end

proc MyClass::Create(a, b):
  $a = new(a)
  $b = new(b)
end

proc MyClass::Free():
  Free($a, $b)
  $rem()
end

func MyClass::Summ():
  return $a + $b
end

proc main():
  x ?= new MyClass(10, 20)
  println(x->Summ())
  x->Free()
end

Выведет: 30.

Наследование и полиморфизм:

uses <bf>
uses <crt>

class MyClass:
  var a, b
  proc Create, Free
  func Summ
end

proc MyClass::Create(a, b):
  $a = new(a)
  $b = new(b)
end

proc MyClass::Free():
  Free($a, $b)
  $rem()
end

func MyClass::Summ():
  return $a + $b
end

class MyNewClass(MyClass):
  func Summ
end

func MyNewClass::Summ():
  return ($a + $b) * 2
end

proc main():
  x ?= new MyNewClass(10, 20)
  println(x->Summ())
  x->Free()
end

Выведет: 60.

Что на счет динамического полиморфизма? Да это же рефлексия!:

uses <bf>
uses <crt>

class MyClass:
  var a, b
  proc Create, Free
  func Summ
end

proc MyClass::Create(a, b):
  $a = new(a)
  $b = new(b)
end

proc MyClass::Free():
  Free($a, $b)
  $rem()
end

func MyClass::Summ():
  return $a + $b
end

class MyNewClass(MyClass):
  func Summ
end

func MyNewClass::Summ():
  return ($a + $b) * 2
end

proc main():
  x ?= new MyClass(10, 20)
  x->Summ ?= MyNewClass::Summ
  println(x->Summ())
  x->Free()
end

Выведет: 60.

Теперь уделим минутку интроспекции для простых значений и классов:

uses <bf>
uses <crt>

class MyClass:
  var a, b
end

proc main():
  x ?= new MyClass
  println(BoolToStr(x->type == MyClass))
  x->rem()
  println(BoolToStr(typeof(3.14) == typeReal))
end

Выведет: true, true.

Об операторах присваивания и явных указателях


Оператор ?= служит для присвоения переменной указателя на значение в памяти.
Оператор = изменяет значение в памяти по указателю из переменной.
И теперь немного о явных указателях. Добавил я их в язык чтобы они были.
@<переменная> — взять явный указатель на переменную.
?<переменная> — получить переменную по указателю.
@= — присвоить значение переменной по явному указателю на неё.

Пример кода:

uses <bf>
uses <crt>

proc main():
  var a = 10, b
  b ?= @a
  PrintLn(b)
  b ?= ?b
  PrintLn(b)
  b++
  PrintLn(a)
  InputLn()
end

Выведет: какое-то число, 10, 11.

Try..[catch..][finally..]end


Пример кода:

uses <bf>
uses <crt>

proc main():
  println("Start")
  try:
    println("Trying to do something...")
    a ?= 10 / 0
  catch:
    println(getError())
  finally:
    println("Finally")
  end
  println("End")
  inputln()
end

Планы на будущее


Все присматриваюсь да присматриваюсь к GraalVM & Truffle. У моей среды выполнения отсутствует JIT компилятор, так что в плане производительности он пока что может составлять конкуренцию разве что питону. Надеюсь, что мне окажется под силу реализовать JIT компиляцию на базе GraalVM или LLVM.

Репозиторий


Вы можете поиграться с наработками и проследить за проектом сами.

Сайт
Репозиторий на GitHub

Спасибо, что дочитали до конца, если вы это сделали.

Комментарии (185)


  1. voidptr0
    02.01.2019 11:38
    +6

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


    1. RoPi0n Автор
      02.01.2019 17:17

      Мне кажется, что язык похож на Pascal очень отдаленно.


  1. mobi
    02.01.2019 12:06
    +1

    оператор break позволяет выйти из процедуры/функции (если он стоит вне циклов)
    А что при этом вернет функция?


    1. RoPi0n Автор
      02.01.2019 13:58

      Ничего. Но можно в стек закинуть что-нибудь если уж нужно сильно. Просто: push


      1. Amomum
        02.01.2019 17:18
        +9

        Эээ, а чему тогда будет равна переменная, которая принимает возвращаемое значение? Случайному значению со стека?


        1. iig
          02.01.2019 19:11

          В языке, претендующем на звание простого, никаких undefined behaviour быть не должно.


          1. RoPi0n Автор
            02.01.2019 19:18

            Тут их и нет. Если палки в колеса себе не пихать)


            1. iig
              02.01.2019 19:55
              +1

              break, в зависимости от контекста, либо выход из цикла, либо из функции, это заготовка для граблей.


              1. RoPi0n Автор
                02.01.2019 20:18
                +1

                Ну да. Но я думаю, что это опасный для использования оператор. Для выхода из функции и возврата значения есть return.


                1. iig
                  02.01.2019 20:27
                  +3

                  Ну да, немного интриги не повредит ;)


                  1. alhimik45
                    02.01.2019 20:32
                    +5

                    Единственный язык со специальным оператором для неопределнного поведения))


                    1. RoPi0n Автор
                      02.01.2019 20:41

                      Что есть, то есть :)


        1. RoPi0n Автор
          02.01.2019 20:15

          Эээ, а чему тогда будет равна переменная, которая принимает возвращаемое значение? Случайному значению со стека?


          Если ожидается значение от функции, а в функции оно в стек не ложится, то да. Либо значение с вершины стека, либо access violation.


          1. Amomum
            02.01.2019 23:54
            +1

            А чем вы руководствовались, когда давали оператору break такой функционал? Ни в одном известном мне языке break такого не делает.


            1. andrey_ssh
              03.01.2019 09:57

              Это Вы мало самодельных языков знаете. В моём тоже делает.


            1. RoPi0n Автор
              03.01.2019 12:23

              Если использовать exit внутри циклов, то это черевато мусором в стеке.


              1. Amomum
                04.01.2019 18:40

                У вас еще и exit есть, помимо return и break?


                1. RoPi0n Автор
                  04.01.2019 19:18

                  Нет, но могу добавить :)


                  1. Amomum
                    04.01.2019 19:19

                    Лучше поясните, о чем был предыдущий комментарий :)


                    1. RoPi0n Автор
                      04.01.2019 19:31

                      Добавил в язык оператор exit для выхода из процедур или функций.
                      Теперь break позволяет выйти только из циклов, case и try/catch блоков.


                      1. Amomum
                        04.01.2019 19:32

                        Так, а exit возвращает значение или нет? И чем он от return'a отличается?


                        1. RoPi0n Автор
                          04.01.2019 19:33

                          Отличается тем, что ничего не возвращает.


                          1. Amomum
                            04.01.2019 19:36
                            +1

                            Погодите, то есть у вас был break из функций, который ничего не возвращал, а теперь у вас есть exit из функций, который ничего не возвращает? :D

                            И точно так же можно словить мусорное значение со стека? Чем это лучше тогда?
                            Зачем вообще из функций возвращаться, не возвращая значение?


                            1. RoPi0n Автор
                              04.01.2019 19:39

                              Зачем ожидать из функции значение, которое не собираетесь в функции возвращать?


                              1. AnutaU
                                04.01.2019 22:02

                                Если в вашем языке некий бессмысленный код является валидным, и количество пользователей языка больше нуля, значит рано или поздно кто-то такой код обязательно напишет.


                            1. RoPi0n Автор
                              04.01.2019 19:43

                              В этом же смысла нету. Тем более, стек открыт и доступен для работы с ним.

                              Получить значение с вершины стека можно и вот так:

                              peek a
                              


                              1. iig
                                04.01.2019 12:07

                                А вот и ассемблером повеяло… ;)


                            1. RoPi0n Автор
                              04.01.2019 19:46

                              Можно даже из процедуры вернуть значение, если сильно нужно.

                              Пример:

                              proc test():
                                push 123
                              end
                              
                              ...
                              
                              x ?= test()
                              


                              1. Amomum
                                04.01.2019 19:50
                                +1

                                А как вызывающий должен догадаться, что функция не возвращает значения, если это функция, а не процедура (раз уж у вас есть разделение на функции и процедуры)?

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

                                Извините, но по-моему вы как будто специально footgun в язык вносите такими фишками :)


                              1. mobi
                                04.01.2019 20:06
                                +1

                                Только у нас самые лучшие револьверы на Диком западе? :-)


                              1. Akon32
                                04.01.2019 15:04

                                У вас Форт какой-то получается.


  1. gnomeby
    02.01.2019 12:45
    +2

    Какую задачу решает ваш язык программирования лучше чем любой другой?


    1. shai_hulud
      02.01.2019 12:53
      +4

      Я думаю, задачу изучения компиляторов и VM RoPi0n. Ведь если бы цель была в создании «языка решения X задач», то выбран был бы какой нибудь LLVM, а лексинг/парсинг отдан сторонней либе. Ведь это затратные по времени пункты, которые не релевантны цели. А автор решил сам всё писать.


      1. RoPi0n Автор
        02.01.2019 14:01
        +2

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


        1. pnovikov
          03.01.2019 14:18

          ИМХО, потому что это никому не нужно. Делать ещё одного "Неуловимого Джо", если ты не MS или Oracle и даже не JetBrains — такая себе идея. Разве что только поиграться. Но как мне кажется, гораздо больше опыта можно получить в попытках написать каких-нибудь расширений для уже существующих языков.


          1. RoPi0n Автор
            04.01.2019 15:24

            Каждому своё. Многие ЯП писались не крупными компаниями, а инициативными людьми.


        1. eclipse20
          04.01.2019 16:53

          Но на Гитхабе вы пишете следующее:

          Основные цели и идеи проекта:

          1) Создать максимально простую для разработчиков (и главное — для конечных пользователей!) среду разработки и выполнения кода.
          2) Создать максимально простой, удобный, гибкий, функционально полный, кроссплатформенный и быстрый язык.


          На Гитхабе пишете:
          Нетипизированный кроссплатформенный язык программирования, поддерживающий базовые парадигмы ООП.

          а здесь в статье:
          В языке Mash поддерживаются все парадигмы объектно-ориентированного программирования.


          Так где правда, в статье или на Гитхабе? :)


          1. RoPi0n Автор
            04.01.2019 16:54

            На момент написания статьи поддерживаются уже все вроде как.


      1. phantom-code
        02.01.2019 14:05
        +2

        Лексер — весьма тривиальная вещь. Не особо сложнее, чем описать набор правил для того же flex. Парсер контекстно-свободной грамматики тоже не является rocket science. Другое дело, что при разработке парсера, придется в любом случае как-то описывать грамматику, что по сути эквивалентно созданию входных данных для bison. Тем не менее, при использовании готовых библиотек-построителей персеров, вы становитесь зависимы от них при весьма сомнительном уменьшении времени на разработку. Насколько оправдана такая зависимость — решать только вам.


        1. KvanTTT
          02.01.2019 14:31

          Тем не менее, при использовании готовых библиотек-построителей персеров, вы становитесь зависимы от них при весьма сомнительном уменьшении времени на разработку.

          Сможете доказать этот тезис? Глядя на грамматики SQL (T-SQL, PL/SQL, MySQL) с кучей ключевых слов в такое что-то не верится...


          1. phantom-code
            02.01.2019 16:01

            В случае реализации парсера самостоятельно, придется написать больше текста и потратить больше времени — это правда. Но время, необходимое на написание самого парсера, сильно меньше времени, необходимого на реализацию остальных компонентов компилятора/интерпретатора/VM. Тем более, что многие элементы парсера похожи, копипаст хорошо ускоряет процесс. Доказать я вам ничего не могу, мои высказывания основаны на небольшом личном опыте. Ученых степеней по теме не имею, в разработке серьезных компиляторов участия не принимал.


            1. 0xd34df00d
              02.01.2019 18:15
              +1

              По опыту разработки парсеров, вещи вроде attoparsec/trifecta (на хаскеле) или boost.spirit (на плюсах) очень помогают в повышении эффективности разработки и, что важнее, поддержки.

              Особенно когда вам нужно сделать хорошие сообщения об ошибках, тут trifecta вообще на высоте.


              1. phantom-code
                02.01.2019 18:32
                +1

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


                1. 0xd34df00d
                  02.01.2019 18:35
                  +1

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


                  1. RoPi0n Автор
                    02.01.2019 18:41

                    Для некоторых ошибок реализованы уведомления.


                  1. phantom-code
                    02.01.2019 18:48

                    Я не работал над серьезными компиляторами (честно говоря никогда не слышал о коммерческой разработке компиляторов в РФ), поэтому не претендую на объективную истину. В моих велосипедах контекст ошибки был всегда понятен и проблемы сформировать хорошее сообщение с указанием точной позиции в тексте не возникало.


                    1. RoPi0n Автор
                      02.01.2019 18:54
                      +3

                      Есть Jet Brains, Excelsior — уже как минимум 2 ру компании, которые занимаются разработкой компиляторов.


                      1. phantom-code
                        02.01.2019 18:56

                        Да, вы правы, о JetBrains я забыл. Можно сказать, что они вообще специализируются на парсерах.


  1. AnutaU
    02.01.2019 12:57
    +7

    Мне хотелось создать на мой взгляд максимально простой, функциональный и удобный язык

    Когда видишь в описании языка слово «функциональный», ожидаешь увидеть нечто другое.


    1. fukkit
      02.01.2019 13:41
      +1

      Некоторые уже настолько упоролись, что и на «функциональные обязанности» в должностной инструкции будут триггерить.


      1. RoPi0n Автор
        02.01.2019 14:04

        Ну, под функциональностью я подразумевал гибкость и потенциал языка. Как по мне, все очень даже хорошо получилось в этом плане. Есть поддержка взаимодействия с натив кодом через простые и удобные импорты, поддержка callback-вызовов ВМ кода из внешних методов, простая в использовании многопоточность, неявные указатели на каждом шагу (а это очень даже как по мне удобно).


        1. TheShock
          03.01.2019 08:49

          Ну, под функциональностью я подразумевал гибкость и потенциал языка
          Подошло бы слово «гибкий»)


    1. RoPi0n Автор
      02.01.2019 17:27

      Исправил это слово в статье. Спасибо.


  1. Jamdaze
    02.01.2019 13:35
    +2

    Лет 10 программирование моё основное «хобби».
    И что я понял за это время — ещё один способ интерпретирования текстового файла (plain text) не нужен.
    Нужен качественный переход, например как переход от текста к гипертексту.
    И самое главное это ориентированность на средства разработки, а не на то какой последовательностью символов заканчивается блок кода\функции\etc.
    В общем, если уж решили потратить свое время и силы, могли бы запилить дополнительный уровень абстракции между бэкендом llvm\gcc и ide.
    Доступны десятки потоков, гигабайтый памяти, а мы всё мусолим эти текстовые файлы, ну бред же.
    Сколько лет уже с++, а до сих пор я не видел ide с его полной поддержкой.
    Ну вот вы сделали язык, а где ide, которая будет разматывать ваш синтаксис в абстрактное дерево? Как рефакторить код на вашем языке?


    1. RoPi0n Автор
      02.01.2019 13:56

      ide тоже реализована. Если бы вы чекнули сайт или репозиторий, то увидели бы её. Вы ожидаете от меня супер новую и мощную технологию с комплексом инструментария, так может поможете мне?) Репозиторий открыт, код доступен всем для ознакомления. Если у вас ести идеи по проекту и руки дотянутся до их реализации, то жду ваши пулы на github.


      Проект изначально не был нацелен на обход современных языков по производительности или в чем-либо. Хотелось попробовать самому реализовать свой ЯП с полностью моими архитектурными решениями и концептами. Получился простой и гибкий язык, как по мне. В ВМ отсутствуют лишние абстракции. Поддержка всех парадигм ООП реализована.


      Написал же, что хочу на GraalVM либо на LLVM направить транслятор. Тут как бы вопрос времени и того, как скоро я наковыряю достаточно информации для реализации транслятора под целевую ВМ. Если буду копать в сторону LLVM, то поддержка GraalVM уже и так будет, т.к. она может и биткод LLVM выполнять. Да и плюсом WebAssembly подтянется.


      Стоит понимать, что архитектуры всех этих вм, в т.ч. и моей реализации по сути схожи. Разница лишь в том, что LLVM и GraalVM заточены под работу со строгой типизацией, а моя ВМ наделена функционалом для автоматического приведения типов и выделения/перевыделения памяти, т.к. нетипизированный язык же писал изначально.


      Идея переноса проекта на новые ВМ у меня появилась не так уж и давно, когда я в серьез задумался над оптимизацией. (К слову, мб месяц назад ВМ выполняла код примерно в 8-10 раз медленней чем сейчас).


      1. AnutaU
        02.01.2019 15:26
        +2

        У вас немного кони и люди смешались. LLVM — это не ВМ.


        1. RoPi0n Автор
          02.01.2019 15:32
          -1

          LLVM (Low Level Virtual Machine) — это ВМ с JIT компилятором на борту.
          Исполняет она абстрактный упакованный биткод. Над LLVM существует куча надстроек и окружений (возможно вы думали именно о них, когда писали этот комментарий). Ничего у меня не путается.


          1. ZaMaZaN4iK
            02.01.2019 15:36
            +5

            Но это не отменяет того факта, что LLVM — не ВМ.


            1. RoPi0n Автор
              02.01.2019 15:44
              -3

              ru.wikipedia.org/wiki/LLVM
              Универсальная система анализа, трансформации и оптимизации программ, реализующая виртуальную машину с RISC-подобными инструкциями.


              1. ZaMaZaN4iK
                02.01.2019 15:56
                +3

                А давайте пройдём на официальный сайт LLVM: llvm.org

                Почитаем. А потом на главной странице поищем слово «virtual». Их там два — одно это сразу "…. Despite its name, LLVM has little to do with traditional virtual machines. ...".

                Второе — это klee, действительно ВМ. Только вот это проект на базе LLVM, а не сам LLVM.


                1. RoPi0n Автор
                  02.01.2019 16:04
                  -1

                  Слов «virtual» там не так уж и много, потому что их роль выполняют другие формулировки.
                  LLVM может использоваться, как компилятор абстрактного биткода в нативный. Так что это по-сути сложная ВМ.


                  1. ZaMaZaN4iK
                    02.01.2019 16:57

                    Нет, даже «по-сути» это не ВМ.


                    1. RoPi0n Автор
                      02.01.2019 17:14

                      Я не буду продолжать это. Надоело.


            1. RoPi0n Автор
              02.01.2019 15:49
              -7

              Достаточно уметь читать и гуглить, чтобы разобраться с тем, что такое LLVM. Можно даже скачать проект и покопаться в нем, если у вас есть на это время.
              К сожалению, ваше мнение не обоснованно и не является весомым. Оно скорее показывает, что один из двух требуемых навыков у вас отсутствует.
              Для вашего блага могу посоветовать вам для ознакомления азбуку и/или поисковую строку google.com


          1. AnutaU
            02.01.2019 15:39
            +2

            The name LLVM was originally an initialism for Low Level Virtual Machine. This initialism has officially been removed to avoid confusion, as the LLVM has evolved into an umbrella project that has little relationship to what most current developers think of as virtual machines


            1. RoPi0n Автор
              02.01.2019 15:59
              -2

              llvm.org
              The LLVM Project is a collection of modular and reusable compiler and toolchain technologies. Despite its name, LLVM has little to do with traditional virtual machines. The name «LLVM» itself is not an acronym; it is the full name of the project.

              In addition to official subprojects of LLVM, there are a broad variety of other projects that use components of LLVM for various tasks. Through these external projects you can use LLVM to compile Ruby, Python, Haskell, Java, D, PHP, Pure, Lua, and a number of other languages. A major strength of LLVM is its versatility, flexibility, and reusability, which is why it is being used for such a wide variety of different tasks: everything from doing light-weight JIT compiles of embedded languages like Lua to compiling Fortran code for massive super computers.

              LLVM — это JIT компилятор с абстрактного биткода в машинный, для его дальнейшего выполнения. Т.е. этот проект можно рассматривать как ВМ. Также он может компилировать абстрактный биткод в натив. Но это уже немного другое.
              Не пойму, от чего так вы зацепились за это.


              1. alhimik45
                02.01.2019 17:16
                +2

                LLVM — это JIT компилятор

                Вот именно. А не виртуальная машина


                А то так можно сказать, что "GCC — это компилятор C в машинный код, для его дальнейшего выполнения. Т.е. этот проект можно рассматривать как ВМ". Чувствуете нелогичность?


                1. RoPi0n Автор
                  02.01.2019 20:03
                  +3

                  Отличие GCC от LLVM в том, что GCC компилирует C/C++ в нативный код, а LLVM может выполнять абстрактный биткод и во время выполнения компилировать его в машинный для оптимизации. Так что я считаю, что LLVM — это ВМ, подобно JVM, Parrot и прочим.


                  1. alhimik45
                    02.01.2019 20:30

                    Почитал, действительно в составе LLVM есть тулза с помощью которой можно запустить биткод. Думаю все придрались именно к определению


                    LLVM — это ВМ

                    LLVM — это всё таки "a collection of modular and reusable compiler and toolchain technologies". И одной из технологий (не самой популярной, кмк) является запускалка биткода.


                  1. rogoz
                    03.01.2019 03:07

                    GCC компилирует C/C++ в нативный код

                    Ну, вроде как не совсем: gcc.gnu.org/wiki/GIMPLE


                    1. RoPi0n Автор
                      04.01.2019 15:36

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


      1. Jamdaze
        02.01.2019 16:01
        +3

        Объём проделанной вами работы, поражает.
        Просто жаль что такие усилия не оставят инфраструктуры для будущего.


        1. RoPi0n Автор
          02.01.2019 16:35
          +2

          Самое главное, что эти усилия оставят для будущего — это мои приобретенный скилл и опыт (и возможно что-то большее, если дойдут руки до более детального изучения LLVM или GraalVM). Проект само собой не с первой попытки был реализован. К самой оптимальной на мой взгляд архитектуре ВМ я пришел далеко не сразу. Но все решения и реализации мне пришлось проектировать и кодить самому. Этот процесс был весьма сложным и интересным.


      1. sumanai
        03.01.2019 12:57

        ide тоже реализована.

        ИМХО, сейчас актуально реализовывать что-то типа Langserver.org, намного удобнее для разработчиков.


    1. NeoCode
      02.01.2019 14:05

      А какие вам нужны файлы? Двоичные чтоли?
      На самом деле правильный подход — оставить текстовые файлы, но предусмотреть синтаксис настолько простой и эффективный, чтобы анализ и построение синтаксического дерева выполнялись буквально «на лету» в любой IDE начиная от профессиональных систем и заканчивая сверхлегкими блокнотоподобными. В С++ этого нет, потому что С++ создавался тогда когда об этом не задумывались.


      1. Jamdaze
        02.01.2019 14:56

        Я думаю лучше текстовый формат файлов, будет проще использовать системы контроля версий.
        А что если просто сохранять дерево в json\xml?


        1. RoPi0n Автор
          02.01.2019 15:35

          Стоит понимать, что дерево кода можно строить не полное, дабы сэкономить время анализа кода (и сохранять не обязательно никуда его). Да и многопоточность никто не мешает использовать, чтобы анализировать все «на лету».


        1. atamanenko
          02.01.2019 22:22

          А что если просто сохранять дерево в json\xml?

          Это называется придумывать решение, сначала придумав инструмент. Надо наоборот
          Чем json с xml полезнее?


      1. AnutaU
        02.01.2019 15:24
        +5

        На самом деле правильный подход — оставить текстовые файлы, но предусмотреть синтаксис настолько простой и эффективный, чтобы анализ и построение синтаксического дерева выполнялись буквально «на лету» в любой IDE начиная от профессиональных систем и заканчивая сверхлегкими

        И получается Lisp!


        1. 0xd34df00d
          02.01.2019 18:26
          -1

          Эх, только я хотел оставить комментарий про хаскель.


      1. oisee
        02.01.2019 19:18

        Отож! Вот Sinclair Basic токенизировал все ключевые слова — опечатку было сделать невозможно! Встроенный Autocomplete с IntelliSense в 1982 году!


      1. DaneSoul
        03.01.2019 09:49
        +1

        но предусмотреть синтаксис настолько простой и эффективный, чтобы анализ и построение синтаксического дерева выполнялись буквально «на лету» в любой IDE
        Синтаксис должен быть максимально простой и эффективный для чтения, написания и понимания ПРОГРАММИСТОМ, а не IDE.
        IDE может быть очень сложной «под капотом» — это не помешает разрабатывать на языке, в конце концов, таких IDE много не надо, достаточно одной хорошей кросс-платформенной.


      1. rustacean137
        04.01.2019 17:04

        ИМХО, не стоит чрезмерно упрощать ЯП, лучше когда IDE будут поддерживать и развивать LSP, а ЯП пуст сам реализует LSP сервер.


  1. amarao
    02.01.2019 15:01
    +2

    Э… Язык в 2019 году без алгебраических типов, pattern matching'а и исчерпывающих перечислений?


    1. RoPi0n Автор
      02.01.2019 15:08

      Первое и второе возможно будет реализовано позже. У меня не так уж и много времени, чтобы круглосуточно кодить.
      Перечисления в языке есть:

      enum MyEnum [meA, meB, meC, meD]
      


      Также поддерживается объявление массивов, содержащих перечень типов данных. Пример:
      a ?= [10, 20, 3.14, "Test", new MyClass(1, 2, "Test"), func1(10, 20, 3.14)]
      


      Из не упомянутого — также в языке поддерживается реализация методов с неограниченным числом аргументов.
      func SummAll(...):
        ...
      end
      
      ...
      
      r ?= SummAll(10, 20, 3.14, "337", 0xFF)
      

      Для получения аргументов есть переменная argcount — хранящая число переданных аргументов и стек — аргументы ложатся в обратном порядке, соответственно принять в методе их весьма просто.


      1. amarao
        02.01.2019 15:14
        +2

        Отлично, а как бы теперь обработать ситуацию, что MyEnum игнорируется? Основная польза от алгебраических типов не в том, что кто-то может положить перечисления, а в том, что попытка использовать перечисления требует полного исчерпания этого перечисления при match.


        1. RoPi0n Автор
          02.01.2019 15:37
          -1

          У вас есть идеи для реализации? Или может у вас имеется готовое решение, которое идеально встанет в код проекта? Пожалуйста — github.com/RoPi0n/mash-lang, жду pull


          1. amarao
            02.01.2019 15:43
            +1

            На паскале? Спасибо, как-нибудь без.

            Готовое решение есть.

            Грамматрика: github.com/rust-lang/rust/blob/master/src/grammar/parser-lalr.y#L1713

            Имплементация match: github.com/rust-lang/rust/blob/master/src/librustc_typeck/check/_match.rs


            1. RoPi0n Автор
              02.01.2019 16:11

              Чем вам FPC не угодил?)
              Посмотрю на этот код, но ничего не обещаю к реализации. Как пойдет.


              1. amarao
                02.01.2019 16:19
                +2

                А чем он должен угодить? Я даже скажу, зачем вам свой язык, если вам паскаль хорош?


        1. 0xd34df00d
          02.01.2019 18:28

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

          Я не уверен, что это хорошая идея в языке без зависимых типов или хотя бы GADTs + DataKinds.


          1. amarao
            02.01.2019 18:43

            В расте прекрасно без GADT приносит массу пользы.


            1. 0xd34df00d
              04.01.2019 15:29

              Я не спорю с тем, что оно способно приносить массу пользы. Однако, как вы обрабатываете случаи, когда семантика окружающего кода означает, что некоторые варианты ADT в данном месте невозможны, и паттерн-матчиться на них не имеет смысла? Не ленитесь создавать новый ADT или просто пишете panic/error/что там в расте?


              1. amarao
                04.01.2019 15:50

                В Rust есть (для наиболее распространённого типа Result) синтаксический сахар — знак вопроса, он говорит "передать ошибку дальше по стеку, т.е. вернуть Result(Err(_)), или .unwrap(), который паникует, если не Ok (т.е. Err).


                Вообще, если у вас по типу не пологается какого-то значения, зачем оно в типе присутствует?


                1. 0xd34df00d
                  04.01.2019 16:36

                  В Rust есть (для наиболее распространённого типа Result) синтаксический сахар — знак вопроса

                  А для других типов?


                  Но это, кстати, немножко не то. Это просто сахар поверх частного случая для do-нотации.


                  Вообще, если у вас по типу не пологается какого-то значения, зачем оно в типе присутствует?

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


                  1. amarao
                    04.01.2019 17:37

                    Ну, GADT в раст пытаются притащить, но, кажется, не в rust 2019. :(


    1. TheShock
      03.01.2019 08:53

      Э… Язык в 2019 году без алгебраических типов, pattern matching'а и исчерпывающих перечислений?
      Кстати, что мешает добавить алгебраические типы данных в более старые языки? Вроде того же c#? Я вот недавно решал одну задачу и очень жалел, что таких нету.


      1. amarao
        04.01.2019 14:20

        Необходимость компилятору знать все элементы перечисления на момент парсинга.



  1. Akon32
    02.01.2019 16:11
    +2

    Немного критики синтаксиса:
    1) Двоеточия для управляющих структур излишни. Можно и без них. Особенно это заметно в try, но и в других конструкциях тоже не нужны.


      try:
        ...
      catch:
        ...
      finally:
        ...
      end

    Без двоеточий это выглядело бы чуть проще.
    2) Не вижу цикла с постусловием, аналог do..while или repeat..until.
    3) Разделение proc-func, наверно, излишне.
    4) Знак $ в переменных и методах лишний.
    5) Синтаксис a ?= 10 непонятен для неподготовленного человека.
    6) Скобки в uses <bf> лишние.
    7) Можно придраться к ->, точка всё же короче.
    8) Оператор @= (разыменование с присваиванием) нелогичен. В паскале для этого используются variable ^ := value, у вас почему-то @ означает то взятие указателя, то разыменование.
    9) Чем отличаются jump и goto? Если ничем, достаточно одного.
    10) Самое главное. Отдельные объявления и определения классов совершенно не нужны.


    И ещё немного замечаний. Типизация, я так понимаю, динамическая? Генераторы (yield), как в питоне — хорошая штука, рекомендую добавить. "Полуавтоматический" сборщик мусора будут постоянно забывать вызывать, это странная идея.


    В языке Mash поддерживаются все парадигмы объектно-ориентированного программирования. Т.е. классы, наследования, полиморфизм (в т.ч. динамический), динамические автоматические рефлексия и интроспекция (полная).

    Это не парадигмы. ООП и есть парадигма. И если уж говорить о всех идеях из ООП, не вижу поддержки мультиметодов.


    1. RoPi0n Автор
      02.01.2019 16:31

      1) Мне наоборот кажется, что немного строгости языку не помешает, а то будет совсем уж аморфный синтаксис :)
      2) Вместо do..while в Mash реализован until <условие>:… end
      Пример:

      until a > 0:
        a--
      end
      

      Получается как в паскале цикл.
      3) Возможно. Но так же код представляется более строго и однозначно. Если разработчик бегло осматривает код, то ему будет удобнее сразу видеть, процедура перед ним или функция.
      4) Знак $ заменяет «this->» — он нужен только для обращения к классовым методам и переменным.
      5) Возможно. Но обычно люди в нашей сфере готовы к многому.
      6) В uses можно добавлять файл через "<имя файла>" или же через <>. В первом случае, транслятор будет искать файл с исходниками возле собираемого файла. Во втором — в папке inc возле транслятора.
      7) Ну, тут уж кому как.
      8) Ну, как сделал…
      9) goto нету, есть jump.
      10) Мне наоборот больше привлекателен код, когда объявление классов и определения раздельны. Если разработчик будет знакомиться с незнакомыми ему либами, то думаю, ему будет удобнее смотреть на объявление классов без их реализации.

      Да, типизация динамическая. Полуавтоматический сборщик мусора — наоборот как по мне забавная штука. Всегда знаешь когда мусор очищен. Сам контролируешь это. Генераторы конечно попробую реализовать в будущем, вещь несомненно полезная.

      Я рассматривал ООП как набор основных парадигм. Мультиметоды и шаблоны считаю немного лишними в языке с динамической типизацией и интроспекцией.
      Можно typeof() или x->type использовать.


      1. AnutaU
        02.01.2019 16:35

        until a > 0:
          a--
        end

        Какова семантика? Условие проверяется до выполнения тела цикла или после? Тело цикла выполняется в случае, если условие истинно или ложно?


        1. RoPi0n Автор
          02.01.2019 17:11

          Условие проверяется после выполнения итерации. Цикл выполняется пока условие ложно. Как в pascal сделал это. Только until вверх объявления цикла перенес.


          1. amarao
            02.01.2019 17:12
            +10

            Большой WTF для любого, читающего код. Написано в одном месте, проверяется в другом.


          1. Akon32
            02.01.2019 17:24
            +1

            Это фейл. Синтаксис until(cond){… } читается как while (! cond) {… }, то есть цикл с предусловием. Рекомендую как-то переставить условие в конец.
            Ещё к паскалевскому repeat… until можно придраться в том ключе, что while выполняется пока условие истинно, а repeat..until — пока условие ложно. С-подобное do… while в этом плане логичнее.
            Кажется, в visual basic я видел все варианты: while(){}, do{}while(), until(){}, do{}until() (но синтаксис там чуть другой).


            1. RoPi0n Автор
              02.01.2019 17:32
              -2

              Ну, кому как. Возможно в будущем изменю эту конструкцию.


          1. AnutaU
            02.01.2019 18:11
            +3

            Цикл выполняется пока условие ложно.

            Тогда не стоит в качестве примера такой конструкции приводить бесконечный цикл.


          1. mas
            04.01.2019 18:57

            JFYI в J парой к while идёт whilst. Получается очень красиво: во-первых, это тоже английское слово, тоже while; во-вторых, оно в J расшифровывается как while-s-t = while + skip test, т.е. тест в первый раз не выполняется.


      1. Akon32
        02.01.2019 17:37
        +2

        Могу слегка одобрить только $ в качестве замены this->. 2,8,10 категорически не одобряю, они не логичны (ну, ничего страшного, учебный язык). Остальные пункты вызывают меньше WTF.


        Я рассматривал ООП как набор основных парадигм.

        "Парадигма" — это и есть набор. "Совокупность идей и понятий" (см.вики). ООП как набор идей — парадигма, отдельные идеи до "парадигмы" не дотягивают. Высказывание в вашем варианте режет глаз.


      1. michael_vostrikov
        02.01.2019 17:41
        +2

        Если разработчик бегло осматривает код, то ему будет удобнее сразу видеть, процедура перед ним или функция.

        Зачем?


        1. RoPi0n Автор
          02.01.2019 20:06

          Доводилось ли вам работать с неизвестным вам кодом? Мб с объемными библиотеками? Несмотря на гибкость языка, строгость должна присутствовать. proc & func реализованы исключительно для этого. Можно было и обойтись без них оставив например только func.


          1. michael_vostrikov
            02.01.2019 20:36
            +1

            Вы не ответили на вопрос. Какая практическая польза от того, что программист будет знать, функция это или процедура? Что случится, если он будет рассматривать все куски кода как функции?


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


            1. RoPi0n Автор
              02.01.2019 22:00
              -1

              Я решил сделать разделение на функции и процедуры, ведь это все же мой язык. Раз вам нет пользы до того, функция перед вами или процедура, то это ваше дело :)
              Тут вопрос в том, как кому больше нравится.


              1. TheShock
                03.01.2019 08:55

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


  1. na9ort
    02.01.2019 16:59
    +1

    Что? Снова новый язык?
    Остановитесь.


    1. RoPi0n Автор
      02.01.2019 17:12
      +1

      Помимо языка тут ещё и ВМ новая с новой архитектурой)


  1. Lex20
    02.01.2019 18:16

    Почему синтаксис языка не на русском основан?


    1. RoPi0n Автор
      02.01.2019 18:18
      +1

      Это был бы ужас.


      1. iig
        02.01.2019 19:23

        Until не ужас, а "пока не" почему-то ужас. Или парсеру не все равно?


        1. RoPi0n Автор
          02.01.2019 19:25
          +3

          Считаю, что ЯП на английском языке будет выглядеть лучше.


          1. iig
            02.01.2019 22:21
            +1

            Пока видно pascal (end в конце блока кода, разделение на процедуры-функции), python (: в начале), php ( $ как префикс переменной), ?= — know-how автора; всё это заботливо перемешано. Не иначе, чтобы всех запутать :). Вот где ужас, а не в способе кодирования ключевых слов.


            1. RoPi0n Автор
              02.01.2019 22:25

              $ — сокращение this->
              Они стоят только в классовых методах, как вы можете посмотреть.
              Разве pascal & python плохие языки?)
              Мне кажется, что Mash больше смахивает на Ruby.


              1. iig
                02.01.2019 22:48

                У всех языков своя изюминка. C — лаконичный, с его {} и ?:. Pascal — строгий. Python — навороченный из коробки. Ruby — продукт сумрачного японского гения одно слово в:) Mash… даже не знаю… адский микс.


                1. DaneSoul
                  02.01.2019 23:55

                  Python — навороченный из коробки

                  Python хорош тем, что он позволяет писать как очень просто, так и навороченно.
                  То есть можно ничего не знать о функциональщине, ООП и даже работе с функциями, но уже начать писать простые скрипты, например для автоматизации каких-то действий в консоли.
                  А потом войти во вкус, изучить тонкости и начать писать компактный и эффективный код, со всякими генераторами, итераторами и т.п.
                  Именно по этому он хорош как язык для обучения программированию — можно не меняя язык показать разные подходы и парадигмы.


                  1. iig
                    03.01.2019 00:06
                    +1

                    И ещё в нем, как правило, нельзя просто взять и скопировать кусок кода; надо ещё и выровнять отступы ;) один из базовых паттернов говнокода нельзя просто использовать.
                    Хороший язык, и синтаксис интересный.


            1. feyd12
              04.01.2019 17:32

              ?= разве не из go позаимствовано вместе с var? Только там :=


          1. mSnus
            03.01.2019 05:06

            Сделайте уж совсем эпично-патриотично, на дореволюционном русском. И капсом все ключевые слова:
            ФУНКЦIЯ
            ...
            КОНЕЦЪ




  1. GreyStrannik
    02.01.2019 18:24
    +1

    К сожалению, из статьи не видна киллер фича (она есть?), зато виден убийственный недостаток — автор одинок.


    1. RoPi0n Автор
      02.01.2019 18:42

      Чтож, что есть — то есть)


  1. rfq
    02.01.2019 19:03
    +1

    Если бы вы в качестве выходного формата взяли Java class file, у вас больше времени осталось бы на вылизывание собственно языка и компилятора, и результат был бы более востребован.


    1. RoPi0n Автор
      02.01.2019 19:07
      +2

      Изначально целью проекта ставил реализовать все самому.


  1. alan008
    02.01.2019 20:50
    +2

    Если статью назвать по-другому, значительная часть комментариев была бы гораздо менее токсичной.
    Я бы назвал статью "Еще одна попытка создать ЯП на основе транслятора и ВМ" или "Попытка разобраться с тем, как создаются языки программирования и ВМ". Тогда бы все поняли, что проект в большей степени учебный, и что реализация больше велосипедная, нежели академическая/профессиональная/промышленная. Я уверен, автор получил классный опыт, разрабатывая всё это. И пусть это велосипед, многие комментаторы-критики и такой бы не создали, причем возможно даже не от нехватки опыта, а чисто из лени. А автор не поленился, разобрался и сделал, еще и выложить не постеснялся. Плюс статье, плюс в карму автору. Давайте уважать старания, а не хаять их.


    1. RoPi0n Автор
      02.01.2019 20:58

      Спасибо. Это мой первый пост на Хабре.


    1. RoPi0n Автор
      02.01.2019 21:03

      Про звезду репозиторию забыли упомянуть :)


      1. alan008
        02.01.2019 23:04
        +1

        Звезда на гитхабе — это немного про другое. Звёзды на Хабре выражают отношение к вашей активности тут (на Хабре), а звезды в гитхабе — это скорее отметки юзеров гитхаба, кому интересен проект, наподобие закладок. Я бы не стал ставить звезды всем подряд проектам на гитхабе, про которые просто "только что" услышал.


  1. GeMir
    02.01.2019 21:11
    +1

    Картофельное пюре (mash) — любый гарнир автора? :)

    Аудитория вас интересует только русскоязычная или по какой причине на сайте из международночитаемого лишь «write, compile and run anywhere»?

    Ну и мелочи…
    Заглушки «Company Name, Company Name, Company Name, Company Name» и «Чтож… Эта страница тоже в скором времени будет заполнена.» как и ваш ник на Patreon (RoPi0n) и выпрашивание «звёзд» на официальном форуме не добавляют серьёзности (а следовательно и доверия) сайту проекта, над которым вы трудитесь на протяжении нескольких лет.


    1. RoPi0n Автор
      02.01.2019 21:57

      Сайт не слишком давно поднят.
      Ему приоритет особо не выделял, т.к. времени небыло. Пока ещё не заполнен как следует. Хочется все по красоте сделать.


  1. domix32
    03.01.2019 01:01

    За использоване $var для переменных людей надо пожизненно отправлять в goto лапшу.
    Вывод типа передачи данных в переменную будет довольно неудобным. Сложил так две переменных, а они по указателю передавались и в итоге попадаем в непонятный раздел памяти.


    1. RoPi0n Автор
      03.01.2019 02:09

      Чтож, пишу в который раз для внимательного талантливого кодера domix32. Оператор $ используется лишь для сокращения записи "this->". В языке нет "$var" переменных. Ваш комментарий вообще не связан с проектом и не несет никакой смысловой нагрузки. Не следует отправлять в непонятный раздел памяти информацию сразу после её прочтения. На хабре предпочтительна конструктивная критика.


      1. TheShock
        03.01.2019 08:59

        омментарий вообще не связан с проектом и не несет никакой смысловой нагрузки
        Автор, вам следует поумерить свой пыл, серьёзно. Тут вы неправы.

        Не следует отправлять в непонятный раздел памяти информацию сразу после её прочтения
        Думаете, люди никогда не ошибаются?


        1. RoPi0n Автор
          03.01.2019 12:27

          Ошибаются, но такой уж я человек. Иногда отвечаю колко))


        1. RoPi0n Автор
          03.01.2019 12:27

          За это могу лишь свои извинения принести заранее людям.


      1. domix32
        04.01.2019 18:14

        Не имеет принципиальной разницы для чего используется такой синтаксис, это сразу выкидывает из определения языка слово «простой». Перл уже использует аналогичное различие переменных, мало кто в восторге от его синтаксиса. Тут та же ситуация — вместо синтаксического сахара выходит перец. Набор символов !@#$%^ далеко не самый быстрый для набора, а при частом использовании мизинчик начинает страдать. Едва ли гуманно пересаживать людей за спецраскладки только ради языка.
        Вторая часть относилась к присвоению переменных вообще. Вывод типа хорошо, но открыть блокнот и написать программу без ошибок из-за особенностей присвоения становится на порядок сложнее. То есть по хорошему нужен линтер или что-то подобное. Тоже далеко не аргумент в пользу простоты языка.
        А так — успехов в своем начинании.


    1. SBC
      03.01.2019 11:44

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


      1. iig
        03.01.2019 12:27

        Тогда $->var, пожалуй, более наглядно и логично. И немного на perl похоже ;)
        $ — синоним this
        -> — признак указателя
        var — имя.


        1. RoPi0n Автор
          03.01.2019 12:47

          Тут же целых 2 символа можно сократить.


          • При передаче $ как аргумента, допустим так:
            MyMethod($) — передается просто this без ->


          1. iig
            03.01.2019 13:01

            Я не о том.

            Внутри класса к его методам вы обращаетесь так:

              $rem()
            

            снаружу — так:
              x->rem()


            Зачем 2 разные формы записи одного и того же действия?


            1. RoPi0n Автор
              04.01.2019 15:43

              Изнутри можно использовать обращение:
              this->rem()
              Которое можно сократить так:
              $rem()


              Также и с любыми другими переменными и методами класса.
              Ну ведь удобнее же так :\


              1. iig
                04.01.2019 15:51
                +1

                Указатель this есть, ок.
                Нотация для записи указателя есть, вот она ->
                Синоним для this есть, вот он $

                Почему вместо $->name использовать дополнительный вариант написания $name, годный только внутри класса? Так короче, да. Но удобнее ли… это дополнительное правило в синтаксисе простого языка.


  1. RegisterWindowClassExA
    03.01.2019 01:39

    Респект Вашему труду, но не ясна концепция языка. Вот в Python всё ясно — это современный крутой аналог бейсика, типизации нет, переменные объявлять не надо, даже поля классов объявлять не обязательно, пиши функционал, никакого занудства. В Си тоже ясно — строгая типизация, переменные объявлять обязательно, ну Вы понимаете. У Вас получилось нечто среднее, причём не ясно, а в чем изюминка? Т.е. для Вас это крутой учебный проект? Тогда ок… На первый взгляд, он ничего не даёт. Никакой крутой концепции, кроме того, что Вы написали свой язык, а я не написал.
    И да, у Вас ведь нет компилятора под некоторую ОС? Ни байт-кода… Т.е. есть синтаксический анализатор, который разбирает строку на команды и тут же исполняет инструкции? Ну мне почти всё ясно тогда, кроме того, как Вы реализовали динамическое построение классов в трансляторе. На чём транслятор написан?
    Т.е. на мой взгляд самое ценное здесь — реализация транслятора, но эта тема в статье не раскрыта. А так — Вашему уровню респект, конечно…


    1. RoPi0n Автор
      03.01.2019 02:19

      Транслятор преобразует код в промежуточное представление (ассемблер-подобный листинг) и затем собирает уже его в абстрактный байткод для написанной ВМ. Исходя из вашего текста, делаю вывод о том, что вам не почти все ясно, а почти ничего не ясно. Рекомендую пост к прочтению повторно.
      Динамическое построение классов реализовано через структурные таблицы и генератор конструктора и деструктора структуры классов.


      На чем написано? Серьезно? Вам сложно клацнуть по ссылке на репозиторий?


      1. RegisterWindowClassExA
        03.01.2019 03:16

        Ну ок, мне было почти ничего не ясно, теперь немного яснее, спасибо :)


        1. RoPi0n Автор
          03.01.2019 12:28

          Спасибо, что уделили внимание моей работе)


    1. 0xd34df00d
      04.01.2019 15:37

      Вот в Python всё ясно — это современный крутой аналог бейсика, типизации нет, переменные объявлять не надо

      И это типа хорошо?


      В Си тоже ясно — строгая типизация

      А, ну понятно.


      1. RegisterWindowClassExA
        04.01.2019 15:44

        Пардон, имелась в виду явная и неявная типизация, а не «строгая» и «типизации нет».

        И это типа хорошо?

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


        1. 0xd34df00d
          04.01.2019 16:37

          Пардон, имелась в виду явная и неявная типизация, а не «строгая» и «типизации нет».

          Но ведь в питоне она строгая и динамическая (хотя динамическая типизация — это немножко оксюморон, если подумать о предназначении типов), а в С явная, слабая и статическая.


          1. RegisterWindowClassExA
            04.01.2019 16:53

            Да, это так. В Питоне лично мне понравилось то, что в нем не нужно объявлять переменные, а также поля классов. Этим он мне и напомнил Бейсик. А «очарование» здесь в том, что это снижает бюрократическую составляющую при написании кода. В этом есть определенное удовольствие, просто садиться и «фристайлить». Необходимость объявлять переменные это удовольствие резко снижает. ИМХО.
            Строгость типизации — это да, это тоже немного мешает, т.к. усложняет текст программы явными преобразованиями.
            Это не значит, что я говорю, что Python лучше чем Си. Скорее, мне кажется наоборот. Как перфекционист я бы вообще кодил на Асме, но увы, это коммерчески нежизнеспособная идея. А в Python как и в Бейсике есть своё очарование. Я знал классных кодеров, которые начинали с Бейсика. Именно потому, что неявная типизация позволяет сосредоточиться на задаче, а не на бюрократии… Это как кафе открыть — одно дело классно готовить и людей кормить, а другое — соблюдать положенный документооборот. Немного разные задачи. Хотя конечным итогом должно стать именно классное обслуживание клиента.


            1. 0xd34df00d
              04.01.2019 17:20

              Ну, это уж кому что. Мне больше нравятся строгие и выразительные системы типов, когда компилятор бьёт меня по рукам и помогает отлавливать ошибки ещё до запуска программы. И это, кстати, совсем не значит, что переменные надо как-то заранее объявлять.

              Да и проектировать типы тоже помогают, ещё как.


  1. FreeBa
    03.01.2019 01:53
    +1

    максимально простой, полнофункциональный и удобный язык

    Взаимоисключающие понятия, имхо. Шарп и ява тоже задумывались такими, а в итоге получилось, то что получилось. Простыми языки может и являются (весьма условно, без хорошего опыта в «строгих» языках, с ходу в них не войдешь), но обвешаны таким количеством библиотек являющимися отраслевыми стандартами, что изучение «обвеса», занимает на порядок больше времени чем изучение непосредственно языка.

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


    1. RoPi0n Автор
      03.01.2019 02:20

      Ну, тут уже как пойдет. Посмотрим что получится)


    1. iig
      03.01.2019 10:59

      Мой внутренний зануда интересуется, в чем измеряют простоту языка. Если задача сделать минимальный набор правил и ключевых слов, то наш ориентир brainfuck.


      1. RoPi0n Автор
        03.01.2019 12:45

        Ну, тут комментатор ниже постарался и ответит по случаю на этот вопрос)


  1. forcam
    03.01.2019 04:57

    Уважаю всех кто берется за глобальные вещи и написание языка программирования явно одна из них. Все языки программирования либо служат определенной цели, либо нескольким целям, либо помогают решить что-то быстрее, эффективнее ну или оптимальнее других.
    Бегло пробежав по коду я понял в нем все очень легко, это несомненно круто, потому что я не имею никакого отношения к программированию и учил когда-то только паскаль.
    Ваш язык это тот же паскаль, но со всеми наваротами, которые присущи современным языкам и ваш вектор явно лежит в сторону того, что бы язык сделать таким же как и любой другой. Но мне кажется вы не осознаете, где именно ниша вашего языка. Есть Goland, есть Python, отличие от них будет в том, что ваш язык будет еще проще.
    Ok, тогда вам нужно понять кому будет полезен ваш язык и я делаю вывод, что в первую очередь он будет полезен тем же, кому полезен паскаль, т.е. новичкам, по этой причине я думаю имело бы смысл сделать сильный док материал, с хорошими туториалами, что бы ваш язык мог освоить любой. Проблема вхождения в язык в его сахарности, если человеку сложно осмыслить логическую цепочку последовательности того как строится программа, то он может бросить пытаться учиться, ваш язык своей простотой помог бы очень многим, а учитывая то, что теоретически он позволит писать все, да еще и будет актуален в плане постоянной поддержки всех современных веяний в языках — такой язык идеален для того, что бы начинать с него изучать программирование.Я не знаю считаете ли вы, что чем больше будет в мире новых программистов — чем-то хорошим, но если да, то лучшим вариантом было бы сделать максимально возможное количество примеров для реализации. Т.е. написание простейших программ с подробным описанием всех кирпичиков работы. Ну и общая исчерпывающая документация. Конкретно такого языка, который бы максимально просто вводил человека в программирование сейчас нет, паскаль давно безнадежно устарел, так что ваш язык помог бы очень многим открыть дверь в мир программирования.


  1. Panzerschrek
    03.01.2019 06:09

    Исключения, сборка мусора — не самые актуальные сейчас элементы в новых ЯП (Rust и т. д.). Не рассматривается ли отказ от них?


    1. RoPi0n Автор
      03.01.2019 12:33

      Как же без них? Мне кажется, что от этого нельзя уходить.


      1. 0xd34df00d
        04.01.2019 15:38

        От исключений можно и нужно уходить.


        1. KaminskyIlya
          04.01.2019 10:03

          От исключений можно и нужно уходить

          Прошу прощения, а можно про это по-подробнее? Есть какая-то техника, или какие-то тренды в этом направлении?


          1. 0xd34df00d
            04.01.2019 16:29

            Да, монадическая обработка ошибок.


      1. feyd12
        04.01.2019 18:36

        А как же писать код совсем без ошибок?))


  1. unC0Rr
    03.01.2019 10:18

    Хочу заметить, что хоть количество поддерживаемых платформ у фрипаскаля велико, оно очень туго расширяется. Уже несколько лет идут разговоры о бэкенде llvm, но реализации до сих пор нет. У нас была попытка сделать браузеры одной из платформ для программы, пришлось реализовать самописным конвертатором из паскаля в си, дальше цепочка из llvm (вот и пригодился бы родной llvm-бэкенд!) и emscripten. Самое интересное, что программа после прямой конвертации в совершенно неидеоматичный си и компиляции с оптимизациями оказывалась быстрее любой сборки фрипаскалем. Кроме того, за 14 лет использования фрипаскаля я уже трижды натыкался на баги релизного компилятора, что тоже несколько удручает.


    1. RoPi0n Автор
      03.01.2019 12:44

      Поэтому и хочу на llvm перенести выполнение кода. Только различие в работе с памятью и пока что недостаток моих знаний по LLVM.


    1. RoPi0n Автор
      04.01.2019 15:44

      Не дают мне реализовать задуменное


  1. SBC
    03.01.2019 11:48

    Добро пожаловать в клуб любителей трансляторов и компиляторов.

    Для целых чисел 32 бита фундаментальное ограничение? Чтобы поближе к машине?
    Не смотрели в сторону длинной арифметики?


    1. RoPi0n Автор
      03.01.2019 12:35

      Максимальная разрядность целого числа — 64 бита.


      1. SBC
        03.01.2019 12:40

        ar i = 2147483647*2+1
        PrintLn(i) // Выводит 4294967295
        i = i + 1
        PrintLn(i) // Выводит 0


  1. SBC
    03.01.2019 12:39

    del


  1. impwx
    03.01.2019 13:48
    +1

    Добро пожаловать в клуб! Теперь, однако, вам необходимо ответить на самый тяжелый вопрос — нужен ли данный язык кому-то, кроме вас? Дело в том, что синтаксис по большому счету никому не сдался, а действительно важно удобство решения задач. Если, как вы пишете в комментариях, основная задача была в том, чтобы получить опыт — считайте, что вы его уже получили. Поставьте данный проект на почетное место на полке и двигайтесь дальше, с опытом и новыми силами, исходя от какой-нибудь конкретной задачи, решение которой с помощью языка принесет кому-то конкретную пользу.


  1. pnovikov
    03.01.2019 14:14

    Извините, но… зачем? Чем вас существующие-то языки не устроили?


    1. kaleman
      03.01.2019 23:36

      Разработка компиляторов очень важная сфера в которой Россия и СНГ сильно отстает от всего мира.


      1. TheShock
        04.01.2019 00:45
        +1

        У остального СНГ нету с этим проблем, т.к. компиляторы — дело международное. Если не самоизолироваться, то ты можешь пользоваться достоянием всего мира


  1. rkfg
    04.01.2019 14:23

    Коммиты не оформлены практически никак, это ужасно. Похоже, для вас Git — это какая-то обязанность (все делают, ну и мне придётся, эххх, а мог бы по-старинке projname-2018-12-20.zip делать и не мучаться), а не инструмент работы. Советую почитать, как оформлять коммит-сообщения, чтобы всем стало лучше.


  1. WRONGWAY4YOU
    04.01.2019 17:41

    Для того, чтоб язык был полезен хоть кому-то после выхода (кроме самого разработчика), он должен обладать некоторым количеством отличающих черт, каждая из которых хоть как-то упрощала б задачу реализации программного обеспечения.


    Извините, конечно, но Вы представили еще один generic язык, который ничего особо нового и не дает людям. Однако, для всего нужен опыт, и, даже один законченный ЯП, я уверен, смог Вас очень многому об этой области CS научить, и, следовательно, следующая попытка будет уже лучше. Нужно просто сделать его уникальным и полезным.


    А вообще, могу точно сказать, что 99% всех программистов никогда в своей жизни не реализуют ничего своего и не напишут об этом статью. К тому же Вы за эту статью (скорее всего) получили приглашение на Хабр. Так что поздравляю!


    1. feyd12
      04.01.2019 18:40

      Присоединяюсь к поздравлениям, хотя статью можно и попроще забацать для такой цели, как приглашение, мою гляньте))


  1. Vitter
    04.01.2019 00:34

    Вопрос стоит — зачем язык создавался? Единственно, что его хоть как-то отличает — синтаксис питоно-паскале-подобный.
    Что критически важно — на сайте добавить синтаксис! Говорить про язык программирования без синтаксиса (даже с репозиторием компилятора) как-то не серьёзно. Я, например, даже не понял — есть ли в этом языке комментарии или нет.
    Далее критически важно — версификация. Какую версию вы нам описали в этой статье? 0.4.12? Или всё же — хэ его зэ? Это уже ближе к правде.
    Ну, а по мелочи — есть к чему придраться.
    Зачем делать until (false)… end постусловием, если уже придуман repeat… until (false)?
    Или зачем создавать процедуры, если есть функции?