Mash, les bases de la langue

image

Préface


Cette langue a Ă©tĂ© dĂ©veloppĂ©e par moi Ă  des fins Ă©ducatives. Je ne le considĂšre pas (pour le moment) comme un langage parfaitement dĂ©veloppĂ©, mais peut-ĂȘtre qu'Ă  l'avenir il pourra rivaliser avec ses concurrents.

Si vous souhaitez l'essayer vous-mĂȘme en action - tĂ©lĂ©chargez le rĂ©fĂ©rentiel du projet, vous y trouverez la version assemblĂ©e du projet ou l'assemblez vous-mĂȘme, pour votre systĂšme d'exploitation.

Cet article décrira un petit manuel de projet et considérera la syntaxe du langage.

Variables et pointeurs implicites


Dans Mash, chaque variable stocke un pointeur sur un objet en mémoire. Lors du transfert de variables vers des méthodes, de l'obtention d'un résultat ou de simples manipulations avec celles-ci, le travail est effectué avec des objets en mémoire par des pointeurs vers eux.

C'est-à-dire dans le code suivant, un tableau sera transmis à la méthode p (arr) comme pointeur vers un objet déjà créé précédemment.

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

La présence de pointeurs dans le langage, à la fois explicites et implicites, à mon avis, lui donne une flexibilité et des fonctionnalités supplémentaires, bien que dans certains cas, il contribue à la génération d'erreurs.

Variables temporaires et garbage collector


Contrairement aux langages de programmation similaires, Mash dispose d'un récupérateur de déchets semi-automatique basé sur le mécanisme des étiquettes de valeur temporelle, plutÎt que de compter les pointeurs.

C'est-Ă -dire le dĂ©veloppeur dĂ©cide lui-mĂȘme quand vider la mĂ©moire des ordures et peut Ă©galement le faire manuellement, dans certains cas.

Le garbage collection est appelé à l'aide de gc () et libÚre de la mémoire sous tous les objets temporaires.

De nombreuses actions simples avec des variables s'accompagnent de la création d'objets temporaires en mémoire.

Le développeur peut déclarer explicitement une allocation de mémoire pour continuer à travailler avec elle, c'est-à-dire déclarer des variables pour une utilisation à long terme.

Exemples de création d'une variable temporaire:

 x ?= 10 

Et les variables non marquées pour le garbage collector:

 x ?= new(10) var x2 = 20 

Un exemple d'utilisation de gc ():

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

La mĂ©moire peut Ă©galement ĂȘtre libĂ©rĂ©e manuellement:

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

Zones de visibilité variable


Les variables dans Mash peuvent ĂȘtre dĂ©clarĂ©es localement et globalement.

Les variables globales sont déclarées entre les méthodes, via l'instruction var. Local - méthodes internes en aucune façon.

Types de données


Dans Mash, la frappe dynamique. DĂ©tectez / remplacez automatiquement les types de donnĂ©es pour les nombres non signĂ©s et signĂ©s, les nombres fractionnaires et les chaĂźnes. De plus, Ă  partir de types de donnĂ©es simples, les tableaux (y compris ceux Ă  plusieurs niveaux), les types d'Ă©numĂ©ration (presque les mĂȘmes que les tableaux), les mĂ©thodes, un type de donnĂ©es logique et peut-ĂȘtre tout est pris en charge.

Exemples de code:

 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"] 

L'introspection vous permet de déterminer le type de variable dont vous avez besoin:

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

Tableaux et énumérations


Les tùches rares n'obligent pas le développeur à déclarer le tableau suivant dans le code.
Mash prend en charge les tableaux composĂ©s d'un nombre arbitraire de niveaux, + les tableaux peuvent ĂȘtre quelque chose comme des arbres, c'est-Ă -dire les tailles des sous-niveaux peuvent varier sur un sous-niveau.

Exemples de déclarations de tableaux et d'énumérations:

 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] 

Les objets déclarés via le nouvel opérateur ne sont pas marqués pour le garbage collector.

Les tableaux, comme les objets normaux en mémoire, sont libérés en appelant Free ()
Un tel travail avec des transferts est assez pratique.

Par exemple, vous pouvez passer à des méthodes ou en renvoyer de nombreuses valeurs d'une variable:
 func doSomething(a, b, c): return [a+c, b+c] end 

Opérateurs d'affectation


Il existe jusqu'à 3 opérateurs d'affectation dans Mash.

  • ? =
    Attribue une variable Ă  un pointeur sur un objet (si une variable est dĂ©clarĂ©e mais ne stocke pas de pointeur sur un objet en mĂ©moire, cet opĂ©rateur doit ĂȘtre utilisĂ© pour lui attribuer une valeur).
  • =
    Affectation normale. Attribue Ă  un objet par pointeur dans une variable la valeur d'un autre objet.
  • @ =
    Attribue une valeur à un objet par un pointeur explicite sur cet objet (cela sera discuté plus tard).

Opérations mathématiques et logiques


Liste des opérations mathématiques et logiques actuellement prises en charge:

  • + , - , * , /
    Aucun commentaire nécessaire.
  • \
    Division complĂštement.
  • %
    Le reste de la division.
  • &
    Logique "et".
  • |
    Logique "ou".
  • ^
    Logique «exclusif ou».
  • ~
    Logique "non".
  • ++ , -
    Incrémenter et décrémenter.
  • << , >>
    Décalages à gauche et à droite au niveau du bit.
  • == , <> , > = , <=
    Opérateurs de comparaison logique.
  • dans
    Vérifie si un objet appartient à une énumération ou à un tableau.
    Un exemple:
     if Flag in [1, 3, 5, 8]: ... 

Pointeurs explicites


Il semblerait, pourquoi sont-ils nĂ©cessaires s'il n'y a pas de pointeurs explicites? Par exemple, pour vĂ©rifier si les variables A et B stockent des pointeurs vers le mĂȘme objet en mĂ©moire.

  • @ - rĂ©cupĂšre un pointeur sur un objet et le place dans une variable, comme un objet.
  • ? - rĂ©cupĂ©rer l'objet par pointeur depuis l'objet dans la variable.
    Un exemple:
     a ?= ?b 

Procédures et fonctions


J'ai décidé de faire la séparation du langage des méthodes de retour des valeurs dans les procédures et les fonctions (comme en Pascal).

Les déclarations de méthode sont faites comme les exemples suivants:

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

Constructions linguistiques


Un exemple de construction if..else..end.

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

Pour boucle.

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

Alors. La condition est vérifiée avant itération.

 whilst <>: ... end 

Tandis que. Une boucle qui diffÚre de while en ce que la condition est vérifiée aprÚs l'itération.

 until <>: ... end 

switch..case..end..else..end ... est une construction familiÚre pour créer des branches logiques.

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

Classes et éléments du langage OOP


Mash implémente le support des classes, l'héritage, l'introspection et la réflexion dynamiques, le polymorphisme. C'est-à-dire Un ensemble standard de langages de script est pris en charge.

Considérons une simple déclaration de classe:

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

Une déclaration de classe ne contient pas d'implémentations des méthodes qui y sont déclarées.
Le constructeur de la classe est la méthode Create. En tant que destructeur - gratuit.

Une fois la classe déclarée, vous pouvez décrire l'implémentation de ses méthodes:

 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 

Vous remarquerez peut-ĂȘtre le symbole $ Ă  certains endroits du code - avec ce symbole, j'ai simplement raccourci le long this->. C'est-Ă -dire code:

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

Équivalent à ce code:
 return (this->a + this->b) / x ... Free(this->a, this->b, this) 

Il contient un pointeur sur une instance de la classe pour le compte de laquelle la méthode de cette classe est appelée.

Afin d'hériter des fonctionnalités d'une classe, vous devez décrire la déclaration d'une nouvelle classe de cette maniÚre:

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

MySecondClass - aura un constructeur et un destructeur de sa fonction ancĂȘtre + SomeFunction, que possĂšde la classe ancĂȘtre, est Ă©crasĂ© par une fonction d'une nouvelle classe.

Pour créer des instances de classe, le nouvel opérateur existe.

Exemples de code:

 a ?= new MyClass //     

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

Le type d'une instance d'une classe peut ĂȘtre dĂ©terminĂ© lors de la crĂ©ation de cette instance; en consĂ©quence, la conversion de type est absente dans le langage.

L'introspection vous permet de déterminer le type d'instance de classe, exemple de code:

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

Parfois, vous devez vous tourner vers une fonction de classe et la remplacer par une nouvelle. Exemple de code:

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

Conclusion


Dans cet article, j'ai essayé de présenter à ma création d'éventuelles personnes intéressées.

Merci d'avoir lu. En attente de commentaires.

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


All Articles