Fixed unary minus
This commit is contained in:
Generated
+1
-1
@@ -3,5 +3,5 @@
|
|||||||
version = 4
|
version = 4
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tea"
|
name = "matcha"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|||||||
+1
-1
@@ -35,7 +35,7 @@ fn get_value(v: Value, scopes: &mut [Scope]) -> Result<TeaValue, InterpreterErro
|
|||||||
match v {
|
match v {
|
||||||
Value::Lit(t) => Ok(t),
|
Value::Lit(t) => Ok(t),
|
||||||
Value::Id(s) => {
|
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")),
|
None => Err(InterpreterError::new("undefined variable")),
|
||||||
Some(scope) => match scope.get(&s).unwrap() {
|
Some(scope) => match scope.get(&s).unwrap() {
|
||||||
VarType::Const(t) => Ok(t.clone()),
|
VarType::Const(t) => Ok(t.clone()),
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ pub fn lex_tokens(s: &str) -> Result<Vec<Token>, (Vec<Token>, &str)> {
|
|||||||
let mut tokens: Vec<Token> = vec![];
|
let mut tokens: Vec<Token> = vec![];
|
||||||
loop {
|
loop {
|
||||||
if input.is_empty() {
|
if input.is_empty() {
|
||||||
|
println!("tokens: {tokens:?}\n\n");
|
||||||
return Ok(tokens);
|
return Ok(tokens);
|
||||||
}
|
}
|
||||||
try_parse!(parse_literal(input), tokens, input);
|
try_parse!(parse_literal(input), tokens, input);
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ pub enum Symbol {
|
|||||||
Semicolon,
|
Semicolon,
|
||||||
OpenBrace,
|
OpenBrace,
|
||||||
CloseBrace,
|
CloseBrace,
|
||||||
|
OpenParen,
|
||||||
|
CloseParen,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_symbol(input: &str) -> Option<(Token, &str)> {
|
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::Semicolon), input)),
|
||||||
'{' => Some((Token::Sym(Symbol::OpenBrace), input)),
|
'{' => Some((Token::Sym(Symbol::OpenBrace), input)),
|
||||||
'}' => Some((Token::Sym(Symbol::CloseBrace), input)),
|
'}' => Some((Token::Sym(Symbol::CloseBrace), input)),
|
||||||
|
'(' => Some((Token::Sym(Symbol::OpenParen), input)),
|
||||||
|
')' => Some((Token::Sym(Symbol::CloseParen), input)),
|
||||||
_ => None
|
_ => None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+53
-10
@@ -71,13 +71,29 @@ fn next_expr_end(tokens: &[Token]) -> usize {
|
|||||||
|
|
||||||
fn next_block_end(tokens: &[Token]) -> Result<usize, ParseError> {
|
fn next_block_end(tokens: &[Token]) -> Result<usize, ParseError> {
|
||||||
let mut index = 0;
|
let mut index = 0;
|
||||||
|
let mut block_count = 0usize;
|
||||||
loop {
|
loop {
|
||||||
let token = tokens.get(index);
|
match tokens.get(index) {
|
||||||
if token.is_none() {
|
Some(Token::Sym(Symbol::OpenBrace)) => block_count += 1,
|
||||||
return Err(ParseError::new("} expected"));
|
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))) {
|
index += 1;
|
||||||
return Ok(index);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
index += 1;
|
||||||
}
|
}
|
||||||
@@ -87,26 +103,30 @@ fn parse_expr(tokens: &[Token]) -> Result<(Vec<ASTNode>, usize), ParseError> {
|
|||||||
let mut ast = vec![];
|
let mut ast = vec![];
|
||||||
let mut index = 0;
|
let mut index = 0;
|
||||||
let mut op_stack: Vec<Operator> = vec![];
|
let mut op_stack: Vec<Operator> = vec![];
|
||||||
|
let mut unary_negate = false;
|
||||||
loop {
|
loop {
|
||||||
match tokens.get(index) {
|
match tokens.get(index) {
|
||||||
None => {
|
None => {
|
||||||
while !op_stack.is_empty() {
|
while !op_stack.is_empty() {
|
||||||
ast.push(ASTNode::BinOp(op_stack.pop().unwrap()));
|
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::Lit(v)) => ast.push(ASTNode::Val(Value::Lit(v.clone()))),
|
||||||
Some(Token::Id(v)) => ast.push(ASTNode::Val(Value::Id(v.clone()))),
|
Some(Token::Id(v)) => ast.push(ASTNode::Val(Value::Id(v.clone()))),
|
||||||
Some(Token::Kw(Keyword::Let)) => {
|
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"));
|
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"));
|
match_or_return!(tokens.get(index + 2), Token::Sym(Symbol::EqualSign), (), ParseError::new("= expected after identifier"));
|
||||||
let tokens = &tokens[(3 + index)..];
|
let stokens = &tokens[(3 + index)..];
|
||||||
let next_end = next_expr_end(tokens);
|
let next_end = next_expr_end(stokens);
|
||||||
let (mut expr, count) = parse_expr(&tokens[..next_end])?;
|
let (mut expr, count) = parse_expr(&stokens[..next_end])?;
|
||||||
ast.push(ASTNode::Val(Value::Id(id.to_owned())));
|
ast.push(ASTNode::Val(Value::Id(id.to_owned())));
|
||||||
ast.append(&mut expr);
|
ast.append(&mut expr);
|
||||||
ast.push(ASTNode::ConstDecl);
|
ast.push(ASTNode::ConstDecl);
|
||||||
index += count + 3; // 4 + count - 1
|
index += count + 2;// 4 + count - 1
|
||||||
},
|
},
|
||||||
Some(Token::Kw(Keyword::Fn)) => {
|
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"));
|
/*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)) => {
|
Some(Token::Sym(Symbol::CloseBrace)) => {
|
||||||
return Err(ParseError::new("unexpected }"));
|
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)) => {
|
Some(Token::Sym(Symbol::Semicolon)) => {
|
||||||
while !op_stack.is_empty() {
|
while !op_stack.is_empty() {
|
||||||
ast.push(ASTNode::BinOp(op_stack.pop().unwrap()));
|
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);
|
ast.push(ASTNode::StatementEnd);
|
||||||
},
|
},
|
||||||
Some(Token::Op(op)) => {
|
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() {
|
match op_stack.last() {
|
||||||
None => op_stack.push(op.clone()),
|
None => op_stack.push(op.clone()),
|
||||||
Some(last_op) if last_op.get_precedence() < op.get_precedence() => {
|
Some(last_op) if last_op.get_precedence() < op.get_precedence() => {
|
||||||
|
|||||||
+2
-2
@@ -1,8 +1,8 @@
|
|||||||
|
|
||||||
let x = 5;
|
let x = 5;
|
||||||
let y = {
|
let y = {
|
||||||
let x = 1;
|
let x = -x;
|
||||||
x + 1
|
x + 1 * -x
|
||||||
};
|
};
|
||||||
x + y
|
x + y
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user