Fixed unary minus

This commit is contained in:
2026-07-09 10:17:31 -05:00
parent 9a0716ced0
commit a34bbba4b1
6 changed files with 62 additions and 14 deletions
Generated
+1 -1
View File
@@ -3,5 +3,5 @@
version = 4
[[package]]
name = "tea"
name = "matcha"
version = "0.1.0"
+1 -1
View File
@@ -35,7 +35,7 @@ fn get_value(v: Value, scopes: &mut [Scope]) -> Result<TeaValue, InterpreterErro
match v {
Value::Lit(t) => 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()),
+1
View File
@@ -67,6 +67,7 @@ pub fn lex_tokens(s: &str) -> Result<Vec<Token>, (Vec<Token>, &str)> {
let mut tokens: Vec<Token> = vec![];
loop {
if input.is_empty() {
println!("tokens: {tokens:?}\n\n");
return Ok(tokens);
}
try_parse!(parse_literal(input), tokens, input);
+4
View File
@@ -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
}
}
+53 -10
View File
@@ -71,13 +71,29 @@ fn next_expr_end(tokens: &[Token]) -> usize {
fn next_block_end(tokens: &[Token]) -> Result<usize, ParseError> {
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<usize, ParseError> {
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<ASTNode>, usize), ParseError> {
let mut ast = vec![];
let mut index = 0;
let mut op_stack: Vec<Operator> = 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()));
}
return Ok((ast, index));
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<ASTNode>, 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() => {
+2 -2
View File
@@ -1,8 +1,8 @@
let x = 5;
let y = {
let x = 1;
x + 1
let x = -x;
x + 1 * -x
};
x + y