Asm statements implemented
This commit is contained in:
@@ -40,6 +40,7 @@ pub enum Statement {
|
|||||||
Conditional(Conditional),
|
Conditional(Conditional),
|
||||||
WhileLoop(WhileLoop),
|
WhileLoop(WhileLoop),
|
||||||
RepeatLoop(RepeatLoop),
|
RepeatLoop(RepeatLoop),
|
||||||
|
Asm(Asm)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Clone, Debug)]
|
#[derive(PartialEq, Clone, Debug)]
|
||||||
@@ -103,6 +104,12 @@ pub struct RepeatLoop {
|
|||||||
pub body: Block,
|
pub body: Block,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Clone, Debug)]
|
||||||
|
pub struct Asm {
|
||||||
|
pub args: Vec<BoxExpr>,
|
||||||
|
pub body: String
|
||||||
|
}
|
||||||
|
|
||||||
/// One of the five arithmetical operators
|
/// One of the five arithmetical operators
|
||||||
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
|
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
|
||||||
pub enum Operator {
|
pub enum Operator {
|
||||||
@@ -136,7 +143,6 @@ pub enum Expr {
|
|||||||
Address(Lvalue),
|
Address(Lvalue),
|
||||||
Call(BoxExpr, Vec<Expr>),
|
Call(BoxExpr, Vec<Expr>),
|
||||||
Subscript(BoxExpr, BoxExpr),
|
Subscript(BoxExpr, BoxExpr),
|
||||||
Member(BoxExpr, String),
|
|
||||||
Infix(BoxExpr, Operator, BoxExpr),
|
Infix(BoxExpr, Operator, BoxExpr),
|
||||||
String(String),
|
String(String),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use crate::ast::*;
|
use crate::ast::*;
|
||||||
|
|
||||||
use std::collections::btree_map::Entry::Vacant;
|
use std::collections::btree_map::Entry::Vacant;
|
||||||
use std::collections::{BTreeMap, HashMap};
|
use std::collections::{BTreeMap};
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
|
|
||||||
#[derive(Eq, Clone, PartialEq, Debug)]
|
#[derive(Eq, Clone, PartialEq, Debug)]
|
||||||
@@ -80,7 +80,7 @@ impl CompiledFn {
|
|||||||
fn add_local(&mut self, name: &str) -> Result<(), CompileError> {
|
fn add_local(&mut self, name: &str) -> Result<(), CompileError> {
|
||||||
if let Vacant(e) = self.local_scope.entry(name.into()) {
|
if let Vacant(e) = self.local_scope.entry(name.into()) {
|
||||||
e.insert(Variable::Local(self.frame_size));
|
e.insert(Variable::Local(self.frame_size));
|
||||||
self.frame_size += 3; // todo: variously-sized structs
|
self.frame_size += 3;
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(CompileError(0, 0, format!("Duplicate name {}", name)))
|
Err(CompileError(0, 0, format!("Duplicate name {}", name)))
|
||||||
@@ -224,6 +224,14 @@ impl Compilable for Function {
|
|||||||
sig.emit("pop")
|
sig.emit("pop")
|
||||||
}
|
}
|
||||||
Statement::VarDecl(vardecl) => vardecl.process(state, Some(&mut sig))?,
|
Statement::VarDecl(vardecl) => vardecl.process(state, Some(&mut sig))?,
|
||||||
|
Statement::Asm(Asm { args, body}) => {
|
||||||
|
// Process all the args, if any
|
||||||
|
for a in args {
|
||||||
|
(*a.0).process(state, Some(&mut sig))?
|
||||||
|
}
|
||||||
|
// Emit the body
|
||||||
|
sig.emit(body.as_str())
|
||||||
|
}
|
||||||
Statement::Conditional(_) | Statement::WhileLoop(_) | Statement::RepeatLoop(_) => {
|
Statement::Conditional(_) | Statement::WhileLoop(_) | Statement::RepeatLoop(_) => {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
@@ -293,7 +301,7 @@ impl Compilable for VarDecl {
|
|||||||
impl Compilable for Lvalue {
|
impl Compilable for Lvalue {
|
||||||
fn process(self, state: &mut State, sig: Option<&mut CompiledFn>) -> Result<(), CompileError> {
|
fn process(self, state: &mut State, sig: Option<&mut CompiledFn>) -> Result<(), CompileError> {
|
||||||
let global_scope = &state.global_scope;
|
let global_scope = &state.global_scope;
|
||||||
let mut sig = sig.expect("lvalue outside a function");
|
let sig = sig.expect("lvalue outside a function");
|
||||||
|
|
||||||
match *(self.0.0) {
|
match *(self.0.0) {
|
||||||
// A bunch of different things that aren't allowed
|
// A bunch of different things that aren't allowed
|
||||||
@@ -340,9 +348,8 @@ impl Compilable for Lvalue {
|
|||||||
Expr::Deref(BoxExpr(expr)) => {
|
Expr::Deref(BoxExpr(expr)) => {
|
||||||
(*expr).process(state, Some(sig))
|
(*expr).process(state, Some(sig))
|
||||||
}
|
}
|
||||||
Expr::Subscript(_, _) |
|
Expr::Subscript(_, _) => {
|
||||||
Expr::Member(_, _) => {
|
Err(CompileError(0, 0, String::from("Arrays are not yet supported")))
|
||||||
Err(CompileError(0, 0, String::from("Arrays and structs are not yet supported")))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -430,7 +437,6 @@ impl Compilable for Expr {
|
|||||||
}
|
}
|
||||||
Expr::Call(_, _) => todo!(),
|
Expr::Call(_, _) => todo!(),
|
||||||
Expr::Subscript(_, _) => todo!("Structs and arrays are not yen supported"),
|
Expr::Subscript(_, _) => todo!("Structs and arrays are not yen supported"),
|
||||||
Expr::Member(_, _) => todo!("Structs and arrays are not yen supported"),
|
|
||||||
Expr::Infix(lhs, op, rhs) => {
|
Expr::Infix(lhs, op, rhs) => {
|
||||||
// Recurse on expressions, handling operators
|
// Recurse on expressions, handling operators
|
||||||
(*lhs.0).process(state, Some(&mut sig))?;
|
(*lhs.0).process(state, Some(&mut sig))?;
|
||||||
@@ -551,7 +557,7 @@ pub fn eval_const(expr: Expr, scope: &Scope) -> Result<i32, CompileError> {
|
|||||||
0,
|
0,
|
||||||
String::from("Addresses are not known at compile time"),
|
String::from("Addresses are not known at compile time"),
|
||||||
)),
|
)),
|
||||||
Expr::Call(_, _) | Expr::Subscript(_, _) | Expr::Member(_, _) => Err(CompileError(
|
Expr::Call(_, _) | Expr::Subscript(_, _) => Err(CompileError(
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
String::from("Constants must be statically defined"),
|
String::from("Constants must be statically defined"),
|
||||||
@@ -812,4 +818,24 @@ mod test {
|
|||||||
.join("\n")
|
.join("\n")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_asm_statements() {
|
||||||
|
let mut state = State::default();
|
||||||
|
parse("fn blah() { var x; asm(&x) { swap 12\nstorew } }")
|
||||||
|
.unwrap()
|
||||||
|
.process(&mut state, None)
|
||||||
|
.expect("Failed to compile");
|
||||||
|
let body = body_as_string(state.functions.get("blah").unwrap());
|
||||||
|
assert_eq!(
|
||||||
|
body,
|
||||||
|
vec![
|
||||||
|
"loadw frame", // Push the addr of x
|
||||||
|
"swap 12", // The asm body, which swaps 12 behind it and stores it there
|
||||||
|
"storew"
|
||||||
|
]
|
||||||
|
.join("\n")
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -232,6 +232,7 @@ impl AstNode for Statement {
|
|||||||
Rule::conditional => Self::Conditional(Conditional::from_pair(pair)),
|
Rule::conditional => Self::Conditional(Conditional::from_pair(pair)),
|
||||||
Rule::while_loop => Self::WhileLoop(WhileLoop::from_pair(pair)),
|
Rule::while_loop => Self::WhileLoop(WhileLoop::from_pair(pair)),
|
||||||
Rule::repeat_loop => Self::RepeatLoop(RepeatLoop::from_pair(pair)),
|
Rule::repeat_loop => Self::RepeatLoop(RepeatLoop::from_pair(pair)),
|
||||||
|
Rule::asm => Self::Asm(Asm::from_pair(pair)),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -239,6 +240,24 @@ impl AstNode for Statement {
|
|||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
impl AstNode for Asm {
|
||||||
|
const RULE: Rule = Rule::asm;
|
||||||
|
fn from_pair(pair: Pair) -> Self {
|
||||||
|
let mut args = Vec::new();
|
||||||
|
let mut body = None;
|
||||||
|
for p in pair.into_inner() {
|
||||||
|
match p.as_rule() {
|
||||||
|
Rule::expr => args.push(Expr::from_pair(p).into()),
|
||||||
|
Rule::asm_body => body = Some(String::from(p.as_str().trim())),
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Self { args, body: body.unwrap() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
impl AstNode for Return {
|
impl AstNode for Return {
|
||||||
const RULE: Rule = Rule::return_stmt;
|
const RULE: Rule = Rule::return_stmt;
|
||||||
fn from_pair(pair: Pair) -> Self {
|
fn from_pair(pair: Pair) -> Self {
|
||||||
@@ -813,6 +832,19 @@ mod test {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_asm() {
|
||||||
|
assert_eq!(
|
||||||
|
Asm::from_str("asm { push 34 }"),
|
||||||
|
Ok(Asm { args: vec![], body: "push 34".into() })
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
Asm::from_str("asm (&a) { swap 34\nstorew }"),
|
||||||
|
Ok(Asm { args: vec![Expr::Address("a".into()).into()], body: "swap 34\nstorew".into() })
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_program() {
|
fn parse_program() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ arglist = { "(" ~ (expr ~ ("," ~ expr)*)? ~ ")" }
|
|||||||
statement = { asm | ((return_stmt | var_decl | assignment | expr) ~ ";") | conditional | while_loop | repeat_loop }
|
statement = { asm | ((return_stmt | var_decl | assignment | expr) ~ ";") | conditional | while_loop | repeat_loop }
|
||||||
|
|
||||||
asm = { "asm" ~ asm_args? ~ "{" ~ asm_body ~ "}" }
|
asm = { "asm" ~ asm_args? ~ "{" ~ asm_body ~ "}" }
|
||||||
asm_args = { "(" ~ expr ~ ("," ~ expr)* ~ ")" }
|
asm_args = _{ "(" ~ expr ~ ("," ~ expr)* ~ ")" }
|
||||||
asm_body = { (!"}" ~ ANY)* }
|
asm_body = { (!"}" ~ ANY)* }
|
||||||
|
|
||||||
block = { "{" ~ statement* ~ "}" }
|
block = { "{" ~ statement* ~ "}" }
|
||||||
|
|||||||
Reference in New Issue
Block a user