Globals work, sizes are no longer part of the grammar
This commit is contained in:
@@ -30,7 +30,7 @@ pub enum Declaration {
|
|||||||
#[derive(PartialEq, Clone, Debug)]
|
#[derive(PartialEq, Clone, Debug)]
|
||||||
pub struct Global {
|
pub struct Global {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub size: Option<Expr>,
|
pub initial: Option<Expr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Clone, Debug)]
|
#[derive(PartialEq, Clone, Debug)]
|
||||||
@@ -105,7 +105,6 @@ impl From<Expr> for Lvalue {
|
|||||||
#[derive(PartialEq, Clone, Debug)]
|
#[derive(PartialEq, Clone, Debug)]
|
||||||
pub struct VarDecl {
|
pub struct VarDecl {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub size: Option<Expr>,
|
|
||||||
pub initial: Option<Expr>,
|
pub initial: Option<Expr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ impl Compilable for Assignment {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
|
||||||
use crate::compiler::test_utils::*;
|
use crate::compiler::test_utils::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ use crate::compiler::utils::Variable;
|
|||||||
|
|
||||||
impl Compilable for Global {
|
impl Compilable for Global {
|
||||||
fn process(self, state: &mut State, _: Option<&mut CompiledFn>, _loc: Location) -> Result<(), CompileError> {
|
fn process(self, state: &mut State, _: Option<&mut CompiledFn>, _loc: Location) -> Result<(), CompileError> {
|
||||||
if self.size.is_some() {
|
if self.initial.is_some() {
|
||||||
todo!("Global arrays are not yet supported")
|
todo!("Globals with initials are not yet supported")
|
||||||
}
|
}
|
||||||
state.add_global(&self.name, |s| Variable::IndirectLabel(s.gensym()))
|
state.add_global(&self.name, |s| Variable::IndirectLabel(s.gensym()))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ impl Compilable for RepeatLoop {
|
|||||||
if named_counter {
|
if named_counter {
|
||||||
let decl = VarDecl {
|
let decl = VarDecl {
|
||||||
name: counter_name.clone(),
|
name: counter_name.clone(),
|
||||||
size: None,
|
|
||||||
initial: Some(Expr::Number(0)),
|
initial: Some(Expr::Number(0)),
|
||||||
};
|
};
|
||||||
decl.process(state, Some(sig), loc)?;
|
decl.process(state, Some(sig), loc)?;
|
||||||
|
|||||||
@@ -7,9 +7,6 @@ use crate::compiler::state::State;
|
|||||||
impl Compilable for VarDecl {
|
impl Compilable for VarDecl {
|
||||||
fn process(self, state: &mut State, sig: Option<&mut CompiledFn>, loc: Location) -> Result<(), CompileError> {
|
fn process(self, state: &mut State, sig: Option<&mut CompiledFn>, loc: Location) -> Result<(), CompileError> {
|
||||||
let sig = sig.expect("Var declaration outside function");
|
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 let Some(initial) = self.initial {
|
||||||
// If it's got an initial value, we have to compile that before we add
|
// 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:
|
// the name to scope, or else UB will ensue if it refers to itself:
|
||||||
|
|||||||
@@ -211,7 +211,6 @@ impl CompiledFn {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
|
||||||
use crate::compiler::test_utils::*;
|
use crate::compiler::test_utils::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -44,6 +44,13 @@ pub fn build_boot(src: &str) -> Result<Vec<String>, CompileError> {
|
|||||||
for (label, val) in state.strings.iter() {
|
for (label, val) in state.strings.iter() {
|
||||||
asm.push(format!("{}: .db \"{}\\0\"", label, val))
|
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() {
|
for (_, val) in state.functions.iter_mut() {
|
||||||
asm.push(format!("{}:", val.label));
|
asm.push(format!("{}:", val.label));
|
||||||
asm.append(val.preamble.as_mut());
|
asm.append(val.preamble.as_mut());
|
||||||
@@ -118,7 +125,24 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_global_vars() {
|
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]
|
#[test]
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ impl AstNode for Global {
|
|||||||
fn from_pair(pair: Pair) -> Self {
|
fn from_pair(pair: Pair) -> Self {
|
||||||
let mut inner = pair.into_inner().peekable();
|
let mut inner = pair.into_inner().peekable();
|
||||||
let name = String::from(inner.next().unwrap().as_str());
|
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;"),
|
Global::from_str("global foo;"),
|
||||||
Ok(Global {
|
Ok(Global {
|
||||||
name: "foo".into(),
|
name: "foo".into(),
|
||||||
size: None,
|
initial: None,
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_global_arrays() {
|
fn parse_global_vars() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Global::from_str("global foo[10];"),
|
Global::from_str("global foo = 10;"),
|
||||||
Ok(Global {
|
Ok(Global {
|
||||||
name: "foo".into(),
|
name: "foo".into(),
|
||||||
size: Some(10.into()),
|
initial: Some(10.into()),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +1,14 @@
|
|||||||
use crate::ast::{Expr, VarDecl};
|
use crate::ast::{Expr, VarDecl};
|
||||||
use crate::parser::{AstNode, Pair, PairExt, PestRule};
|
use crate::parser::{AstNode, Pair, PestRule};
|
||||||
|
|
||||||
impl AstNode for VarDecl {
|
impl AstNode for VarDecl {
|
||||||
const RULE: PestRule = PestRule::var_decl;
|
const RULE: PestRule = PestRule::var_decl;
|
||||||
fn from_pair(pair: Pair) -> Self {
|
fn from_pair(pair: Pair) -> Self {
|
||||||
let mut inner = pair.into_inner();
|
let mut inner = pair.into_inner();
|
||||||
let name = String::from(inner.next().unwrap().as_str());
|
let name = String::from(inner.next().unwrap().as_str());
|
||||||
let mut size = None;
|
let initial = inner.next().map(Expr::from_pair);
|
||||||
let mut initial = None;
|
|
||||||
|
|
||||||
for p in inner {
|
Self { name, initial }
|
||||||
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 }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,7 +24,6 @@ mod test {
|
|||||||
Statement::from_str("var blah;"),
|
Statement::from_str("var blah;"),
|
||||||
Ok(Statement::VarDecl(VarDecl {
|
Ok(Statement::VarDecl(VarDecl {
|
||||||
name: "blah".into(),
|
name: "blah".into(),
|
||||||
size: None,
|
|
||||||
initial: None,
|
initial: None,
|
||||||
}))
|
}))
|
||||||
);
|
);
|
||||||
@@ -42,10 +32,9 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn parse_var_decl_with_value() {
|
fn parse_var_decl_with_value() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
VarDecl::from_str("var blah[7] = 35"),
|
VarDecl::from_str("var blah = 35"),
|
||||||
Ok(VarDecl {
|
Ok(VarDecl {
|
||||||
name: "blah".into(),
|
name: "blah".into(),
|
||||||
size: Some(7.into()),
|
|
||||||
initial: Some(35.into()),
|
initial: Some(35.into()),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -91,7 +91,6 @@ return_stmt = { "return" ~ expr? }
|
|||||||
conditional = { "if" ~ "(" ~ expr ~ ")" ~ block ~ ("else" ~ block)? }
|
conditional = { "if" ~ "(" ~ expr ~ ")" ~ block ~ ("else" ~ block)? }
|
||||||
while_loop = { "while" ~ "(" ~ expr ~ ")" ~ block }
|
while_loop = { "while" ~ "(" ~ expr ~ ")" ~ block }
|
||||||
repeat_loop = { "repeat" ~ "(" ~ expr ~ ")" ~ name? ~ block }
|
repeat_loop = { "repeat" ~ "(" ~ expr ~ ")" ~ name? ~ block }
|
||||||
var_decl = { "var" ~ name ~ size? ~ ("=" ~ expr)? }
|
var_decl = { "var" ~ name ~ ("=" ~ expr)? }
|
||||||
global = { "global" ~ name ~ size? ~ ";" }
|
global = { "global" ~ name ~ ("=" ~ expr)? ~ ";" }
|
||||||
size = { "[" ~ expr ~ "]" }
|
|
||||||
const_decl = { "const" ~ name ~ "=" ~ (string | expr) ~ ";" }
|
const_decl = { "const" ~ name ~ "=" ~ (string | expr) ~ ";" }
|
||||||
|
|||||||
@@ -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]
|
//#[test]
|
||||||
// This is no longer cursed, or a test. The revised calling convention with the pool pointer makes
|
// 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.
|
// it now perfectly sane. Left here for posterity.
|
||||||
|
|||||||
Reference in New Issue
Block a user