CE QUI EST DÉCRIT CI-DESSOUS EST SUSCEPTIBLE DE CHANGER.
Dernière mise à jour du document : 28/09/2014
Tout n'est sûrement pas exhaustif. Ne pas hésiter à poser des questions. Cependant les grandes lignes du langage ne changeront pas.
Une variable qui n'a pas été initialisée, si elle est utilisée, renverra null. Elle n'est pas différenciable des variables initialisée ayant la valeur null.
Le séparateur d'instructions est le saut de ligne. Cependant, le ; peut remplacer ce rôle, permettant ainsi de placer plusieurs instructions sur la même ligne.
Les variables ont une portée locale dans le bloc où elles sont définies. Si elle sont définies à la racine du programme, elle seront donc globales.
Les structures de contrôles sont des expressions. C'est-à-dire qu'elles retournent la dernière valeur de leur bloc et donc qu'il est possible de la récupérer dans une variable.
Les variables sont typées statiquement. Le typage est donc fixe et ne peut pas changer durant l'exécution excepté avec le type Var qui permet de typer une variable dynamiquement.
_ est un caractère spécial qui indique le vide, il permet notamment d'indiquer à une valeur qu'elle ne doit pas être capturée.
Tout est objet. C'est à dire que ce code est correct :
Num a = 5 Str b = 120.to_str() # = "120"
Bool Num Char Str List<T> Dict<V> Var # Partie pas claire, à rectifier Func<(T n)*>:T Obj Void Null
null est la valeur d'une variable non initialisée ou sans valeur.
Bool prend pour valeur true (vrai) et false (faux).Num correspond au type numérique.Char correspond à un caractère.Str correspond au chaînes de caractères.List<T> correspond à une liste (un ensemble) de valeurs du type T.Dict<T> correspond à un ensemble de clés (de type Str) auxquels sont associées une valeur de type T.Var correspond au type dynamique, utile quand on ne sait pas quel type on veut recevoir dans une fonction.Func<(T n)*>:TObjVoidNullfalse : false, 0, 0.0, "", [], {}, nulltrue : le restePour évitez de multiples mots-clés pour définir des types, un seul mot-clé permet de créer des alias, des structures et des énumérations : type
# Alias
type int = Num
type ListOf<T> = List<T>
type ListOfNum = ListOf<Num>
type Add = (Num, Num -> Num)
type EmptyFunc = (-> Void)
# Structures
type Person = { String name, Num age = 18 }
# Enumérations
type Dir = { Up, Down, Left, Right }
type Color = { Red, Green, Blue, Rgb(Num, Num, Num) }
type Volume = {
No = 0
Low = 20
Medium = 50
High = 80
Max = 100
}Les fonctions retournent par défaut la dernière expression. Le mot-clé return peut être utilisé seul pour ne rien retourner (la valeur null sera renvoyée si le programme essaye de la récupérer) ou être utilisé avec une expression pour expliciter de manière précise la valeur retournée.
Num add(Num a, Num b) { a + b }
Les fonctions peuvent être surchargées. L'exemple précédent peut ainsi être surchargé ainsi afin de concaténer deux chaînes de caractères :
Str add(Str a, Str b) { a + b }
La fonction appelée dépend ainsi des types des paramètres qui y sont passés.
Les fonctions retournent la dernière expression excepté si un return est rencontré.
Les arguments de fonctions peuvent avoir des valeurs par défaut.
Void ma_fonction(Num a, Num b = 5) {
# ...
}
L'appel d'une fonction demande obligatoirement des parenthèses, même si elle ne possède aucun paramètre.
Num mon_num = add(2, 5) # 7
Str mon_str = add("Hello", " World!") # "Hello World!"
Les fonctions peuvent accepter un nombre variable de paramètres.
Num somme(Num nb, Num args...) {
# args sera un tableau (de nombres ici) contenant les valeurs passées lors de l'appel
# ...
}
Les fonctions à nombre de paramètres variables peuvent s'appeler de différentes manières.
Num nb nb = somme(2) # args vaudra [] (un tableau vide) nb = somme(2, 3, 4, 5) # args vaudra [ 3, 4, 5 ] # il est aussi possible de faire passer plusieurs valeurs via une liste # le ...[] sert à préciser qu'on fait passer plusieurs valeurs et non une liste nb = sommes(2, ...[ 3, 4, 5 ]) # args vaudra [ 3, 4, 5 ]
Il est possible de créer des fonctions anonymes. Elles servent généralement à faire des callbacks ou des fonctions qui changent durant l'exécution du programme.
# Fonction anonyme dans une variable
# La fonction dans une variable peut être changée durant l'exécution mais pas surchargée
Func ma_func = (Num a, Num b) { a + b }
# Fonction anonyme dans une fonction
une_fonction_avec_callback((Num a, Num b) {
# ...
})
# Fonction anonyme auto-appelée
(Num a, Num b) {
# ...
}(3, 6)
Il est possible de retourner plusieurs valeur à la fin d'une fonction. En fait il s'agit de retourner une liste et de la récupérer via la syntaxe spécifique [ var1, var2, etc. ] = fonction().
une_fonction(Num a) {
[ a + 1, a + 2, a + 3]
}
[ a, b, c ] = une_fonction(0) # a = 1 ; b = 2 ; c = 3
d = une_fonction(0) # d = [ 1, 2, 3 ]
[ e, f, g ] = d # comme a, b et c
[ b, a, c ] = [ a, b, c ] # b = 1 ; a = 2 ; c = 3
Il est possible de "binder" une fonction. _ permet d'indiquer des paramètres manquants qui seront les paramètres de la nouvelle fonction :
Num add(Num a, Num b) { a + b } # (Num, Num -> Num)
Num add5 = add.bind(_, 5) # (Num -> Num)
Num ma_var = add5(20) # = 25La condition if se compose ainsi : if ... { } else if ... { } else { }.
if condition {
# ...
} else if condition {
# ...
} else {
# ...
}
Le if fonctionne comme une expression et peut être assignée à une variable, c'est la dernière expression qui est retournée à la variable. Si aucune des conditions ne correspond, la variable prend la valeur du else s'il y en a un ou garde sa valeur s'il n'y en a pas.
Num a = if condition {
5
} else if condition {
0
} else {
1
}
Le if profite de l'écriture raccourcie suivante :
Str a = if condition ? "ok" : "nop"
<, <=, >, >=, ==, <>, and, or, not, in
Exemple de l'opérateur in qui retourne le nombre d'occurences :
List<Str> names = [ "Aymeric", "Guillaume", "Yannick" ]
Bool has_yannick = "Yannick" in names # 1
Bool o_in_helloworld = "o" in "Hello World!" # 2
Dict<Num> scores = { "Aymerick" = 200, "Guillaume" = 180, "Yannick" = 20 }
Bool has_guillaume = "Guillaume" in scores # 1
Le match permet de tester plusieurs valeurs d'une variable ou expression.
match ma_var {
"a" {
# ...
}
"b" {
# ...
}
else { # code par défaut, "else" peut être remplacé par "_"
# ...
}
}
Le match permet de tester des plages de valeurs, des valeurs multiples et des conditions :
match ma_var {
0 .. 5 { # [0;5]
# ...
}
6 ... 10, 50 ... 120 { # [6;10[ ou [50;120[
# ...
}
v if v > 200 { # si ma_var est supérieur à 200
# ...
}
}
Le match fonctionne comme une expression et peut être assignée à une variable. Si aucune des valeurs n'est possédée par l'expression passée, la variable gardera sa valeur :
Str card = "as"
Num card_value = match card {
"valet" { 11 }
"dame" { 12 }
"roi" { 13 }
"as" { 14 }
else { card.to_num() }
} # = 14La boucle simple est une boucle infinie. Pour la stopper, il faut effectuer un break.
loop {
# ...
}
Il est cependant possible de définir le nombre d'itérations ;
loop 5 {
# 1
# 2
}
Il est aussi possible de définir un pas :
loop 8 by 2 {
# 0
# 2
# ...
}
La boucle while itère dans la condition est respectée.
Num i = 5
while i-- {
# i = 4
# i = 3
# ...
}
La boucle do-while fonctionne de la même manière que la boucle while sauf qu'il y a une itération au minumum et que l'expression est évaluée à la fin de l'itération.
Num i = 5
do {
# i = 5
# i = 4
# ...
} while i--
La boucle itérative demande une valeur initiale et une valeur finale.
for i = 0 to 5 {
# i = 0
# i = 1
# ...
}
Vous pouvez aussi spécifier un pas :
for i = 0 to 12 by 2 {
# i = 0
# i = 2
# ...
}
Parcours tous les éléments de la liste.
List<Num> ma_list = [ 2, 3, 5, 7, 11, 13 ]
for k, v in ma_list {
# k = 0, v = 2
# k = 1, v = 3
# ...
}
Parcours tous les éléments du dictionnaire.
Dict<Str> mon_dict = { "a" = "b", "b" = "c", "c" = "d" }
for k, v in mon_dict {
# k = "a", v = "b"
# k = "b", v = "c"
# ...
}
Parcours chaque caractères d'une chaîne.
Str mon_str = "Hello"
for k, v in mon_str {
# k = 0, v = "H"
# k = 1, v = "e"
# ...
}
Lors des boucles for, il arrive que parfois vous ne souhaitiez pas nommer de variable itérative. Cela est possible grâce au mot-clé _ qui indique de ne pas capturer la valeur dans une variable :
for _ = 0 to 20 { }
Ainsi, la boucle aura 20 itérations mais aucune variable.
Cela fonctionne aussi pour les boucles for ... in. Vous pouvez capturer, au choix, rien, la valeur, la clé ou les deux. Voici les différentes syntaxes utilisables :
# for in my_val { } # syntaxe à réfléchir
# for _ in my_val { } # syntaxe à réfléchir
# for _, _ in my_val { } # syntaxe à réfléchir
# for v in my_val { } # syntaxe à réfléchir
for _, v in my_val { }
for k, _ in my_val { }
for k, v in my_val { }La création de classe fonctionne simplement. Comme la plupart des langages mais de manière simplifiée, sans visibilité ni futilités.
Le @ (this. dans les autres langages) est obligatoire pour accéder à un attribut ou appeler une méthode de la classe.
class Point {
public new(Num x, Num y) {
@x = x
@y = y
}
public Void add(Num x, Num y) {
@x += x
@y += y
}
public Void add(Point2D p) {
@add(p.x, p.y)
}
}
class Point3D < Point {
public new(Num x, Num y, Num z) {
@parent(x, y)
@z = z
}
public Void add(Num x, Num y, Num z) {
@add(p.x, p.y)
@z += z
}
public Void add(Point3D p) {
@add(p.x, p.y, p.z)
}
}
Il est possible d'ajouter des méthodes à une classe native (Str, Int, etc.) ou à une classe que vous avez créé ou que vous utilisez.
@ dans une classe native représente la valeur de l'objet (vous n'avez pas accès aux valeurs internes). @ dans une classe que vous avez créé ou que vous utilisez représente l'objet et avez donc accès aux attributs.
# Prototyper une classe native
Num::negative_abs() {
-@abs() # "@" représente ici la valeur du nombre
}
# Prototyper votre propre classe
# Les sous-classes hérite des méthodes que vous créez ici
Point::sub(Point p) {
@x -= p.x
@y -= p.y
}
class Math {
public const PI = 3.14159265359
public static get_pi() {
return @PI
}
}
Num PI
pi = Math.PI
pi = Math.get_pi()Il y a deux méthodes pour accéder à une valeur dans une liste :
List<Num> ma_list = [ 0, 1, 2, 3, 4, 5 ] # Récupérer la valeur de l'indice 0 # ma_list.0 # syntaxe à réfléchir ma_list[0] ma_list.get(0)
Il y a trois méthodes pour accéder à une valeur dans un dictionnaire :
Dict<Num> ma_list = { "foo" = "bar", "bar" = "foo" }
# Récupérer la valeur de la clé "foo"
mon_dict.foo
mon_dict["foo"]
mon_dict.get("foo")Aucune réflexion.
List<Num> a = [ 0 loop 5 ]
# a = [ 0, 0, 0, 0, 0 ]
List<Num> b = [ i for i from 0 to 4 ]
# b = [ 0, 1, 2, 3, 4 ]
List<Num> c = [ i for i from 0 to 4 if i % 2 == 0 ]
# c = [ 0, 2, 4 ]
Dict<Num> ages = { "Robert" = 34, "Léa" = 26, "Jean" = 55 }
List<Str> names = [ name for name, _ in ages ]
# names = [ "Robert", "Léa", "Jean" ]pack fc.examples.plus_ou_moins
use stdio as io
use math
Num nb = math.rand(1, 100)
Num cpt = 0
Num val_test
do {
val_test = io.ask("Saisissez un nombre entre 1 et 100 : ").to_num()
cpt++
if val_test > nb {
io.writeln("C'est moins")
} else if val_test < nb {
io.writeln("C'est plus")
}
} while val_test <> nb
io.writeln("Bravo, tu as gagné en ${cpt} coups !")
Num me = 38
Dict<Num> friends = {
"Robert" = 32,
"Paul" = 54,
"Jean" = 29,
"Jacques" = 42
}
List<Num> ages = [ age for _, age in friends ]
# [ 32, 54, 29, 42 ]
ages.sort((Num a, Num b) { a - b })
# [ 29, 32, 42, 54 ]
# Syntaxe de Bootmonkey (BM)
# Par Pif, booti386, Gorgio et SuperMonkey
# Dernière mise à jour : 31/07/2014
enum Volume {
LOW = 20
MEDIUM = 50
HIGH = 100
}
interface Animal {
Void
}
# S'inspirer de :
# - http://haxe.org/manual/lf-pattern-matching.html
# - http://fr.wikibooks.org/wiki/OCaml/Structures#Filtrage_par_motifs
switch value { when < 0 { } when < 5 { } when >= 5 { } }
when ::= < 0 (inférieur) | <> 20 (différent) | 0 or 5 (ou) | 0 to 5 (entre (bornes includes))
# Déclarer un type
"type" nom_type = type
exemple :
type Player = {
Str name,
{ Num x, Num y } position
}
# Déclarer une variable
type nom_variable = valeur
# Déclarer une constante
"const" [type] nom_variable [ = valeur ]
# Déclarer une fonction
type nom_fonction(arguments) { }
# Déclarer une classe
[final] class NomClasse [ < NomClasseParente ] { }
# Déclarer un attribut
[public|protected|private] [static|const] type nom_attribut [ = valeur ]
# Déclarer une méthode
[public|protected|private] [static] [final] type nom_methode(arguments) { }
# Suite de fibonacci
Num fibo(Num n) {
if n <= 1 {
n
} else {
fibo(n - 1) + fibo(n - 2)
}
}
class Player {
String name
List<Card> cards
new (String name) {
this.name = name
cards = []
}
Void add_card(Card c) {
cards.push(c)
}
}
class Card {
Int value
String type
String name
new(Int value, String type) {
this.value = value
this.type = type
name = "$value de $type"
}
Num get_value() {
match value {
"valet" { 11 }
"dame" { 12 }
"roi" { 13 }
"as" { 14 }
else { value.to_num() }
}
}
}
class Game {
List<Card> cards
List<Player> players
new() {
List<Var> value_cards = [ 2, 3, 4, 5, 6, 7, 8, 9, 10, "valet", "dame", "roi", "as" ]
List<String> types_cards = [ "coeur", "pique", "trèfle", "carreau" ]
for _, value in value_cards {
for _, type in type_cards {
add_card(value, type)
}
}
players = []
}
Void add_card(Var value, String type) {
cards.push(new Card(value, type))
}
Void add_player(String player_name) {
players.push(new Player(player_name))
}
}
Game game = new Game()
game.add_player("Yannick")
game.add_player("Guillaume")use pour importer un packageVoici les portés des variables, fonctions, classes, interfaces et énumérations dans les packages :
private par défautpublic par défautprivate = limité au fichierprotected = limité au packagepublic = ouvertnoref pour copier la valeurrefL'entrée du programme s'effectue dans une fonction nommée main que vous pouvez placer où vous voulez :
Num main(List<Str> args) {
# votre code
return 0
}
@nom_meta(cle=value)