statement framework

This commit is contained in:
tezlm 2023-05-10 05:05:45 -07:00
parent 4cc77ce885
commit 7cc7c5c73c
Signed by: tezlm
GPG key ID: 649733FCD94AFBBA
6 changed files with 163 additions and 33 deletions

View file

@ -27,6 +27,14 @@ pub enum Instruction {
input: Pointer,
dest: Register,
},
LoadVariable {
variable: Pointer,
dest: Register,
},
SetVariable {
source: Register,
variable: Pointer
},
Array {
dest: Register,
},
@ -45,6 +53,7 @@ pub enum Instruction {
#[derive(Debug)]
pub enum BinaryOperation {
Add, Subtract, Multiply, Divide,
Equals,
In,
}
@ -65,14 +74,17 @@ fn get_binary_type(operation: &BinaryOperation, data_type_left: &ValueType, data
(Add | Subtract | Multiply | Divide, ValueType::Float, ValueType::Float) => ValueType::Float,
(In, item, ValueType::Array(generic)) if item == generic.as_ref() => ValueType::Boolean,
(Add, ValueType::String, ValueType::String) => ValueType::String,
(Equals, left, right) if left == right => ValueType::Boolean,
_ => panic!("invalid types"),
}
}
use parser::Expr;
impl Compiler {
fn tree(&mut self, tree: &parser::Tree) -> (ValueType, Register) {
fn tree(&mut self, tree: &Expr) -> (ValueType, Register) {
match tree {
parser::Tree::Value { term, kind } => {
Expr::Value { term, kind } => {
use crate::lexer::TokenType;
let (data_type, data) = match kind {
TokenType::Float => {
@ -82,6 +94,15 @@ impl Compiler {
TokenType::String => {
(ValueType::String, Value::String(term[1..term.len() - 1].to_string()))
},
TokenType::Ident => {
let reg = self.next_register();
let idx = self.push_data(Value::String(term.clone()));
self.code.push(Instruction::LoadVariable {
variable: idx,
dest: reg,
});
return (ValueType::Float, reg);
},
_ => todo!(),
};
let reg = self.next_register();
@ -92,7 +113,7 @@ impl Compiler {
});
(data_type, reg)
},
parser::Tree::Unary { op, term } => {
Expr::Unary { op, term } => {
let (data_type, reg_input) = self.tree(term);
let reg_dest = self.next_register();
let operator = match op.as_str() {
@ -106,7 +127,7 @@ impl Compiler {
});
(data_type, reg_dest)
},
parser::Tree::Binary { op, left, right } => {
Expr::Binary { op, left, right } => {
let (data_type_left, reg_left) = self.tree(left);
let (data_type_right, reg_right) = self.tree(right);
let reg_dest = self.next_register();
@ -115,6 +136,7 @@ impl Compiler {
"-" => BinaryOperation::Subtract,
"*" => BinaryOperation::Multiply,
"/" => BinaryOperation::Divide,
"==" => BinaryOperation::Equals,
"in" => BinaryOperation::In,
_ => todo!(),
};
@ -127,7 +149,20 @@ impl Compiler {
});
(data_type, reg_dest)
},
parser::Tree::Array { terms } => {
// Tree::Ternary { op, left, middle, right } => {
// let (data_type_left, reg_left) = self.tree(left);
// let (data_type_middle, reg_middle) = self.tree(middle);
// let (data_type_right, reg_right) = self.tree(right);
// if data_type_left != ValueType::Boolean {
// panic!("different data types");
// }
// if data_type_middle != data_type_right {
// panic!("different data types");
// }
// // reg_left, reg_right
// (ValueType::Boolean, 0)
// },
Expr::Array { terms } => {
let mut terms = terms.iter();
let (kind, first_reg) = self.tree(terms.next().expect("needs at least 1 item for now"));
let mut array = vec![self.data[first_reg as usize].clone()];
@ -169,7 +204,7 @@ impl Compiler {
}
}
pub fn expr(tree: &parser::Tree) -> Bytecode {
pub fn expr(tree: &parser::Expr) -> Bytecode {
let mut compiler = Compiler {
code: Vec::new(),
data: Vec::new(),

View file

@ -13,6 +13,8 @@ mod types;
use types::Value;
use parser::Kind;
use crate::runner::Runtime;
fn test(code: &str) -> Value {
let tokens = lexer::lex(code);
let tokens: Vec<_> = tokens
@ -22,7 +24,9 @@ fn test(code: &str) -> Value {
let tree = parser::expr(&mut tokens.iter().peekable(), 0);
let bytecode = compiler::expr(&tree);
dbg!(&bytecode);
let result = runner::execute(&bytecode);
let mut runtime = Runtime::new();
runtime.global.insert("foo".to_owned(), Value::Float(3.5));
let result = runner::execute(&bytecode, &mut runtime);
dbg!(&result);
result
}
@ -39,14 +43,6 @@ fn parse_kind(code: &str) -> Kind {
}
fn main() {
// test("math.sin");
// test("math.sin(10 * math.pi)");
test("\"foo\" == \"foo\" ? 1 : 4");
test("false ? 3 : 4");
// test("\"hello\".length");
// test("[1, 2, 3].length");
// test("str.capitalize(\"hello world\")");
// test("\"apple\" in str.split(\"apple banana orange\") ? \"apple exists\" : \"apple doesn\'t exist\"");
}
#[cfg(test)]
@ -145,4 +141,28 @@ mod tests {
]));
assert_eq!(parse_kind("struct { foo: u8, bar: u8, baz: struct { one: u8, two: u8 } }"), k);
}
#[test]
fn test_variable() {
assert_eq!(test("foo"), Value::Float(3.5));
}
#[test]
fn test_variable_in_expr() {
assert_eq!(test("(foo + 5) * 4"), Value::Float(34.0));
}
// #[test]
// fn test_ternary() {
// assert_eq!(test("false ? 3 : 4"), Value::Float(4.0));
// }
// test("math.sin");
// test("math.sin(10 * math.pi)");
// test("\"foo\" == \"foo\" ? 1 : 4");
// test("\"hello\".length");
// test("[1, 2, 3].length");
// test("str.capitalize(\"hello world\")");
// test("\"apple\" in str.split(\"apple banana orange\") ? \"apple exists\" : \"apple doesn\'t exist\"");
}

View file

@ -6,13 +6,13 @@ pub enum ParserError {
}
#[derive(Debug, Clone)]
pub enum Tree {
Unary { op: String, term: Box<Tree> },
Binary { op: String, left: Box<Tree>, right: Box<Tree> },
Ternary { op: String, left: Box<Tree>, middle: Box<Tree>, right: Box<Tree> },
Function { ident: Box<Tree>, terms: Vec<Tree> },
Index { array: Box<Tree>, index: Box<Tree> },
Array { terms: Vec<Tree> },
pub enum Expr {
Unary { op: String, term: Box<Expr> },
Binary { op: String, left: Box<Expr>, right: Box<Expr> },
Ternary { op: String, left: Box<Expr>, middle: Box<Expr>, right: Box<Expr> },
Function { ident: Box<Expr>, terms: Vec<Expr> },
Index { array: Box<Expr>, index: Box<Expr> },
Array { terms: Vec<Expr> },
Value { term: String, kind: lexer::TokenType },
}
@ -83,9 +83,9 @@ impl TryFrom<&str> for TernaryOpType {
}
}
pub fn parse(tokens: &mut std::iter::Peekable<std::slice::Iter<&(lexer::TokenType, &str)>>, min_bp: usize) -> Tree {
pub fn parse(tokens: &mut std::iter::Peekable<std::slice::Iter<&(lexer::TokenType, &str)>>, min_bp: usize) -> Expr {
let mut lhs = match tokens.next().expect("missing token") {
token @ (_, "-") | token @ (_, "!") => Tree::Unary { op: token.1.to_owned(), term: Box::new(parse(tokens, 19)) },
token @ (_, "-") | token @ (_, "!") => Expr::Unary { op: token.1.to_owned(), term: Box::new(parse(tokens, 19)) },
(_, "(") => {
if tokens.peek().map(|i| i.1) == Some(")") {
panic!("empty paranthases");
@ -114,11 +114,11 @@ pub fn parse(tokens: &mut std::iter::Peekable<std::slice::Iter<&(lexer::TokenTyp
panic!("missing closing bracket");
}
tokens.next();
Tree::Array { terms: cons }
Expr::Array { terms: cons }
},
token @ (lexer::TokenType::Symbol, _) => panic!("unexpected token {}", token.1),
token @ (_, "in") => panic!("unexpected token {}", token.1),
token @ (kind, _) => Tree::Value { term: token.1.to_owned(), kind: *kind },
token @ (kind, _) => Expr::Value { term: token.1.to_owned(), kind: *kind },
};
loop {
@ -135,7 +135,7 @@ pub fn parse(tokens: &mut std::iter::Peekable<std::slice::Iter<&(lexer::TokenTyp
t @ "(" | t @ "[" => {
tokens.next();
if t == "(" {
let mut cons: Vec<Tree> = Vec::new();
let mut cons: Vec<Expr> = Vec::new();
while tokens.peek().map(|i| i.1) != Some(")") {
cons.push(parse(tokens, 0));
if tokens.peek().map(|i| i.1) == Some(",") {
@ -145,18 +145,18 @@ pub fn parse(tokens: &mut std::iter::Peekable<std::slice::Iter<&(lexer::TokenTyp
}
}
if tokens.peek().map(|i| i.1) != Some(")") { panic!("missing a closing paranthase") }
lhs = Tree::Function { ident: Box::new(lhs), terms: cons };
lhs = Expr::Function { ident: Box::new(lhs), terms: cons };
} else {
let index = parse(tokens, 0);
if tokens.peek().map(|i| i.1) != Some("]") { panic!("missing a closing bracket") }
lhs = Tree::Index { array: Box::new(lhs), index: Box::new(index) };
lhs = Expr::Index { array: Box::new(lhs), index: Box::new(index) };
}
},
"?" => {
tokens.next();
let middle = parse(tokens, 0);
if tokens.next().map(|i| i.1) != Some(":") { panic!("missing a colon") }
lhs = Tree::Ternary {
lhs = Expr::Ternary {
op: "?".into(),
left: Box::new(lhs),
middle: Box::new(middle),
@ -165,7 +165,7 @@ pub fn parse(tokens: &mut std::iter::Peekable<std::slice::Iter<&(lexer::TokenTyp
},
symbol => {
tokens.next();
lhs = Tree::Binary {
lhs = Expr::Binary {
op: symbol.to_owned(),
left: Box::new(lhs),
right: Box::new(parse(tokens, right_bp)),

View file

@ -1,11 +1,16 @@
mod expr;
mod kind;
mod statement;
pub use expr::{
UnaryOpType, BinaryOpType, TernaryOpType,
parse as expr, Tree, ParserError,
parse as expr, Expr, ParserError,
};
pub use kind::{
parse as kind, Kind,
};
pub use statement::{
parse as statement, Statement,
};

44
src/parser/statement.rs Normal file
View file

@ -0,0 +1,44 @@
use crate::lexer::{self, TokenType};
use super::{expr, Expr};
pub enum Statement {
Expression(Box<Expr>),
Let(String, Box<Expr>),
Block(Vec<Statement>),
None,
}
pub fn parse(tokens: &mut std::iter::Peekable<std::slice::Iter<&(lexer::TokenType, &str)>>) -> Statement {
match tokens.peek() {
Some((_, "{")) => {
tokens.next();
let mut statements = Vec::new();
while let Some(next) = tokens.peek() {
if matches!(next, (_, "}")) {
break;
}
tokens.next();
statements.push(parse(tokens));
if !matches!(tokens.peek(), Some((_, ";"))) {
break;
}
tokens.next();
}
if !matches!(tokens.next(), Some((_, "}"))) {
panic!("missing }}");
}
Statement::Block(statements)
},
Some((lexer::TokenType::Keyword, "let")) => {
tokens.next();
let Some((TokenType::Ident, var)) = tokens.next() else {
panic!("expected variable name");
};
assert!(matches!(tokens.next(), Some((_, "="))));
let ex = Box::new(expr(tokens, 0));
Statement::Let(var.to_string(), ex)
},
Some(_) => Statement::Expression(Box::new(expr(tokens, 0))),
None => panic!("no more"),
}
}

View file

@ -4,8 +4,23 @@ use crate::types;
use crate::compiler;
use types::Value;
use std::collections::HashMap;
pub fn execute(bytecode: &compiler::Bytecode) -> Value {
pub struct Runtime {
pub global: HashMap<String, Value>,
pub variables: HashMap<String, Value>,
}
impl Runtime {
pub fn new() -> Self {
Self {
global: HashMap::new(),
variables: HashMap::new(),
}
}
}
pub fn execute(bytecode: &compiler::Bytecode, runtime: &mut Runtime) -> Value {
// let mut data: [f64; 256] = [0.0; 256];
let mut data: [Value; 8] = [0; 8].map(|_| Value::Float(0.0));
for instruction in &bytecode.code {
@ -59,6 +74,17 @@ pub fn execute(bytecode: &compiler::Bytecode) -> Value {
let Value::Array { data: ref mut arr, .. } = data[*dest as usize] else { panic!("not an array") };
arr.push(item);
},
LoadVariable { variable, dest } => {
let Value::String(ref s) = bytecode.data[*variable as usize] else { panic!("not a string") };
data[*dest as usize] = runtime.variables.get(s.as_str())
.or_else(|| runtime.global.get(s.as_str()))
.expect("variable does not exist")
.clone();
},
SetVariable { variable, source } => {
let Value::String(ref s) = bytecode.data[*variable as usize] else { panic!("not a string") };
runtime.variables.insert(s.to_string(), bytecode.data[*variable as usize].clone());
},
_ => todo!(),
}
}