From b986dacf4a22fa1340f7dd7d1e223c559844edbf Mon Sep 17 00:00:00 2001 From: linsy king Date: Wed, 5 Apr 2023 22:14:04 +0800 Subject: [PATCH] feat: lazycat --- examples/iexpr.meow | 132 ------------------------------- examples/syn.cat | 43 +++++++--- examples/syn.meow | 187 ++++++++++++++++++++++++++++++++++++++++---- examples/token.cat | 2 - examples/token.meow | 9 --- src/cat.rs | 95 +++++++++++++++------- src/expr.lalrpop | 2 +- src/parse.lalrpop | 2 +- src/prog.rs | 12 ++- 9 files changed, 283 insertions(+), 201 deletions(-) delete mode 100644 examples/iexpr.meow delete mode 100644 examples/token.cat delete mode 100644 examples/token.meow diff --git a/examples/iexpr.meow b/examples/iexpr.meow deleted file mode 100644 index 62963f6..0000000 --- a/examples/iexpr.meow +++ /dev/null @@ -1,132 +0,0 @@ - -digit(x) { - "1" = "S0"; - "2" = "SS0"; - "3" = "SSS0"; - "4" = "SSSS0"; - "5" = "SSSSS0"; - "6" = "SSSSSS0"; - "7" = "SSSSSSS0"; - "8" = "SSSSSSSS0"; - "9" = "SSSSSSSSS0"; - x -} - -exp(x,y) { - var sm = { - " 0" = ""; - "S" = `"`+x+`" `; - y - }; - var pre = { - "S" = "mul "; - "S0" = ""; - y - }; - !(pre + sm) -} - -nrep(x,p) { - "0" = p; - "1" = p; - "2" = p; - "3" = p; - "4" = p; - "5" = p; - "6" = p; - "7" = p; - "8" = p; - "9" = p; - x -} - -len(x) { - var s = nrep(x, "S"); - s + "0" -} - -ten() { - succ(digit("9")) -} - -revdigit(x) { - "S0" = "1"; - "SS0" = "2"; - "SSS0" = "3"; - "SSSS0" = "4"; - "SSSSS0" = "5"; - "SSSSSS0" = "6"; - "SSSSSSS0" = "7"; - "SSSSSSSS0" = "8"; - "SSSSSSSSS0" = "9"; - x -} - -head(x) { - var s = { - "$0" = "S"; - "$1" = "SS"; - "$2" = "SSS"; - "$3" = "SSSS"; - "$4" = "SSSSS"; - "$5" = "SSSSSS"; - "$6" = "SSSSSSS"; - "$7" = "SSSSSSSS"; - "$8" = "SSSSSSSSS"; - "$9" = "SSSSSSSSSS"; - "$" + x - }; - var rep = nrep(s, ""); - pred(rep + "0") -} - -num(x) { - var nl = pred(len(x)); - var hd = head(x); - var hdnum = revdigit(hd); - var remain = { - "$" + hdnum = ""; - "$" + x - }; - !(if( - eq(len(x), "S0"), - spack(digit(x)), - `add mul "` + hd + `" exp ten "` + nl + `" ` + `num "` + remain + `"` - )) -} - -spack(x) { - `"` + x + `"` -} - -leq(x,y) { - in(x,y) -} - -show(x) { - var la = { - "SSSSSSSSSS" = ""; - x - }; - var rem = { - "SSSSSSSSSS" = "S"; - sub(x,la) - }; - !(if( - leq(len(x), digit("9")), - spack(revdigit(x)), - `cat show "` + rem + `" revdigit "` + la + `"` - )) -} - -fib(x) { - if( - eq(x, zero()), - zero(), - !(if( - leq(x, num("2")), - spack(num("1")), - `add fib pred x fib pred pred x` - )) - ) -} diff --git a/examples/syn.cat b/examples/syn.cat index 9cab8a4..4b2ad1f 100644 --- a/examples/syn.cat +++ b/examples/syn.cat @@ -1,20 +1,41 @@ -true = "T" -false = "F" -zero = "0" +true = "T" +false = "F" +0 = "0" +1 = "S0" +2 = "SS0" +3 = "SSS0" +4 = "SSSS0" +5 = "SSSSS0" +6 = "SSSSSS0" +7 = "SSSSSSS0" +8 = "SSSSSSSS0" +9 = "SSSSSSSSS0" +10 = "SSSSSSSSSS0" succ x = cat "S" x -pred x = let "S0" "0" x -add x y = let "0" y x -sub x y = let y "0" x -mul x y = let "S" let "0" "" y x +pred x = let 1 0 x +add x y = let 0 y x +sub x y = let y 0 x +mul x y = let "S" let 0 "" y x dr x y z = let y x let x y z encode s = cat cat "#$" let "$" "\$" let "#" "\#" let "\" "\\" s "$#" -decode s = let "\\" "\" let "\$" "$" let "\#" "#" let "_#" "" let "_$" "" s +decode s = let "\\" "\" let "\#" "#" let "\$" "$" let "$#" "" let "#$" "" s encat x y = cat let "#$" "" x let "$#" "" y enraw s = let "#$" "" let "$#" "" encode s enrep s x y = let enraw x y s -rep2 s x xr y yr = decode let "x$" enraw xr let "y$" enraw yr enrep enrep encode s x "x$" y "y$" +rep2 s x xr y yr = decode let "x#" enraw xr let "y#" enraw yr enrep enrep encode s x "x#" y "y#" eq x y = let encode x "F" let encode y "T" encode x -if c x y = decode let "T$" encode x let "F$" encode y cat c "$" +if c x y = decode let "T#" encode x let "F#" encode y cat c "#" in x y = not eq y let x "" y not x = if x false true -ife x = eq x "" +eq0 x = eq x 0 +factorial x = if eq x 1 1 mul x factorial pred x +digit x = let "1" 1 let "2" 2 let "3" 3 let "4" 4 let "5" 5 let "6" 6 let "7" 7 let "8" 8 let "9" 9 x +exp x y = if eq0 y 1 mul x exp x pred y +nrep x p = let "0" p let "1" p let "2" p let "3" p let "4" p let "5" p let "6" p let "7" p let "8" p let "9" p x +len x = cat nrep x "S" 0 +revdigit x = let 1 "1" let 2 "2" let 3 "3" let 4 "4" let 5 "5" let 6 "6" let 7 "7" let 8 "8" let 9 "9" x +head x = pred cat nrep let "$0" let "0" "" cat "S" 0 let "$1" let "0" "" cat "S" 1 let "$2" let "0" "" cat "S" 2 let "$3" let "0" "" cat "S" 3 let "$4" let "0" "" cat "S" 4 let "$5" let "0" "" cat "S" 5 let "$6" let "0" "" cat "S" 6 let "$7" let "0" "" cat "S" 7 let "$8" let "0" "" cat "S" 8 let "$9" let "0" "" cat "S" 9 cat "$" x "" 0 +num x = if eq len x 1 digit x add mul head x exp succ 9 pred len x num let cat "$" revdigit head x "" cat "$" x +leq x y = in x y +show x = if leq len x 9 revdigit x cat show let "SSSSSSSSSS" "S" sub x let "SSSSSSSSSS" "" x revdigit let "SSSSSSSSSS" "" x +fib x = if eq0 x 0 if leq x 2 1 add fib pred x fib pred pred x diff --git a/examples/syn.meow b/examples/syn.meow index b1749de..0926d7f 100644 --- a/examples/syn.meow +++ b/examples/syn.meow @@ -2,27 +2,47 @@ true() {"T"} false() {"F"} -zero() {"0"} +0() {"0"} + +1() {"S0"} + +2() {"SS0"} + +3() {"SSS0"} + +4() {"SSSS0"} + +5() {"SSSSS0"} + +6() {"SSSSSS0"} + +7() {"SSSSSSS0"} + +8() {"SSSSSSSS0"} + +9() {"SSSSSSSSS0"} + +10() {"SSSSSSSSSS0"} succ(x) {"S"+x} pred(x) { - "S0" = "0"; + 1() = 0(); x } add (x,y) { - "0" = y; + 0() = y; x } sub (x,y) { - y = "0"; + y = 0(); x } mul(x,y) { - "S" = {"0"=""; y}; + "S" = {0()=""; y}; x } @@ -70,11 +90,11 @@ enrep(s,x,y) { } rep2(s,x,xr,y,yr) { - var repx = enrep(encode(s),x,"x$"); - var repy = enrep(repx,y,"y$"); + var repx = enrep(encode(s),x,"x#"); + var repy = enrep(repx,y,"y#"); decode({ - "x$" = enraw(xr); - "y$" = enraw(yr); + "x#" = enraw(xr); + "y#" = enraw(yr); repy }) } @@ -86,10 +106,10 @@ eq(x,y) { } if(c,x,y) { - var cc = c + "$"; + var cc = c + "#"; var enc = { - "T$" = encode(x); - "F$" = encode(y); + "T#" = encode(x); + "F#" = encode(y); cc }; decode(enc) @@ -103,6 +123,145 @@ not(x) { if(x, false(), true()) } -ife(x) { - eq(x,"") +eq0(x) { + eq(x, 0()) +} + +factorial(x) { + if( + eq(x, 1()), + 1(), + mul( + x, + factorial(pred(x)) + ) + ) +} + +digit(x) { + "1" = 1(); + "2" = 2(); + "3" = 3(); + "4" = 4(); + "5" = 5(); + "6" = 6(); + "7" = 7(); + "8" = 8(); + "9" = 9(); + x +} + +exp(x,y) { + if( + eq0(y), + 1(), + mul( + x, + exp(x, pred(y)) + ) + ) +} + +nrep(x,p) { + "0" = p; + "1" = p; + "2" = p; + "3" = p; + "4" = p; + "5" = p; + "6" = p; + "7" = p; + "8" = p; + "9" = p; + x +} + +len(x) { + var s = nrep(x, "S"); + s + 0() +} + +revdigit(x) { + 1() = "1"; + 2() = "2"; + 3() = "3"; + 4() = "4"; + 5() = "5"; + 6() = "6"; + 7() = "7"; + 8() = "8"; + 9() = "9"; + x +} + +head(x) { + var s = { + "$0" = {"0"=""; "S" + 0()}; + "$1" = {"0"=""; "S" + 1()}; + "$2" = {"0"=""; "S" + 2()}; + "$3" = {"0"=""; "S" + 3()}; + "$4" = {"0"=""; "S" + 4()}; + "$5" = {"0"=""; "S" + 5()}; + "$6" = {"0"=""; "S" + 6()}; + "$7" = {"0"=""; "S" + 7()}; + "$8" = {"0"=""; "S" + 8()}; + "$9" = {"0"=""; "S" + 9()}; + "$" + x + }; + var rep = nrep(s, ""); + pred(rep + 0()) +} + +num(x) { + var ten = succ(9()); + var nl = pred(len(x)); + var hd = head(x); + var hdnum = revdigit(hd); + var remain = { + "$" + hdnum = ""; + "$" + x + }; + if( + eq(len(x), 1()), + digit(x), + add( + mul(hd, exp(ten, nl)), + num(remain) + ) + ) +} + +leq(x,y) { + in(x,y) +} + +show(x) { + var la = { + "SSSSSSSSSS" = ""; + x + }; + var rem = { + "SSSSSSSSSS" = "S"; + sub(x,la) + }; + if( + leq(len(x), 9()), + revdigit(x), + show(rem) + revdigit(la) + ) +} + +fib(x) { + if( + eq0(x), + 0(), + if( + leq(x, 2()), + 1(), + add( + fib(pred(x)), + fib(pred(pred(x))) + ) + ) + ) } diff --git a/examples/token.cat b/examples/token.cat deleted file mode 100644 index 87f4910..0000000 --- a/examples/token.cat +++ /dev/null @@ -1,2 +0,0 @@ -eat x w = x -head x = ! cat cat `eat "` let " " `" eat "` x `" ""` diff --git a/examples/token.meow b/examples/token.meow deleted file mode 100644 index 6f8e06b..0000000 --- a/examples/token.meow +++ /dev/null @@ -1,9 +0,0 @@ -eat(x,w) { - x -} - -head(x) { - var xx = {" " = `" eat "`; x}; - !(`eat "` + xx + `" ""`) -} - diff --git a/src/cat.rs b/src/cat.rs index 01ac9f2..2e27b24 100644 --- a/src/cat.rs +++ b/src/cat.rs @@ -3,22 +3,18 @@ use std::collections::HashMap; use crate::ast::Tok; use crate::eval::*; -// Cat Evaluater -// Given a cat expression, evaluate it to a string -// Also given a context - -lalrpop_mod!(pub expr); +// lazycat Evaluater #[derive(Debug, Clone)] struct Rule { // [y/x]z x: String, - y: String, + y: Vec, } #[derive(Debug, Clone)] pub enum Symbol { - Variable(String), + Variable(Vec), Macro(Macro), } @@ -36,7 +32,7 @@ impl Context { } } } -fn eval_macap(mac: &Macro, args: &Vec, context: &Box) -> String { +fn eval_macap(mac: &Macro, args: &Vec>, context: &Box) -> String { let mut newcontext = *context.clone(); // add vars to the context for (result, name) in args.iter().zip(mac.args.iter()) { @@ -45,7 +41,7 @@ fn eval_macap(mac: &Macro, args: &Vec, context: &Box) -> String .insert(name.clone(), Symbol::Variable(result.clone())); } let block = &mut mac.body.clone(); - take_one_para(block, &Box::new(newcontext)) + eval_strict(block, &Box::new(newcontext)) } fn clear_context(context: &Context) -> Context { @@ -70,19 +66,21 @@ fn clear_rules(context: &Context) -> Context { newcontext } -fn apply_rule(x: &String, rules: &Vec) -> String { +fn apply_rule(x: &String, rules: &Vec, context: &Box) -> String { // apply rules to a string let mut result = x.clone(); for rule in rules.iter().rev() { if rule.x.is_empty() { panic!("empty rule detected"); } - result = result.replace(rule.x.as_str(), rule.y.as_str()); + if result.contains(rule.x.as_str()) { + result = result.replace(rule.x.as_str(), &eval_strict(&mut rule.y.clone(), context)); + } } result } -fn take_one_para(expr: &mut Vec, context: &Box) -> String { +fn eval_strict(expr: &mut Vec, context: &Box) -> String { // Take one argument from the expression let first = eat_one_para(expr); match &first { @@ -92,26 +90,65 @@ fn take_one_para(expr: &mut Vec, context: &Box) -> String { "let" => { // Let expression // let x y z = [y/x]z - let x = take_one_para(expr, context); - let y = take_one_para(expr, context); + let x = eval_strict(expr, context); + let y = eval_lazy(expr, context); let mut rules: Vec = (*context.rules.clone()).to_vec(); rules.push(Rule { x, y }); - let z = take_one_para(expr, context); + let z = eval_strict(expr, context); // Only here apply rule! - apply_rule(&z, &rules) + apply_rule(&z, &rules, context) } "cat" => { // Concatenate expression let cleancontext = &Box::new(clear_rules(context)); - let x = take_one_para(expr, cleancontext); - let y = take_one_para(expr, cleancontext); + let x = eval_strict(expr, cleancontext); + let y = eval_strict(expr, cleancontext); x + y.as_str() } - "!" => { - // Eval expression - let exp = take_one_para(expr, context); - let pres = &mut expr::ExpressionParser::new().parse(&exp).unwrap(); - take_one_para(pres, &Box::new(clear_rules(context))) + _ => { + let sym = context + .symbols + .get(var) + .expect(format!("symbol {} not in scope", var).as_str()); + match &sym { + Symbol::Variable(y) => { + eval_strict(&mut y.clone(), &Box::new(clear_rules(context))) + } + Symbol::Macro(y) => { + // Apply macro here + let argnum = y.args.len(); + let narg = + take_paras_lazy(argnum, expr, &Box::new(clear_rules(context))); + eval_macap(y, &narg, &Box::new(clear_context(context))) + } + } + } + } + } + } +} + +fn eval_lazy(expr: &mut Vec, context: &Box) -> Vec { + // Take one argument from the expression + let first = eat_one_para(expr); + match &first { + Tok::Literal(lit) => vec![Tok::Literal(lit.clone())], + Tok::Var(var) => { + match var.as_str() { + "let" => { + // Let expression + // let x y z = [y/x]z + let x = eval_lazy(expr, context); + let y = eval_lazy(expr, context); + let z = eval_lazy(expr, context); + [vec![first], x, y, z].concat() + } + "cat" => { + // Concatenate expression + // let cleancontext = &Box::new(clear_rules(context)); + let x = eval_lazy(expr, context); + let y = eval_lazy(expr, context); + [vec![first], x, y].concat() } _ => { let sym = context @@ -123,8 +160,8 @@ fn take_one_para(expr: &mut Vec, context: &Box) -> String { Symbol::Macro(y) => { // Apply macro here let argnum = y.args.len(); - let narg = take_paras(argnum, expr, &Box::new(clear_rules(context))); - eval_macap(y, &narg, &Box::new(clear_context(context))) + let narg = take_paras_lazy(argnum, expr, context); + [vec![first], narg.concat()].concat() } } } @@ -133,11 +170,11 @@ fn take_one_para(expr: &mut Vec, context: &Box) -> String { } } -fn take_paras(n: usize, expr: &mut Vec, context: &Box) -> Vec { +fn take_paras_lazy(n: usize, expr: &mut Vec, context: &Box) -> Vec> { // Take n arguments from the expression (0..n) - .map(|_| take_one_para(expr, context)) - .collect::>() + .map(|_| eval_lazy(expr, context)) + .collect::>>() } fn eat_one_para(expr: &mut Vec) -> Tok { @@ -154,5 +191,5 @@ pub fn eval(macros: &HashMap, expr: &Vec) -> String { context.symbols.insert(k.clone(), Symbol::Macro(v.clone())); } let exp = &mut expr.clone(); - take_one_para(exp, &Box::new(context)) + eval_strict(exp, &Box::new(context)) } diff --git a/src/expr.lalrpop b/src/expr.lalrpop index 1463c94..3e8842a 100644 --- a/src/expr.lalrpop +++ b/src/expr.lalrpop @@ -12,7 +12,7 @@ Tokz: Tok = { } VarName: String = { - r"[a-z]?[a-z0-9_]*" => String::from_str(<>).unwrap(), + r"[a-z0-9_]*" => String::from_str(<>).unwrap(), } Literal: String = { diff --git a/src/parse.lalrpop b/src/parse.lalrpop index ca54a51..124ec72 100644 --- a/src/parse.lalrpop +++ b/src/parse.lalrpop @@ -61,7 +61,7 @@ VarDef: (String, String) = { } VarName: String = { - r"[a-z]?[a-z0-9_]*" => String::from_str(<>).unwrap() + r"[a-z0-9_]*" => String::from_str(<>).unwrap() } Literal: String = { diff --git a/src/prog.rs b/src/prog.rs index 0e1dc56..56bf9fe 100644 --- a/src/prog.rs +++ b/src/prog.rs @@ -84,7 +84,10 @@ fn trans_expr(expr: &Box, context: &Box) -> Vec { tok.append(&mut trans_expr(y, context)); } Expr::Var(x) => { - let vartok = context.variables.get(x).expect("variable not in scope"); + let vartok = context + .variables + .get(x) + .expect(format!("variable {} not in scope", x).as_str()); tok.append(&mut vartok.clone()) } Expr::MacAp(x) => { @@ -126,7 +129,12 @@ pub fn translate(prog: &Box, context: &Box) -> String { Prog::Stmts(x, y) => { let v = context.macros.get(x.name.as_str()).unwrap(); let res = compose_tok(&v.body); - let output = format!("{} {} = {}\n", x.name, x.args.join(" "), res); + let output; + if x.args.is_empty() { + output = format!("{} = {}\n", x.name, res); + } else { + output = format!("{} {} = {}\n", x.name, x.args.join(" "), res); + } output + &translate(y, context) } }