Umka: nouveau langage de script typé statiquement


La première version du langage de script embarquable typé Umka que j'ai développé vient de sortir . Il vise à combiner la flexibilité des langages de script familiers avec la protection contre les erreurs de type au stade de la compilation en bytecode. L'idée principale du langage - explicite vaut mieux qu'implicite - est empruntée au "Zen de Python", cependant, il devrait acquérir ici un sens légèrement différent et plus évident.

Quelles que soient les impressions privées et subjectives qui m'ont poussé à entreprendre le développement de la langue, j'espère que le plan n'était pas naïf. Sous la coupe, je parlerai brièvement des capacités de la langue et des motifs de sa création.

Les motifs


La première vertu du typage dynamique est généralement appelée raccourcissement du cycle de développement / débogage et gain de temps du programmeur. Au risque de déplaire au public, je dois admettre que ma propre expérience ne le confirme nullement. Chaque fois après une correction mineure de mon script de formation de réseau de neurones en Python, je dois attendre que Python, NumPy, PyTorch se chargent, lire un grand tableau de données à partir de fichiers, le transférer vers le GPU, commencer le traitement - et seulement ensuite découvrir que PyTorch s'attendait à un tenseur de taille (1, 1 , m, n, 3) au lieu de (1, m, n, 3).

J'admets volontiers que beaucoup de gens préfèrent les langues typées dynamiquement pour leurs raisons personnelles. Il est même possible que la tendance ou l'hostilité au typage dynamique soit un phénomène du même ordre que l'attitude envers les olives et le jus de tomate. Les tentatives d'une étude objective de cette question conduisent apparemment à des résultats peu concluants .

Dans le même temps, la popularité de TypeScript, l'introduction d'annotations de type en Python, les discussions animées sur Reddit et Habré nous font penser que l'identification réelle des langages de script avec des langages typés dynamiquement n'est pas du tout un dogme, mais une coïncidence, et un langage de script typé statiquement a parfaitement le droit d'exister.

Il y avait donc une langue nommée d'après un chat nommé d'après un ours.

Langue


La syntaxe de la langue dans son ensemble a été inspirée par Go. Des exemples de constructions de syntaxe peuvent être trouvés sur la page du projet . Lors de la déclaration de variables, une notation abrégée avec inférence de type peut être utilisée. Il convient de noter l'écart par rapport aux règles Go dans la syntaxe des pointeurs. Les créateurs de Go se sont plaints que suivre littéralement l'exemple C s'est avéré être une complication inutile de la syntaxe ici et qu'il serait plus raisonnable d'introduire un opérateur de déréférencement postfix comme Pascal à la p^place *p. C'est exactement ce qu'a fait Umka.

TraducteurUmka se compile en bytecode, qui est ensuite exécuté par la machine virtuelle de pile. Toutes les vérifications de type sont effectuées au stade de la compilation. Les données de la pile ne contiennent plus aucune information de type. Le traducteur se présente sous la forme d'une bibliothèque dynamique avec sa propre API et un petit "wrapper" - le fichier exécutable. Le code source est écrit en C99 et porté sur différentes plateformes. Les versions pour le processeur x86-64 (Windows et Linux) sont maintenant disponibles .

Gestion de la mémoirefait jusqu'à présent sur la base de compteurs de référence. Si le langage suscite de l'intérêt et que des tentatives sont faites pour l'utiliser, il sera judicieux d'organiser un garbage collector plus avancé. Le langage prend en charge les types de données composites classiques (tableaux et structures) placés sur la pile et les tableaux dynamiques placés sur le tas. Tout tableau ou structure classique peut également être placé sur le tas avec un appel explicite new().

Le polymorphisme est fourni par des interfaces de style Go. Il n'y a pas de concepts de classe, d'objet et d'héritage.

MultitâcheIl est basé sur le concept de «fibres» - des flux simplifiés qui s'exécutent dans la même machine virtuelle et se provoquent clairement. En substance, cela est synonyme de coroutines. Étant donné que la logique d'utilisation de ces coroutines s'écarte légèrement de la tradition Go et se rapproche de Lua et Wren, il est logique de donner un exemple de code:

fn childFunc(parent: std.Fiber, buf: ^int) {
    for i := 0; i < 5; i++ {
        std.println("Child : i=" + std.itoa(i) + " buf=" + std.itoa(buf^))
        buf^ = i * 3
        fibercall(parent)
    }
}

fn parentFunc() {
    a := 0
    child := fiberspawn(childFunc, &a)    
    for i := 0; i < 10; i++ {
        std.println("Parent: i=" + std.itoa(i) + " buf=" + std.itoa(a))
        a = i * 7
        if fiberalive(child) {
            fibercall(child)
        }
    }    
    fiberfree(child)
}

Exemples


Comme exemple de base démontrant les capacités du langage, je recommande de regarder un programme de rendu pour les scènes tridimensionnelles basé sur le tracé de rayons inverses. Il s'agit de récursions très utilisées de façon organique, d'interfaces, de tableaux dynamiques; un peu plus artificiel - multitâche.

Un exemple d'incorporation du traducteur Umka dans un projet C est le code source du wrapper exécutable du traducteur lui-même. Il y a aussi un exemple d'extension de langage Umka avec des fonctions externes en C.

image

All Articles