We have blocks & scopes
This commit is contained in:
+30
-12
@@ -31,12 +31,16 @@ macro_rules! some_or_error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_value(v: Value, scope: &HashMap<String, VarType>) -> Result<TeaValue, InterpreterError> {
|
fn get_value(v: Value, scopes: &mut [Scope]) -> Result<TeaValue, InterpreterError> {
|
||||||
match v {
|
match v {
|
||||||
Value::Lit(t) => Ok(t),
|
Value::Lit(t) => Ok(t),
|
||||||
Value::Id(s) => match scope.get(&s) {
|
Value::Id(s) => {
|
||||||
None => Err(InterpreterError::new("undefined variable")),
|
match scopes.iter().rev().skip_while(|scope| !scope.contains_key(&s)).next() {
|
||||||
Some(VarType::Const(t)) => Ok(t.clone()),
|
None => Err(InterpreterError::new("undefined variable")),
|
||||||
|
Some(scope) => match scope.get(&s).unwrap() {
|
||||||
|
VarType::Const(t) => Ok(t.clone()),
|
||||||
|
},
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -58,20 +62,28 @@ macro_rules! apply_op {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn interpret(ast: Vec<ASTNode>) -> Result<Vec<Value>, InterpreterError> {
|
type Scope = HashMap<String, VarType>;
|
||||||
|
|
||||||
|
fn interpret_block(ast: Vec<ASTNode>, scopes: &mut Vec<Scope>) -> Result<Vec<Value>, InterpreterError> {
|
||||||
let mut ast = ast.clone();
|
let mut ast = ast.clone();
|
||||||
ast.reverse();
|
ast.reverse();
|
||||||
let mut stack = vec![];
|
let mut stack = vec![];
|
||||||
let mut global_scope: HashMap<String, VarType> = HashMap::new();
|
//let mut scope = Scope::new();
|
||||||
loop {
|
loop {
|
||||||
match ast.pop() {
|
match ast.pop() {
|
||||||
None => return Ok(stack),
|
None => return Ok(stack),
|
||||||
|
Some(ASTNode::Block(tokens)) => {
|
||||||
|
scopes.push(HashMap::new());
|
||||||
|
let mut result = interpret_block(tokens, scopes)?;
|
||||||
|
scopes.pop();
|
||||||
|
stack.append(&mut result);
|
||||||
|
},
|
||||||
Some(ASTNode::Val(v)) => stack.push(v),
|
Some(ASTNode::Val(v)) => stack.push(v),
|
||||||
Some(ASTNode::BinOp(op)) => {
|
Some(ASTNode::BinOp(op)) => {
|
||||||
let b = some_or_error!(stack.pop(), InterpreterError::new("right value needed"));
|
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 a = some_or_error!(stack.pop(), InterpreterError::new("left value needed"));
|
||||||
let b: TeaValue = get_value(b, &global_scope)?;
|
let b: TeaValue = get_value(b, scopes)?;
|
||||||
let a: TeaValue = get_value(a, &global_scope)?;
|
let a: TeaValue = get_value(a, scopes)?;
|
||||||
stack.push(Value::Lit(match op {
|
stack.push(Value::Lit(match op {
|
||||||
Operator::Plus => {
|
Operator::Plus => {
|
||||||
apply_op!(a, b, +)
|
apply_op!(a, b, +)
|
||||||
@@ -89,7 +101,7 @@ pub fn interpret(ast: Vec<ASTNode>) -> Result<Vec<Value>, InterpreterError> {
|
|||||||
},
|
},
|
||||||
Some(ASTNode::UnaryMinus) => {
|
Some(ASTNode::UnaryMinus) => {
|
||||||
let x = some_or_error!(stack.pop(), InterpreterError::new("value needed"));
|
let x = some_or_error!(stack.pop(), InterpreterError::new("value needed"));
|
||||||
let x: TeaValue = get_value(x, &global_scope)?;
|
let x: TeaValue = get_value(x, scopes)?;
|
||||||
stack.push(Value::Lit(match x {
|
stack.push(Value::Lit(match x {
|
||||||
TeaValue::Float(f) => TeaValue::Float(-f),
|
TeaValue::Float(f) => TeaValue::Float(-f),
|
||||||
TeaValue::Int(i) => TeaValue::Int(-i),
|
TeaValue::Int(i) => TeaValue::Int(-i),
|
||||||
@@ -100,14 +112,15 @@ pub fn interpret(ast: Vec<ASTNode>) -> Result<Vec<Value>, InterpreterError> {
|
|||||||
Some(ASTNode::ConstDecl) => {
|
Some(ASTNode::ConstDecl) => {
|
||||||
let rhs = some_or_error!(stack.pop(), InterpreterError::new("rhs value needed"));
|
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 lhs = some_or_error!(stack.pop(), InterpreterError::new("lhs value needed"));
|
||||||
let rhs: TeaValue = get_value(rhs, &global_scope)?;
|
let rhs: TeaValue = get_value(rhs, scopes)?;
|
||||||
|
//let current_scope = .unwrap();
|
||||||
match lhs {
|
match lhs {
|
||||||
Value::Lit(_) => return Err(InterpreterError::new("invalid left hand side")),
|
Value::Lit(_) => return Err(InterpreterError::new("invalid left hand side")),
|
||||||
Value::Id(s) => {
|
Value::Id(s) => {
|
||||||
if global_scope.contains_key(&s) {
|
if scopes.last().unwrap().contains_key(&s) {
|
||||||
return Err(InterpreterError::new("already defined constant"));
|
return Err(InterpreterError::new("already defined constant"));
|
||||||
} else {
|
} else {
|
||||||
global_scope.insert(s, VarType::Const(rhs));
|
scopes.last_mut().unwrap().insert(s, VarType::Const(rhs));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -120,3 +133,8 @@ pub fn interpret(ast: Vec<ASTNode>) -> Result<Vec<Value>, InterpreterError> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn interpret(ast: Vec<ASTNode>) -> Result<Vec<Value>, InterpreterError> {
|
||||||
|
let mut scopes = vec![HashMap::new()];
|
||||||
|
interpret_block(ast, &mut scopes)
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ use super::{ whitespace_chars, Token };
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Keyword {
|
pub enum Keyword {
|
||||||
Let,
|
Let,
|
||||||
|
Fn,
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! match_keyword {
|
macro_rules! match_keyword {
|
||||||
@@ -15,5 +16,6 @@ macro_rules! match_keyword {
|
|||||||
|
|
||||||
pub fn parse_keyword(input: &str) -> Option<(Token, &str)> {
|
pub fn parse_keyword(input: &str) -> Option<(Token, &str)> {
|
||||||
match_keyword!("let", Token::Kw(Keyword::Let), input);
|
match_keyword!("let", Token::Kw(Keyword::Let), input);
|
||||||
|
match_keyword!("fn", Token::Kw(Keyword::Fn), input);
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ use super::Token;
|
|||||||
pub enum Symbol {
|
pub enum Symbol {
|
||||||
EqualSign,
|
EqualSign,
|
||||||
Semicolon,
|
Semicolon,
|
||||||
|
OpenBrace,
|
||||||
|
CloseBrace,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_symbol(input: &str) -> Option<(Token, &str)> {
|
pub fn parse_symbol(input: &str) -> Option<(Token, &str)> {
|
||||||
@@ -12,6 +14,8 @@ pub fn parse_symbol(input: &str) -> Option<(Token, &str)> {
|
|||||||
match c {
|
match c {
|
||||||
'=' => Some((Token::Sym(Symbol::EqualSign), input)),
|
'=' => Some((Token::Sym(Symbol::EqualSign), input)),
|
||||||
';' => Some((Token::Sym(Symbol::Semicolon), input)),
|
';' => Some((Token::Sym(Symbol::Semicolon), input)),
|
||||||
|
'{' => Some((Token::Sym(Symbol::OpenBrace), input)),
|
||||||
|
'}' => Some((Token::Sym(Symbol::CloseBrace), input)),
|
||||||
_ => None
|
_ => None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+44
-3
@@ -20,6 +20,7 @@ pub enum ASTNode {
|
|||||||
BinOp(Operator), // binary operation
|
BinOp(Operator), // binary operation
|
||||||
UnaryMinus,
|
UnaryMinus,
|
||||||
StatementEnd,
|
StatementEnd,
|
||||||
|
Block(Vec<ASTNode>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -55,9 +56,28 @@ macro_rules! assert_match {
|
|||||||
|
|
||||||
fn next_expr_end(tokens: &[Token]) -> usize {
|
fn next_expr_end(tokens: &[Token]) -> usize {
|
||||||
let mut index = 0;
|
let mut index = 0;
|
||||||
|
let mut block_count = 0usize;
|
||||||
loop {
|
loop {
|
||||||
if matches!(tokens.get(index), Some(Token::Sym(Symbol::Semicolon)) | None) {
|
match tokens.get(index) {
|
||||||
return index;
|
Some(Token::Sym(Symbol::OpenBrace)) => block_count += 1,
|
||||||
|
Some(Token::Sym(Symbol::CloseBrace)) => block_count -= 1,
|
||||||
|
Some(Token::Sym(Symbol::Semicolon)) if block_count == 0 => return index,
|
||||||
|
None => return index,
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next_block_end(tokens: &[Token]) -> Result<usize, ParseError> {
|
||||||
|
let mut index = 0;
|
||||||
|
loop {
|
||||||
|
let token = tokens.get(index);
|
||||||
|
if token.is_none() {
|
||||||
|
return Err(ParseError::new("} expected"));
|
||||||
|
}
|
||||||
|
if matches!(token, Some(Token::Sym(Symbol::CloseBrace))) {
|
||||||
|
return Ok(index);
|
||||||
}
|
}
|
||||||
index += 1;
|
index += 1;
|
||||||
}
|
}
|
||||||
@@ -82,10 +102,31 @@ fn parse_expr(tokens: &[Token]) -> Result<(Vec<ASTNode>, usize), ParseError> {
|
|||||||
ast.push(ASTNode::ConstDecl);
|
ast.push(ASTNode::ConstDecl);
|
||||||
index += count + 3; // 4 + count - 1
|
index += count + 3; // 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"));
|
||||||
|
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::Sym(Symbol::EqualSign)) => todo!(),
|
||||||
|
Some(Token::Sym(Symbol::OpenBrace)) => {
|
||||||
|
let end = next_block_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::CloseBrace)) => {
|
||||||
|
return Err(ParseError::new("unexpected }"));
|
||||||
|
},
|
||||||
Some(Token::Sym(Symbol::Semicolon)) => {
|
Some(Token::Sym(Symbol::Semicolon)) => {
|
||||||
ast.push(ASTNode::StatementEnd);
|
ast.push(ASTNode::StatementEnd);
|
||||||
},
|
},
|
||||||
Some(Token::Sym(Symbol::EqualSign)) => todo!(),
|
|
||||||
Some(Token::Op(op)) => {
|
Some(Token::Op(op)) => {
|
||||||
if ast.is_empty() && matches!(op, Operator::Minus) {
|
if ast.is_empty() && matches!(op, Operator::Minus) {
|
||||||
ast.push(match tokens.get(index + 1) {
|
ast.push(match tokens.get(index + 1) {
|
||||||
|
|||||||
Reference in New Issue
Block a user