diff --git a/forge_core/src/ast.rs b/forge_core/src/ast.rs index 1da378f..f6911a3 100644 --- a/forge_core/src/ast.rs +++ b/forge_core/src/ast.rs @@ -30,7 +30,7 @@ pub enum Declaration { #[derive(PartialEq, Clone, Debug)] pub struct Global { pub name: String, - pub size: Option, + pub initial: Option, } #[derive(PartialEq, Clone, Debug)] @@ -105,7 +105,6 @@ impl From for Lvalue { #[derive(PartialEq, Clone, Debug)] pub struct VarDecl { pub name: String, - pub size: Option, pub initial: Option, } diff --git a/forge_core/src/compiler/ast_nodes/assignment.rs b/forge_core/src/compiler/ast_nodes/assignment.rs index 4f34d50..5da7917 100644 --- a/forge_core/src/compiler/ast_nodes/assignment.rs +++ b/forge_core/src/compiler/ast_nodes/assignment.rs @@ -18,7 +18,6 @@ impl Compilable for Assignment { #[cfg(test)] mod test { - use super::*; use crate::compiler::test_utils::*; #[test] diff --git a/forge_core/src/compiler/ast_nodes/global.rs b/forge_core/src/compiler/ast_nodes/global.rs index dec3d01..96d9452 100644 --- a/forge_core/src/compiler/ast_nodes/global.rs +++ b/forge_core/src/compiler/ast_nodes/global.rs @@ -7,8 +7,8 @@ use crate::compiler::utils::Variable; impl Compilable for Global { fn process(self, state: &mut State, _: Option<&mut CompiledFn>, _loc: Location) -> Result<(), CompileError> { - if self.size.is_some() { - todo!("Global arrays are not yet supported") + if self.initial.is_some() { + todo!("Globals with initials are not yet supported") } state.add_global(&self.name, |s| Variable::IndirectLabel(s.gensym())) } diff --git a/forge_core/src/compiler/ast_nodes/repeat_loop.rs b/forge_core/src/compiler/ast_nodes/repeat_loop.rs index 4bde2d2..34ca485 100644 --- a/forge_core/src/compiler/ast_nodes/repeat_loop.rs +++ b/forge_core/src/compiler/ast_nodes/repeat_loop.rs @@ -15,7 +15,6 @@ impl Compilable for RepeatLoop { if named_counter { let decl = VarDecl { name: counter_name.clone(), - size: None, initial: Some(Expr::Number(0)), }; decl.process(state, Some(sig), loc)?; diff --git a/forge_core/src/compiler/ast_nodes/var_decl.rs b/forge_core/src/compiler/ast_nodes/var_decl.rs index 3481385..7b66bb8 100644 --- a/forge_core/src/compiler/ast_nodes/var_decl.rs +++ b/forge_core/src/compiler/ast_nodes/var_decl.rs @@ -7,9 +7,6 @@ use crate::compiler::state::State; impl Compilable for VarDecl { fn process(self, state: &mut State, sig: Option<&mut CompiledFn>, loc: Location) -> Result<(), CompileError> { let sig = sig.expect("Var declaration outside function"); - if self.size.is_some() { - todo!("Arrays are not yet supported") - } if let Some(initial) = self.initial { // If it's got an initial value, we have to compile that before we add // the name to scope, or else UB will ensue if it refers to itself: diff --git a/forge_core/src/compiler/compiled_fn.rs b/forge_core/src/compiler/compiled_fn.rs index d0abc6e..3b8445f 100644 --- a/forge_core/src/compiler/compiled_fn.rs +++ b/forge_core/src/compiler/compiled_fn.rs @@ -211,7 +211,6 @@ impl CompiledFn { #[cfg(test)] mod test { - use super::*; use crate::compiler::test_utils::*; #[test] diff --git a/forge_core/src/compiler/mod.rs b/forge_core/src/compiler/mod.rs index 524bd99..f0a7fe1 100644 --- a/forge_core/src/compiler/mod.rs +++ b/forge_core/src/compiler/mod.rs @@ -44,6 +44,13 @@ pub fn build_boot(src: &str) -> Result, CompileError> { for (label, val) in state.strings.iter() { asm.push(format!("{}: .db \"{}\\0\"", label, val)) } + for (label, val) in state.global_scope.iter() { + // All global variables are indirect labels; anything in scope that's not that is a const, + // fn, or string, which we'll emit elsewhere. + if let Variable::IndirectLabel(label) = val { + asm.push(format!("{}: .db 0", label)) + } + } for (_, val) in state.functions.iter_mut() { asm.push(format!("{}:", val.label)); asm.append(val.preamble.as_mut()); @@ -118,7 +125,24 @@ mod test { #[test] fn test_global_vars() { - + // Trying a non-str global var + let asm = build_boot("global foo; fn main() { foo = 3; }".into()).unwrap(); + assert_eq!(asm.join("\n"), vec![ + ".org 0x400", + "push stack", + "call _forge_gensym_2", + "hlt", + "_forge_gensym_1: .db 0", // The global var + "_forge_gensym_2:", // main() + "dup", "pushr", "pushr", // The frame is zero length; that's a global we're assigning to + "push 3", // rvalue + "push _forge_gensym_1", // lvalue + "storew", + "push 0", + "_forge_gensym_3:", + "popr", "pop", "popr", "pop", "ret", + "stack: .db 0", + ].join("\n")) } #[test] diff --git a/forge_core/src/parser/ast_nodes/global.rs b/forge_core/src/parser/ast_nodes/global.rs index 8b10071..614707a 100644 --- a/forge_core/src/parser/ast_nodes/global.rs +++ b/forge_core/src/parser/ast_nodes/global.rs @@ -6,9 +6,9 @@ impl AstNode for Global { fn from_pair(pair: Pair) -> Self { let mut inner = pair.into_inner().peekable(); let name = String::from(inner.next().unwrap().as_str()); - let size = inner.next().map(Expr::from_pair); + let initial = inner.next().map(Expr::from_pair); - Global { name, size } + Global { name, initial } } } @@ -23,18 +23,18 @@ mod test { Global::from_str("global foo;"), Ok(Global { name: "foo".into(), - size: None, + initial: None, }) ) } #[test] - fn parse_global_arrays() { + fn parse_global_vars() { assert_eq!( - Global::from_str("global foo[10];"), + Global::from_str("global foo = 10;"), Ok(Global { name: "foo".into(), - size: Some(10.into()), + initial: Some(10.into()), }) ); } diff --git a/forge_core/src/parser/ast_nodes/var_decl.rs b/forge_core/src/parser/ast_nodes/var_decl.rs index 8606109..510d5ef 100644 --- a/forge_core/src/parser/ast_nodes/var_decl.rs +++ b/forge_core/src/parser/ast_nodes/var_decl.rs @@ -1,23 +1,14 @@ use crate::ast::{Expr, VarDecl}; -use crate::parser::{AstNode, Pair, PairExt, PestRule}; +use crate::parser::{AstNode, Pair, PestRule}; impl AstNode for VarDecl { const RULE: PestRule = PestRule::var_decl; fn from_pair(pair: Pair) -> Self { let mut inner = pair.into_inner(); let name = String::from(inner.next().unwrap().as_str()); - let mut size = None; - let mut initial = None; + let initial = inner.next().map(Expr::from_pair); - for p in inner { - match p.as_rule() { - PestRule::size => { size = Some(Expr::from_pair(p.first())) } - PestRule::expr => { initial = Some(Expr::from_pair(p)) } - _ => unreachable!() - } - } - - Self { name, size, initial } + Self { name, initial } } } @@ -33,7 +24,6 @@ mod test { Statement::from_str("var blah;"), Ok(Statement::VarDecl(VarDecl { name: "blah".into(), - size: None, initial: None, })) ); @@ -42,10 +32,9 @@ mod test { #[test] fn parse_var_decl_with_value() { assert_eq!( - VarDecl::from_str("var blah[7] = 35"), + VarDecl::from_str("var blah = 35"), Ok(VarDecl { name: "blah".into(), - size: Some(7.into()), initial: Some(35.into()), }) ); diff --git a/forge_core/src/parser/forge.pest b/forge_core/src/parser/forge.pest index ea502bc..af200f9 100644 --- a/forge_core/src/parser/forge.pest +++ b/forge_core/src/parser/forge.pest @@ -91,7 +91,6 @@ return_stmt = { "return" ~ expr? } conditional = { "if" ~ "(" ~ expr ~ ")" ~ block ~ ("else" ~ block)? } while_loop = { "while" ~ "(" ~ expr ~ ")" ~ block } repeat_loop = { "repeat" ~ "(" ~ expr ~ ")" ~ name? ~ block } -var_decl = { "var" ~ name ~ size? ~ ("=" ~ expr)? } -global = { "global" ~ name ~ size? ~ ";" } -size = { "[" ~ expr ~ "]" } +var_decl = { "var" ~ name ~ ("=" ~ expr)? } +global = { "global" ~ name ~ ("=" ~ expr)? ~ ";" } const_decl = { "const" ~ name ~ "=" ~ (string | expr) ~ ";" } diff --git a/vtest/src/forge_tests.rs b/vtest/src/forge_tests.rs index b3b6416..381ef2a 100644 --- a/vtest/src/forge_tests.rs +++ b/vtest/src/forge_tests.rs @@ -126,6 +126,20 @@ fn array_test() { ) } +#[test] +fn global_test() { + // Declare an array and do things + assert_eq!( + main_return( + "global a; + fn main() { + a = 10; + return a; + }"), + 10 + ) +} + //#[test] // This is no longer cursed, or a test. The revised calling convention with the pool pointer makes // it now perfectly sane. Left here for posterity.