From d74a887c4ed858da7ecca2bdb4b3e1c9c2d1128b Mon Sep 17 00:00:00 2001 From: Sofia Date: Sat, 14 Mar 2026 18:31:40 +0200 Subject: [PATCH] Find constants --- examples/test.lua | 2 +- src/ast.rs | 12 ++++--- src/compile.rs | 74 +++++++++++++++++++++++++++++++++++++++ src/main.rs | 7 ++-- src/token_stream/lexer.rs | 3 ++ src/vm.rs | 23 ++++++++++++ 6 files changed, 114 insertions(+), 7 deletions(-) create mode 100644 src/compile.rs create mode 100644 src/vm.rs diff --git a/examples/test.lua b/examples/test.lua index 7dff1e4..9e1d02d 100644 --- a/examples/test.lua +++ b/examples/test.lua @@ -1 +1 @@ -c = max(5, 7) \ No newline at end of file +global c = max(5, 7) \ No newline at end of file diff --git a/src/ast.rs b/src/ast.rs index 7b3ac8b..3a10a93 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -241,12 +241,16 @@ impl Parse for Statement { let then = stream.parse()?; stream.expect(Token::Keyword(Keyword::End))?; Ok(Self::If(cond, then)) - } else if peeked == Some(Token::Keyword(Keyword::Local)) { - stream.next(); + } else if let Some(Token::Keyword(Keyword::Local | Keyword::Global)) = peeked { + let access_modifier = match stream.next() { + Some(Token::Keyword(Keyword::Local)) => AccessModifier::Local, + Some(Token::Keyword(Keyword::Global)) => AccessModifier::Global, + _ => panic!(), + }; let name = stream.parse()?; stream.expect(Token::Symbol('='))?; let expr = stream.parse()?; - Ok(Statement::Assignment(AccessModifier::Local, name, expr)) + Ok(Statement::Assignment(access_modifier, name, expr)) } else if let Some(Token::Word(_)) = peeked && stream.peek2() == Some(Token::Symbol('=')) { @@ -263,7 +267,7 @@ impl Parse for Statement { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] pub enum AccessModifier { Local, Global, diff --git a/src/compile.rs b/src/compile.rs new file mode 100644 index 0000000..39da5b7 --- /dev/null +++ b/src/compile.rs @@ -0,0 +1,74 @@ +use std::collections::HashSet; + +use crate::{ + ast::{AccessModifier, Block, Expression, Literal, Statement}, + vm::{Constant, VMNumber}, +}; + +struct State { + pub constants: Vec, +} + +impl Block { + pub fn find_constants(&self) -> HashSet { + let mut constants = HashSet::new(); + + for statement in &self.statements { + constants.extend(statement.kind.find_constants()); + } + + constants + } +} + +impl Statement { + pub fn find_constants(&self) -> HashSet { + match self { + Statement::Assignment(access, name, expr) => { + let mut constants = HashSet::new(); + if *access == AccessModifier::Global { + constants.insert(Constant::String(name.kind.clone())); + } + constants.extend(expr.kind.find_constants()); + constants + } + Statement::Return(expr) => expr.kind.find_constants(), + Statement::If(cond, then) => { + let mut constants = HashSet::new(); + constants.extend(cond.kind.find_constants()); + constants.extend(then.find_constants()); + constants + } + } + } +} + +impl Expression { + pub fn find_constants(&self) -> HashSet { + match self { + Expression::ValueRef(_) => HashSet::new(), + Expression::BinOp(_, lhs, rhs) => { + let mut constants = HashSet::new(); + constants.extend(lhs.kind.find_constants()); + constants.extend(rhs.kind.find_constants()); + constants + } + Expression::FunctionDefinition(_, block) => block.find_constants(), + Expression::FunctionCall(expr, params) => { + let mut constants = HashSet::new(); + constants.extend(expr.kind.find_constants()); + for param in ¶ms.kind.0 { + constants.extend(param.kind.find_constants()); + } + constants + } + Expression::Literal(literal) => match literal { + Literal::Number(value) => { + let mut constants = HashSet::new(); + constants.insert(Constant::Number(value.to_bits())); + constants + } + }, + } + } +} diff --git a/src/main.rs b/src/main.rs index ea591df..9e0d44c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,7 +9,9 @@ use crate::{ }; mod ast; +mod compile; mod token_stream; +mod vm; static TEST: &str = include_str!("../examples/test.lua"); @@ -23,7 +25,8 @@ fn main() { let chunk = stream.parse::().unwrap(); stream.expect(Token::Eof).unwrap(); - dbg!(chunk); + dbg!(&chunk); - println!("Hello, world!"); + let constants = chunk.find_constants(); + dbg!(&constants); } diff --git a/src/token_stream/lexer.rs b/src/token_stream/lexer.rs index 4dfc4cc..5e8a143 100644 --- a/src/token_stream/lexer.rs +++ b/src/token_stream/lexer.rs @@ -12,6 +12,7 @@ pub enum Keyword { Function, End, Local, + Global, Return, If, Then, @@ -23,6 +24,7 @@ impl Keyword { "function" => Keyword::Function, "end" => Keyword::End, "local" => Keyword::Local, + "global" => Keyword::Global, "return" => Keyword::Return, "if" => Keyword::If, "then" => Keyword::Then, @@ -37,6 +39,7 @@ impl ToString for Keyword { Keyword::Function => "function", Keyword::End => "end", Keyword::Local => "local", + Keyword::Global => "global", Keyword::Return => "return", Keyword::If => "if", Keyword::Then => "then", diff --git a/src/vm.rs b/src/vm.rs new file mode 100644 index 0000000..a817cce --- /dev/null +++ b/src/vm.rs @@ -0,0 +1,23 @@ +use std::fmt::Debug; + +use crate::ast::LuaNumber; + +pub type VMNumber = u64; + +#[derive(Clone, Hash, PartialEq, Eq)] +pub enum Constant { + String(String), + Number(VMNumber), +} + +impl Debug for Constant { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::String(arg0) => f.debug_tuple("String").field(arg0).finish(), + Self::Number(arg0) => f + .debug_tuple("Number") + .field(&LuaNumber::from_bits(*arg0)) + .finish(), + } + } +}