diff --git a/forge_core/src/ast.rs b/forge_core/src/ast.rs index 704c306..bea9c54 100644 --- a/forge_core/src/ast.rs +++ b/forge_core/src/ast.rs @@ -174,6 +174,8 @@ pub enum Expr { Call(Call), New(BoxExpr), Static(BoxExpr), + Peek(BoxExpr), + Poke(BoxExpr, BoxExpr), Subscript(BoxExpr, BoxExpr), Infix(BoxExpr, Operator, BoxExpr), String(String), diff --git a/forge_core/src/compiler/ast_nodes/const.rs b/forge_core/src/compiler/ast_nodes/const.rs index 258c900..0886ab0 100644 --- a/forge_core/src/compiler/ast_nodes/const.rs +++ b/forge_core/src/compiler/ast_nodes/const.rs @@ -49,7 +49,7 @@ pub fn eval_const(expr: Expr, scope: &Scope) -> Result { 0, String::from("Addresses are not known at compile time"), )), - Expr::Call(_) | Expr::Subscript(_, _) | Expr::New(_) => Err(CompileError( + Expr::Call(_) | Expr::Subscript(_, _) | Expr::New(_) | Expr::Peek(_) | Expr::Poke(_, _) => Err(CompileError( 0, 0, String::from("Constants must be statically defined"), diff --git a/forge_core/src/compiler/ast_nodes/expr.rs b/forge_core/src/compiler/ast_nodes/expr.rs index a0f4dec..dc344f5 100644 --- a/forge_core/src/compiler/ast_nodes/expr.rs +++ b/forge_core/src/compiler/ast_nodes/expr.rs @@ -90,10 +90,25 @@ impl Compilable for Expr { size_expr.0.process(state, Some(sig), loc)?; compile_alloc(&mut sig); Ok(()) - }, + } Expr::Static(size_expr) => { compile_static(size_expr, state, sig) } + Expr::Peek(addr) => { + addr.0.process(state, Some(sig), loc)?; + sig.emit("load"); + Ok(()) + } + Expr::Poke(addr, val) => { + // To avoid confusion, we'll evaluate the args in this order and swap + addr.0.process(state, Some(sig), loc)?; + val.0.process(state, Some(sig), loc)?; + // This is an expr, so, we have to evaluate to something. So let's evaluate to the value poked. + // To that end, we'll grab the addr from the stack + sig.emit("pick 1"); + sig.emit("store"); // The store consumes the new copy of the addr and the value, leaving the value + Ok(()) + } Expr::Subscript(array, index) => { array.0.process(state, Some(sig), loc)?; index.0.process(state, Some(sig), loc)?; @@ -304,4 +319,21 @@ mod test { ].join("\n") ) } + + #[test] + fn test_peekpoke() { + assert_eq!( + test_body(state_for("fn test() { peek(10); poke(20, 30); }")), + vec![ + "push 10", + "load", + "pop", + "push 20", + "push 30", + "pick 1", + "store", + "pop" + ].join("\n") + ) + } } \ No newline at end of file diff --git a/forge_core/src/compiler/ast_nodes/lvalue.rs b/forge_core/src/compiler/ast_nodes/lvalue.rs index d8795d0..56f7f34 100644 --- a/forge_core/src/compiler/ast_nodes/lvalue.rs +++ b/forge_core/src/compiler/ast_nodes/lvalue.rs @@ -20,6 +20,8 @@ impl Compilable for Lvalue { Expr::Call(_) | Expr::New(_) | Expr::Static(_) | + Expr::Peek(_) | + Expr::Poke(_, _) | Expr::Infix(_, _, _) | Expr::String(_) => { Err(CompileError(0, 0, String::from("Not a valid lvalue"))) diff --git a/forge_core/src/parser/ast_nodes/expr.rs b/forge_core/src/parser/ast_nodes/expr.rs index 73d0061..7991ab7 100644 --- a/forge_core/src/parser/ast_nodes/expr.rs +++ b/forge_core/src/parser/ast_nodes/expr.rs @@ -20,6 +20,13 @@ impl AstNode for Expr { PestRule::number => Expr::Number(term.into_number()), PestRule::alloc => Expr::New(Expr::from_pair(term.first()).into()), PestRule::static_alloc => Expr::Static(Expr::from_pair(term.first()).into()), + PestRule::peek_expr => Expr::Peek(Expr::from_pair(term.first()).into()), + PestRule::poke_expr => { + let mut it = term.into_inner(); + let first = it.next().unwrap(); + let second = it.next().unwrap(); + Expr::Poke(Expr::from_pair(first).into(), Expr::from_pair(second).into()) + }, PestRule::name => Expr::Name(String::from(term.as_str())), PestRule::expr => Expr::from_pair(term), PestRule::string => Self::String(term.into_quoted_string()), @@ -281,4 +288,14 @@ mod test { fn static_alloc() { assert_eq!(Expr::from_str("static(8)"), Ok(Expr::Static(8.into()))); } + + #[test] + fn peek() { + assert_eq!(Expr::from_str("peek(8)"), Ok(Expr::Peek(8.into()))); + } + + #[test] + fn poke() { + assert_eq!(Expr::from_str("poke(10, 20)"), Ok(Expr::Poke(10.into(), 20.into()))); + } } \ No newline at end of file diff --git a/forge_core/src/parser/forge.pest b/forge_core/src/parser/forge.pest index 4211571..ebf189c 100644 --- a/forge_core/src/parser/forge.pest +++ b/forge_core/src/parser/forge.pest @@ -63,9 +63,11 @@ operator = _{ } expr = { prefix* ~ term ~ suffix* ~ (operator ~ prefix* ~ term ~ suffix*)* } -term = _{ number | alloc | static_alloc | name | "(" ~ expr ~ ")" | string } +term = _{ number | alloc | static_alloc | peek_expr | poke_expr | name | "(" ~ expr ~ ")" | string } alloc = { "new" ~ "(" ~ expr ~ ")" } static_alloc = { "static" ~ "(" ~ expr ~ ")" } +peek_expr = { "peek" ~ "(" ~ expr ~ ")" } +poke_expr = { "poke" ~ "(" ~ expr ~ "," ~ expr ~ ")" } suffix = _{ subscript | arglist } subscript = { "[" ~ expr ~ "]" }