Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Litil, Growing a functional language on the JVM

Litil, Growing a functional language on the JVM

Les slides de ma présentation de Litil, un petit langage fonctionnel sur JVM inspiré de ML lors d'une technozaure à Zenika.

Jawher Moussa

May 23, 2013
Tweet

More Decks by Jawher Moussa

Other Decks in Programming

Transcript

  1. LitiL
    Growing a (functional)
    language
    Thursday, 23 May, 13

    View Slide

  2. LitiL
    J’ai crée un
    langage
    Thursday, 23 May, 13

    View Slide

  3. LitiL
    C’est facile !
    Thursday, 23 May, 13

    View Slide

  4. LitiL
    Thursday, 23 May, 13

    View Slide

  5. LitiL
    Thursday, 23 May, 13

    View Slide

  6. LitiL
    à quoi ça va
    ressembler ?
    Thursday, 23 May, 13

    View Slide

  7. En gros
    •Syntaxe “propre”
    •Fonctionnel
    •Inférence de types totale (HM)
    •Blancs significatifs
    Thursday, 23 May, 13

    View Slide

  8. LitiL
    Exemples
    Thursday, 23 May, 13

    View Slide

  9. LitiL
    affectations, expressions & fonctions
    let  five  =  3
    let  twice  x  =  3  *  x  -­‐  (42  -­‐  41)  *  x
    let  x2  =  twice  5
    let  add  x  y  =  x  +  y
    let  seven  =  add  4  (1  +  2)
    let  fact  n  =
       if  n  <  2  then
           1
       else
           n  *  fact  (n-­‐1)
    Thursday, 23 May, 13

    View Slide

  10. LitiL
    Tuples et Listes
    let  x  =  (5,  "a",  true)
    let  pair  x  y  =  (x,  y)
    let  xs  =  [1,  2,  3]
    Thursday, 23 May, 13

    View Slide

  11. LitiL
    Deconstruction
    let  (a,  b)  =  (4,  "d")
    let  d  =  ((4,  true),  ("test",  'c',  a))
    let  ((_,  bool),  (_,  _,  _))  =  d
    Thursday, 23 May, 13

    View Slide

  12. LitiL
    ADTs
    data  Option  a  =  Some  a  |  None
    let  o  =  Some  "thing"
    data  List  a  =  Cons  a  (List  a)  |  Nil
    let  l  =  Cons  5  (Cons  6  Nil)
    data  Tree  a  =  Null  |  Leaf  a  |  Node  (Tree  a)  a  (Tree  a)
    let  t  =  Node  (Leaf  5)  4  (Leaf  3)
    Thursday, 23 May, 13

    View Slide

  13. LitiL
    Application partielle
    let  add  x  y  =  x  +  y
    let  inc  =  add  1
    let  three  =  inc  2
    Thursday, 23 May, 13

    View Slide

  14. LitiL
    Lambdas & closures
    let  map  f  xs  =
       match  xs
           []          =>  Nil
           h  ::  t  =>  (f  h)  ::  (map  f  t)
    let  l  =  [1,  2]
    let  double  x  =  2  *  x
    -­‐-­‐  pass  a  function  by  name
    let  l2  =  map  double  l
    -­‐-­‐  or  simply  a  lambda
    let  l2  =  map  (\x  =>  2  *  x)  l
    let  a  =  4
    let  f  =  \x  =>  a  *  x  -­‐-­‐  f  captures  the  lexical  value  of  a,  i.e.  4
    let  a  =  5
    f  5
    Thursday, 23 May, 13

    View Slide

  15. Plan
    •Lexer
    •Parser
    •Descente récursive
    •Pratt
    •Type checker
    •Monomorphique
    •Polymorphique
    •Evaluator
    Thursday, 23 May, 13

    View Slide

  16. Vue d’ensemble
    Lexer Parser
    Sources Tokens
    AST
    Type
    Checker
    Evaluator AST+Env
    Thursday, 23 May, 13

    View Slide

  17. LitiL
    Lexer
    Thursday, 23 May, 13

    View Slide

  18. Lexer
    •A partir du texte brut
    •Générer des tokens
    Thursday, 23 May, 13

    View Slide

  19. Lexer :: Token
    •Type: SYM,  NAME,  KEYWORD,  ...
    •Valeur: ‘+’,  ‘x’,  ‘let’
    •ligne, colonne
    Thursday, 23 May, 13

    View Slide

  20. Exemple
    let  five  =  3
    KEYWORD
    let
    NAME
    five
    SYM
    =
    NUM
    3
    EOF
    $
    Thursday, 23 May, 13

    View Slide

  21. Types
    •NAME
    •NUM, STRING, CHAR, BOOL
    •KEYWORD
    •EOF
    •NEWLINE, INDENT, DEINDENT
    Thursday, 23 May, 13

    View Slide

  22. Algo
    pop()  :  Token
    c  =  nextChar()
    if  c  =  \n  return  blackMagic()
    elif  c  :  [0-­‐9]  return  readNum()
    elif  c  =  “  return  readString()
    elif  c  =  ‘  return  readString()
    elif  c  in  symsRoots  return  readSym()
    elif  return  readNameOrKwOrBool()
    Thursday, 23 May, 13

    View Slide

  23. Les blancs ...
    ligne1
    ligne2
    NEWLINE
    ligne1
    ligne2
    INDENT + NEWLINE
    ligne1
    ligne2
    DEINDENT + NEWLINE
    Thursday, 23 May, 13

    View Slide

  24. LitiL
    Parser
    Thursday, 23 May, 13

    View Slide

  25. Parsing
    •A partir des tokens
    •Générer l’AST
    Thursday, 23 May, 13

    View Slide

  26. Exemple
    let  add  x  y  =  x  +  y
    KEYWORD
    let
    NAME
    add
    NAME
    x
    NAME
    y
    SYM
    =
    SYM
    +
    NAME
    x
    NAME
    y
    Expr.EName
    name:  y
    LetBinding
    name:  add
    type:_
    args:  [x,  y]
    instructions EAp
    fn
    arg
    EAp
    fn
    arg
    Expr.EName
    name:  +
    Expr.EName
    name:  x
    Thursday, 23 May, 13

    View Slide

  27. Parseurs
    •Plusieures méthodes et algos
    •Bottom-Up: LR, LALR, SLR, etc.
    •Top-Down: LL, RDP
    Thursday, 23 May, 13

    View Slide

  28. Grammaire
    •BNF: Spécification formelle d’un
    langage
    •Ensemble de règles de dérivation
    Thursday, 23 May, 13

    View Slide

  29. BNF
    let  :  “let”  id  args  “=”  body
    args:  id  args  |  ε
    id:  [a-­‐zA-­‐Z]+[a-­‐zA-­‐Z0-­‐9]*
    body:  ...
    Thursday, 23 May, 13

    View Slide

  30. EBNF
    •Augmente BNF avec les opérateurs
    “+”, “*” et “?”
    •Grammaires plus compactes
    Thursday, 23 May, 13

    View Slide

  31. EBNF
    let  :  “let”  id  args  “=”  body
    args:  id*
    id:  [a-­‐zA-­‐Z]+[a-­‐zA-­‐Z0-­‐9]*
    body:  ...
    Thursday, 23 May, 13

    View Slide

  32. RDP
    •Traduction EBNF vers le code
    •Règle => méthode
    •Référence à un non terminal => appel
    d’une méthode
    Thursday, 23 May, 13

    View Slide

  33. RDP
    public  LetBinding  let()  {
    expect(KEYWORD,  “let”);
    String  name  =  name();
    List  args  =  args();
    expect(SYM,  “=”);
    Body  body  =  body();
    return  new  LetBinding(name,  args,  body);
    }
    Thursday, 23 May, 13

    View Slide

  34. EBNF RDP
    let  :  “let”  id  args  “=”  
    body
    args:  id*
    id:  [a-­‐zA-­‐Z]+[a-­‐zA-­‐
    Z0-­‐9]*
    body:  ...
    public  LetBinding  let()  {
    expect(KEYWORD,  “let”);
    String  name  =  name();
    List  args  =  args();
    expect(SYM,  “=”);
    Body  body  =  body();
    return  new  LetBinding(name,  args,  
    body);
    }
    Thursday, 23 May, 13

    View Slide

  35. Parseur RDP
    •Un champ token
    •Méthodes expect(Token.Type) et
    expect(Token.Type, String value)
    •Méthodes found(Token.Type) et
    found(Token.Type, String value)
    Thursday, 23 May, 13

    View Slide

  36. LitiL
    Litil::RDP::1
    public  Program  program()  {
           Program  p  =  new  Program();
           p.instructions.addAll(body());
           return  p;
    }
    private  List  body()  {
           List  res  =  new  ArrayList();
           while  (found(Token.Type.NEWLINE))  {
                   res.add(instruction());
           }
           return  res;
    }
    Thursday, 23 May, 13

    View Slide

  37. LitiL
    Litil::RDP::instruction
    private  Instruction  instruction()  {
           if  (found(Token.Type.KEYWORD,  "let"))  {
                   return  letBinding();
           }  else  if  (found(Token.Type.KEYWORD,  "data"))  {
                   return  dataDecl();
           }  else  if  (found(Token.Type.KEYWORD,  "exception"))  {
                   return  exceptionDecl();
           }  else  {
                   return  expr();
           }
    }
    Thursday, 23 May, 13

    View Slide

  38. LitiL
    Litil::RDP::let
    private  LetBinding  letBinding()  {
           expect(Token.Type.NAME);
           String  functionName  =  token.text;
           Type  functionReturnType  =  null;
           List  args  =  params();
           List  argTypes  =  new  ArrayList(args.size());
           for  (Named  arg  :  args)  {
                   argTypes.add(arg.type);
           }
           if  (found(Token.Type.SYM,  ":"))  {
                   functionReturnType  =  type();
                   Type  letType  =  argTypes.isEmpty()  ?  functionReturnType  :  
    Type.Function(argTypes,  functionReturnType);
           }
           expect(Token.Type.SYM,  "=");
           List  instructions  =  bloc();
           LetBinding  letBinding  =  new  LetBinding(functionName,  
    functionReturnType,  args,  instructions);
           return  letBinding;
    }
    Thursday, 23 May, 13

    View Slide

  39. LitiL
    Litil::RDP::match
    if  (found(Token.Type.KEYWORD,  "match"))  {
           Expr  input  =  expr(0);
           expect(Token.Type.INDENT);
           List  cases  =  new  
    ArrayList();
           while  (found(Token.Type.NEWLINE))  {
                   cases.add(patMatchCase());
           }
           expect(Token.Type.DEINDENT);
           return  new  Expr.PatterMatching(input,  cases);
    }
    Thursday, 23 May, 13

    View Slide

  40. Expressions
    •ça craint avec les RDP
    •Des stacks d’appel trop profonds
    Thursday, 23 May, 13

    View Slide

  41. Priorité
    expr  :  expr  op  expr  
    |  [0-­‐9]+
    op:  “+”  |  “-­‐”  |  “*”  |  “/”
    1  +  2  *  3  =  ?
    Thursday, 23 May, 13

    View Slide

  42. Priorité WTF ?
    1  +  2  *  3
    =  9
    W
    AT
    ?
    Thursday, 23 May, 13

    View Slide

  43. Because
    1  +  2  *  3
    val
    op
    expr
    val op val
    Thursday, 23 May, 13

    View Slide

  44. Du coup
    •Encoder les règles de précédence dans
    la grammaire
    •En introduisant des productions
    intermédiaires
    Thursday, 23 May, 13

    View Slide

  45. EBNF Révisé
    expr  :  expr  (“+”|”-­‐”)  prod  |  prod
    prod:  prod  (“*”|”/”)  val  |  val
    val:  [0-­‐9]+
    Thursday, 23 May, 13

    View Slide

  46. Mais avec N opérateurs
    •On finit avec beaucoup de niveaux
    intermédiaires
    •Et donc avec autant de niveaux dans la
    stack avec le RDP
    Thursday, 23 May, 13

    View Slide

  47. Pour parser “5”
    •atom()
    •mulDivExpr()
    •addRemExpr()
    •compExpr()
    •andExpr()
    •orExpr()
    Thursday, 23 May, 13

    View Slide

  48. Prattman pour nous
    sauver !
    •Parser les expressions en un temps
    linéaire
    •Des stacks beaucoup moins profondes
    (fonction du nombre d’opérateurs)
    Thursday, 23 May, 13

    View Slide

  49. Pratt parser
    •Opère sur les tokens pas les règles
    •Chaque token a une priorité
    •lbp(+) = 10 et lbp(*) = 20 par exemple
    •handler pour les tokens “infix”: led
    •nud pour les “prefix”
    Thursday, 23 May, 13

    View Slide

  50. LitiL
    Priorités
    LBP.put("and",  5);
    LBP.put("or",  5);
    LBP.put("not",  7);
    LBP.put("=",  7);
    LBP.put("LBP.put(">",  7);
    LBP.put("::",  11);
    LBP.put("+",  15);
    LBP.put("-­‐",  15);
    LBP.put("%",  20);
    LBP.put("*",  20);
    LBP.put("/",  20);
    LBP.put("[",  90);
    LBP.put("]",  1);
    LBP.put("(",  100);
    LBP.put(")",  1);
    Thursday, 23 May, 13

    View Slide

  51. LitiL
    Pratt parser :: expr
    public  Expr  expr(int  rbp)  {
           Token  tk  =  advance();
           Expr  left  =  nud(tk);
           while  (rbp  <  lbp(lexer.peek(1)))  {
                   tk  =  advance();
                   left  =  led(left,  tk);
           }
           return  left;
    }
    Thursday, 23 May, 13

    View Slide

  52. LitiL
    Pratt parser :: nud
    private  Expr  nud(Token  tk)  {
           if  (is(tk,  Token.Type.SYM,  "-­‐"))  {
                   Expr  expr  =  expr(100);
                   return  new  Expr.EAp(new  Expr.EName("-­‐/1"),  expr);
           }  else  if  (is(tk,  Token.Type.NUM))  {
                   return  new  Expr.ENum(Integer.parseInt(tk.text));
           }  else  if  (is(tk,  Token.Type.BOOL))  {
                   return  new  Expr.EBool(Boolean.parseBoolean(tk.text));
           }  else  if  (is(tk,  Token.Type.NAME))  {
                   return  new  Expr.EName(tk.text);
           }
    }
    Thursday, 23 May, 13

    View Slide

  53. LitiL
    Pratt parser :: led
    private  Expr  led(Expr  left,  Token  tk)  {
           int  bp  =  lbp(tk);
           if  (is(tk,  Token.Type.SYM,  "+")  ||  is(tk,  Token.Type.SYM,  "*"))  {
                   Expr  right  =  expr(bp);
     return  new  Expr.EAp(
    new  Expr.EAp(new  Expr.EName(tk.text),  left),
    right);
           }  else  if  (left  instanceof  Expr.EName)  {
                   return  new  Expr.EAp(left,  nud(tk));
           }  else  {
                   throw  error("Unexpected  token  "  +  tk);
           }
    }
    Thursday, 23 May, 13

    View Slide

  54. LitiL
    Type
    Checker
    Thursday, 23 May, 13

    View Slide

  55. Type checker
    •Plusieures possiblités:
    •Typage explicite
    •Typage mono-mophique avec
    inférence
    •Typage poly-morphique avec
    inférence (HM)
    Thursday, 23 May, 13

    View Slide

  56. Type
    •Oper: couple
    •nom
    •List de sous types
    Thursday, 23 May, 13

    View Slide

  57. Types “natifs”
    •Num  =  Oper(“Num”,  [])
    •Bool  =  Oper(“Bool”,  [])
    •Char  =  Oper(“Char”,  [])
    •String  =  Oper(“List”,  [Type.Char])
    •...
    Thursday, 23 May, 13

    View Slide

  58. Prelude
    •not  :  Oper(“-­‐>”,  [Bool,  Bool])
    •+  :  Oper(“-­‐>”,  [Num,  Num,  Num])
    •...
    Thursday, 23 May, 13

    View Slide

  59. Type checker
    •Etant donné:
    •Un noeud de l’AST
    •Et un environnement de types
    •Retourner le type du noeud
    •Ou exception en cas de problème
    Thursday, 23 May, 13

    View Slide

  60. Typage explicite
    •Pas d’inférence
    •On vérifie que tous les types sont
    renseignés
    •Et qu’ils sont compatibles
    Thursday, 23 May, 13

    View Slide

  61. LitiL
    Typage explicite
    let  max  (x:  Num)  (y:  Num)  :  Num  =
      if  x  >  y
        x
      else
        y
    • Vérifier que les arguments (x, y) déclarent leur type
    • Vérifier que le type de retour est précisé
    •Vérifier que le type de la condition de if est Bool
    • Vérifier que le type de retour du “then” est le même
    que celui déclaré comme retour
    • Idem pour le “else”
    Thursday, 23 May, 13

    View Slide

  62. LitiL
    Typage statique :: impl
    public  Type  analyze(AstNode  node,  TypeScope  env)  {
           if  (node  instanceof  Expr.ENum)  {
                   return  Type.INT;
           }  else  if  (node  instanceof  Expr.EName)  {
                   Type  res  =  env.get(((Expr.EName)  node).name);
                   if  (res  ==  null)
                           throw  new  TypeError("Undeclared  entity  '"  +  node  +  "'");
                   return  res;
           }  else  if  (node  instanceof  Expr.EIf)  {
                   Expr.EIf  eif  =  (Expr.EIf)  node;
                   Type  condType  =  analyze(eif.cond,  env);
                   unify(condType,  Type.BOOL);
                   Type  thenType  =  null;
                   for  (Instruction  instr  :  eif.thenInstructions)
                           thenType  =  analyze(instr,  env);
                   Type  elseType  =  null;
                   for  (Instruction  instr  :  eif.elseInstructions)
                           elseType  =  analyze(instr,  env);
                   unify(thenType,  elseType);
                   return  thenType;
           }
    }
    Thursday, 23 May, 13

    View Slide

  63. TypeChecker
    mono-morphique
    •Peut inférer les types non présents
    •Pas de généralisation
    Thursday, 23 May, 13

    View Slide

  64. mono-morphisme
    let  first  x  y  =  x
    let  f  =  first  4  false
    “first” sera typé:
    Num  -­‐>  Bool  -­‐>  Num
    Et non pas
    a  -­‐>  b  -­‐>  a static    X  first(X  x,  Y  y)  {
      return  x
    }
    Thursday, 23 May, 13

    View Slide

  65. Type variable
    •Type qu’on cherche à déterminer
    •identifié par un nom généré
    automatiquement
    •Peut être “remplacée” par un autre
    type
    Thursday, 23 May, 13

    View Slide

  66. Unification
    •Etant donné 2 types
    •On cherche à vérifier qu’ils sont
    compatibles/équivalents
    •En effectuant de l’inférence s’il le faut
    Thursday, 23 May, 13

    View Slide

  67. Unify(t1, t2)
    ‣ Si  t1  est  une  variable  =>  t1  inféré  à  
    t2
    ‣ Si  t2  variable,  unifier  t2  et  t1  (cas  
    1)
    ‣ Sinon,  t1  et  t2  sont  du  type  Oper
    ‣ Si  t1.name  !=  t2.name  =>  erreur
    ‣ Si  t1.types.size  !=  t2  =>  erreur
    ‣ Unifier  t1.types  et  t2.types
    Thursday, 23 May, 13

    View Slide

  68. Algo
    •Même que typage explicite
    •Sans la vérif de la présence obligatoire
    des déclarations de types
    •unify qui effectue l’inférence
    Thursday, 23 May, 13

    View Slide

  69. LitiL
    Typage monomorphique :: impl
    public  Type  analyze(AstNode  node,  TypeScope  env)  {
           if  (node  instanceof  Expr.ENum)  {
                   return  Type.INT;
           }  else  if  (node  instanceof  Expr.EName)  {
                   Type  res  =  env.get(((Expr.EName)  node).name);
                   if  (res  ==  null)
                           throw  new  TypeError("Undeclared  entity  '"  +  node  +  "'");
                   return  res;
           }  else  if  (node  instanceof  Expr.EIf)  {
                   Expr.EIf  eif  =  (Expr.EIf)  node;
                   Type  condType  =  analyze(eif.cond,  env);
                   unify(condType,  Type.BOOL);
                   Type  thenType  =  null;
                   for  (Instruction  instr  :  eif.thenInstructions)
                           thenType  =  analyze(instr,  env);
                   Type  elseType  =  null;
                   for  (Instruction  instr  :  eif.elseInstructions)
                           elseType  =  analyze(instr,  env);
                   unify(thenType,  elseType);
                   return  thenType;
           }
    }
    Thursday, 23 May, 13

    View Slide

  70. LitiL
    Typage monomorphique :: impl :: let
    if  (node  instanceof  LetBinding)  {
           LetBinding  let  =  (LetBinding)  node;
           TypeScope  ss  =  new  TypeScope(scope);
           List  argTypes  =  new  ArrayList();
           ss.define(let.name,  new  Type.Variable());
           for  (Named  arg  :  let.args)  {
                   Type  argType  =  new  Type.Variable();
                   argTypes.add(argType);
                   ss.define(arg.name,  argType);
           }
           Type  resultType  =  null;
           for  (Instruction  instr  :  let.instructions)  {
                   resultType  =  analyze(instr,  ss);
           }
           if  (let.type  !=  null)  {
                   unify(resultType,  let.type);
           }
           Type  letType  =  Type.Function(argTypes,  resultType);
           scope.define(let.name,  letType);
           return  letType;
    }
    Thursday, 23 May, 13

    View Slide

  71. TypeChecker poly-
    morphique
    •Peut inférer les types non présents de
    façon globale
    •Trouve systématiquement le type le plus
    général et plus générique
    •Utilise L’algo W de Hindley-Milner
    Thursday, 23 May, 13

    View Slide

  72. poly-morphisme
    let  first  x  y  =  x
    let  f  =  first  4  false
    “first” sera typé:
    a  -­‐>  b  -­‐>  a
    Et non pas
    Num  -­‐>  Bool  -­‐>  Num
    static    X  first(X  x,  Y  y)  {
      return  x
    }
    Thursday, 23 May, 13

    View Slide

  73. L’astuce ?
    •Dupliquer les variables d’un type à
    chaque unification
    •Ainsi, on garde la forme la plus
    générale
    Thursday, 23 May, 13

    View Slide

  74. Exemple
    • analyze(let  first  ...)
    • Types  {first=v1,  x=v2,  y=v3}
    • Au  final,  first:  a  -­‐>  b  -­‐>  a
    • analyze(let  f  =  ...)
    • unify(Num  -­‐>  Bool  -­‐>  v4,  a2  -­‐>  b2  -­‐>  a2)
    • a2  =  Num,  b2  =  Bool
    • v4  =  a2  =  Num
    • f:  Num
    • mais  first  est  toujours  a  -­‐>  b  -­‐>  c
    let  first  x  y  =  x
    let  f  =  first  4  false
    Fresh
    Thursday, 23 May, 13

    View Slide

  75. I lied
    •C’est plus compliqué que ça en fait ...
    •Ne pas dupliquer systématiquement
    •Sinon on va laisser passer des erreurs
    Thursday, 23 May, 13

    View Slide

  76. Exemple
    let  f  x  =
      let  y  =  x  +  1  -­‐-­‐  x  inferred  to  be  Num
      if  x  -­‐-­‐  x  inferred  to  be  Bool
        2
      else
        3
    Thursday, 23 May, 13

    View Slide

  77. Donc
    •Ne pas dupliquer les arguments et le
    type de retour d’un let dans sa
    définition
    •Celui de l’expression du match dans les
    cases
    •etc.
    Thursday, 23 May, 13

    View Slide

  78. Bref
    •Hindley et Milner s’en sont déjà occupé
    •Tout que j’avais à faire c’était de:
    •Décoder les papiers de recherche
    •Adapter à Litil:
    •Pas de pattern-matching dans HM
    •Let différent
    •...
    Thursday, 23 May, 13

    View Slide

  79. LitiL
    Evaluator
    Thursday, 23 May, 13

    View Slide

  80. Evaluator
    •Pour que ça tourne
    •Plus facile à faire qu’un compilateur
    Thursday, 23 May, 13

    View Slide

  81. Comment ?
    •Etant donné:
    •Un noeud de l’AST
    •Et un environnement de valeurs
    •Retourner le resultat de l’évaluation du
    noeud
    •Ou exception en cas de problème
    Thursday, 23 May, 13

    View Slide

  82. LitiL
    Expr :: Name
    public  Object  eval(AstNode  node,  ValScope  scope)  {
           if  (node  instanceof  Expr)  {
                   if  (node  instanceof  Expr.EName)  {
                           Object  val  =  scope.get(((Expr.EName)  node).name);
                           if  (val  ==  null)  {
                                   throw  new  EvalException("Unknwon  identifier  "  +  node);
                           }  else  {
                                   return  val;
                           }
                   }
    Thursday, 23 May, 13

    View Slide

  83. LitiL
    Expr :: Types simples
    public  Object  eval(AstNode  node,  ValScope  scope)  {
           else  if  (node  instanceof  Expr.ENum)  {
                   return  ((Expr.ENum)  node).value;
           }  else  if  (node  instanceof  Expr.EBool)  {
                   return  ((Expr.EBool)  node).value;
           }  else  if  (node  instanceof  Expr.EChar)  {
                   return  ((Expr.EChar)  node).value;
           }  ...
    Thursday, 23 May, 13

    View Slide

  84. LitiL
    Expr :: Tuples
    public  Object  eval(AstNode  node,  ValScope  scope)  {
           if  (node  instanceof  Expr.ETuple)  {
                   Expr.ETuple  tuple  =  ((Expr.ETuple)  node);
                   List  res  =  new  ArrayList();
                   for  (Expr  value  :  tuple.values)  {
                           res.add(eval(value,  scope));
                   }
                   return  res;
           }
    Thursday, 23 May, 13

    View Slide

  85. LitiL
    Expr :: If
    if  (node  instanceof  Expr.EIf)  {
           Expr.EIf  eif  =  (Expr.EIf)  node;
           Object  cond  =  eval(eif.cond,  scope);
           if  (cond  instanceof  Boolean)  {
                   if  ((Boolean)  cond)  {
                           Object  val  =  null;
                           ValScope  thenScope  =  scope.child();
                           for  (Instruction  instr  :  eif.thenInstructions)  {
                                   val  =  eval(instr,  thenScope);
                           }
                           return  val;
                   }  else  {
                           Object  val  =  null;
                           ValScope  elseScope  =  scope.child();
                           for  (Instruction  instr  :  eif.elseInstructions)  {
                                   try  {
                                           val  =  eval(instr,  elseScope);
                                   }  catch  (LitilException  e)  {
                                           //erreur
                                   }
                           }
                           return  val;
                   }
           }  else  ...
    Thursday, 23 May, 13

    View Slide

  86. LitiL
    Expr :: Let
    if  (node  instanceof  LetBinding)  {
           LetBinding  let  =  (LetBinding)  node;
           ValScope  letScope  =  scope.child();
           Fn  fn  =  null;
           for  (int  i  =  let.args.size()  -­‐  1;  i  >=  0;  i-­‐-­‐)  {
                   Named  arg  =  let.args.get(i);
                   if  (i  ==  let.args.size()  -­‐  1)  {//last  argument
                           fn  =  new  ChaininLastFn(arg.name,  let.instructions);
                   }  else  {
                           fn  =  new  ChainingFn(arg.name,  fn);
                   }
           }
           fn  =  new  EnvCapturingFnWrapper(fn,  let,  scope);
           scope.define(let.name,  fn);
           return  fn;
    }
    Thursday, 23 May, 13

    View Slide

  87. LitiL
    Expr :: Ap
    if  (node  instanceof  Expr.EAp)  {
           ValScope  ss  =  scope.child();
           Expr.EAp  ap  =  (Expr.EAp)  node;
           Object  fn  =  eval(ap.fn,  ss);
           if  (fn  instanceof  Fn)  {
                   Object  evalArg  =  eval(ap.arg,  ss);
                   return  ((Fn)  fn).eval(evalArg,  ss);
           }
    }
    Thursday, 23 May, 13

    View Slide

  88. LitiL
    What the Fn ?
    public  interface  Fn  {
           public  Object  eval(Object  arg,  ValScope  scope);
    }
    ChainingFn
    argName
    nextFn
    eval:
    •Reprend les arguments précédents {name, value}
    •Rajoute le sien (arg) de façon anonyme
    •Retourne une implem de Fn (argument arg2) qui:
    •Reprend l’arg anonyme et l’indexe sous argName
    •Done la main à next
    ChainingLastFn
    argName
    instructions
    eval:
    •Reprend les arguments précédents {name, value}
    •Reprend l’arg anonyme et l’indexe sous argName
    •Prépare un environnement avec les args
    •Exécute instructions
    •Retourne le résultat
    Thursday, 23 May, 13

    View Slide

  89. LitiL
    And suddently boxes !
    let  add  x  y  =  x  +  y
    Expr.EName
    name:  y
    LetBinding
    name:  add
    type:_
    args:  [x,  y]
    instructions EAp
    fn
    arg
    EAp
    fn
    arg
    Expr.EName
    name:  +
    Expr.EName
    name:  x
    AST
    add  1  2
    ChainingFn
    argName:  x
    next ChainingLastFn
    argName:  y
    instructions
    Trop com
    pliqué*
    * En fait j’avais plus de temps pour préparer les schémas, et puis ça fait longtemps que j’avais pas touché à ça
    Thursday, 23 May, 13

    View Slide

  90. LitiL
    Thursday, 23 May, 13

    View Slide

  91. La suite
    •Refaire la partie records
    •Compilation vers bytecode (rapide)
    •Typeclasses, exhaustivité patmat, GADT ?
    •Intégration Java
    •Inception
    •A moi broadway !
    Thursday, 23 May, 13

    View Slide

  92. LitiL
    github.com/
    jawher/litil
    Thursday, 23 May, 13

    View Slide

  93. LitiL
    jawher.me
    blog.zenika.com
    Thursday, 23 May, 13

    View Slide

  94. LitiL
    Merci !
    Thursday, 23 May, 13

    View Slide