Added print statement, various other fixes
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
# TODO
|
||||
+ function calling
|
||||
+ functions
|
||||
+ mutable bindings
|
||||
+ arrays
|
||||
+ type syntax
|
||||
+ error handling
|
||||
+ pattern matching
|
||||
+ closures
|
||||
+ structs & tuples
|
||||
+ loops
|
||||
+ proper vm
|
||||
+38
-10
@@ -1,12 +1,12 @@
|
||||
|
||||
use crate::lex::{ TeaValue, Operator };
|
||||
use crate::parse::{ ASTNode, Value };
|
||||
use crate::parse::{ ASTNode, Value, KeywordFunction };
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Debug)]
|
||||
enum VarType {
|
||||
pub enum VarType {
|
||||
Const(TeaValue),
|
||||
//Mut,
|
||||
}
|
||||
|
||||
enum BlockType {
|
||||
@@ -16,7 +16,7 @@ enum BlockType {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct InterpreterError {
|
||||
description: String,
|
||||
pub description: String,
|
||||
}
|
||||
|
||||
impl InterpreterError {
|
||||
@@ -47,6 +47,7 @@ fn get_value(v: Value, scopes: &mut [Scope]) -> Result<TeaValue, InterpreterErro
|
||||
},
|
||||
}
|
||||
},
|
||||
Value::KwFn(_) => Err(InterpreterError::new("not yet implemented"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,24 +60,49 @@ macro_rules! apply_op {
|
||||
(TeaValue::Int(aa), TeaValue::Int(bb)) => {
|
||||
TeaValue::Int(aa $op bb)
|
||||
},
|
||||
//(TeaValue::Uint(aa), TeaValue::Uint(bb)) => {
|
||||
// TeaValue::Uint(aa $op bb)
|
||||
//},
|
||||
(TeaValue::Uint(aa), TeaValue::Uint(bb)) => {
|
||||
TeaValue::Uint(aa $op bb)
|
||||
},
|
||||
_ => panic!("Invalid types"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type Scope = HashMap<String, VarType>;
|
||||
pub type Scope = HashMap<String, VarType>;
|
||||
|
||||
fn interpret_block(ast: Vec<ASTNode>, scopes: &mut Vec<Scope>, block_type: BlockType) -> Result<Vec<Value>, InterpreterError> {
|
||||
//println!("{ast:?}\n");
|
||||
let mut ast = ast.clone();
|
||||
ast.reverse();
|
||||
let mut stack = vec![];
|
||||
//let mut scope = Scope::new();
|
||||
loop {
|
||||
match ast.pop() {
|
||||
None => return Ok(stack),
|
||||
Some(ASTNode::ArgColl(count)) => {
|
||||
let start = stack.len() - count;
|
||||
if stack.len() > count {
|
||||
let call_stack: Vec<Value> = stack.drain(start..).collect();
|
||||
match stack.pop() {
|
||||
None => return Err(InterpreterError::new("invalid function call")),
|
||||
Some(Value::KwFn(KeywordFunction::Print)) => {
|
||||
let mut iter = call_stack.into_iter();
|
||||
if let Some(i) = iter.next() {
|
||||
let val = get_value(i, scopes)?;
|
||||
print!("{val}");
|
||||
}
|
||||
for i in iter {
|
||||
let val = get_value(i, scopes)?;
|
||||
print!(", {val}");
|
||||
}
|
||||
println!();
|
||||
}
|
||||
Some(Value::Lit(_)) => return Err(InterpreterError::new("cannot call literal")),
|
||||
Some(Value::Id(_)) => return Err(InterpreterError::new("not yet implemented")),
|
||||
}
|
||||
} else {
|
||||
return Err(InterpreterError::new("invalid call"));
|
||||
}
|
||||
},
|
||||
Some(ASTNode::Block(tokens)) => {
|
||||
scopes.push(HashMap::new());
|
||||
let mut result = interpret_block(tokens, scopes, BlockType::Block)?;
|
||||
@@ -125,7 +151,6 @@ fn interpret_block(ast: Vec<ASTNode>, scopes: &mut Vec<Scope>, block_type: Block
|
||||
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, scopes)?;
|
||||
//let current_scope = .unwrap();
|
||||
match lhs {
|
||||
Value::Lit(_) => return Err(InterpreterError::new("invalid left hand side")),
|
||||
Value::Id(s) => {
|
||||
@@ -135,6 +160,9 @@ fn interpret_block(ast: Vec<ASTNode>, scopes: &mut Vec<Scope>, block_type: Block
|
||||
scopes.last_mut().unwrap().insert(s, VarType::Const(rhs));
|
||||
}
|
||||
}
|
||||
Value::KwFn(s) => {
|
||||
return Err(InterpreterError::new(format!("unable to assign to keyword {s:?}").as_str()))
|
||||
}
|
||||
}
|
||||
},
|
||||
Some(ASTNode::StatementEnd) => {
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
|
||||
use crate::parse::ASTNode;
|
||||
|
||||
fn get_domain(ast: &mut Vec<ASTNode>) -> Vec<ASTNode> {
|
||||
ast.iter().take_while(|x| !matches!(x, ASTNode::StatementEnd)).cloned().collect()
|
||||
}
|
||||
|
||||
pub fn operator_chain(ast: &mut Vec<ASTNode>) {
|
||||
let tree = get_domain(ast);
|
||||
}
|
||||
+47
@@ -26,6 +26,18 @@ pub enum TeaValue {
|
||||
String(String),
|
||||
}
|
||||
|
||||
use std::fmt;
|
||||
impl fmt::Display for TeaValue {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
TeaValue::Int(i) => write!(f, "{i}"),
|
||||
TeaValue::Uint(u) => write!(f, "{u}u"),
|
||||
TeaValue::Float(l) => write!(f, "{l}"),
|
||||
TeaValue::String(s) => write!(f, "{s}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Token {
|
||||
Lit(TeaValue),
|
||||
@@ -52,6 +64,33 @@ fn skip_whitespace(input: &str) -> &str {
|
||||
&input[whitespace.len()..]
|
||||
}
|
||||
|
||||
fn skip_singleline_comment(input: &str) -> Option<usize> {
|
||||
if input.get(0..2) != Some("//") {
|
||||
return None;
|
||||
}
|
||||
let mut index = 2;
|
||||
loop {
|
||||
if matches!(input.chars().nth(index), None | Some('\n')) {
|
||||
return Some(index);
|
||||
}
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn skip_multiline_comment(input: &str) -> Option<usize> {
|
||||
if input.get(0..2) != Some("/*") {
|
||||
return None;
|
||||
}
|
||||
let mut index = 2;
|
||||
loop {
|
||||
let s = input.get(index..(index + 2))?;
|
||||
if s == "*/" {
|
||||
return Some(index + 2);
|
||||
}
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! try_parse {
|
||||
($e:expr, $arr:ident, $str:ident) => {
|
||||
if let Some((v, s)) = $e {
|
||||
@@ -69,6 +108,14 @@ pub fn lex_tokens(s: &str) -> Result<Vec<Token>, (Vec<Token>, &str)> {
|
||||
if input.is_empty() {
|
||||
return Ok(tokens);
|
||||
}
|
||||
if let Some(count) = skip_singleline_comment(input) {
|
||||
input = &input[count..];
|
||||
continue;
|
||||
}
|
||||
if let Some(count) = skip_multiline_comment(input) {
|
||||
input = &input[count..];
|
||||
continue;
|
||||
}
|
||||
try_parse!(parse_literal(input), tokens, input);
|
||||
try_parse!(parse_operator(input), tokens, input);
|
||||
try_parse!(parse_symbol(input), tokens, input);
|
||||
|
||||
@@ -4,6 +4,7 @@ use super::{ whitespace_chars, Token };
|
||||
pub enum Keyword {
|
||||
Let,
|
||||
Fn,
|
||||
Print, // print is a keyword for... reasons
|
||||
}
|
||||
|
||||
macro_rules! match_keyword {
|
||||
@@ -17,5 +18,6 @@ macro_rules! match_keyword {
|
||||
pub fn parse_keyword(input: &str) -> Option<(Token, &str)> {
|
||||
match_keyword!("let", Token::Kw(Keyword::Let), input);
|
||||
match_keyword!("fn", Token::Kw(Keyword::Fn), input);
|
||||
match_keyword!("print", Token::Kw(Keyword::Print), input);
|
||||
None
|
||||
}
|
||||
|
||||
@@ -86,16 +86,61 @@ fn parse_dec_int(input: &str) -> Option<(i32, &str)> {
|
||||
Some((sign * s.parse::<i32>().unwrap(), &input[s.len()..]))
|
||||
}
|
||||
|
||||
fn parse_uint(input: &str) -> Option<(u32, &str)> {
|
||||
if input.starts_with("-") {
|
||||
return None;
|
||||
}
|
||||
input.strip_prefix("0x").map(|input| -> String {
|
||||
input.chars().take_while(|c| matches!(c, hex_chars!())).collect()
|
||||
}).filter(|s| !s.is_empty() && input.chars().nth(s.len()) == Some('u')).map(|s|
|
||||
(u32::from_str_radix(&s, 16).unwrap(), &input[(s.len() + 1)..])
|
||||
).or({
|
||||
let s: String = input.chars().take_while(|c| matches!(c, dec_chars!())).collect();
|
||||
if s.is_empty() || input.chars().nth(s.len()) != Some('u') {
|
||||
None
|
||||
} else {
|
||||
Some ((s.parse::<u32>().unwrap(), &input[(s.len() + 1)..]))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_str(input: &str) -> Option<(String, &str)> {
|
||||
let x = input.chars().next()?;
|
||||
if x != '"' {
|
||||
return None;
|
||||
}
|
||||
let mut index = 1;
|
||||
let mut terminated = false;
|
||||
while index < input.len() {
|
||||
// this is definitely stupid but idk how to do this properly
|
||||
if Some('"') == input.chars().nth(index) && Some('\'') != input.chars().nth(index - 1) {
|
||||
terminated = true;
|
||||
break;
|
||||
}
|
||||
index += 1;
|
||||
}
|
||||
if !terminated {
|
||||
return None;
|
||||
}
|
||||
Some((input.get(1..index).unwrap().to_owned().replace("\\n", "\n").replace("\\r", "\r").replace("\\0", "\0"), &input[(index + 1)..]))
|
||||
}
|
||||
|
||||
pub fn parse_literal(input: &str) -> Option<(Token, &str)> {
|
||||
if let Some((val, s)) = parse_float(input) {
|
||||
return Some((Token::Lit(TeaValue::Float(val)), s))
|
||||
}
|
||||
if let Some((val, s)) = parse_uint(input) {
|
||||
return Some((Token::Lit(TeaValue::Uint(val)), s))
|
||||
}
|
||||
if let Some((val, s)) = parse_hex_int(input) {
|
||||
return Some((Token::Lit(TeaValue::Int(val)), s))
|
||||
}
|
||||
if let Some((val, s)) = parse_dec_int(input) {
|
||||
return Some((Token::Lit(TeaValue::Int(val)), s))
|
||||
}
|
||||
if let Some((val, s)) = parse_str(input) {
|
||||
return Some((Token::Lit(TeaValue::String(val)), s))
|
||||
}
|
||||
// TODO: other values
|
||||
None
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ pub enum Symbol {
|
||||
CloseBrace,
|
||||
OpenParen,
|
||||
CloseParen,
|
||||
Comma,
|
||||
}
|
||||
|
||||
pub fn parse_symbol(input: &str) -> Option<(Token, &str)> {
|
||||
@@ -16,6 +17,7 @@ pub fn parse_symbol(input: &str) -> Option<(Token, &str)> {
|
||||
match c {
|
||||
'=' => Some((Token::Sym(Symbol::EqualSign), input)),
|
||||
';' => Some((Token::Sym(Symbol::Semicolon), input)),
|
||||
',' => Some((Token::Sym(Symbol::Comma), input)),
|
||||
'{' => Some((Token::Sym(Symbol::OpenBrace), input)),
|
||||
'}' => Some((Token::Sym(Symbol::CloseBrace), input)),
|
||||
'(' => Some((Token::Sym(Symbol::OpenParen), input)),
|
||||
|
||||
+14
-4
@@ -10,9 +10,19 @@ mod interpret;
|
||||
use interpret::interpret;
|
||||
|
||||
fn main() {
|
||||
println!("\n"); // makes output easier to visually parse when run with cargo run
|
||||
let args: String = args().skip(1).collect::<Vec<_>>().join(" ");
|
||||
let k = lex_tokens(&args).unwrap();
|
||||
let p = parse(k).unwrap();
|
||||
let i = interpret(p);
|
||||
println!("{i:?}");
|
||||
let k = match lex_tokens(&args) {
|
||||
Ok(a) => a,
|
||||
Err((_, a)) => panic!("{a:?}"),
|
||||
};
|
||||
let p = match parse(k) {
|
||||
Ok(a) => a,
|
||||
Err(a) => panic!("{:?}", a.description),
|
||||
};
|
||||
let stack = match interpret(p) {
|
||||
Ok(a) => a,
|
||||
Err(a) => panic!("{:?}", a.description),
|
||||
};
|
||||
println!("\nreturn: {stack:?}\n");
|
||||
}
|
||||
|
||||
+96
-58
@@ -11,6 +11,12 @@ use crate::lex::{
|
||||
pub enum Value {
|
||||
Lit(TeaValue),
|
||||
Id(String),
|
||||
KwFn(KeywordFunction),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum KeywordFunction {
|
||||
Print,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -22,11 +28,12 @@ pub enum ASTNode {
|
||||
StatementEnd,
|
||||
Block(Vec<ASTNode>),
|
||||
Parenthetical(Vec<ASTNode>),
|
||||
ArgColl(usize),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ParseError {
|
||||
description: String,
|
||||
pub description: String,
|
||||
}
|
||||
|
||||
impl ParseError {
|
||||
@@ -37,6 +44,11 @@ impl ParseError {
|
||||
}
|
||||
}
|
||||
|
||||
pub enum ExprType {
|
||||
Block,
|
||||
Arg,
|
||||
}
|
||||
|
||||
macro_rules! match_or_return {
|
||||
($matchee:expr, $pattern:pat, $extract:expr, $ret:expr) => {
|
||||
match $matchee {
|
||||
@@ -46,15 +58,6 @@ macro_rules! match_or_return {
|
||||
}
|
||||
}
|
||||
|
||||
/*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;
|
||||
let mut block_count = 0usize;
|
||||
@@ -100,7 +103,51 @@ fn next_paren_end(tokens: &[Token]) -> Result<usize, ParseError> {
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_expr(tokens: &[Token]) -> Result<(Vec<ASTNode>, usize), ParseError> {
|
||||
fn next_arg_end(tokens: &[Token]) -> Result<(bool, usize), ParseError> {
|
||||
let mut index = 0;
|
||||
let mut paren_count = 0usize;
|
||||
let mut block_count = 0usize;
|
||||
loop {
|
||||
match tokens.get(index) {
|
||||
Some(Token::Sym(Symbol::OpenParen)) => paren_count += 1,
|
||||
Some(Token::Sym(Symbol::CloseParen)) => paren_count -= 1,
|
||||
Some(Token::Sym(Symbol::OpenBrace)) => block_count += 1,
|
||||
Some(Token::Sym(Symbol::CloseBrace)) => block_count -= 1,
|
||||
Some(Token::Sym(Symbol::Comma)) if paren_count == 0 && block_count == 0 => return Ok((false, index)),
|
||||
Some(Token::Sym(Symbol::Semicolon)) if paren_count == 0 && block_count == 0 => return Ok((true, index)),
|
||||
None => {
|
||||
if paren_count > 0 || block_count > 0 {
|
||||
return Err(ParseError::new("mismatched ( or {"));
|
||||
}
|
||||
return Ok((true, index))
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! check_if_call {
|
||||
($tree:ident, $tkn:expr, $i:ident, $o:ident) => {
|
||||
if matches!($tree.last(), Some(ASTNode::Val(_))) && $o.is_empty() {
|
||||
let mut arg_count = 0;
|
||||
loop {
|
||||
let (finished, count) = next_arg_end(&$tkn[$i..])?;
|
||||
let (mut stack, _) = parse_expr(&$tkn[$i..($i + count)], ExprType::Arg)?;
|
||||
$tree.append(&mut stack);
|
||||
$i += count + 1;
|
||||
arg_count += 1;
|
||||
if finished {
|
||||
break;
|
||||
}
|
||||
}
|
||||
$tree.push(ASTNode::ArgColl(arg_count));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_expr(tokens: &[Token], expr_type: ExprType) -> Result<(Vec<ASTNode>, usize), ParseError> {
|
||||
let mut ast = vec![];
|
||||
let mut index = 0;
|
||||
let mut op_stack: Vec<Operator> = vec![];
|
||||
@@ -108,43 +155,47 @@ fn parse_expr(tokens: &[Token]) -> Result<(Vec<ASTNode>, usize), ParseError> {
|
||||
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);
|
||||
}
|
||||
while !op_stack.is_empty() {
|
||||
ast.push(ASTNode::BinOp(op_stack.pop().unwrap()));
|
||||
}
|
||||
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::Lit(v)) => {
|
||||
check_if_call!(ast, tokens, index, op_stack);
|
||||
ast.push(ASTNode::Val(Value::Lit(v.clone())));
|
||||
},
|
||||
Some(Token::Id(v)) => {
|
||||
check_if_call!(ast, tokens, index, op_stack);
|
||||
ast.push(ASTNode::Val(Value::Id(v.clone())));
|
||||
},
|
||||
Some(Token::Kw(Keyword::Let)) => {
|
||||
if matches!(expr_type, ExprType::Arg) {
|
||||
return Err(ParseError::new("let not allowed in argument list"));
|
||||
}
|
||||
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 stokens = &tokens[(3 + index)..];
|
||||
let next_end = next_expr_end(stokens);
|
||||
let (mut expr, count) = parse_expr(&stokens[..next_end])?;
|
||||
let (mut expr, count) = parse_expr(&stokens[..next_end], ExprType::Block)?;
|
||||
ast.push(ASTNode::Val(Value::Id(id.to_owned())));
|
||||
ast.append(&mut expr);
|
||||
ast.push(ASTNode::ConstDecl);
|
||||
index += count + 2;// 4 + count - 1
|
||||
index += count + 2;
|
||||
},
|
||||
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"));
|
||||
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*/
|
||||
todo!()
|
||||
},
|
||||
Some(Token::Kw(Keyword::Print)) => {
|
||||
ast.push(ASTNode::Val(Value::KwFn(KeywordFunction::Print)));
|
||||
},
|
||||
Some(Token::Sym(Symbol::EqualSign)) => todo!(),
|
||||
Some(Token::Sym(Symbol::OpenBrace)) => {
|
||||
check_if_call!(ast, tokens, index, op_stack);
|
||||
let end = next_block_end(&tokens[(index + 1)..])?;
|
||||
let (expr, count) = parse_expr(&tokens[(index + 1)..(index + end + 1)])?;
|
||||
let (expr, count) = parse_expr(&tokens[(index + 1)..(index + end + 1)], ExprType::Block)?;
|
||||
ast.push(ASTNode::Block(expr));
|
||||
index += count + 1;
|
||||
},
|
||||
@@ -152,8 +203,9 @@ fn parse_expr(tokens: &[Token]) -> Result<(Vec<ASTNode>, usize), ParseError> {
|
||||
return Err(ParseError::new("unexpected }"));
|
||||
},
|
||||
Some(Token::Sym(Symbol::OpenParen)) => {
|
||||
check_if_call!(ast, tokens, index, op_stack);
|
||||
let end = next_paren_end(&tokens[(index + 1)..])?;
|
||||
let (expr, count) = parse_expr(&tokens[(index + 1)..(index + end + 1)])?;
|
||||
let (expr, count) = parse_expr(&tokens[(index + 1)..(index + end + 1)], ExprType::Block)?;
|
||||
ast.push(ASTNode::Parenthetical(expr));
|
||||
index += count + 1;
|
||||
},
|
||||
@@ -161,56 +213,42 @@ fn parse_expr(tokens: &[Token]) -> Result<(Vec<ASTNode>, usize), ParseError> {
|
||||
return Err(ParseError::new("unexpected )"));
|
||||
},
|
||||
Some(Token::Sym(Symbol::Semicolon)) => {
|
||||
if matches!(expr_type, ExprType::Arg) {
|
||||
return Err(ParseError::new("semicolon within argument"));
|
||||
}
|
||||
if unary_negate && !matches!(tokens.get(index), Some(Token::Sym(Symbol::Semicolon))) {
|
||||
ast.push(ASTNode::UnaryMinus);
|
||||
unary_negate = false;
|
||||
}
|
||||
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::Sym(Symbol::Comma)) => {
|
||||
if matches!(expr_type, ExprType::Arg) {
|
||||
return Err(ParseError::new("comma within argument"));
|
||||
}
|
||||
},
|
||||
Some(Token::Op(op)) => {
|
||||
if (matches!(ast.last(), Some(ASTNode::StatementEnd) | None) || !op_stack.is_empty()) && matches!(op, Operator::Minus) {
|
||||
if (ast.is_empty() || matches!(tokens.get(index - 1), Some(Token::Sym(Symbol::Semicolon) | Token::Op(_)))) && 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() => {
|
||||
op_stack.push(op.clone())
|
||||
},
|
||||
Some(_) => {
|
||||
while op_stack.last().is_some_and(|l| l.get_precedence() < op.get_precedence()) {
|
||||
while op_stack.last().is_some_and(|l| l.get_precedence() > op.get_precedence()) {
|
||||
ast.push(ASTNode::BinOp(op_stack.pop().unwrap()));
|
||||
}
|
||||
op_stack.push(op.clone())
|
||||
}
|
||||
}
|
||||
/*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;
|
||||
}*/
|
||||
|
||||
},
|
||||
}
|
||||
@@ -223,7 +261,7 @@ pub fn parse(tokens: Vec<Token>) -> Result<Vec<ASTNode>, ParseError> {
|
||||
let tokens: &[Token] = &tokens;
|
||||
let mut next = 0;
|
||||
loop {
|
||||
let (mut nodes, count) = parse_expr(&tokens[next..])?;
|
||||
let (mut nodes, count) = parse_expr(&tokens[next..], ExprType::Block)?;
|
||||
ast.append(&mut nodes);
|
||||
next += count;
|
||||
if tokens.get(next).is_none() {
|
||||
|
||||
+1
-1
@@ -1,2 +1,2 @@
|
||||
|
||||
(5 + 6) * 4
|
||||
print "Hello, world!";
|
||||
|
||||
Reference in New Issue
Block a user