نئی پروگرامنگ زبان میش

کئی سالوں سے میں نے اپنی پروگرامنگ زبان تیار کرنے میں اپنا ہاتھ آزمایا۔ میں اپنی رائے میں، سب سے آسان، مکمل طور پر فعال اور آسان زبان بنانا چاہتا تھا۔

اس مضمون میں میں اپنے کام کے اہم مراحل کو اجاگر کرنا چاہتا ہوں اور شروع میں زبان کے تخلیق شدہ تصور اور اس کے پہلے نفاذ کو بیان کرنا چاہتا ہوں، جس پر میں فی الحال کام کر رہا ہوں۔

مجھے پہلے ہی بتانے دو کہ میں نے پورا پروجیکٹ فری پاسکل میں لکھا ہے، کیونکہ... اس پر موجود پروگراموں کو بڑی تعداد میں پلیٹ فارمز کے لیے جمع کیا جا سکتا ہے، اور کمپائلر خود بہت بہتر بائنریز تیار کرتا ہے (میں پروجیکٹ کے تمام اجزاء کو O2 پرچم کے ساتھ جمع کرتا ہوں)۔

زبان کا رن ٹائم

سب سے پہلے، یہ اس ورچوئل مشین کے بارے میں بات کرنے کے قابل ہے جسے مجھے اپنی زبان میں مستقبل کی ایپلی کیشنز چلانے کے لیے لکھنا پڑا۔ میں نے اسٹیک فن تعمیر کو نافذ کرنے کا فیصلہ کیا، شاید، کیونکہ یہ سب سے آسان طریقہ تھا۔ مجھے روسی زبان میں ایسا کرنے کے بارے میں ایک بھی عام مضمون نہیں ملا، لہذا انگریزی زبان کے مواد سے واقف ہونے کے بعد، میں اپنی سائیکل کو ڈیزائن کرنے اور لکھنے کے لیے بیٹھ گیا۔ آگے میں اس معاملے میں اپنے "جدید" خیالات اور پیشرفت پیش کروں گا۔

اسٹیک نفاذ

ظاہر ہے، VM کے اوپری حصے میں اسٹیک ہے۔ میرے نفاذ میں یہ بلاکس میں کام کرتا ہے۔ بنیادی طور پر یہ پوائنٹرز کی ایک سادہ صف ہے اور اسٹیک کے اوپری حصے کے انڈیکس کو ذخیرہ کرنے کے لیے ایک متغیر ہے۔
جب اسے شروع کیا جاتا ہے، 256 عناصر کی ایک صف بنائی جاتی ہے۔ اگر مزید پوائنٹرز کو اسٹیک پر دھکیل دیا جائے تو اس کا سائز اگلے 256 عناصر سے بڑھ جاتا ہے۔ اس کے مطابق، اسٹیک سے عناصر کو ہٹاتے وقت، اس کا سائز ایڈجسٹ کیا جاتا ہے.

VM کئی اسٹیک استعمال کرتا ہے:

  1. مین اسٹیک۔
  2. واپسی پوائنٹس کو ذخیرہ کرنے کے لیے ایک اسٹیک۔
  3. کچرا جمع کرنے والا ڈھیر۔
  4. ہینڈلر اسٹیک کو آزمائیں/پکڑیں/آخر میں بلاک کریں۔

مستقل اور متغیرات

یہ ایک سادہ ہے. Constants کو کوڈ کے ایک الگ چھوٹے ٹکڑے میں سنبھالا جاتا ہے اور مستقبل کی ایپلی کیشنز میں جامد پتوں کے ذریعے دستیاب ہوتا ہے۔ متغیرات ایک خاص سائز کے پوائنٹرز کی ایک صف ہیں، اس کے خلیوں تک رسائی انڈیکس کے ذریعہ کی جاتی ہے - یعنی جامد پتہ. متغیرات کو اسٹیک کے اوپری حصے تک پہنچایا جا سکتا ہے یا وہاں سے پڑھا جا سکتا ہے۔ اصل میں، کیونکہ اگرچہ ہمارے متغیرات بنیادی طور پر VM میموری میں اقدار کی طرف پوائنٹرز کو ذخیرہ کرتے ہیں، لیکن زبان پر مضمر پوائنٹرز کے ساتھ کام کرنے کا غلبہ ہوتا ہے۔

کوڑا اکٹھا کرنے والا

میرے VM میں یہ نیم خودکار ہے۔ وہ. ڈویلپر خود فیصلہ کرتا ہے کہ کب کچرا اٹھانے والے کو کال کرنا ہے۔ یہ باقاعدہ پوائنٹر کاؤنٹر کا استعمال کرتے ہوئے کام نہیں کرتا، جیسا کہ Python، Perl، Ruby، Lua وغیرہ میں ہے۔ اسے مارکر سسٹم کے ذریعے لاگو کیا جاتا ہے۔ وہ. جب ایک متغیر کو ایک عارضی قدر تفویض کرنے کا ارادہ کیا جاتا ہے، تو اس قدر کی طرف ایک پوائنٹر کو کوڑا اٹھانے والے کے اسٹیک میں شامل کیا جاتا ہے۔ مستقبل میں، کلکٹر تیزی سے پوائنٹرز کی پہلے سے تیار کردہ فہرست سے گزرتا ہے۔

ہینڈل کرنے کی کوشش/پکڑنا/آخر میں بلاکس

کسی بھی جدید زبان کی طرح، استثنیٰ ہینڈلنگ ایک اہم جز ہے۔ VM کور کو ٹرائی..کیچ بلاک میں لپیٹ دیا گیا ہے، جو اسٹیک پر اس کے بارے میں کچھ معلومات کو دھکیل کر ایک استثناء کو پکڑنے کے بعد کوڈ پر عمل درآمد پر واپس آ سکتا ہے۔ ایپلیکیشن کوڈ میں، آپ کوڈ کے ٹرائی/کیچ/آخر میں بلاکس کی وضاحت کر سکتے ہیں، کیچ (استثنیٰ ہینڈلر) اور آخر میں/اختتام (بلاک کا اختتام) پر انٹری پوائنٹس کی وضاحت کر سکتے ہیں۔

ملٹی تھریڈنگ

یہ VM سطح پر تعاون یافتہ ہے۔ یہ آسان اور استعمال میں آسان ہے۔ یہ بغیر کسی مداخلت کے نظام کے کام کرتا ہے، اس لیے کوڈ کو بالترتیب کئی دھاگوں میں کئی گنا تیزی سے عمل میں لایا جانا چاہیے۔

VMs کے لیے بیرونی لائبریریاں

اس کے بغیر کوئی راستہ نہیں ہے۔ VM درآمدات کی حمایت کرتا ہے، جیسا کہ اسے دوسری زبانوں میں لاگو کیا جاتا ہے۔ آپ کوڈ کا کچھ حصہ Mash میں اور کوڈ کا کچھ حصہ مقامی زبانوں میں لکھ سکتے ہیں، پھر انہیں ایک میں جوڑ سکتے ہیں۔

VMs کے لیے ہائی لیول میش لینگویج سے بائٹ کوڈ تک مترجم

انٹرمیڈیٹ زبان

ایک پیچیدہ زبان سے VM کوڈ میں مترجم کو تیزی سے لکھنے کے لیے، میں نے پہلے ایک درمیانی زبان تیار کی۔ نتیجہ ایک جمع کرنے والے جیسا خوفناک تماشا تھا جس پر غور کرنے کا یہاں کوئی خاص فائدہ نہیں۔ میں صرف اتنا کہوں گا کہ اس سطح پر مترجم زیادہ تر مستقل اور متغیرات پر کارروائی کرتا ہے، ان کے جامد پتوں اور داخلی مقامات کے پتے کا حساب لگاتا ہے۔

مترجم فن تعمیر

میں نے نفاذ کے لیے بہترین فن تعمیر کا انتخاب نہیں کیا۔ مترجم کوڈ ٹری نہیں بناتا، جیسا کہ دوسرے مترجم کرتے ہیں۔ وہ ساخت کے آغاز کو دیکھتا ہے۔ وہ. اگر پارس کیے جانے والے کوڈ کا ٹکڑا "while :" کی طرح لگتا ہے، تو یہ ظاہر ہے کہ یہ تھوڑی دیر کے لوپ کی تعمیر ہے اور اس پر ایک while loop construct کے طور پر کارروائی کرنے کی ضرورت ہے۔ ایک پیچیدہ سوئچ کیس کی طرح کچھ۔

اس تعمیراتی حل کی بدولت مترجم بہت تیز نہیں نکلا۔ تاہم، اس کی ترمیم کی آسانی نمایاں طور پر بڑھ گئی ہے. میں نے ضروری ڈھانچے کو اپنی کافی کے ٹھنڈا ہونے سے زیادہ تیزی سے شامل کیا۔ مکمل OOP سپورٹ ایک ہفتے سے بھی کم عرصے میں نافذ کر دی گئی۔

کوڈ کی اصلاح

یہاں، بلاشبہ، اس کو بہتر طور پر نافذ کیا جا سکتا تھا (اور نافذ کیا جائے گا، لیکن بعد میں، جیسے ہی کوئی اس کے ارد گرد آتا ہے). ابھی تک، اصلاح کار صرف یہ جانتا ہے کہ اسمبلی سے غیر استعمال شدہ کوڈ، مستقل اور درآمدات کو کیسے کاٹنا ہے۔ اس کے علاوہ، ایک ہی قدر کے ساتھ کئی مستقل کو ایک سے بدل دیا جاتا ہے۔ بس۔

ماش زبان

زبان کا بنیادی تصور

بنیادی خیال سب سے زیادہ فعال اور آسان زبان کو تیار کرنا تھا۔ مجھے لگتا ہے کہ ترقی اپنے کام کو ایک دھماکے کے ساتھ مقابلہ کرتی ہے۔

کوڈ بلاکس، طریقہ کار اور افعال

زبان میں تمام تعمیرات بڑی آنت سے کھولی جاتی ہیں۔ : اور آپریٹر کے ذریعہ بند ہیں۔ آخر.

طریقہ کار اور افعال کو بالترتیب proc اور func قرار دیا جاتا ہے۔ دلائل قوسین میں درج ہیں۔ سب کچھ دوسری زبانوں کی طرح ہے۔

آپریٹر واپسی آپ کسی فنکشن، آپریٹر سے کوئی ویلیو واپس کر سکتے ہیں۔ توڑ آپ کو طریقہ کار/فنکشن سے باہر نکلنے کی اجازت دیتا ہے (اگر یہ لوپس سے باہر ہے)۔

نمونہ کوڈ:

...

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

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

تائید شدہ ڈیزائن

  • لوپس: for..end، جبکہ..end، جب تک..end
  • شرائط: اگر...[اور...]اختتام، سوئچ کریں...[کیس..اینڈ...
  • طریقے: proc ():... end, func ():... end
  • لیبل اور جائیں: :، jump
  • اینوم شماریات اور مستقل صفیں۔

متغیرات۔

مترجم خود بخود ان کا تعین کر سکتا ہے، یا اگر ڈویلپر ان کی وضاحت کرنے سے پہلے 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

آؤٹ پٹ: سچ، سچ.

اسائنمنٹ آپریٹرز اور واضح پوائنٹرز کے بارے میں

?= آپریٹر کا استعمال ایک متغیر کو میموری میں کسی قدر کے لیے پوائنٹر تفویض کرنے کے لیے کیا جاتا ہے۔
= آپریٹر متغیر سے پوائنٹر کا استعمال کرتے ہوئے میموری میں قدر تبدیل کرتا ہے۔
اور اب تھوڑا سا واضح اشارے کے بارے میں۔ میں نے انہیں زبان میں شامل کیا تاکہ وہ موجود ہوں۔
@ — متغیر کی طرف ایک واضح پوائنٹر لیں۔
? — پوائنٹر کے ذریعے متغیر حاصل کریں۔
@= — ایک واضح پوائنٹر کے ذریعے متغیر کو قدر تفویض کریں۔

نمونہ کوڈ:

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۔

کوشش کریں...

نمونہ کوڈ:

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 کمپائلر نہیں ہے، لہذا کارکردگی کے لحاظ سے یہ فی الحال صرف Python کے ساتھ مسابقتی ہے۔ مجھے امید ہے کہ میں GraalVM یا LLVM کی بنیاد پر JIT کی تالیف کو نافذ کرنے کے قابل ہو جاؤں گا۔

ذخیرہ

آپ پیشرفت کے ساتھ کھیل سکتے ہیں اور خود پروجیکٹ کی پیروی کرسکتے ہیں۔

سائٹ
GitHub پر ذخیرہ

اگر آپ نے پڑھا تو آخر تک پڑھنے کا شکریہ۔

ماخذ: www.habr.com

نیا تبصرہ شامل کریں