From ec3b20ffbe2ccfbd36139a886a49e2874083135e Mon Sep 17 00:00:00 2001 From: linsy king Date: Tue, 4 Apr 2023 12:21:52 +0800 Subject: [PATCH] cat lang --- examples/syn.cat | 2 +- examples/syn.meow | 7 -- src/expr.lalrpop | 4 +- src/main.rs | 8 ++- src/prog.rs | 165 ++++++++++++++++++++++++++++++++++++++++------ 5 files changed, 154 insertions(+), 32 deletions(-) diff --git a/examples/syn.cat b/examples/syn.cat index 10e9ed9..7de0996 100644 --- a/examples/syn.cat +++ b/examples/syn.cat @@ -23,7 +23,7 @@ eq(x,y) { } if(c,x,y) { - decode let "T$" encode x let "F$" encode y cat x "$" + decode let "T$" encode x let "F$" encode y cat c "$" } in(x,y) { diff --git a/examples/syn.meow b/examples/syn.meow index 6af0f8e..87fa290 100644 --- a/examples/syn.meow +++ b/examples/syn.meow @@ -72,10 +72,3 @@ decode_add(s,x) { ife(x) { eq(x,"") } - -test2() { - "bb" = "g"; - var x = "bc"; - var y = { x }; - y+x -} diff --git a/src/expr.lalrpop b/src/expr.lalrpop index 92e974a..4311c06 100644 --- a/src/expr.lalrpop +++ b/src/expr.lalrpop @@ -12,9 +12,11 @@ Tokz: Box = { } VarName: String = { - r"[a-z]?[a-z0-9_]*" => String::from_str(<>).unwrap() + r"[a-z]?[a-z0-9_]*" => String::from_str(<>).unwrap(), + "!" => String::from_str("!").unwrap() } Literal: String = { r#""[^"]*""# => String::from_str(&<>[1..<>.len() - 1]).unwrap(), + r#"`[^`]*`"# => String::from_str(&<>[1..<>.len() - 1]).unwrap() } diff --git a/src/main.rs b/src/main.rs index c531891..7e40e22 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,6 +8,7 @@ mod prog; extern crate lalrpop_util; lalrpop_mod!(pub parse); // synthesized by LALRPOP +lalrpop_mod!(pub expr); fn main() { let mut argv = args(); @@ -20,6 +21,9 @@ fn main() { let context = &mut Box::new(prog::Context::new()); prog::eval_prog(res, context); + // Print the translated program + prog::trans_layout(context); + // Rustyline let mut rl = rustyline::DefaultEditor::new().unwrap(); loop { @@ -40,11 +44,11 @@ fn main() { break; } } - let expr = parse::ExpressionParser::new() + let expr = &mut expr::ExpressionParser::new() .parse(line.as_str()) .expect("invalid expression!"); // Eval! - let res = prog::eval(&expr, context); + let res = prog::take_one_para(expr, context); println!("{}", res); } } diff --git a/src/prog.rs b/src/prog.rs index 77d29c7..8b4520c 100644 --- a/src/prog.rs +++ b/src/prog.rs @@ -7,7 +7,7 @@ lalrpop_mod!(pub expr); // synthesized by LALRPOP #[derive(Debug, Clone)] struct Rule { - // [x/y]z + // [y/x]z x: String, y: String, } @@ -16,6 +16,7 @@ struct Rule { pub enum Symbol { Variable(String), Macro(Stmt), + VarTok(Vec), } #[derive(Debug, Clone)] @@ -60,10 +61,10 @@ fn apply_rule(x: &String, rules: &Vec) -> String { // apply rules to a string let mut result = x.clone(); for rule in rules.iter().rev() { - if rule.y.is_empty() { + if rule.x.is_empty() { panic!("empty rule detected"); } - result = result.replace(rule.y.as_str(), rule.x.as_str()); + result = result.replace(rule.x.as_str(), rule.y.as_str()); } result } @@ -79,6 +80,7 @@ pub fn eval_macap(macap: &MacAp, context: &Box) -> String { let mac = match mac { Symbol::Variable(_) => panic!("variable used as macro"), Symbol::Macro(x) => x, + Symbol::VarTok(_) => panic!("variable token used as macro"), }; // First evaluate arguments (by value) let args = macap @@ -104,6 +106,7 @@ fn clear_context(context: &Context) -> Context { .filter(|(_, v)| match v { Symbol::Variable(_) => false, Symbol::Macro(_) => true, + Symbol::VarTok(_) => false, }) .map(|(k, v)| (k.clone(), v.clone())) .collect(); @@ -130,6 +133,7 @@ pub fn eval_raw(expr: &Box, context: &Box) -> String { match sym { Symbol::Variable(x) => x.clone(), Symbol::Macro(_) => panic!("macro used as variable"), + Symbol::VarTok(_) => panic!("variable token used as variable"), } } Expr::MacAp(macap) => eval_macap(macap, context), @@ -137,7 +141,7 @@ pub fn eval_raw(expr: &Box, context: &Box) -> String { Expr::IExpr(x) => { let res = eval_raw(x, context); let pres = &mut expr::ExpressionParser::new().parse(&res).unwrap(); - take_one_para(pres, context) + take_one_para(pres, &Box::new(clear_rules(context))) } } } @@ -161,8 +165,8 @@ pub fn eval_block(block: &Box, context: &Box) -> String { } BStmt::MEq(lv, rv) => { lcontext.rules.push(Rule { - x: eval_raw(rv, lcontext), - y: eval_raw(lv, lcontext), + x: eval_raw(lv, lcontext), + y: eval_raw(rv, lcontext), }); } } @@ -170,24 +174,53 @@ pub fn eval_block(block: &Box, context: &Box) -> String { eval(&block.expr, lcontext) } -fn take_one_para(expr: &mut Vec>, context: &Box) -> String { +pub fn take_one_para(expr: &mut Vec>, context: &Box) -> String { // Take one argument from the expression let first = eat_one_para(expr); match &*first { - Tok::Literal(x) => x.clone(), - Tok::Var(x) => { - let sym = context.symbols.get(x).expect("symbol not in scope"); - match sym { - Symbol::Variable(y) => y.clone(), - Symbol::Macro(y) => { - // Apply macro here - let argnum = y.args.len(); - let narg = take_paras(argnum, expr, context); - let macap = MacAp { - name: x.clone(), - args: narg, - }; - eval_macap(&macap, context) + Tok::Literal(lit) => lit.clone(), + Tok::Var(var) => { + match var.as_str() { + "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 mut rules: Vec = (*context.rules.clone()).to_vec(); + rules.push(Rule { x, y }); + let z = take_one_para(expr, context); + // Only here apply rule! + apply_rule(&z, &rules) + } + "cat" => { + // Concatenate expression + let cleancontext = &Box::new(clear_rules(context)); + let x = take_one_para(expr, cleancontext); + let y = take_one_para(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("symbol not in scope"); + match sym { + Symbol::Variable(y) => y.clone(), + Symbol::Macro(y) => { + // Apply macro here + let argnum = y.args.len(); + let narg = take_paras(argnum, expr, &Box::new(clear_rules(context))); + let macap = MacAp { + name: var.clone(), + args: narg, + }; + eval_macap(&macap, context) + } + Symbol::VarTok(_) => panic!("variable token used as variable"), + } } } } @@ -207,3 +240,93 @@ fn eat_one_para(expr: &mut Vec>) -> Box { expr.remove(0); sd } + +pub fn translate(stmt: Stmt, context: &Box) -> String { + // Add para to context var + let newcontext = &mut Box::new(*context.clone()); + for arg in &stmt.args { + newcontext + .symbols + .insert(arg.clone(), Symbol::VarTok(vec![Tok::Var(arg.clone())])); + } + let toks = trans_block(&stmt.block, newcontext); + toks.iter() + .map(|x| match x { + Tok::Literal(y) => { + if y.contains("\"") { + format!("`{}`", y) + } else { + format!("\"{}\"", y) + } + } + Tok::Var(y) => y.clone(), + }) + .collect::>() + .join(" ") +} + +fn trans_expr(expr: &Box, context: &Box) -> Vec { + let tok: &mut Vec = &mut Vec::new(); + match &**expr { + Expr::Literal(x) => tok.push(Tok::Literal(x.clone())), + Expr::Cat(x, y) => { + tok.push(Tok::Var("cat".to_string())); + tok.append(&mut trans_expr(x, context)); + tok.append(&mut trans_expr(y, context)); + } + Expr::Var(x) => { + let sym = context.symbols.get(x).expect("symbol not in scope"); + match sym { + Symbol::VarTok(y) => tok.append(&mut y.clone()), + _ => panic!("symbol not found"), + } + } + Expr::MacAp(x) => { + tok.push(Tok::Var(x.name.clone())); + for a in &x.args { + tok.append(&mut trans_expr(a, context)); + } + } + Expr::Block(x) => tok.append(&mut trans_block(x, &mut context.clone())), + Expr::IExpr(x) => { + tok.push(Tok::Var("!".to_string())); + tok.append(&mut trans_expr(x, context)); + } + } + tok.to_vec() +} + +fn trans_block(block: &Box, context: &mut Box) -> Vec { + // Translate one block to a list of tokens + // let newcontext = &mut Box::new(*context.clone()); + let tok: &mut Vec = &mut Vec::new(); + for bs in &block.bstmts { + match &**bs { + BStmt::VarDefine(name, expr) => { + context + .symbols + .insert(name.clone(), Symbol::VarTok(trans_expr(expr, context))); + } + BStmt::MEq(lv, rv) => { + tok.push(Tok::Var("let".to_string())); + tok.append(&mut trans_expr(lv, context)); + tok.append(&mut trans_expr(rv, context)); + } + } + } + tok.append(&mut trans_expr(&block.expr, context)); + tok.clone() +} + +pub fn trans_layout(context: &Box) { + for (k, v) in &context.symbols { + match v { + Symbol::Macro(x) => { + let args = x.args.join(","); + let res = translate(x.clone(), context); + println!("{}({}){{\n{}\n}}", k, args, res); + } + _ => {} + } + } +}