Chaque programmeur a un rêve - créer son propre langage de programmation. Le meilleur et le plus pratique, bien sûr - pas comme ceux existants. Pour moi personnellement, l'idée fixe était de créer un langage dans lequel il n'y aurait absolument pas de passe-partout, qui serait aussi court que possible, mais extrêmement éloquent. Depuis deux ans, j'essaye d'obtenir le résultat souhaité, mais partout où je commence, au final, après avoir coupé tout ce qui est superflu, j'ai toujours eu Lisp. Et puis une pensée ingénieuse m'est venue à l'esprit: prendre Lisp et l'améliorer conformément à mes idées. En l'honneur de la première chose qui a attiré mon attention, le projet a été nommé Sova.
Pour que la langue prête à l'emploi fonctionne sur le serveur, sur le Web et sur les plates-formes mobiles, j'ai décidé de la compiler en Javascript, qui, à mon avis, n'est pas une blague l'une des langues les mieux conçues de notre temps et, plus important encore, dispose d'un écosystème npm puissant, Node.js, React et React Native.
Et avant de commencer notre voyage, afin de susciter immédiatement un intérêt pour la suite de la lecture de l'article, voici un exemple de dossier d'application Express sur Sova:
=-> './database' database =-> 'express' express = application express () application.get '/' -> (request response) (response.sendStatus 200) application.get '/user/:id' -> (request response) (response.send (database.getUserById request.params.id)) application.listen 8080 -> () (console.log 'Application is listening on port 8080')
Eh bien, commençons ...
Étape 1: extraire les parenthèses de Lisp à l'aide de l'indentation Python

Bien que cette bande dessinée me fasse sourire à chaque fois que je la regarde, je suis totalement en désaccord avec sa déclaration principale. Les supports ne sont pas élégants; les supports sont passe-partout.
Par conséquent, la première chose dans mon merveilleux langage, j'ai décidé de me débarrasser des crochets. La meilleure solution était l'indentation pertinente, tout comme en Python. Prenons, par exemple, un tel morceau de code lisp:
(* 2 (+ 1 2) (- 4 (/ 2 1)))
Bien sûr, cette expression peut être répartie sur différentes lignes, mais cela ne nous libère pas du clown des yeux qui se bouchent.
(* 2 (+ 1 2) (- 4 (/ 2 1)))
Voyons maintenant avec quelle élégance et aération il est possible d'écrire la même expression dans Sova à l'aide d'une indentation importante:
* 2 + 1 2 - 4 (/ 2 1)
Autrement dit, dans Sova, l'expression a (bc) (d (ef))
équivalente à l'expression:
a bc d ef
Étape 2: rendre la langue concise
Ce que je n'aimais pas dans la plupart des langages de programmation était le colmatage de la syntaxe sans rien de significatif, mais un passe-partout occupant une place à l'écran - des mots-clés supplémentaires, des signes de ponctuation sans signification et bien d'autres. Même dans le langage courant, au lieu de caractères simples et compréhensibles, les mots sont souvent utilisés pour désigner des opérations simples, comme le même defn
.
Déclaration des constantes
Prenons par exemple la déclaration d'une constante en Javascript:
const a = 1
Sova est un langage extrêmement fonctionnel et toutes les variables y sont immuables, vous n'avez donc pas besoin de spécifier un mot-clé supplémentaire const, mais tout est écrit simplement:
= a 1
Les fonctions
L'élément central de tout langage est la fonction. Ils sont si minimalistes dans Sova:
= addOne -> number + number 1 = doubleAndAddOne -> number = doubled (* number 2) addOne doubled console.log (doubleAndAddOne 2)
Comme dans tout langage fonctionnel, la dernière expression dans le corps de la fonction est renvoyable. Autrement dit, le code ci-dessus en JavaScript compilé ressemblera à:
const addOne = number => { return number + 1 } const doubleAndAddOne = number => { const doubled = number * 2 return addOne(doubled) } console.log(doubleAndAddOne(2))
Comparaisons et conditions
Une expression conditionnelle dans Sova peut avoir deux ou un argument.
Voici des exemples de conditions qui ont deux arguments:
console.log ? true 1 0 console.log ? (> 2 1) 'Greater' 'Less' console.log ? (> 2 1) ? (> 1 2) 'x' 'y' 'z'
Et ici, par exemple, dans la fonction checkNumber, nous retournons des valeurs par condition:
= checkNumber -> number ? (=== number 1) (<- 'One') ? (=== number 2) (<- 'Two') ? (<= number 9) (<- 'From three to nine') 'Ten or more' console.log (checkNumber 1) console.log (checkNumber 4) console.log (checkNumber 11)
Dans JavaScipt compilé, cela ressemble à:
const checkNumber = number => { if (number === 1) return 'One' if (number === 2) return 'Two' if (number <= 9) return 'From three to nine' return 'Ten or more' } console.log(checkNumber(1)) console.log(checkNumber(4)) console.log(checkNumber(11))
Les collections
Array
La collection principale de n'importe quelle langue est un tableau. Voici à quoi ressemble la déclaration et la déconstruction du tableau dans Sova:
= list | 1 2 3 4 console.log list console.log list.map (-> x (+ x 1)) = (| first second) list console.log first console.log second
En JavaScript compilé, cela ressemblera à:
const list = [1, 2, 3, 4] console.log(list) console.log(list.map(x => x + 1)) const [first, second] = list console.log(first) console.log(second)
Objet
La deuxième collection la plus importante est la table de hachage. À Sova, l'annonce et la déconstruction de la carte ressemblent à ceci:
= map : a 1 b 2 c : d 3 e 4 f 'Hello' console.log map = (: a (c (: de))) map console.log a console.log d console.log e
En JavaScript compilé, cela ressemble à ceci:
const map = { a: 1, b: 2, c: { d: 3, e: 4 }, f: 'Hello' } console.log(map) const { a, c: { d, e }} = map console.log(a) console.log(d) console.log(e)
Si nous voulons appeler une méthode sur un objet, il y a deux façons de le faire. Nous pouvons l'appeler comme object.method parameter1 parameter2
ou comme .method object parameter1 parameter2
. La deuxième méthode nous permet de créer une chaîne d'appels de méthode.
Modules d'importation et d'exportation
Importer
Vous pouvez importer des modules dans le code Sova à partir d'autres fichiers .sv
ainsi que des fichiers .js
. Par exemple, dans cet exemple, deux modules sont importés - data/index.js
et handler/index.sv
:
=-> './data' (: greeting name) =-> './handler' handle handle greeting name
En JavaScript compilé, cela ressemble à ceci:
const { greeting, name } = require('./data') const handle = require('./handler') handle(greeting, name)
L'importation de modules JavaScript et Sova permet d'intégrer légèrement Sova dans un projet Javascript existant.
Exporter
Dans cet exemple, la fonction est exportée à partir du module:
<-= -> (greeting name) console.log greeting console.log name
En JavaScript compilé, cela ressemble à ceci:
module.exports = (greeting, name) => { console.log(greeting) console.log(name) }
Exemples d'utilisation
Pour voir toute la beauté, la légèreté et la concision de Sova, vous devez regarder un programme plus ou moins grand. Par exemple, voici un programme qui calcule l'âge moyen des personnes et trouve le nom de la personne dont l'âge est le plus proche de l'âge moyen.
=-> 'lodash' _ = people | : (name 'Alice') (age 24) : (name 'Bob') (age 15) : (name 'Chris') (age 46) : (name 'Daniel') (age 35) : (name 'Elisabeth') (age 29) : (name 'Fred') (age 52) = averageAge / .reduce (.map people (-> man man.age)) -> (xy) (+ xy) 0 .length people = manWithClosestToAverageAge _.minBy .map people (-> man (: (name man.name) (distance (Math.abs (- averageAge man.age))))) 'distance' console.log averageAge console.log manWithClosestToAverageAge.name
Du fait que le langage est compilé en JavaScript, le développement pour n'importe quelle plateforme devient possible. Par exemple, voici un petit exemple d'application React pour les navigateurs Web:
=-> 'react' React =-> 'react-dom' ReactDOM =-> './styles' styles = (: createElement:e) React = App -> ((: name)) e 'div' (: (style styles.container)) e 'div' (: (style styles.hello)) 'Hello' e 'div' (: (style styles.name)) name ReactDOM.render (e App (: (name 'John'))) (document.getElementById 'root')
Le référentiel contient également des exemples d'applications Express Server et React Native pour les plates-formes mobiles.
Conclusion
Ainsi, Sova intègre le meilleur de plusieurs autres langues:
- la simplicité et la puissance de Lisp
- Python indentation clean
- runtime et écosystème JavaScript
Le code du compilateur avec des exemples d'utilisation du langage se trouve ici https://github.com/sergeyshpadyrev/sova . Je serai heureux de voir les étoiles sur le référentiel de tous ceux qui ont aimé le concept de la langue et qui aimeraient continuer à travailler dessus. Mais je vous avertis immédiatement que pour le moment, ce n'est qu'une preuve de concept, et même jouer avec la langue en raison du manque de documentation et de certaines fonctionnalités est extrêmement difficile. Par exemple, le langage n'a pas encore de gestion des exceptions, de classes et d'autres choses nécessaires. Et il est peu probable que l'exécution de Windows réussisse.
Dans les étapes suivantes, je prévois de compléter et de stabiliser la syntaxe, de réécrire l'analyseur, d'écrire des tests pour l'analyseur et le traducteur, d'écrire de la documentation. En attendant, merci de votre attention et à bientôt.