From a34bbba4b110b8d6b6c53df8c9af33133eeb3b52 Mon Sep 17 00:00:00 2001 From: Seoxi Ryouko Date: Thu, 9 Jul 2026 10:17:31 -0500 Subject: [PATCH] Fixed unary minus --- Cargo.lock | 2 +- src/interpret.rs | 2 +- src/lex.rs | 1 + src/lex/symbol.rs | 4 +++ src/parse.rs | 63 +++++++++++++++++++++++++++++++++++++++-------- test.matcha | 4 +-- 6 files changed, 62 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 59b2d33..2501596 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,5 +3,5 @@ version = 4 [[package]] -name = "tea" +name = "matcha" version = "0.1.0" diff --git a/src/interpret.rs b/src/interpret.rs index 9334300..ad872d2 100644 --- a/src/interpret.rs +++ b/src/interpret.rs @@ -35,7 +35,7 @@ fn get_value(v: Value, scopes: &mut [Scope]) -> Result Ok(t), Value::Id(s) => { - match scopes.iter().rev().skip_while(|scope| !scope.contains_key(&s)).next() { + match scopes.iter().rev().find(|scope| scope.contains_key(&s)) { None => Err(InterpreterError::new("undefined variable")), Some(scope) => match scope.get(&s).unwrap() { VarType::Const(t) => Ok(t.clone()), diff --git a/src/lex.rs b/src/lex.rs index 9b3c8c0..28b3851 100644 --- a/src/lex.rs +++ b/src/lex.rs @@ -67,6 +67,7 @@ pub fn lex_tokens(s: &str) -> Result, (Vec, &str)> { let mut tokens: Vec = vec![]; loop { if input.is_empty() { + println!("tokens: {tokens:?}\n\n"); return Ok(tokens); } try_parse!(parse_literal(input), tokens, input); diff --git a/src/lex/symbol.rs b/src/lex/symbol.rs index ab44b3e..788cd61 100644 --- a/src/lex/symbol.rs +++ b/src/lex/symbol.rs @@ -6,6 +6,8 @@ pub enum Symbol { Semicolon, OpenBrace, CloseBrace, + OpenParen, + CloseParen, } pub fn parse_symbol(input: &str) -> Option<(Token, &str)> { @@ -16,6 +18,8 @@ pub fn parse_symbol(input: &str) -> Option<(Token, &str)> { ';' => Some((Token::Sym(Symbol::Semicolon), input)), '{' => Some((Token::Sym(Symbol::OpenBrace), input)), '}' => Some((Token::Sym(Symbol::CloseBrace), input)), + '(' => Some((Token::Sym(Symbol::OpenParen), input)), + ')' => Some((Token::Sym(Symbol::CloseParen), input)), _ => None } } diff --git a/src/parse.rs b/src/parse.rs index 91c0336..eb03b51 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -71,13 +71,29 @@ fn next_expr_end(tokens: &[Token]) -> usize { fn next_block_end(tokens: &[Token]) -> Result { let mut index = 0; + let mut block_count = 0usize; loop { - let token = tokens.get(index); - if token.is_none() { - return Err(ParseError::new("} expected")); + match tokens.get(index) { + Some(Token::Sym(Symbol::OpenBrace)) => block_count += 1, + Some(Token::Sym(Symbol::CloseBrace)) if block_count == 0 => return Ok(index), + Some(Token::Sym(Symbol::CloseBrace)) => block_count -= 1, + None => return Err(ParseError::new("mismatched {")), + _ => (), } - if matches!(token, Some(Token::Sym(Symbol::CloseBrace))) { - return Ok(index); + index += 1; + } +} + +fn next_paren_end(tokens: &[Token]) -> Result { + let mut index = 0; + let mut paren_count = 0usize; + loop { + match tokens.get(index) { + Some(Token::Sym(Symbol::OpenParen)) => paren_count += 1, + Some(Token::Sym(Symbol::CloseParen)) if paren_count == 0 => return Ok(index), + Some(Token::Sym(Symbol::CloseParen)) => paren_count -= 1, + None => return Err(ParseError::new("mismatched (")), + _ => (), } index += 1; } @@ -87,26 +103,30 @@ fn parse_expr(tokens: &[Token]) -> Result<(Vec, usize), ParseError> { let mut ast = vec![]; let mut index = 0; let mut op_stack: Vec = vec![]; + let mut unary_negate = false; loop { match tokens.get(index) { None => { while !op_stack.is_empty() { ast.push(ASTNode::BinOp(op_stack.pop().unwrap())); } + if unary_negate && !matches!(tokens.get(index), Some(Token::Sym(Symbol::Semicolon))) { + ast.push(ASTNode::UnaryMinus); + } 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])?; + let stokens = &tokens[(3 + index)..]; + let next_end = next_expr_end(stokens); + let (mut expr, count) = parse_expr(&stokens[..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 + index += count + 2;// 4 + count - 1 }, Some(Token::Kw(Keyword::Fn)) => { /*let id = match_or_return!(tokens.get(index + 1), Token::Id(a), a, ParseError::new("identifier expected after 'let' keyword")); @@ -130,13 +150,36 @@ fn parse_expr(tokens: &[Token]) -> Result<(Vec, usize), ParseError> { Some(Token::Sym(Symbol::CloseBrace)) => { return Err(ParseError::new("unexpected }")); }, + Some(Token::Sym(Symbol::OpenParen)) => { + let end = next_paren_end(&tokens[(index + 1)..])?; + let (expr, count) = parse_expr(&tokens[(index + 1)..(index + end + 1)])?; + ast.push(ASTNode::Block(expr)); + index += count + 1; + }, + Some(Token::Sym(Symbol::CloseParen)) => { + return Err(ParseError::new("unexpected )")); + }, Some(Token::Sym(Symbol::Semicolon)) => { while !op_stack.is_empty() { ast.push(ASTNode::BinOp(op_stack.pop().unwrap())); } + // I'll macro this later + if unary_negate && !matches!(tokens.get(index), Some(Token::Sym(Symbol::Semicolon))) { + ast.push(ASTNode::UnaryMinus); + unary_negate = false; + } ast.push(ASTNode::StatementEnd); }, Some(Token::Op(op)) => { + if (matches!(ast.last(), Some(ASTNode::StatementEnd) | None) || !op_stack.is_empty()) && matches!(op, Operator::Minus) { + unary_negate = true; + index += 1; + continue; + } + if unary_negate && !matches!(tokens.get(index), Some(Token::Sym(Symbol::Semicolon))) { + ast.push(ASTNode::UnaryMinus); + unary_negate = false; + } match op_stack.last() { None => op_stack.push(op.clone()), Some(last_op) if last_op.get_precedence() < op.get_precedence() => { diff --git a/test.matcha b/test.matcha index 31e3119..495a3bc 100644 --- a/test.matcha +++ b/test.matcha @@ -1,8 +1,8 @@ let x = 5; let y = { - let x = 1; - x + 1 + let x = -x; + x + 1 * -x }; x + y