We have SSA
This commit is contained in:
@@ -0,0 +1,122 @@
|
|||||||
|
use crate::lex::{ TeaValue, Operator };
|
||||||
|
use crate::parse::{ ASTNode, Value };
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum VarType {
|
||||||
|
Const(TeaValue),
|
||||||
|
//Mut,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct InterpreterError {
|
||||||
|
description: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InterpreterError {
|
||||||
|
pub fn new(e: &str) -> Self {
|
||||||
|
Self {
|
||||||
|
description: e.to_owned(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! some_or_error {
|
||||||
|
($matchee:expr, $ret:expr) => {
|
||||||
|
match $matchee {
|
||||||
|
Some(s) => s,
|
||||||
|
_ => return Err($ret),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_value(v: Value, scope: &HashMap<String, VarType>) -> Result<TeaValue, InterpreterError> {
|
||||||
|
match v {
|
||||||
|
Value::Lit(t) => Ok(t),
|
||||||
|
Value::Id(s) => match scope.get(&s) {
|
||||||
|
None => Err(InterpreterError::new("undefined variable")),
|
||||||
|
Some(VarType::Const(t)) => Ok(t.clone()),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! apply_op {
|
||||||
|
($a:ident, $b:ident, $op:tt) => {
|
||||||
|
match ($a, $b) {
|
||||||
|
(TeaValue::Float(aa), TeaValue::Float(bb)) => {
|
||||||
|
TeaValue::Float(aa $op bb)
|
||||||
|
},
|
||||||
|
(TeaValue::Int(aa), TeaValue::Int(bb)) => {
|
||||||
|
TeaValue::Int(aa $op bb)
|
||||||
|
},
|
||||||
|
//(TeaValue::Uint(aa), TeaValue::Uint(bb)) => {
|
||||||
|
// TeaValue::Uint(aa $op bb)
|
||||||
|
//},
|
||||||
|
_ => panic!("Invalid types"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn interpret(ast: Vec<ASTNode>) -> Result<Vec<Value>, InterpreterError> {
|
||||||
|
let mut ast = ast.clone();
|
||||||
|
ast.reverse();
|
||||||
|
let mut stack = vec![];
|
||||||
|
let mut global_scope: HashMap<String, VarType> = HashMap::new();
|
||||||
|
loop {
|
||||||
|
match ast.pop() {
|
||||||
|
None => return Ok(stack),
|
||||||
|
Some(ASTNode::Val(v)) => stack.push(v),
|
||||||
|
Some(ASTNode::BinOp(op)) => {
|
||||||
|
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 b: TeaValue = get_value(b, &global_scope)?;
|
||||||
|
let a: TeaValue = get_value(a, &global_scope)?;
|
||||||
|
stack.push(Value::Lit(match op {
|
||||||
|
Operator::Plus => {
|
||||||
|
apply_op!(a, b, +)
|
||||||
|
},
|
||||||
|
Operator::Minus => {
|
||||||
|
apply_op!(a, b, -)
|
||||||
|
},
|
||||||
|
Operator::Star => {
|
||||||
|
apply_op!(a, b, *)
|
||||||
|
},
|
||||||
|
Operator::Slash => {
|
||||||
|
apply_op!(a, b, /)
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
Some(ASTNode::UnaryMinus) => {
|
||||||
|
let x = some_or_error!(stack.pop(), InterpreterError::new("value needed"));
|
||||||
|
let x: TeaValue = get_value(x, &global_scope)?;
|
||||||
|
stack.push(Value::Lit(match x {
|
||||||
|
TeaValue::Float(f) => TeaValue::Float(-f),
|
||||||
|
TeaValue::Int(i) => TeaValue::Int(-i),
|
||||||
|
TeaValue::Uint(u) => TeaValue::Int(-(u as i32)),
|
||||||
|
TeaValue::String(_) => return Err(InterpreterError::new("cannot invert string")),
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
Some(ASTNode::ConstDecl) => {
|
||||||
|
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, &global_scope)?;
|
||||||
|
match lhs {
|
||||||
|
Value::Lit(_) => return Err(InterpreterError::new("invalid left hand side")),
|
||||||
|
Value::Id(s) => {
|
||||||
|
if global_scope.contains_key(&s) {
|
||||||
|
return Err(InterpreterError::new("already defined constant"));
|
||||||
|
} else {
|
||||||
|
global_scope.insert(s, VarType::Const(rhs));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Some(ASTNode::StatementEnd) => {
|
||||||
|
if !stack.is_empty() {
|
||||||
|
return Err(InterpreterError::new("stack not empty"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+15
-7
@@ -1,16 +1,24 @@
|
|||||||
|
|
||||||
pub mod literal;
|
pub mod literal;
|
||||||
use self::literal::parse_literal;
|
|
||||||
pub mod identifier;
|
pub mod identifier;
|
||||||
use self::identifier::parse_identifier;
|
|
||||||
pub mod operator;
|
pub mod operator;
|
||||||
use self::operator::{ parse_operator, Operator };
|
|
||||||
pub mod symbol;
|
pub mod symbol;
|
||||||
use self::symbol::{ parse_symbol, Symbol };
|
|
||||||
pub mod keyword;
|
pub mod keyword;
|
||||||
use self::keyword::{ parse_keyword, Keyword };
|
use self::{
|
||||||
|
literal::parse_literal,
|
||||||
|
identifier::parse_identifier,
|
||||||
|
operator::parse_operator,
|
||||||
|
symbol::parse_symbol,
|
||||||
|
keyword::parse_keyword,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
pub use self::{
|
||||||
|
operator::Operator,
|
||||||
|
symbol::Symbol,
|
||||||
|
keyword::Keyword,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
pub enum TeaValue {
|
pub enum TeaValue {
|
||||||
Int(i32),
|
Int(i32),
|
||||||
Uint(u32),
|
Uint(u32),
|
||||||
@@ -54,7 +62,7 @@ macro_rules! try_parse {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_tokens(s: &str) -> Result<Vec<Token>, (Vec<Token>, &str)> {
|
pub fn lex_tokens(s: &str) -> Result<Vec<Token>, (Vec<Token>, &str)> {
|
||||||
let mut input = s;
|
let mut input = s;
|
||||||
let mut tokens: Vec<Token> = vec![];
|
let mut tokens: Vec<Token> = vec![];
|
||||||
loop {
|
loop {
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
use super::Token;
|
use super::Token;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum Operator {
|
pub enum Operator {
|
||||||
Plus,
|
Plus,
|
||||||
Minus,
|
Minus,
|
||||||
|
|||||||
+9
-3
@@ -3,10 +3,16 @@ use std::env::args;
|
|||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod lex;
|
mod lex;
|
||||||
use lex::parse_tokens;
|
use lex::lex_tokens;
|
||||||
|
mod parse;
|
||||||
|
use parse::parse;
|
||||||
|
mod interpret;
|
||||||
|
use interpret::interpret;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let args: String = args().skip(1).collect::<Vec<_>>().join(" ");
|
let args: String = args().skip(1).collect::<Vec<_>>().join(" ");
|
||||||
let k = parse_tokens(&args);
|
let k = lex_tokens(&args).unwrap();
|
||||||
println!("{k:?}");
|
let p = parse(k).unwrap();
|
||||||
|
let i = interpret(p);
|
||||||
|
println!("{i:?}");
|
||||||
}
|
}
|
||||||
|
|||||||
+126
@@ -0,0 +1,126 @@
|
|||||||
|
|
||||||
|
use crate::lex::{
|
||||||
|
Token,
|
||||||
|
TeaValue,
|
||||||
|
Operator,
|
||||||
|
Keyword,
|
||||||
|
Symbol,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum Value {
|
||||||
|
Lit(TeaValue),
|
||||||
|
Id(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum ASTNode {
|
||||||
|
Val(Value),
|
||||||
|
ConstDecl, // Const declaration
|
||||||
|
BinOp(Operator), // binary operation
|
||||||
|
UnaryMinus,
|
||||||
|
StatementEnd,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ParseError {
|
||||||
|
description: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ParseError {
|
||||||
|
pub fn new(e: &str) -> Self {
|
||||||
|
Self {
|
||||||
|
description: e.to_owned(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! match_or_return {
|
||||||
|
($matchee:expr, $pattern:pat, $extract:expr, $ret:expr) => {
|
||||||
|
match $matchee {
|
||||||
|
Some($pattern) => $extract,
|
||||||
|
_ => return Err($ret),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
loop {
|
||||||
|
if matches!(tokens.get(index), Some(Token::Sym(Symbol::Semicolon)) | None) {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_expr(tokens: &[Token]) -> Result<(Vec<ASTNode>, usize), ParseError> {
|
||||||
|
let mut ast = vec![];
|
||||||
|
let mut index = 0;
|
||||||
|
loop {
|
||||||
|
match tokens.get(index) {
|
||||||
|
None => 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])?;
|
||||||
|
ast.push(ASTNode::Val(Value::Id(id.to_owned())));
|
||||||
|
ast.append(&mut expr);
|
||||||
|
ast.push(ASTNode::ConstDecl);
|
||||||
|
index += count + 3; // 4 + count - 1
|
||||||
|
},
|
||||||
|
Some(Token::Sym(Symbol::Semicolon)) => {
|
||||||
|
ast.push(ASTNode::StatementEnd);
|
||||||
|
},
|
||||||
|
Some(Token::Sym(Symbol::EqualSign)) => todo!(),
|
||||||
|
Some(Token::Op(op)) => {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse(tokens: Vec<Token>) -> Result<Vec<ASTNode>, ParseError> {
|
||||||
|
let mut ast = vec![];
|
||||||
|
let tokens: &[Token] = &tokens;
|
||||||
|
let mut next = 0;
|
||||||
|
loop {
|
||||||
|
let (mut nodes, count) = parse_expr(&tokens[next..])?;
|
||||||
|
ast.append(&mut nodes);
|
||||||
|
next += count;
|
||||||
|
if tokens.get(next).is_none() {
|
||||||
|
return Ok(ast);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user