From 7cc7c5c73ce373704bf93d83e9e23eac848340a1 Mon Sep 17 00:00:00 2001 From: tezlm Date: Wed, 10 May 2023 05:05:45 -0700 Subject: [PATCH] statement framework --- src/compiler.rs | 47 +++++++++++++++++++++++++++++++++++------ src/main.rs | 38 +++++++++++++++++++++++++-------- src/parser/expr.rs | 32 ++++++++++++++-------------- src/parser/mod.rs | 7 +++++- src/parser/statement.rs | 44 ++++++++++++++++++++++++++++++++++++++ src/runner.rs | 28 +++++++++++++++++++++++- 6 files changed, 163 insertions(+), 33 deletions(-) create mode 100644 src/parser/statement.rs diff --git a/src/compiler.rs b/src/compiler.rs index 56eadbe..72b1cb6 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -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(), diff --git a/src/main.rs b/src/main.rs index 1a6e678..f6f5d92 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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\""); + } diff --git a/src/parser/expr.rs b/src/parser/expr.rs index 000a8bc..15d1b85 100644 --- a/src/parser/expr.rs +++ b/src/parser/expr.rs @@ -6,13 +6,13 @@ pub enum ParserError { } #[derive(Debug, Clone)] -pub enum Tree { - Unary { op: String, term: Box }, - Binary { op: String, left: Box, right: Box }, - Ternary { op: String, left: Box, middle: Box, right: Box }, - Function { ident: Box, terms: Vec }, - Index { array: Box, index: Box }, - Array { terms: Vec }, +pub enum Expr { + Unary { op: String, term: Box }, + Binary { op: String, left: Box, right: Box }, + Ternary { op: String, left: Box, middle: Box, right: Box }, + Function { ident: Box, terms: Vec }, + Index { array: Box, index: Box }, + Array { terms: Vec }, Value { term: String, kind: lexer::TokenType }, } @@ -83,9 +83,9 @@ impl TryFrom<&str> for TernaryOpType { } } -pub fn parse(tokens: &mut std::iter::Peekable>, min_bp: usize) -> Tree { +pub fn parse(tokens: &mut std::iter::Peekable>, 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 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 { tokens.next(); if t == "(" { - let mut cons: Vec = Vec::new(); + let mut cons: Vec = 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 { 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 { tokens.next(); - lhs = Tree::Binary { + lhs = Expr::Binary { op: symbol.to_owned(), left: Box::new(lhs), right: Box::new(parse(tokens, right_bp)), diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 09095b1..464ed43 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -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, +}; diff --git a/src/parser/statement.rs b/src/parser/statement.rs new file mode 100644 index 0000000..bb189c0 --- /dev/null +++ b/src/parser/statement.rs @@ -0,0 +1,44 @@ +use crate::lexer::{self, TokenType}; +use super::{expr, Expr}; + +pub enum Statement { + Expression(Box), + Let(String, Box), + Block(Vec), + None, +} + +pub fn parse(tokens: &mut std::iter::Peekable>) -> 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"), + } +} diff --git a/src/runner.rs b/src/runner.rs index 34e46fc..b721384 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -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, + pub variables: HashMap, +} + +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!(), } }