Kafe, un langage de programmation (encore, oui)

Un Java-like, en mieux (je troll mais au moins ça attire des gens)

a marqué ce sujet comme résolu.
Auteur du sujet

Salut à tous ! Cela faisait longtemps que je n’étais pas venu ici dis donc

J’aimerais vous présenter un projet qui me tient à coeur (déjà parce que je commence enfin à avoir quelque chose de potable et ensuite parce que des retours sur le code, je dirais pas non :p) : Kafe. Kafe est un langage de programmation (oui, encore un, parmi plusieurs milliers déjà existants, je vous explique après pourquoi je bosse dessus) fonctionnant sur machine virtuelle (VM), comme Java (d’où mon inspiration), codé en C++ (comme Java m’a-t-on dit). Le but est de faire grosso modo un langage de programmation utilisable comment langage de scripting pour jeux vidéo.

logo-kafe

Logo par Tartiflemme

Alors, pourquoi un n-ieme langage ? Petite liste de réponses :

  1. pour apprendre comment fonctionne une VM dans la pratique, se confronter aux problèmes lors de la conception d’une telle chose (optimisations et tout)

  2. je voulais pouvoir dire "oh la la regardez j’ai fait un langage de programmation" même s’il est nul, c’est toujours sympa sur un portfolio et (je l’ai déjà dit) on apprend beaucoup en faisant des projets (ce point est un peu anecdotique oui, mais c’est souvent comme ça quand je démarre un projet, ça part sur un coup de tête et j’ai envie de le mettre sur mon portfolio)

  3. c’est drôle je trouve :)

  4. pour l’utiliser dans des jeux vidéos en lieu et place de Lua (qui d’après moi manque de classes et de tableaux convenables (comprendre: qui ne commencent pas à 1)) ;)

Avancement

Actuellement, je travaille beaucoup sur la VM (implémentation de byte codes comme ceux de la gestion des listes, des classes…) et le parser, qui doit pouvoir lire du code, le transformer en AST et en faire un bytecode.

Ce qui fonctionne très bien, c’est la VM, le parser n’est pas fonctionnel mais je bosse dessus (grâce à ANTLR je n’ai qu’à visiter l’AST pour le transformer en bytecode).

C’est pas la partie la plus passionnante en effet (l’avancement je veux dire, par contre coder ça c’est trop cool).

Les technologies utilisées

Le projet est en C++ (17) de A à Z, la VM est terminée à quasiment 90% et faite entièrement à la main (pas de LLVM ou quoi). Pour le parser, j’ai opté pour ANTLR (Another Tool for Language Recognition) qui me génère lexer, parser et visistor (plein de trucs assez long à écrire, et sources d’erreurs de façon récurrente quand on les fait mal) à partir d’une grammaire (un fichier décrivant le langage, comment on doit écrire un if, une boucle while, une fonction…). Cela me permet de ne me concentrer que sur la construction du bytecode (si vous voulez des détails techniques : j’hérite d’un visitor qui permet d’explorer de façon récursive un AST généré par le parser, et de là je génère le bytecode).

Côté fonctionnement interne, j’explique des choses plus "poussées" si ça vous intéresse, histoire de pas grossir le pavé et de pas perdre des gens, je vous laisse seulement un lien : https://kafe-lang.github.io/documentation/vm/bytecode.html

Bon sinon, ça ressemble à quoi ?

cls Character
    dyn name
    dyn life

    fun __init__(self)
        self.name = "georges"
        ret

    fun update(self dt)
    # creating and adding attributes on the go
    self.dt = dt
        # we need to tell the compiler the function has ended
        ret
end

dyn player = new Character("John Doe" 120)
dyn mob = new Character("Rabbit" 15)

# comma in arg list is optionnal
fun update(dt component)
    dyn status = 0

    if component == "player" then
        print("updating player")
        player.update(dt)
    elif component == "mob" then
        print("updating mob")
        mod.update(dt)
    else
        print("unknow component : " component)
        status = 1  # an error occured
    end

    ret status

update(0.005 "player")

while player.name == "John Doe" do
    player.name = input("What's your name? ")
end

L’héritage n’est pas encore prévu, mais faisable.

Petite différence sur la création de classes / valeurs simple:

dyn a = 10  # le parser lira 10 et le mettra dans la catégorie Int, donc le visitor en construisant le bytecode déclarera a comme un entier
dyn b = new MonObjet(argument1 argument2)  # la syntaxe n'est pas la même car on défini un objet

Des liens pour la route

Le site "officiel" du projet (je mets officiel entre guillemets parce que je suis pas une organisation donc je ne sais pas trop si la dénomination peut s’appliquer, mais c’est tout de même le seul site avec des informations sur Kafe (un peu logique en soit ahah)) : https://kafe-lang.github.io

Le dépôt Github : https://github.com/Kafe-lang/Kafe

Sur ce, je vous souhaite de passer une agréable journée !

Édité par SuperFola

Python is good | CV | Kafe lang (C++17) et Unamed (C++14/SFML2.4)

+6 -0
Auteur du sujet

Hum, je n’ai jamais entendu ça perso. Je ne pense qu’il y ai de règles à proprement dit, juste des habitudes :)

Par exemple un snippet de Rust :

1
2
3
4
5
6
fn factorial(i: u64) -> u64 {
    match i {
        0 => 1,
        n => n * factorial(n-1)
    }
}

ou encore Haxe

1
2
3
4
5
6
class Fly implements ICreature {
    public var birth:Date;
    public var name:String;

    public function age():Int return Date.now().getFullYear() - birth.getFullYear();
}

ou même Swift :

1
2
3
4
5
6
extension String: SupportsToString {
    func toString() -> String
    {
        return self
    }
}

J’ai pris trois langages tous développés par des entreprises différentes, pas dans le même but, et je trouve (ça reste personnel mais ce genre de chose, la syntaxe d’un langage, c’est inspiré de ressentis personnels (désolé pour la redondance :/)) que ces codes sont lisibles, au même titre qu’un

1
2
3
4
uint64_t factorial(uint64_t n) {
    if (n <= 1) return 1;
    return n * factorial(n - 1);
}

Juste un petit pavé pour expliquer que c’est une question de goût x)

Python is good | CV | Kafe lang (C++17) et Unamed (C++14/SFML2.4)

+0 -0
Auteur du sujet

Après, c’est "formattable" à souhait. Un code tel que celui-ci (pour reprendre celui du post principal) :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
fun update(dt:double, component:str)
-> int

    dyn status = 0
    if component == "player" then
        print("updating player") player.update(dt)
    elif component == "mob" then
        print("updating mob")    mod.update(dt)
    else
        print("unknow component : " component)
        status = 1  # an error occured
    end

ret status

devrait pouvoir être parsé sans problème par ANTLR (pour rappel, c’est ce que j’utilise pour créer mon lexer/parser/visitor).

Python is good | CV | Kafe lang (C++17) et Unamed (C++14/SFML2.4)

+0 -0

Côté architecture, ce n’est pas très élégant de mélanger le parsing et le typage – ça mélange deux aspects différents dans le même code qui devient compliqué, pénible à maintenir, et limite l’évolution du langage. Il vaut mieux avoir une représentation intermédiaire des programmes typés, avec une structure séparée de celle des arbres syntaxiques, où toutes les parties du programme qui en ont besoin contiennent l’information de typage. L’étape de typage est alors une traduction de l’arbre de syntaxe abstraite vers l’arbre typé, et le bytecode est produit à partir de l’arbre typé (et les optimisations travaillent dessus).

+2 -0

Cette réponse a aidé l’auteur du sujet

Dans l’AST tu vois que 10 est un nombre, mais pas que status (dans dyn status = 10) est une variable qui contiendra toujours un nombre (pour cela il faut faire des hypothèses sur ton système de types, et propager des information de l’assignant à l’assigné).

Édité par gasche

+1 -0
Auteur du sujet

Oh je vois !

Je me suis mal exprimé alors. Je compte bien voir que status a une valeur qui lui est assignée (10) et que celle ci est un integer, et en construisant le bytecode on déduira que status est un integer valant 10

Python is good | CV | Kafe lang (C++17) et Unamed (C++14/SFML2.4)

+0 -0

Pour répondre à A-312, le C++ a adopté une syntaxe similaire pour le type de retour de la fonction (utile particulièrement lorsque le type est complexe, dépendant ). L’information la plus importante à mon sens c’est le nom de la fonction, pas son type de retour qui n’est qu’une information secondaire parmi tant d’autres.

Nouveauté C++17 : les décompositions | Nouveautés du C++14 | FYS : une bibliothèque C++ dans le domaine public

+1 -0

Je pense qu’il fait plutôt référence aux fonctions avec un auto sur le type de retour par exemple (trailing return type syntax).

Édité par mehdidou99

Plus on apprend, et, euh… Plus on apprend.

+1 -0

Cette réponse a aidé l’auteur du sujet

en construisant le bytecode on déduira que status est un integer valant 10

SuperFola

Ce que je propose, c’est de séparer en plusieurs phases:

1
Source -{Parsing}-> AST -{Typage}-> AST Typé -{Optimisations}-> AST Typé -{Compilation}-> Bytecode

Aujourd’hui tu as l’air de faire

1
Source -{Parsing}-> AST -{Typage + Compilation}-> Bytecode

ce qui rend le code de "Typage + Compilation" plus compliqué qu’il n’a besoin de l’être, et te limite dans tes capacités à étendre ces aspects.

Édité par gasche

+2 -0
Auteur du sujet

Actuellement dans ma tête ça se présentait plus comme la deuxième option que tu évoques ici effectivement. Maintenant que tu le dis (et aussi comme je n’ai qu’un parser, donc je peux encore revenir sur mes choix), la première solution semble effectivement mieux, merci de ton aide !

Python is good | CV | Kafe lang (C++17) et Unamed (C++14/SFML2.4)

+0 -0

Je n’ai rien à t’apporter. Ce projet dépasse largement mon domaine de compétences. Mais ça à l’air prometteur. Chapeau.

Découvrez régulièrement de nouveaux projets sur Bit-Studio.com.

+2 -0
Auteur du sujet

Bonjour à tous !

Je reviens vers vous après un mois sans nouvelle(s), après avoir corrigé pas mal de petites choses sur Kafe. Entre autre j’ai fait un fork d’ANTLR parce que je commençais à en avoir un peu marre d’avoir des erreurs avec le ERROR dans l’ATN (une variable est nommée ainsi dans leur code et est remplacée par la macro ERROR de windows.h, enfin bref) et j’ai appliqué ce fork à Kafe pour m’éviter de futurs ennuis.

Sinon j’ai ajouté des benchmarks (je dois encore les adapter pour Linux) : https://github.com/SuperFola/Kafe/tree/master/benchmarks, des tests, et Kafe compile enfin sur Linux (testé sur Lubuntu 17.10 avec gcc-7.2.0) !

Je vais travail ma VM de façon à supporter les listes, et sûrement commencer à bosser sur ce fameux parser, je vous tiens au jus ! ;)

Python is good | CV | Kafe lang (C++17) et Unamed (C++14/SFML2.4)

+0 -0
Auteur du sujet

Salut à tous !

J’ai mis à jour le post principal (syntaxe et documentation).

Concernant les nouveautés, voici donc :

  • j’ai tout passé sur https://github.com/Kafe-lang, le nombre de dépôts augmentant un peu trop, pour centraliser tout ça

  • on a donc un site de présentation du projet, et un début de documentation

  • par rapport au dernier point: j’aimerai écrire la documentation relative au langage de façon succincte pour fixer la grammaire avant de continuer mon travail sur le compilateur

  • à propos de la VM, je viens de rentrer de vacances avec un classeur plein d’idées et de descriptifs techniques, il va donc y avoir du mouvement (sur la doc en premier lieu, que je puisse définir exactement ces nouveautés pour m’y reporter lors de l’implémentation), dès que j’aurais fini mon rapport de stage :p

Je vous remets les nouveaux liens ici :

Python is good | CV | Kafe lang (C++17) et Unamed (C++14/SFML2.4)

+2 -0
Vous devez être connecté pour pouvoir poster un message.
Connexion

Pas encore inscrit ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte