Mash, die Grundlagen der Sprache

Bild

Vorwort


Diese Sprache wurde von mir zu Bildungszwecken entwickelt. Ich halte es (im Moment) nicht für eine perfekt entwickelte Sprache, aber vielleicht wird es in Zukunft in der Lage sein, mit Wettbewerbern zu konkurrieren.

Wenn Sie es selbst in Aktion ausprobieren möchten, laden Sie das Projekt- Repository herunter. Dort finden Sie die zusammengestellte Version des Projekts oder können sie selbst für Ihr Betriebssystem zusammenstellen.

Dieser Artikel beschreibt ein kleines Projekthandbuch und berücksichtigt die Syntax der Sprache.

Variablen und implizite Zeiger


In Mash speichert jede Variable einen Zeiger auf ein Objekt im Speicher. Beim Übertragen von Variablen auf Methoden, beim Erhalten eines Ergebnisses oder bei einfachen Manipulationen mit diesen wird mit Objekten im Speicher unter Verwendung von Zeigern auf diese gearbeitet.

Das heißt, Im folgenden Code wird ein Array als Zeiger auf ein bereits zuvor erstelltes Objekt an die p (arr) -Methode übergeben.

proc p(arr): ... end proc main(): arr ?= [1, 2, 3, 4, 5] p(arr) end 

Das Vorhandensein expliziter und impliziter Zeiger in der Sprache verleiht ihr meiner Meinung nach zusätzliche Flexibilität und Funktionalität, obwohl sie in einigen Fällen zur Erzeugung von Fehlern beiträgt.

Temporäre Variablen und Garbage Collector


Im Gegensatz zu ähnlichen Programmiersprachen verfügt Mash über einen halbautomatischen Garbage Collector, der auf dem Mechanismus von Zeitwertbezeichnungen basiert, anstatt Zeiger zu zählen.

Das heißt, Der Entwickler entscheidet selbst, wann der Speicher von Müll gelöscht werden soll, und kann dies in bestimmten Fällen auch manuell tun.

Die Garbage Collection wird mit gc () aufgerufen und gibt Speicher unter allen temporären Objekten frei.

Viele einfache Aktionen mit Variablen werden von der Erstellung temporärer Objekte im Speicher begleitet.

Der Entwickler kann explizit eine Speicherzuweisung für die weitere Arbeit damit deklarieren, d. H. Deklarieren Sie Variablen für die langfristige Verwendung.

Beispiele zum Erstellen einer temporären Variablen:

 x ?= 10 

Und Variablen, die für den Garbage Collector nicht markiert sind:

 x ?= new(10) var x2 = 20 

Ein Beispiel für die Verwendung von gc ():

 while a > b: doSomething(a, b) gc() end 

Der Speicher kann auch manuell freigegeben werden:

 var a = 10, b = 20, c = 30 ... Free(a, b, c) 

Variable Sichtbarkeitszonen


Variablen in Mash können sowohl lokal als auch global deklariert werden.

Globale Variablen werden zwischen Methoden über die var-Anweisung deklariert. Local-Inside-Methoden in irgendeiner Weise.

Datentypen


In Mash dynamisches Tippen. Es unterstützt die automatische Erkennung / Neudefinition von Datentypen für vorzeichenlose und vorzeichenlose Zahlen, Bruchzahlen und Zeichenfolgen. Darüber hinaus werden von einfachen Datentypen Arrays (einschließlich mehrstufiger), Aufzählungstypen (fast die gleichen wie Arrays), Methoden, ein logischer Datentyp und möglicherweise alles unterstützt.

Codebeispiele:

 x ?= 10 x += 3.14 x *= "3" x /= "2,45" x ?= [1, 2, 3.33, func1(1, 2, 3), "String", ["Enum type", 1, 2, 3], "3,14"] 

Mit Introspection können Sie den Typ der Variablen bestimmen, die Sie benötigen:

 if typeof(x) == TypeInt: ... end 

Arrays & Enums


Seltene Tasks zwingen den Entwickler nicht, das nächste Array im Code zu deklarieren.
Mash unterstützt Arrays, die aus einer beliebigen Anzahl von Ebenen bestehen. + Arrays können so etwas wie Bäume sein, d. H. Die Größe der Unterebenen kann auf einer Unterebene variieren.

Beispiele für Deklarationen von Arrays und Aufzählungen:

 a ?= new[10][20] var b = new[10][20] c ?= [1, [], 3, 3.14, "Test", [1, 2, 3, 4, 5], 7.7, a, b, ["77", func1()]] var d = [1, 2, 3] 

Über den neuen Operator deklarierte Objekte werden für den Garbage Collector nicht markiert.

Arrays werden wie normale Objekte im Speicher durch Aufrufen von Free () freigegeben
Eine solche Arbeit mit Transfers ist sehr praktisch.

Sie können beispielsweise Methoden übergeben oder von ihnen viele Werte einer Variablen zurückgeben:
 func doSomething(a, b, c): return [a+c, b+c] end 

Zuweisungsoperatoren


Es gibt bis zu 3 Zuweisungsoperatoren in Mash.

  • ? =
    Weist einem Zeiger auf ein Objekt eine Variable zu (wenn eine Variable deklariert ist, aber keinen Zeiger auf ein Objekt im Speicher speichert, muss dieser Operator verwendet werden, um ihm einen Wert zuzuweisen).
  • =
    Normale Zuordnung. Weist einem Objekt durch einen Zeiger in einer Variablen den Wert eines anderen Objekts zu.
  • @ =
    Weist einem Objekt einen Wert durch einen expliziten Zeiger auf dieses Objekt zu (dies wird später erläutert).

Mathematische und logische Operationen


Liste der derzeit unterstützten mathematischen und logischen Operationen:

  • + , - , * , /
    Keine Kommentare erforderlich.
  • \.
    Teilung vollständig.
  • %.
    Der Rest der Division.
  • &
    Logisches "und".
  • |
    Logisches "oder".
  • ^
    Logisch "exklusiv oder".
  • ~
    Logisches "nicht".
  • ++ , -
    Inkrementieren und Dekrementieren.
  • << , >>
    Bitweise Verschiebung nach links und rechts.
  • == , <> , > = , <=
    Logische Vergleichsoperatoren.
  • in
    Überprüft, ob ein Objekt zu einer Aufzählung oder zu einem Array gehört.
    Ein Beispiel:
     if Flag in [1, 3, 5, 8]: ... 

Explizite Zeiger


Es scheint, warum werden sie benötigt, wenn es keine expliziten Hinweise gibt? Überprüfen Sie beispielsweise, ob die Variablen A und B Zeiger auf dasselbe Objekt im Speicher speichern.

  • @ - Holen Sie sich einen Zeiger auf ein Objekt und setzen Sie es in eine Variable, wie ein Objekt.
  • ? - Holen Sie sich das Objekt per Zeiger vom Objekt in der Variablen.
    Ein Beispiel:
     a ?= ?b 

Prozeduren und Funktionen


Ich entschied mich für die sprachliche Trennung von Methoden zur Rückgabe von Werten in Prozeduren und Funktionen (wie in Pascal).

Methodendeklarationen erfolgen wie folgt:

 proc SayHello(arg1, arg2, argN): println("Hello, ", arg1, arg2, argN) end func SummIt(a, b): return a + b end 

Sprachkonstruktionen


Ein Beispiel if..else..end Konstrukt.

 if <>: ... else: ... end 

Für Schleife.

 for([]; <>; [  ]): ... end 

Während. Die Bedingung wird vor der Iteration überprüft.

 whilst <>: ... end 

Während. Eine Schleife, die sich dadurch unterscheidet, dass die Bedingung nach der Iteration überprüft wird.

 until <>: ... end 

switch..case..end..else..end ... ist eine bekannte Konstruktion zum Erstellen logischer Zweige.

 switch <>: case < 1>: ... end case < 2>: ... end else: ... end 

Klassen und Elemente der OOP-Sprache


Mash implementiert Unterstützung für Klassen, Vererbung, dynamische Selbstbeobachtung und Reflexion sowie Polymorphismus. Das heißt, Ein Standardsatz von Skriptsprachen wird unterstützt.

Betrachten Sie eine einfache Klassendeklaration:

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

Eine Klassendeklaration enthält keine Implementierungen der darin deklarierten Methoden.
Der Konstruktor der Klasse ist die Create-Methode. Als Destruktor - Frei.

Nachdem die Klasse deklariert wurde, können Sie die Implementierung ihrer Methoden beschreiben:

 proc MyClass::Create(a, b): $a ?= new(a) $b ?= new(b) end proc MyClass::Free(): Free($a, $b, $) end func MyClass::SomeFunction(x): return ($a + $b) / x end 

Möglicherweise bemerken Sie das $ -Symbol an einigen Stellen im Code - mit diesem Symbol habe ich einfach das lange this-> gekürzt. Das heißt, Code:

 return ($a + $b) / x ... Free($a, $b, $) 

Entspricht diesem Code:
 return (this->a + this->b) / x ... Free(this->a, this->b, this) 

Dieser enthält einen Zeiger auf eine Instanz der Klasse, für die die Methode dieser Klasse aufgerufen wird.

Um die Funktionalität einer Klasse zu erben, müssen Sie die Deklaration einer neuen Klasse folgendermaßen beschreiben:

 class MySecondClass(MyClass): func SomeFunction end func MySecondClass::SomeFunction(x): return ($a - $b) / x end 

MySecondClass - hat einen Konstruktor und einen Destruktor von seinem Vorfahren + SomeFunction-Funktion, die die Vorfahrenklasse hat, wird von einer Funktion aus einer neuen Klasse überschrieben.

Zum Erstellen von Klasseninstanzen ist der neue Operator vorhanden.

Codebeispiele:

 a ?= new MyClass //     

 b ?= new MyClass(10, 20) //         

Der Typ einer Instanz einer Klasse kann beim Erstellen dieser Instanz bestimmt werden. Dementsprechend fehlt in der Sprache die Typkonvertierung.

Mit Introspection können Sie den Typ der Klasseninstanz bestimmen, Codebeispiel:

 x ?= new MyClass(10, 20) ... if x->type == MyClass: // -... end 

Manchmal müssen Sie sich einer Klassenfunktion zuwenden und diese mit einer neuen überschreiben. Codebeispiel:

 func class::NewSomeFunction(x): return $x * $y * x end ... x ?= new MyClass(10, 20) x->SomeFunction ?= class::NewSomeFunction x->SomeFunction(33) // NewSomeFunction,     . 

Fazit


In diesem Artikel habe ich versucht, mögliche Interessenten in meine Kreation einzuführen.

Danke fürs Lesen. Warten auf Kommentare.

Source: https://habr.com/ru/post/de437632/


All Articles