From 4aa9341bf33d7865754c230289361140a99bc789 Mon Sep 17 00:00:00 2001 From: Seoxi Ryouko Date: Tue, 7 Jul 2026 13:47:45 -0500 Subject: [PATCH] We have SSA --- src/interpret.rs | 122 ++++++++++++++++++++++++++++++++++++++++++ src/lex.rs | 22 +++++--- src/lex/operator.rs | 2 +- src/main.rs | 12 +++-- src/parse.rs | 126 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 273 insertions(+), 11 deletions(-) create mode 100644 src/interpret.rs create mode 100644 src/parse.rs diff --git a/src/interpret.rs b/src/interpret.rs new file mode 100644 index 0000000..8604634 --- /dev/null +++ b/src/interpret.rs @@ -0,0 +1,122 @@ +use crate::lex::{ TeaValue, Operator }; +use crate::parse::{ ASTNode, Value }; + +use std::collections::HashMap; + +#[derive(Debug)] +enum VarType { + Const(TeaValue), + //Mut, +} + +#[derive(Debug)] +pub struct InterpreterError { + description: String, +} + +impl InterpreterError { + pub fn new(e: &str) -> Self { + Self { + description: e.to_owned(), + } + } +} + +macro_rules! some_or_error { + ($matchee:expr, $ret:expr) => { + match $matchee { + Some(s) => s, + _ => return Err($ret), + } + } +} + +fn get_value(v: Value, scope: &HashMap) -> Result { + match v { + Value::Lit(t) => Ok(t), + Value::Id(s) => match scope.get(&s) { + None => Err(InterpreterError::new("undefined variable")), + Some(VarType::Const(t)) => Ok(t.clone()), + }, + } +} + +macro_rules! apply_op { + ($a:ident, $b:ident, $op:tt) => { + match ($a, $b) { + (TeaValue::Float(aa), TeaValue::Float(bb)) => { + TeaValue::Float(aa $op bb) + }, + (TeaValue::Int(aa), TeaValue::Int(bb)) => { + TeaValue::Int(aa $op bb) + }, + //(TeaValue::Uint(aa), TeaValue::Uint(bb)) => { + // TeaValue::Uint(aa $op bb) + //}, + _ => panic!("Invalid types"), + } + } +} + +pub fn interpret(ast: Vec) -> Result, InterpreterError> { + let mut ast = ast.clone(); + ast.reverse(); + let mut stack = vec![]; + let mut global_scope: HashMap = HashMap::new(); + loop { + match ast.pop() { + None => return Ok(stack), + Some(ASTNode::Val(v)) => stack.push(v), + Some(ASTNode::BinOp(op)) => { + let b = some_or_error!(stack.pop(), InterpreterError::new("right value needed")); + let a = some_or_error!(stack.pop(), InterpreterError::new("left value needed")); + let b: TeaValue = get_value(b, &global_scope)?; + let a: TeaValue = get_value(a, &global_scope)?; + stack.push(Value::Lit(match op { + Operator::Plus => { + apply_op!(a, b, +) + }, + Operator::Minus => { + apply_op!(a, b, -) + }, + Operator::Star => { + apply_op!(a, b, *) + }, + Operator::Slash => { + apply_op!(a, b, /) + }, + })); + }, + Some(ASTNode::UnaryMinus) => { + let x = some_or_error!(stack.pop(), InterpreterError::new("value needed")); + let x: TeaValue = get_value(x, &global_scope)?; + stack.push(Value::Lit(match x { + TeaValue::Float(f) => TeaValue::Float(-f), + TeaValue::Int(i) => TeaValue::Int(-i), + TeaValue::Uint(u) => TeaValue::Int(-(u as i32)), + TeaValue::String(_) => return Err(InterpreterError::new("cannot invert string")), + })); + }, + Some(ASTNode::ConstDecl) => { + let rhs = some_or_error!(stack.pop(), InterpreterError::new("rhs value needed")); + let lhs = some_or_error!(stack.pop(), InterpreterError::new("lhs value needed")); + let rhs: TeaValue = get_value(rhs, &global_scope)?; + match lhs { + Value::Lit(_) => return Err(InterpreterError::new("invalid left hand side")), + Value::Id(s) => { + if global_scope.contains_key(&s) { + return Err(InterpreterError::new("already defined constant")); + } else { + global_scope.insert(s, VarType::Const(rhs)); + } + } + } + }, + Some(ASTNode::StatementEnd) => { + if !stack.is_empty() { + return Err(InterpreterError::new("stack not empty")); + } + } + } + } +} diff --git a/src/lex.rs b/src/lex.rs index 81a6c17..9b3c8c0 100644 --- a/src/lex.rs +++ b/src/lex.rs @@ -1,16 +1,24 @@ pub mod literal; -use self::literal::parse_literal; pub mod identifier; -use self::identifier::parse_identifier; pub mod operator; -use self::operator::{ parse_operator, Operator }; pub mod symbol; -use self::symbol::{ parse_symbol, Symbol }; pub mod keyword; -use self::keyword::{ parse_keyword, Keyword }; +use self::{ + literal::parse_literal, + identifier::parse_identifier, + operator::parse_operator, + symbol::parse_symbol, + keyword::parse_keyword, +}; -#[derive(Debug)] +pub use self::{ + operator::Operator, + symbol::Symbol, + keyword::Keyword, +}; + +#[derive(Clone, Debug)] pub enum TeaValue { Int(i32), Uint(u32), @@ -54,7 +62,7 @@ macro_rules! try_parse { } } -pub fn parse_tokens(s: &str) -> Result, (Vec, &str)> { +pub fn lex_tokens(s: &str) -> Result, (Vec, &str)> { let mut input = s; let mut tokens: Vec = vec![]; loop { diff --git a/src/lex/operator.rs b/src/lex/operator.rs index 3e4a3f7..c67a811 100644 --- a/src/lex/operator.rs +++ b/src/lex/operator.rs @@ -1,6 +1,6 @@ use super::Token; -#[derive(Debug)] +#[derive(Clone, Debug)] pub enum Operator { Plus, Minus, diff --git a/src/main.rs b/src/main.rs index 237ad08..2e35789 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,10 +3,16 @@ use std::env::args; #[macro_use] mod lex; -use lex::parse_tokens; +use lex::lex_tokens; +mod parse; +use parse::parse; +mod interpret; +use interpret::interpret; fn main() { let args: String = args().skip(1).collect::>().join(" "); - let k = parse_tokens(&args); - println!("{k:?}"); + let k = lex_tokens(&args).unwrap(); + let p = parse(k).unwrap(); + let i = interpret(p); + println!("{i:?}"); } diff --git a/src/parse.rs b/src/parse.rs new file mode 100644 index 0000000..d7f4602 --- /dev/null +++ b/src/parse.rs @@ -0,0 +1,126 @@ + +use crate::lex::{ + Token, + TeaValue, + Operator, + Keyword, + Symbol, +}; + +#[derive(Debug, Clone)] +pub enum Value { + Lit(TeaValue), + Id(String), +} + +#[derive(Debug, Clone)] +pub enum ASTNode { + Val(Value), + ConstDecl, // Const declaration + BinOp(Operator), // binary operation + UnaryMinus, + StatementEnd, +} + +#[derive(Debug)] +pub struct ParseError { + description: String, +} + +impl ParseError { + pub fn new(e: &str) -> Self { + Self { + description: e.to_owned(), + } + } +} + +macro_rules! match_or_return { + ($matchee:expr, $pattern:pat, $extract:expr, $ret:expr) => { + match $matchee { + Some($pattern) => $extract, + _ => return Err($ret), + } + } +} + +macro_rules! assert_match { + ($matchee:expr, $pattern:pat, $ret:expr) => { + match $matchee { + Some($pattern) => (), + _ => return Err($ret), + } + } +} + +fn next_expr_end(tokens: &[Token]) -> usize { + let mut index = 0; + loop { + if matches!(tokens.get(index), Some(Token::Sym(Symbol::Semicolon)) | None) { + return index; + } + index += 1; + } +} + +fn parse_expr(tokens: &[Token]) -> Result<(Vec, usize), ParseError> { + let mut ast = vec![]; + let mut index = 0; + loop { + match tokens.get(index) { + None => return Ok((ast, index)), + Some(Token::Lit(v)) => ast.push(ASTNode::Val(Value::Lit(v.clone()))), + Some(Token::Id(v)) => ast.push(ASTNode::Val(Value::Id(v.clone()))), + Some(Token::Kw(Keyword::Let)) => { + let id = match_or_return!(tokens.get(index + 1), Token::Id(a), a, ParseError::new("identifier expected after 'let' keyword")); + match_or_return!(tokens.get(index + 2), Token::Sym(Symbol::EqualSign), (), ParseError::new("= expected after identifier")); + let tokens = &tokens[(3 + index)..]; + let next_end = next_expr_end(tokens); + let (mut expr, count) = parse_expr(&tokens[..next_end])?; + ast.push(ASTNode::Val(Value::Id(id.to_owned()))); + ast.append(&mut expr); + ast.push(ASTNode::ConstDecl); + index += count + 3; // 4 + count - 1 + }, + Some(Token::Sym(Symbol::Semicolon)) => { + ast.push(ASTNode::StatementEnd); + }, + Some(Token::Sym(Symbol::EqualSign)) => todo!(), + Some(Token::Op(op)) => { + if ast.is_empty() && matches!(op, Operator::Minus) { + ast.push(match tokens.get(index + 1) { + Some(Token::Id(v)) => ASTNode::Val(Value::Id(v.clone())), + Some(Token::Lit(v)) => ASTNode::Val(Value::Lit(v.clone())), + _ => return Err(ParseError::new("literal or identifier expected after operator")), + }); + ast.push(ASTNode::UnaryMinus); + index += 1; + } else { + assert_match!(ast.last(), ASTNode::Val(_), ParseError::new("literal or identifier expected before operator")); + ast.push(match tokens.get(index + 1) { + Some(Token::Id(v)) => ASTNode::Val(Value::Id(v.clone())), + Some(Token::Lit(v)) => ASTNode::Val(Value::Lit(v.clone())), + _ => return Err(ParseError::new("literal or identifier expected after operator")), + }); + ast.push(ASTNode::BinOp(op.clone())); + index += 1; + } + }, + } + index += 1; + } +} + +pub fn parse(tokens: Vec) -> Result, ParseError> { + let mut ast = vec![]; + let tokens: &[Token] = &tokens; + let mut next = 0; + loop { + let (mut nodes, count) = parse_expr(&tokens[next..])?; + ast.append(&mut nodes); + next += count; + if tokens.get(next).is_none() { + return Ok(ast); + } + } +}