Browse Source

switch function syntax

Getty Ritter 1 year ago
parent
commit
7d978707da
5 changed files with 75 additions and 51 deletions
  1. 26 21
      src/ast.rs
  2. 4 6
      src/builtins.rs
  3. 13 4
      src/grammar.lalrpop
  4. 27 20
      src/interp.rs
  5. 5 0
      src/lexer.rs

+ 26 - 21
src/ast.rs

@@ -148,12 +148,14 @@ impl ASTArena {
                 writeln!(f, ")")
             }
 
-            Expr::Ap(func, arg) => {
+            Expr::Ap(func, args) => {
                 writeln!(f, "Ap(")?;
                 self.indent(f, depth + 2)?;
                 self.show_expr(&self[*func], f, depth + 2)?;
-                self.indent(f, depth + 2)?;
-                self.show_expr(&self[*arg], f, depth + 2)?;
+                for arg in args {
+                    self.indent(f, depth + 2)?;
+                    self.show_expr(&self[*arg], f, depth + 2)?;
+                }
                 self.indent(f, depth)?;
                 writeln!(f, ")")
             }
@@ -214,7 +216,10 @@ impl ASTArena {
                 writeln!(f, "Fun(")?;
                 for case in cases {
                     self.indent(f, depth + 2)?;
-                    self.show_pat(&case.pat, f)?;
+                    for pat in case.pats.iter() {
+                        self.show_pat(pat, f)?;
+                        writeln!(f, ", ")?;
+                    }
                     writeln!(f, " =>")?;
                     self.indent(f, depth + 4)?;
                     self.show_expr(&self[case.expr], f, depth + 4)?;
@@ -223,20 +228,20 @@ impl ASTArena {
                 writeln!(f, ")")
             }
 
-            Expr::Case(expr, cases) => {
-                writeln!(f, "Case(")?;
-                self.indent(f, depth)?;
-                self.show_expr(&self[*expr], f, depth)?;
-                for case in cases {
-                    self.indent(f, depth + 2)?;
-                    self.show_pat(&case.pat, f)?;
-                    writeln!(f, " =>")?;
-                    self.indent(f, depth + 4)?;
-                    self.show_expr(&self[case.expr], f, depth + 4)?;
-                }
-                self.indent(f, depth)?;
-                writeln!(f, ")")
-            }
+            // Expr::Case(expr, cases) => {
+            //     writeln!(f, "Case(")?;
+            //     self.indent(f, depth)?;
+            //     self.show_expr(&self[*expr], f, depth)?;
+            //     for case in cases {
+            //         self.indent(f, depth + 2)?;
+            //         self.show_pat(&case.pat, f)?;
+            //         writeln!(f, " =>")?;
+            //         self.indent(f, depth + 4)?;
+            //         self.show_expr(&self[case.expr], f, depth + 4)?;
+            //     }
+            //     self.indent(f, depth)?;
+            //     writeln!(f, ")")
+            // }
         }
     }
 }
@@ -315,12 +320,12 @@ pub enum Expr {
     Cat(Vec<ExprRef>),
     Chc(Vec<Choice>),
     Lit(Literal),
-    Ap(ExprRef, ExprRef),
+    Ap(ExprRef, Vec<ExprRef>),
     Tup(Vec<ExprRef>),
     Let(bool, Name, ExprRef, ExprRef),
     Fun(Vec<Case>),
     Range(ExprRef, ExprRef),
-    Case(ExprRef, Vec<Case>),
+    // Case(ExprRef, Vec<Case>),
     Nil,
 }
 
@@ -340,7 +345,7 @@ impl ExprId {
 /// A single case in an anonymous function or `case` statement
 #[derive(Debug, Clone)]
 pub struct Case {
-    pub pat: Pat,
+    pub pats: Vec<Pat>,
     pub expr: ExprRef,
 }
 

+ 4 - 6
src/builtins.rs

@@ -167,12 +167,10 @@ pub fn builtins() -> Vec<BuiltinFunc> {
 
                     let mut result = init.clone();
                     for t in tup.as_tup(&state.ast.borrow())? {
-                        let partial =
-                            state.eval_closure(func.as_closure(&state.ast.borrow())?, result)?;
-                        result =
-                            Thunk::Value(state.eval_closure(
-                                partial.as_closure(&state.ast.borrow())?,
-                                t.clone(),
+                        result = Thunk::Value(
+                            state.eval_closure(
+                                func.as_closure(&state.ast.borrow())?,
+                                vec![result, t.clone()],
                             )?);
                     }
 

+ 13 - 4
src/grammar.lalrpop

@@ -14,6 +14,8 @@ extern {
         ")" => Token::RPar,
         "{" => Token::LCurl,
         "}" => Token::RCurl,
+        "[" => Token::LBrac,
+        "]" => Token::RBrac,
         "|" => Token::Pipe,
         ":" => Token::Colon,
         "," => Token::Comma,
@@ -103,7 +105,11 @@ pub Term: ExprId = {
 };
 
 pub Branch: ExprId = {
-    <l:Located<Branch>> "." <r:Located<Subbranch>> => ast.add_expr(Expr::Ap(l, r)),
+//    <l:Located<Branch>> "." <r:Located<Subbranch>> => ast.add_expr(Expr::Ap(l, r)),
+    <l:Located<Branch>> "[" <mut rs:Located<(<Expr> ",")>*> <r:Located<Expr>> "]" => {
+        rs.push(r);
+        ast.add_expr(Expr::Ap(l, rs))
+    },
     <Subbranch> => <>,
 };
 
@@ -127,8 +133,8 @@ pub Leaf: ExprId = {
         ast.add_expr(Expr::Let(fixed.is_some(), name, e1, e2)),
     "{" <cs:Cases> "}" =>
         ast.add_expr(Expr::Fun(cs)),
-    "case" <e:Located<Expr>> "in" "{" <cs:Cases> "}" =>
-        ast.add_expr(Expr::Case(e, cs)),
+//    "case" <e:Located<Expr>> "in" "{" <cs:Cases> "}" =>
+//        ast.add_expr(Expr::Case(e, cs)),
     "(" <e:Expr> ")" => e,
 };
 
@@ -140,7 +146,10 @@ pub Cases: Vec<Case> = {
 };
 
 pub Case: Case = {
-    <pat:Pat> "=>" <expr:Located<Expr>> => Case { pat, expr },
+    "[" <mut pats:(<Pat> ",")*> <pat:Pat> "]" "=>" <expr:Located<Expr>> => {
+        pats.push(pat);
+        Case { pats, expr }
+    }
 };
 
 pub Pat: Pat = {

+ 27 - 20
src/interp.rs

@@ -538,14 +538,16 @@ impl State {
             // either a closure (i.e. the result of evaluating a
             // function) or a builtin, and then handle it
             // appropriately
-            Expr::Ap(func, val) => match self.eval(*func, env)? {
+            Expr::Ap(func, vals) => match self.eval(*func, env)? {
                 Value::Closure(c) => {
-                    let scrut = Thunk::Expr(*val, env.clone());
-                    self.eval_closure(&c, scrut)
+                    let scruts = vals.iter().map(|v| {
+                        Thunk::Expr(*v, env.clone())
+                    }).collect();
+                    self.eval_closure(&c, scruts)
                 }
                 Value::Builtin(b) => {
                     let builtin = &self.builtins[b.idx];
-                    (builtin.callback)(self, *val, env)
+                    (builtin.callback)(self, vals[0], env)
                 }
                 _ => bail!("Bad function: {:?}", func),
             },
@@ -569,13 +571,13 @@ impl State {
                 self.eval(*body, &Some(new_scope))
             }
 
-            Expr::Case(scrut, _) => {
-                let closure = Closure {
-                    func: expr_ref,
-                    scope: env.clone(),
-                };
-                self.eval_closure(&closure, Thunk::Expr(*scrut, env.clone()))
-            }
+            // Expr::Case(scrut, _) => {
+            //     let closure = Closure {
+            //         func: expr_ref,
+            //         scope: env.clone(),
+            //     };
+            //     self.eval_closure(&closure, Thunk::Expr(*scrut, env.clone()))
+            // }
         }
     }
 
@@ -596,7 +598,7 @@ impl State {
     /// careful is here:
     ///
     /// ```ignore
-    /// {Foo => "1"; Foo => "2"; _ => "..."}.(Foo | Bar)
+    /// {[Foo] => "1"; [Foo] => "2"; _ => "..."}[Foo | Bar]
     /// ```
     ///
     /// It should be impossible to get `"2"` in this case. That means
@@ -605,7 +607,7 @@ impl State {
     /// contain non-determinism:
     ///
     /// ```ignore
-    /// {<Foo, x> => x x "!"; <Bar, x> => x x "?"}.<Foo | Bar, "a" | "b">
+    /// {[<Foo, x>] => x x "!"; [<Bar, x>] => x x "?"}[<Foo | Bar, "a" | "b">]
     /// ```
     ///
     /// The above program should print one of "aa!", "bb!", "aa?", or
@@ -622,25 +624,30 @@ impl State {
     /// function to mutably replace it with progressively more
     /// evaluated versions of the same expression, and then that's the
     /// thing we put into scope in the body of the function.
-    pub fn eval_closure(&self, closure: &Closure, mut scrut: Thunk) -> Result<Value, Error> {
+    pub fn eval_closure(&self, closure: &Closure, mut scruts: Vec<Thunk>) -> Result<Value, Error> {
         let ast = self.ast.borrow();
         let cases = match &ast[closure.func] {
             Expr::Fun(cases) => cases,
-            Expr::Case(_, cases) => cases,
+            // Expr::Case(_, cases) => cases,
             // see the note attached to the definition of `Closure`
             _ => bail!("INVARIANT FAILED"),
         };
 
         // for each case
-        for c in cases {
+        'cases: for c in cases {
             // build a set of potential bindings, which `match_pat`
             // will update if it finds matching variables
             let mut bindings = Vec::new();
-            if !self.match_pat(&c.pat, &mut scrut, &mut bindings)? {
-                // if we didn't match, we don't care about any
-                // bindings we've found: simply skip it
+            if scruts.len() != c.pats.len() {
                 continue;
             }
+            for (scrut, pat) in scruts.iter_mut().zip(c.pats.iter()) {
+                if !self.match_pat(&pat, scrut, &mut bindings)? {
+                    // if we didn't match, we don't care about any
+                    // bindings we've found: simply skip it
+                    continue 'cases;
+                }
+            }
 
             // build a new scope from the bindings discovered
             let mut new_scope = HashMap::new();
@@ -658,7 +665,7 @@ impl State {
         }
 
         // we couldn't find a matching pattern, so throw an error
-        bail!("No pattern in {:?} matched {:?}", cases, scrut);
+        bail!("No pattern in {:?} matched {:?}", cases, scruts);
     }
 
     /// attempt to match the thunk `scrut` against the pattern

+ 5 - 0
src/lexer.rs

@@ -90,6 +90,11 @@ pub enum Token<'a> {
     #[token("}")]
     RCurl,
 
+    #[token("[")]
+    LBrac,
+    #[token("]")]
+    RBrac,
+
     #[token("|")]
     Pipe,