Yangi dasturlash tili Mash

Bir necha yil davomida men o'z dasturlash tilimni ishlab chiqishda o'z kuchimni sinab ko'rdim. Men, mening fikrimcha, mumkin bo'lgan eng sodda, to'liq funktsional va qulay tilni yaratmoqchi edim.

Ushbu maqolada men o'z ishimning asosiy bosqichlarini ta'kidlamoqchiman va avvalo, men hozir ishlayotgan tilning yaratilgan kontseptsiyasi va uning birinchi amalga oshirilishini tasvirlab bermoqchiman.

Oldindan aytamanki, men butun loyihani Free Paskalda yozganman, chunki... undagi dasturlar juda ko'p platformalar uchun yig'ilishi mumkin va kompilyatorning o'zi juda optimallashtirilgan ikkilik fayllarni ishlab chiqaradi (men loyihaning barcha komponentlarini O2 bayrog'i bilan to'playman).

Tilning ishlash vaqti

Avvalo, mening tilimdagi kelajakdagi ilovalarni ishga tushirish uchun yozishim kerak bo'lgan virtual mashina haqida gapirishga arziydi. Men stek arxitekturasini amalga oshirishga qaror qildim, ehtimol bu eng oson yo'li edi. Men buni rus tilida qanday qilish kerakligi haqida oddiy maqola topmadim, shuning uchun ingliz tilidagi material bilan tanishib chiqqanimdan so'ng, men o'z velosipedimni loyihalash va yozishga o'tirdim. Keyinchalik men bu boradagi "ilg'or" g'oyalarim va ishlanmalarimni taqdim etaman.

Stackni amalga oshirish

Shubhasiz, VM ning yuqori qismida stek joylashgan. Mening amaliyotimda u bloklarda ishlaydi. Aslini olganda, bu oddiy ko'rsatkichlar qatori va stekning yuqori qismidagi indeksni saqlash uchun o'zgaruvchidir.
U ishga tushirilganda 256 ta elementdan iborat massiv yaratiladi. Agar stekga ko'proq ko'rsatkichlar surilsa, uning o'lchami keyingi 256 ta elementga ortadi. Shunga ko'ra, elementlarni stekdan olib tashlashda uning o'lchami o'rnatiladi.

VM bir nechta steklardan foydalanadi:

  1. Asosiy to'plam.
  2. Qaytish nuqtalarini saqlash uchun stek.
  3. Axlat yig'uvchilar to'plami.
  4. Ishlovchilar to'plamini sinab ko'ring/tutib oling/nihoyat blokirovka qiling.

Konstantalar va o'zgaruvchilar

Bu oddiy. Konstantalar alohida kichik kod bo'lagida ishlanadi va kelajakdagi ilovalarda statik manzillar orqali foydalanish mumkin. O'zgaruvchilar ma'lum o'lchamdagi ko'rsatkichlar massivi bo'lib, uning hujayralariga kirish indeks orqali amalga oshiriladi - ya'ni. statik manzil. O'zgaruvchilar stekning yuqori qismiga surilishi yoki u erdan o'qilishi mumkin. Aslida, chunki Bizning o'zgaruvchilarimiz ko'rsatkichlarni VM xotirasida qiymatlarga asosan saqlasa-da, tilda yashirin ko'rsatkichlar bilan ishlash ustunlik qiladi.

Axlat yig'uvchi

Mening VMimda u yarim avtomatik. Bular. chiqindi yig'uvchiga qachon qo'ng'iroq qilishni ishlab chiquvchining o'zi hal qiladi. Python, Perl, Ruby, Lua va boshqalarda bo'lgani kabi oddiy ko'rsatkich hisoblagichi yordamida ishlamaydi. U marker tizimi orqali amalga oshiriladi. Bular. o'zgaruvchiga vaqtinchalik qiymat berish mo'ljallangan bo'lsa, axlat yig'uvchining stekiga ushbu qiymatga ko'rsatgich qo'shiladi. Kelajakda kollektor allaqachon tayyorlangan ko'rsatkichlar ro'yxatidan tezda ishlaydi.

try/catch/nihoyat bloklari bilan ishlash

Har qanday zamonaviy tilda bo'lgani kabi, istisnolardan foydalanish muhim komponent hisoblanadi. VM yadrosi try..catch blokiga o‘ralgan bo‘lib, u istisno holatini qo‘lga kiritgandan so‘ng, u haqidagi ba’zi ma’lumotlarni stekga surish orqali kod bajarilishiga qaytishi mumkin. Ilova kodida siz try/catch/nihoyat kod bloklarini belgilashingiz mumkin, bunda catch (istisno ishlov beruvchisi) va nihoyat/end (blokning oxiri) da kirish nuqtalarini belgilashingiz mumkin.

Ko'p tarmoqli

U VM darajasida qo'llab-quvvatlanadi. Bu oddiy va foydalanish uchun qulay. U uzilish tizimisiz ishlaydi, shuning uchun kod mos ravishda bir necha marta tezroq bajarilishi kerak.

VMlar uchun tashqi kutubxonalar

Busiz qilishning iloji yo'q. VM boshqa tillarda qanday amalga oshirilganiga o'xshash importni qo'llab-quvvatlaydi. Siz Mash-da kodning bir qismini va kodning bir qismini ona tillarida yozishingiz, keyin ularni biriga bog'lashingiz mumkin.

VMlar uchun yuqori darajadagi Mash tilidan bayt-kodga tarjimon

O'rta til

Tarjimonni murakkab tildan VM kodiga tezda yozish uchun men birinchi navbatda oraliq tilni ishlab chiqdim. Natijada assemblerga o'xshash dahshatli tomosha paydo bo'ldi, bu erda alohida ahamiyatga ega emas. Faqat shuni aytmoqchimanki, bu darajada tarjimon ko'pchilik konstantalar va o'zgaruvchilarni qayta ishlaydi, ularning statik manzillari va kirish nuqtalarining manzillarini hisoblaydi.

Tarjimon arxitekturasi

Amalga oshirish uchun eng yaxshi arxitekturani tanlamadim. Tarjimon boshqa tarjimonlar singari kodlar daraxtini qurmaydi. U strukturaning boshiga qaraydi. Bular. agar tahlil qilinayotgan kod qismi “while :” ga o‘xshab ko‘rinsa, bu while tsikli konstruksiyasi ekanligi va uni while tsikli konstruksiyasi sifatida qayta ishlash kerakligi aniq. Murakkab kommutatorga o'xshash narsa.

Ushbu me'moriy yechim tufayli tarjimon unchalik tez emas edi. Biroq, uni o'zgartirish qulayligi sezilarli darajada oshdi. Men kerakli tuzilmalarni qahvam sovib ketishidan tezroq qo'shdim. To'liq OOP yordami bir haftadan kamroq vaqt ichida amalga oshirildi.

Kodni optimallashtirish

Bu erda, albatta, uni yaxshiroq amalga oshirish mumkin edi (va amalga oshiriladi, lekin keyinroq, unga yaqinlashish bilanoq). Hozircha optimallashtiruvchi faqat foydalanilmagan kodni, konstantalarni va yig'ilishdan importni qanday qilib kesishni biladi. Shuningdek, bir xil qiymatga ega bo'lgan bir nechta konstantalar bittaga almashtiriladi. Ana xolos.

Til Mash

Til haqida asosiy tushuncha

Asosiy g'oya iloji boricha funktsional va sodda tilni ishlab chiqish edi. O'ylaymanki, rivojlanish o'z vazifasini portlash bilan engadi.

Kod bloklari, protseduralari va funktsiyalari

Tildagi barcha konstruktsiyalar ikki nuqta bilan ochiladi. : va operator tomonidan yopiladi oxiri.

Protseduralar va funksiyalar mos ravishda proc va func deb e'lon qilinadi. Argumentlar qavs ichida keltirilgan. Hammasi boshqa tillar kabi.

Operator Qaytish funksiyadan, operatordan qiymat qaytarishingiz mumkin tanaffus protsedura/funksiyadan chiqish imkonini beradi (agar u looplardan tashqarida bo'lsa).

Kod namunasi:

...

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

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

Qo'llab-quvvatlanadigan dizaynlar

  • Davrlar: for..end, while..end, to.. end
  • Shartlar: agar..[else..]end, switch..[case..end..][else..]end
  • Usullari: proc ():... end, func ():... end
  • Yorliq va o'tish: :, o'tish
  • Sanoqlar va doimiy massivlarni sanash.

O'zgaruvchilar

Tarjimon ularni avtomatik ravishda aniqlashi mumkin yoki ishlab chiquvchi ularni belgilashdan oldin var yozsa.

Kod misollari:

a ?= 10
b ?= a + 20

var a = 10, b = a + 20

Global va mahalliy o'zgaruvchilar qo'llab-quvvatlanadi.

OOP

Xo'sh, biz eng mazali mavzuga keldik. Mash barcha ob'ektga yo'naltirilgan dasturlash paradigmalarini qo'llab-quvvatlaydi. Bular. sinflar, meros, polimorfizm (shu jumladan dinamik), dinamik avtomatik aks ettirish va introspektsiya (to'liq).

Ko'proq vaqt o'tkazmasdan, shunchaki kod misollarini keltirgan ma'qul.

Oddiy sinf va u bilan ishlash:

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

Chiqarish: 30.

Meros va polimorfizm:

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

Chiqarish: 60.

Dinamik polimorfizm haqida nima deyish mumkin? Ha, bu aks ettirish!:

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

Chiqarish: 60.

Keling, oddiy qadriyatlar va sinflar bilan tanishish uchun bir oz vaqt ajratamiz:

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

Chiqarish: rost, rost.

Tayinlash operatorlari va aniq ko'rsatkichlar haqida

?= operatori o'zgaruvchiga xotiradagi qiymatga ko'rsatgichni belgilash uchun ishlatiladi.
= operatori o'zgaruvchidan ko'rsatgich yordamida xotiradagi qiymatni o'zgartiradi.
Va endi aniq ko'rsatkichlar haqida bir oz. Men ularni tilga qo'shdim, shunda ular mavjud.
@ — oʻzgaruvchiga aniq koʻrsatgichni olish.
? — ko‘rsatkich bo‘yicha o‘zgaruvchini olish.
@= — oʻzgaruvchiga aniq koʻrsatgich yordamida qiymat berish.

Kod namunasi:

uses <bf>
uses <crt>

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

Chiqarish: ba'zi raqamlar, 10, 11.

Sinab ko'ring..[tutib oling..][nihoyat..]end

Kod namunasi:

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

Kelajak uchun rejalar

Men GraalVM & Truffle-ga qarashda davom etaman. Mening ish vaqti muhitimda JIT kompilyatori yo'q, shuning uchun unumdorlik nuqtai nazaridan u hozirda faqat Python bilan raqobatlasha oladi. Umid qilamanki, men GraalVM yoki LLVM asosida JIT kompilyatsiyasini amalga oshira olaman.

ombori

Siz ishlanmalar bilan o'ynashingiz va loyihani o'zingiz kuzatib borishingiz mumkin.

veb-sayt
GitHub-dagi ombor

Oxirigacha o'qigan bo'lsangiz rahmat.

Manba: www.habr.com

a Izoh qo'shish