From fd3d3a2b8593261caa3c8b44bbcf7eefff26df14 Mon Sep 17 00:00:00 2001 From: linsy king Date: Mon, 3 Apr 2023 20:24:35 +0800 Subject: [PATCH] fix: - Use symbol instead of two different items --- examples/syn.meow | 16 ++++++++++++++- src/main.rs | 18 +++++++++++++++-- src/prog.rs | 50 ++++++++++++++++++++++++++++++++--------------- 3 files changed, 65 insertions(+), 19 deletions(-) diff --git a/examples/syn.meow b/examples/syn.meow index a4d141c..87fa290 100644 --- a/examples/syn.meow +++ b/examples/syn.meow @@ -52,9 +52,23 @@ if(c,x,y) { "F$" = encode(y); cc }; - decode(enc) + decode(enc) } in(x,y) { eq(y,{x=""; y}) } + +encode_add(s,x) { + x = "\" + x; + s +} + +decode_add(s,x) { + "\" + x = x; + s +} + +ife(x) { + eq(x,"") +} diff --git a/src/main.rs b/src/main.rs index 0802ce5..c531891 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,4 @@ +use rustyline::error::ReadlineError; use std::env::args; mod ast; @@ -18,13 +19,26 @@ fn main() { .expect("unexpected token!"); let context = &mut Box::new(prog::Context::new()); prog::eval_prog(res, context); + + // Rustyline let mut rl = rustyline::DefaultEditor::new().unwrap(); loop { - let mut line = String::new(); + let line: String; let readline = rl.readline("> "); match readline { Ok(l) => line = l.trim().to_string(), - Err(_) => println!("invalid input"), + Err(ReadlineError::Interrupted) => { + println!("Interrupted"); + break; + } + Err(ReadlineError::Eof) => { + println!("EOF"); + break; + } + Err(_) => { + println!("invalid input"); + break; + } } let expr = parse::ExpressionParser::new() .parse(line.as_str()) diff --git a/src/prog.rs b/src/prog.rs index 8238190..f1fd1df 100644 --- a/src/prog.rs +++ b/src/prog.rs @@ -11,18 +11,22 @@ struct Rule { y: String, } +#[derive(Debug, Clone)] +pub enum Symbol { + Variable(String), + Macro(Stmt), +} + #[derive(Debug, Clone)] pub struct Context { - variables: HashMap, - macros: HashMap, + symbols: HashMap, rules: Vec, } impl Context { pub fn new() -> Self { Context { - variables: HashMap::new(), - macros: HashMap::new(), + symbols: HashMap::new(), rules: vec![], } } @@ -45,13 +49,19 @@ pub fn eval_prog(prog: Box, context: &mut Box) { pub fn eval_stmt(stmt: Stmt, context: &mut Box) { // Add a macro to the context // Context will be modified - context.as_mut().macros.insert(stmt.name.clone(), stmt); + context + .as_mut() + .symbols + .insert(stmt.name.clone(), Symbol::Macro(stmt)); } 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() { + panic!("empty rule detected"); + } result = result.replace(rule.y.as_str(), rule.x.as_str()); } result @@ -66,16 +76,23 @@ pub fn eval_raw(expr: &Box, context: &Box) -> String { Expr::Var(x) => // use variables { - context - .variables - .get(x) - .expect("variable not in scope") - .clone() + let sym = context.symbols.get(x).expect("variable not in scope"); + match sym { + Symbol::Variable(x) => x.clone(), + Symbol::Macro(_) => panic!("macro used as variable"), + } } Expr::MacAp(macap) => { let mut newcontext: Context = *context.clone(); // macro application - let mac = context.macros.get(&macap.name).expect("macro not in scope"); + let mac = context + .symbols + .get(&macap.name) + .expect("macro not in scope"); + let mac = match mac { + Symbol::Variable(_) => panic!("variable used as macro"), + Symbol::Macro(x) => x, + }; // First evaluate arguments (by value) let args = macap .args @@ -84,7 +101,9 @@ pub fn eval_raw(expr: &Box, context: &Box) -> String { .collect::>(); // add vars to the context for (result, name) in args.iter().zip(mac.args.iter()) { - newcontext.variables.insert(name.clone(), result.clone()); + newcontext + .symbols + .insert(name.clone(), Symbol::Variable(result.clone())); } eval_block(&mac.block, &Box::new(newcontext)) } @@ -117,8 +136,8 @@ pub fn eval_block(block: &Box, context: &Box) -> String { match &**bs { BStmt::VarDefine(name, expr) => { lcontext - .variables - .insert(name.clone(), eval_raw(expr, lcontext)); + .symbols + .insert(name.clone(), Symbol::Variable(eval_raw(expr, lcontext))); } BStmt::MEq(lv, rv) => { lcontext.rules.push(Rule { @@ -141,8 +160,7 @@ mod tests { fn eval_test(expr: &Expr) -> String { let context = Box::new(super::Context { - variables: HashMap::new(), - macros: HashMap::new(), + symbols: HashMap::new(), rules: vec![], }); let newexpr = Box::new(expr.clone());