From 1e344a165bb364e1a159821b1d7bd2e4f8c83435 Mon Sep 17 00:00:00 2001 From: fix-fix Date: Sun, 21 Nov 2021 22:58:25 +0500 Subject: [PATCH 1/8] compiler: use more structured codegen for future optimizations --- Cargo.lock | 1 + src/compiler/Cargo.toml | 3 + src/compiler/src/codegen.rs | 115 +++++++++++++++++++---- src/compiler/src/compiler.rs | 162 +++++++++++++++++++++----------- src/compiler/src/instruction.rs | 1 + src/compiler/src/lib.rs | 2 + src/compiler/src/utils.rs | 23 +++++ src/vm/src/instruction.rs | 10 ++ src/vm/src/lib.rs | 2 +- 9 files changed, 248 insertions(+), 71 deletions(-) create mode 100644 src/compiler/src/instruction.rs create mode 100644 src/compiler/src/utils.rs diff --git a/Cargo.lock b/Cargo.lock index d2c3234..e5acb2a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -37,6 +37,7 @@ name = "compiler" version = "0.1.0" dependencies = [ "insta", + "vm", ] [[package]] diff --git a/src/compiler/Cargo.toml b/src/compiler/Cargo.toml index efa8c96..b1c051a 100644 --- a/src/compiler/Cargo.toml +++ b/src/compiler/Cargo.toml @@ -17,5 +17,8 @@ name = "parser" [[bin]] name = "compiler" +[dependencies] +vm = { path = "../vm" } + [dev-dependencies] insta = { version = "^1.8.0", features = ["glob"] } diff --git a/src/compiler/src/codegen.rs b/src/compiler/src/codegen.rs index 8f87402..08dcf94 100644 --- a/src/compiler/src/codegen.rs +++ b/src/compiler/src/codegen.rs @@ -1,31 +1,114 @@ -pub fn write_pop(seg: &str, index: u16) -> String { - format!("pop {} {}", seg, index) +use vm::instruction::{PushPop, PushPopInstruction}; + +use crate::instruction::Instruction; + +#[derive(Debug)] +pub struct CompilerInstruction { + instruction: Instruction, +} + +#[derive(Debug)] +pub struct WriteResult { + instruction: CompilerInstruction, +} + +impl WriteResult { + pub fn new(instruction: CompilerInstruction) -> Self { + Self { instruction } + } + + pub fn code(&self) -> String { + self.instruction.code() + } + + pub fn instruction(&self) -> &CompilerInstruction { + &self.instruction + } +} + +impl CompilerInstruction { + pub fn new(instruction: Instruction) -> Self { + Self { instruction } + } + + #[allow(unreachable_patterns)] + pub fn code(&self) -> String { + match &self.instruction { + Instruction::Arithmetic(op) => op.into(), + Instruction::PushPop(PushPopInstruction { + segment, + addr: index, + inst_type, + }) => match inst_type { + PushPop::Push => format!("push {} {}", segment, index), + PushPop::Pop => format!("pop {} {}", segment, index), + }, + Instruction::Label(label, _) => format!("label {}", label), + Instruction::Goto(label, _) => format!("goto {}", label), + Instruction::IfGoto(label, _) => format!("if-goto {}", label), + Instruction::Function(name, n_locals) => format!("function {} {}", name, n_locals), + Instruction::Return() => "return".to_string(), + Instruction::Call(name, n_args) => format!("call {} {}", name, n_args), + _ => unreachable!("Unreachable instruction: {:?}", self.instruction), + } + } +} + +pub fn write_arith(op: &str) -> WriteResult { + WriteResult::new(CompilerInstruction::new(Instruction::Arithmetic(op.into()))) +} + +pub fn write_not() -> WriteResult { + write_arith("not") +} + +pub fn write_pop(seg: &str, index: u16) -> WriteResult { + WriteResult::new(CompilerInstruction::new(Instruction::PushPop( + PushPopInstruction::new(PushPop::Pop, seg.into(), index), + ))) } -pub fn write_push(seg: &str, index: u16) -> String { - format!("push {} {}", seg, index) +pub fn write_push(seg: &str, index: u16) -> WriteResult { + WriteResult::new(CompilerInstruction::new(Instruction::PushPop( + PushPopInstruction::new(PushPop::Push, seg.into(), index), + ))) } -pub fn write_function(name: String, n_locals: u16) -> String { - format!("function {} {}", name, n_locals) +pub fn write_function(name: String, n_locals: u16) -> WriteResult { + WriteResult::new(CompilerInstruction::new(Instruction::Function( + name, + n_locals.into(), + ))) } -pub fn write_call(name: S, n_args: usize) -> String { - format!("call {} {}", name, n_args) +pub fn write_call(name: S, n_args: usize) -> WriteResult { + WriteResult::new(CompilerInstruction::new(Instruction::Call( + name.to_string(), + n_args, + ))) } -pub fn write_return() -> String { - "return".to_string() +pub fn write_return() -> WriteResult { + WriteResult::new(CompilerInstruction::new(Instruction::Return())) } -pub fn write_label(label: S) -> String { - format!("label {}", label) +pub fn write_label(label: S) -> WriteResult { + WriteResult::new(CompilerInstruction::new(Instruction::Label( + label.to_string(), + None, + ))) } -pub fn write_if(label: S) -> String { - format!("if-goto {}", label) +pub fn write_if(label: S) -> WriteResult { + WriteResult::new(CompilerInstruction::new(Instruction::IfGoto( + label.to_string(), + None, + ))) } -pub fn write_goto(label: S) -> String { - format!("goto {}", label) +pub fn write_goto(label: S) -> WriteResult { + WriteResult::new(CompilerInstruction::new(Instruction::Goto( + label.to_string(), + None, + ))) } diff --git a/src/compiler/src/compiler.rs b/src/compiler/src/compiler.rs index 8bb92cc..27755af 100644 --- a/src/compiler/src/compiler.rs +++ b/src/compiler/src/compiler.rs @@ -4,6 +4,7 @@ use crate::{ parser::ParseResult, symbol_table::{Entry, SubVarKind, SymbolTable}, token::Keyword, + utils::LimitedVecDeque, }; use std::{collections::HashSet, fmt::Write}; @@ -13,31 +14,79 @@ type Res = Result; struct CompilerState<'a> { class_name: String, label_id: usize, + last_written_instructions: LimitedVecDeque>, methods: HashSet, sym_table: SymbolTable, out: &'a mut (dyn Write), } +/* +struct LabelRef<'a> { + label_id: &'a mut usize, + last_written_instruction_type: &'a mut Option, +} + +impl<'a> LabelRef<'a> { + fn new( + label_id: &'a mut usize, + last_written_instruction_type: &'a mut Option, + ) -> Self { + Self { + label_id, + last_written_instruction_type, + } + } + + pub fn label_value(&mut self) -> String { + *self.label_id += if CompilerState::is_at_label(self.last_written_instruction_type.as_ref()) + { + 0 + } else { + 1 + }; + return CompilerState::get_label_id(*self.label_id); + } +} + */ impl<'a> CompilerState<'a> { fn new(class_name: String, sym_table: SymbolTable, out: &'a mut (dyn Write)) -> Self { Self { class_name, label_id: 0, + last_written_instructions: LimitedVecDeque::new(16), methods: Default::default(), sym_table, out, } } - pub fn write(&mut self, s: S) { + fn write_inner(&mut self, s: S) { writeln!(self.out, "{}", s).expect("Error writing"); } + pub fn write_result(&mut self, res: WriteResult) { + self.write_inner(res.code()); + self.remember_write_meta(Some(res)); + } + pub fn get_label(&mut self) -> String { self.label_id += 1; - format!("__VM_LABEL_{}", self.label_id) + Self::get_label_id(self.label_id) + } + + fn get_label_id(label_id: usize) -> String { + format!("__VM_LABEL_{}", label_id) } + // fn is_at_label(last_written_instruction_type: Option<&CompilerInstruction>) -> bool { + // matches!( + // last_written_instruction_type, + // Some(CompilerInstruction { + // instruction: Instruction::Label(..) + // }) + // ) + // } + fn register_method(&mut self, sub_dec: &SubroutineDec) { if let SubroutineDec(GrammarSubroutineVariant::Method, _, ident, ..) = sub_dec { self.methods.insert(ident.into()); @@ -47,6 +96,10 @@ impl<'a> CompilerState<'a> { fn has_method(&self, method: &str) -> bool { self.methods.contains(method) } + + fn remember_write_meta(&mut self, res: Option) { + self.last_written_instructions.push(res); + } } #[derive(Debug, Default, Clone)] @@ -84,6 +137,7 @@ pub fn compile_program(parse_result: ParseResult) -> Res { // dbg!(state.class_name, state.sym_table); e })?; + dbg!(state.last_written_instructions); Ok(out) } @@ -116,7 +170,7 @@ fn compile_subroutine_dec( ) -> Res { state.sym_table.reset_subroutine_table(); let n_locals: u16 = sub.0.iter().map(|var_dec| var_dec.1.len() as u16).sum(); - state.write(write_function( + state.write_result(write_function( format!("{}.{}", state.class_name, ident), n_locals, )); @@ -126,13 +180,13 @@ fn compile_subroutine_dec( match variant { GrammarSubroutineVariant::Constructor => { let object_size = state.sym_table.count_instance_fields(); - state.write(write_push("constant", object_size)); - state.write(write_call("Memory.alloc", 1)); - state.write(write_pop("pointer", 0)); + state.write_result(write_push("constant", object_size)); + state.write_result(write_call("Memory.alloc", 1)); + state.write_result(write_pop("pointer", 0)); } GrammarSubroutineVariant::Method => { - state.write(write_push("argument", 0)); - state.write(write_pop("pointer", 0)); + state.write_result(write_push("argument", 0)); + state.write_result(write_pop("pointer", 0)); // Offset arguments in methods by setting fake value, since we also pass 'this' state.sym_table.define_subroutine_var( @@ -203,18 +257,18 @@ fn compile_statement_let( .ok_or(format!("Unknown var: {}", &stmt.name))?; match stmt.index_expr { Some(expr) => { - state.write(write_push(var.kind.as_str(), var.index)); + state.write_result(write_push(var.kind.as_str(), var.index)); compile_expression(state, context, expr)?; - state.write("add"); + state.write_result(write_arith("add")); compile_expression(state, context, stmt.value_expr)?; - state.write(write_pop("temp", 0)); - state.write(write_pop("pointer", 1)); - state.write(write_push("temp", 0)); - state.write(write_pop("that", 0)); + state.write_result(write_pop("temp", 0)); + state.write_result(write_pop("pointer", 1)); + state.write_result(write_push("temp", 0)); + state.write_result(write_pop("that", 0)); } _ => { compile_expression(state, context, stmt.value_expr)?; - state.write(write_pop(var.kind.as_str(), var.index)); + state.write_result(write_pop(var.kind.as_str(), var.index)); } }; Ok(()) @@ -232,15 +286,15 @@ fn compile_statement_if( end_label.clone() }; compile_expression(state, context, stmt.if_expr)?; - state.write("not"); - state.write(write_if(&else_label)); + state.write_result(write_not()); + state.write_result(write_if(&else_label)); compile_statements(state, context, stmt.if_statements)?; - state.write(write_goto(&end_label)); + state.write_result(write_goto(&end_label)); if let Some(else_statements) = stmt.else_statements { - state.write(write_label(&else_label)); + state.write_result(write_label(&else_label)); compile_statements(state, context, else_statements)?; } - state.write(write_label(&end_label)); + state.write_result(write_label(&end_label)); Ok(()) } @@ -251,13 +305,13 @@ fn compile_statement_while( ) -> Res { let start_label = state.get_label(); let end_label = state.get_label(); - state.write(write_label(&start_label)); + state.write_result(write_label(&start_label)); compile_expression(state, context, stmt.cond_expr)?; - state.write("not"); - state.write(write_if(&end_label)); + state.write_result(write_not()); + state.write_result(write_if(&end_label)); compile_statements(state, context, stmt.statements)?; - state.write(write_goto(&start_label)); - state.write(write_label(&end_label)); + state.write_result(write_goto(&start_label)); + state.write_result(write_label(&end_label)); Ok(()) } @@ -268,7 +322,7 @@ fn compile_statement_do( ) -> Res { compile_call(state, context, stmt.call)?; // Pop return value, not used - state.write(write_pop("temp", 0)); + state.write_result(write_pop("temp", 0)); Ok(()) } @@ -292,10 +346,10 @@ fn compile_statement_return( compile_expression(state, context, expr)?; } None => { - state.write(write_push("constant", 0)); + state.write_result(write_push("constant", 0)); } } - state.write(write_return()); + state.write_result(write_return()); Ok(()) } @@ -322,7 +376,7 @@ fn compile_call(state: &mut CompilerState, context: &CompilerContext, call: Subr }; let n_args = args.len(); compile_expression_list(state, context, args)?; - state.write(write_call(func_name, n_args)); + state.write_result(write_call(func_name, n_args)); Ok(()) } @@ -373,32 +427,32 @@ fn compile_term(state: &mut CompilerState, context: &CompilerContext, term: Term match term { Term::VarName(name) => { let var = lookup_var(state, context, name)?; - state.write(write_push(var.kind.as_str(), var.index)); + state.write_result(write_push(var.kind.as_str(), var.index)); } Term::KeywordConstant(kw) => { match kw { Keyword::True => { - state.write(write_push("constant", 0)); - state.write("not"); + state.write_result(write_push("constant", 0)); + state.write_result(write_not()); } Keyword::False | Keyword::Null => { - state.write(write_push("constant", 0)); + state.write_result(write_push("constant", 0)); } Keyword::This => { - state.write(write_push("pointer", 0)); + state.write_result(write_push("pointer", 0)); } _ => return Err(format!("Unexpected constant used as term: {:?}", kw).into()), }; } Term::IntegerConstant(i) => { - state.write(write_push("constant", i)); + state.write_result(write_push("constant", i)); } Term::StringConst(s) => { - state.write(write_push("constant", s.len() as u16)); - state.write(write_call("String.new", 1)); + state.write_result(write_push("constant", s.len() as u16)); + state.write_result(write_call("String.new", 1)); for c in s.chars() { - state.write(write_push("constant", (c as u8).into())); - state.write(write_call("String.appendChar", 2)); + state.write_result(write_push("constant", (c as u8).into())); + state.write_result(write_call("String.appendChar", 2)); } } Term::UnaryOp(op, term) => { @@ -410,11 +464,11 @@ fn compile_term(state: &mut CompilerState, context: &CompilerContext, term: Term } Term::IndexExpr(name, expr) => { let var = lookup_var(state, context, name)?; - state.write(write_push(var.kind.as_str(), var.index)); + state.write_result(write_push(var.kind.as_str(), var.index)); compile_expression(state, context, *expr)?; - state.write("add"); - state.write(write_pop("pointer", 1)); - state.write(write_push("that", 0)); + state.write_result(write_arith("add")); + state.write_result(write_pop("pointer", 1)); + state.write_result(write_push("that", 0)); } Term::SubroutineCall(call) => { compile_call(state, context, call)?; @@ -424,14 +478,14 @@ fn compile_term(state: &mut CompilerState, context: &CompilerContext, term: Term } fn compile_op(state: &mut CompilerState, _context: &CompilerContext, Op(op): Op) -> Res { - state.write(match op.as_str() { - "+" => "add".to_string(), - "-" => "sub".to_string(), - "=" => "eq".to_string(), - ">" => "gt".to_string(), - "<" => "lt".to_string(), - "&" => "and".to_string(), - "|" => "or".to_string(), + state.write_result(match op.as_str() { + "+" => write_arith("add"), + "-" => write_arith("sub"), + "=" => write_arith("eq"), + ">" => write_arith("gt"), + "<" => write_arith("lt"), + "&" => write_arith("and"), + "|" => write_arith("or"), "*" => write_call("Math.multiply", 2), "/" => write_call("Math.divide", 2), other => unreachable!("Unsupported op: {:?}", other), @@ -440,9 +494,9 @@ fn compile_op(state: &mut CompilerState, _context: &CompilerContext, Op(op): Op) } fn compile_unary_op(state: &mut CompilerState, _context: &CompilerContext, Op(op): Op) -> Res { - state.write(match op.as_str() { - "-" => "neg".to_string(), - "~" => "not".to_string(), + state.write_result(match op.as_str() { + "-" => write_arith("neg"), + "~" => write_not(), other => unreachable!("Unsupported unary op: {:?}", other), }); Ok(()) diff --git a/src/compiler/src/instruction.rs b/src/compiler/src/instruction.rs new file mode 100644 index 0000000..0219643 --- /dev/null +++ b/src/compiler/src/instruction.rs @@ -0,0 +1 @@ +pub use vm::instruction::{Instruction, PushPop}; diff --git a/src/compiler/src/lib.rs b/src/compiler/src/lib.rs index 305781e..8f58e29 100644 --- a/src/compiler/src/lib.rs +++ b/src/compiler/src/lib.rs @@ -3,6 +3,7 @@ pub mod compiler; pub mod compiler_cli; pub mod config; pub mod input; +pub mod instruction; pub mod line_chars; pub mod node; pub mod node_printer; @@ -10,4 +11,5 @@ pub mod parser; pub mod symbol_table; pub mod token; pub mod tokenizer; +pub mod utils; pub mod xml; diff --git a/src/compiler/src/utils.rs b/src/compiler/src/utils.rs new file mode 100644 index 0000000..1d8c314 --- /dev/null +++ b/src/compiler/src/utils.rs @@ -0,0 +1,23 @@ +use std::collections::VecDeque; + +#[derive(Debug)] +pub struct LimitedVecDeque { + capacity: usize, + deque: VecDeque, +} + +impl LimitedVecDeque { + pub fn new(capacity: usize) -> Self { + Self { + capacity, + deque: VecDeque::with_capacity(capacity), + } + } + + pub fn push(&mut self, value: T) { + if self.deque.len() == self.capacity { + self.deque.pop_front(); + } + self.deque.push_back(value) + } +} diff --git a/src/vm/src/instruction.rs b/src/vm/src/instruction.rs index e36b294..dd3be2d 100644 --- a/src/vm/src/instruction.rs +++ b/src/vm/src/instruction.rs @@ -11,6 +11,16 @@ pub struct PushPopInstruction { pub inst_type: PushPop, } +impl PushPopInstruction { + pub fn new(inst_type: PushPop, segment: String, addr: u16) -> Self { + Self { + segment, + addr, + inst_type, + } + } +} + #[derive(Debug, Clone)] pub enum Instruction { PushPop(PushPopInstruction), diff --git a/src/vm/src/lib.rs b/src/vm/src/lib.rs index 7aa6f3c..679f060 100644 --- a/src/vm/src/lib.rs +++ b/src/vm/src/lib.rs @@ -1,6 +1,6 @@ mod code; pub mod config; -mod instruction; +pub mod instruction; mod parser; use std::error::Error; From 692d7ee849a6ea83e14189e6292376ce2a4e2a0e Mon Sep 17 00:00:00 2001 From: fix-fix Date: Tue, 23 Nov 2021 01:44:41 +0500 Subject: [PATCH 2/8] compiler: write out only after full pass --- src/compiler/src/codegen.rs | 46 +++++++++++------------ src/compiler/src/compiler.rs | 73 ++++++++++-------------------------- 2 files changed, 42 insertions(+), 77 deletions(-) diff --git a/src/compiler/src/codegen.rs b/src/compiler/src/codegen.rs index 08dcf94..e1bb68e 100644 --- a/src/compiler/src/codegen.rs +++ b/src/compiler/src/codegen.rs @@ -8,11 +8,11 @@ pub struct CompilerInstruction { } #[derive(Debug)] -pub struct WriteResult { +pub struct WriteInst { instruction: CompilerInstruction, } -impl WriteResult { +impl WriteInst { pub fn new(instruction: CompilerInstruction) -> Self { Self { instruction } } @@ -21,8 +21,8 @@ impl WriteResult { self.instruction.code() } - pub fn instruction(&self) -> &CompilerInstruction { - &self.instruction + pub fn instruction(&self) -> &Instruction { + &self.instruction.instruction } } @@ -54,60 +54,60 @@ impl CompilerInstruction { } } -pub fn write_arith(op: &str) -> WriteResult { - WriteResult::new(CompilerInstruction::new(Instruction::Arithmetic(op.into()))) +pub fn write_arith(op: &str) -> WriteInst { + WriteInst::new(CompilerInstruction::new(Instruction::Arithmetic(op.into()))) } -pub fn write_not() -> WriteResult { +pub fn write_not() -> WriteInst { write_arith("not") } -pub fn write_pop(seg: &str, index: u16) -> WriteResult { - WriteResult::new(CompilerInstruction::new(Instruction::PushPop( +pub fn write_pop(seg: &str, index: u16) -> WriteInst { + WriteInst::new(CompilerInstruction::new(Instruction::PushPop( PushPopInstruction::new(PushPop::Pop, seg.into(), index), ))) } -pub fn write_push(seg: &str, index: u16) -> WriteResult { - WriteResult::new(CompilerInstruction::new(Instruction::PushPop( +pub fn write_push(seg: &str, index: u16) -> WriteInst { + WriteInst::new(CompilerInstruction::new(Instruction::PushPop( PushPopInstruction::new(PushPop::Push, seg.into(), index), ))) } -pub fn write_function(name: String, n_locals: u16) -> WriteResult { - WriteResult::new(CompilerInstruction::new(Instruction::Function( +pub fn write_function(name: String, n_locals: u16) -> WriteInst { + WriteInst::new(CompilerInstruction::new(Instruction::Function( name, n_locals.into(), ))) } -pub fn write_call(name: S, n_args: usize) -> WriteResult { - WriteResult::new(CompilerInstruction::new(Instruction::Call( +pub fn write_call(name: S, n_args: usize) -> WriteInst { + WriteInst::new(CompilerInstruction::new(Instruction::Call( name.to_string(), n_args, ))) } -pub fn write_return() -> WriteResult { - WriteResult::new(CompilerInstruction::new(Instruction::Return())) +pub fn write_return() -> WriteInst { + WriteInst::new(CompilerInstruction::new(Instruction::Return())) } -pub fn write_label(label: S) -> WriteResult { - WriteResult::new(CompilerInstruction::new(Instruction::Label( +pub fn write_label(label: S) -> WriteInst { + WriteInst::new(CompilerInstruction::new(Instruction::Label( label.to_string(), None, ))) } -pub fn write_if(label: S) -> WriteResult { - WriteResult::new(CompilerInstruction::new(Instruction::IfGoto( +pub fn write_if(label: S) -> WriteInst { + WriteInst::new(CompilerInstruction::new(Instruction::IfGoto( label.to_string(), None, ))) } -pub fn write_goto(label: S) -> WriteResult { - WriteResult::new(CompilerInstruction::new(Instruction::Goto( +pub fn write_goto(label: S) -> WriteInst { + WriteInst::new(CompilerInstruction::new(Instruction::Goto( label.to_string(), None, ))) diff --git a/src/compiler/src/compiler.rs b/src/compiler/src/compiler.rs index 27755af..6c3f209 100644 --- a/src/compiler/src/compiler.rs +++ b/src/compiler/src/compiler.rs @@ -4,69 +4,43 @@ use crate::{ parser::ParseResult, symbol_table::{Entry, SubVarKind, SymbolTable}, token::Keyword, - utils::LimitedVecDeque, }; use std::{collections::HashSet, fmt::Write}; type CompilerError = Box; type Res = Result; -struct CompilerState<'a> { +struct CompilerState { class_name: String, label_id: usize, - last_written_instructions: LimitedVecDeque>, + instructions: Vec, methods: HashSet, sym_table: SymbolTable, - out: &'a mut (dyn Write), -} -/* -struct LabelRef<'a> { - label_id: &'a mut usize, - last_written_instruction_type: &'a mut Option, } -impl<'a> LabelRef<'a> { - fn new( - label_id: &'a mut usize, - last_written_instruction_type: &'a mut Option, - ) -> Self { - Self { - label_id, - last_written_instruction_type, - } - } - - pub fn label_value(&mut self) -> String { - *self.label_id += if CompilerState::is_at_label(self.last_written_instruction_type.as_ref()) - { - 0 - } else { - 1 - }; - return CompilerState::get_label_id(*self.label_id); - } -} - */ - -impl<'a> CompilerState<'a> { - fn new(class_name: String, sym_table: SymbolTable, out: &'a mut (dyn Write)) -> Self { +impl CompilerState { + fn new(class_name: String, sym_table: SymbolTable) -> Self { Self { class_name, label_id: 0, - last_written_instructions: LimitedVecDeque::new(16), + instructions: vec![], methods: Default::default(), sym_table, - out, } } - fn write_inner(&mut self, s: S) { - writeln!(self.out, "{}", s).expect("Error writing"); + fn write_all(&mut self, out: &mut (dyn Write)) { + for inst in self.instructions.iter() { + self.write_inner(out, inst.code()) + } + } + + fn write_inner(&self, out: &mut (dyn Write), s: S) { + writeln!(out, "{}", s).expect("Error writing"); } - pub fn write_result(&mut self, res: WriteResult) { - self.write_inner(res.code()); - self.remember_write_meta(Some(res)); + pub fn write_result(&mut self, res: WriteInst) { + self.save_result(res); } pub fn get_label(&mut self) -> String { @@ -78,15 +52,6 @@ impl<'a> CompilerState<'a> { format!("__VM_LABEL_{}", label_id) } - // fn is_at_label(last_written_instruction_type: Option<&CompilerInstruction>) -> bool { - // matches!( - // last_written_instruction_type, - // Some(CompilerInstruction { - // instruction: Instruction::Label(..) - // }) - // ) - // } - fn register_method(&mut self, sub_dec: &SubroutineDec) { if let SubroutineDec(GrammarSubroutineVariant::Method, _, ident, ..) = sub_dec { self.methods.insert(ident.into()); @@ -97,8 +62,8 @@ impl<'a> CompilerState<'a> { self.methods.contains(method) } - fn remember_write_meta(&mut self, res: Option) { - self.last_written_instructions.push(res); + fn save_result(&mut self, res: WriteInst) { + self.instructions.push(res); } } @@ -131,13 +96,13 @@ fn lookup_var(state: &mut CompilerState, context: &CompilerContext, name: String pub fn compile_program(parse_result: ParseResult) -> Res { let mut out = String::new(); let sym_table = SymbolTable::new(); - let mut state = CompilerState::new(Default::default(), sym_table, &mut out); + let mut state = CompilerState::new(Default::default(), sym_table); let context = CompilerContext::new(); compile_class(&mut state, &context, parse_result.root).map_err(|e| { // dbg!(state.class_name, state.sym_table); e })?; - dbg!(state.last_written_instructions); + state.write_all(&mut out); Ok(out) } From f34d7c02187ecbd5474de9bfb8674269350c91ff Mon Sep 17 00:00:00 2001 From: fix-fix Date: Wed, 24 Nov 2021 00:34:30 +0500 Subject: [PATCH 3/8] compiler: add basic useless negation optimization --- src/compiler/src/codegen.rs | 4 +-- src/compiler/src/compiler.rs | 2 ++ src/compiler/src/lib.rs | 1 + src/compiler/src/optimizer/mod.rs | 3 ++ .../src/optimizer/optimize_vm_instructions.rs | 30 +++++++++++++++++++ ...e example: snake__Game.jack@Game.jack.snap | 12 -------- ...e example: snake__List.jack@List.jack.snap | 8 ----- ...example: snake__Snake.jack@Snake.jack.snap | 8 ----- ... code example: snake__UI.jack@UI.jack.snap | 2 -- ...uare__SquareGame.jack@SquareGame.jack.snap | 4 --- ...11__ConvertToBin__Main.jack@Main.jack.snap | 4 --- ...inputs__11__Pong__Ball.jack@Ball.jack.snap | 8 ----- ...11__Pong__PongGame.jack@PongGame.jack.snap | 4 --- ...uare__SquareGame.jack@SquareGame.jack.snap | 4 --- 14 files changed, 38 insertions(+), 56 deletions(-) create mode 100644 src/compiler/src/optimizer/mod.rs create mode 100644 src/compiler/src/optimizer/optimize_vm_instructions.rs diff --git a/src/compiler/src/codegen.rs b/src/compiler/src/codegen.rs index e1bb68e..0ffe7c6 100644 --- a/src/compiler/src/codegen.rs +++ b/src/compiler/src/codegen.rs @@ -2,12 +2,12 @@ use vm::instruction::{PushPop, PushPopInstruction}; use crate::instruction::Instruction; -#[derive(Debug)] +#[derive(Clone, Debug)] pub struct CompilerInstruction { instruction: Instruction, } -#[derive(Debug)] +#[derive(Clone, Debug)] pub struct WriteInst { instruction: CompilerInstruction, } diff --git a/src/compiler/src/compiler.rs b/src/compiler/src/compiler.rs index 6c3f209..55847b9 100644 --- a/src/compiler/src/compiler.rs +++ b/src/compiler/src/compiler.rs @@ -1,6 +1,7 @@ use crate::{ codegen::*, node::*, + optimizer::opimize_vm_instructions, parser::ParseResult, symbol_table::{Entry, SubVarKind, SymbolTable}, token::Keyword, @@ -102,6 +103,7 @@ pub fn compile_program(parse_result: ParseResult) -> Res { // dbg!(state.class_name, state.sym_table); e })?; + opimize_vm_instructions(&mut state.instructions); state.write_all(&mut out); Ok(out) } diff --git a/src/compiler/src/lib.rs b/src/compiler/src/lib.rs index 8f58e29..e9601c8 100644 --- a/src/compiler/src/lib.rs +++ b/src/compiler/src/lib.rs @@ -7,6 +7,7 @@ pub mod instruction; pub mod line_chars; pub mod node; pub mod node_printer; +pub mod optimizer; pub mod parser; pub mod symbol_table; pub mod token; diff --git a/src/compiler/src/optimizer/mod.rs b/src/compiler/src/optimizer/mod.rs new file mode 100644 index 0000000..fe98c41 --- /dev/null +++ b/src/compiler/src/optimizer/mod.rs @@ -0,0 +1,3 @@ +mod optimize_vm_instructions; + +pub use self::optimize_vm_instructions::opimize_vm_instructions; diff --git a/src/compiler/src/optimizer/optimize_vm_instructions.rs b/src/compiler/src/optimizer/optimize_vm_instructions.rs new file mode 100644 index 0000000..549c12c --- /dev/null +++ b/src/compiler/src/optimizer/optimize_vm_instructions.rs @@ -0,0 +1,30 @@ +use crate::codegen::WriteInst; + +use crate::instruction::Instruction; + +pub fn opimize_vm_instructions(instructions: &mut Vec) { + let mut out = Vec::::with_capacity(instructions.len()); + let mut insts_iter = instructions.iter().peekable(); + + while let Some(&wi) = insts_iter.peek() { + let inst = wi.instruction(); + match inst { + Instruction::Arithmetic(op) => { + insts_iter.next(); + match (op.as_str(), insts_iter.peek().map(|i| i.instruction())) { + ("not", Some(Instruction::Arithmetic(op2))) if op2 == "not" => { + insts_iter.next(); + continue; + } + _ => {} + } + } + _ => { + insts_iter.next(); + } + } + out.push(wi.to_owned()); + } + + *instructions = out; +} diff --git a/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__Game.jack@Game.jack.snap b/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__Game.jack@Game.jack.snap index 4f44dc3..f36a0d9 100644 --- a/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__Game.jack@Game.jack.snap +++ b/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__Game.jack@Game.jack.snap @@ -73,8 +73,6 @@ pop pointer 0 push this 6 push constant 0 eq -not -not if-goto __VM_LABEL_1 push this 6 call Snake.dispose 1 @@ -87,8 +85,6 @@ label __VM_LABEL_2 push this 3 push constant 0 eq -not -not if-goto __VM_LABEL_3 call Screen.clearScreen 0 pop temp 0 @@ -143,16 +139,12 @@ call Snake.drawFull 1 pop temp 0 label __VM_LABEL_4 push local 1 -not -not if-goto __VM_LABEL_5 call Keyboard.keyPressed 0 pop local 0 push local 0 push constant 0 eq -not -not if-goto __VM_LABEL_6 push local 0 pop this 0 @@ -254,8 +246,6 @@ label __VM_LABEL_10 push local 2 push constant 0 eq -not -not if-goto __VM_LABEL_17 push this 6 push local 2 @@ -352,8 +342,6 @@ push argument 1 call Snake.getHead 1 push this 4 eq -not -not if-goto __VM_LABEL_22 push this 4 return diff --git a/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__List.jack@List.jack.snap b/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__List.jack@List.jack.snap index ffd669c..2ae15eb 100644 --- a/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__List.jack@List.jack.snap +++ b/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__List.jack@List.jack.snap @@ -47,8 +47,6 @@ label __VM_LABEL_1 push local 0 push constant 0 eq -not -not if-goto __VM_LABEL_2 push local 0 call List.getData 1 @@ -70,8 +68,6 @@ pop pointer 0 push this 1 push constant 0 eq -not -not if-goto __VM_LABEL_3 push this 1 call List.dispose 1 @@ -119,8 +115,6 @@ push local 2 call List.getNext 1 push constant 0 eq -not -not if-goto __VM_LABEL_6 push local 1 call List.getNext 1 @@ -152,8 +146,6 @@ push local 0 call List.getNext 1 push constant 0 eq -not -not if-goto __VM_LABEL_8 push local 0 call List.getNext 1 diff --git a/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__Snake.jack@Snake.jack.snap b/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__Snake.jack@Snake.jack.snap index 25098af..228fab5 100644 --- a/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__Snake.jack@Snake.jack.snap +++ b/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__Snake.jack@Snake.jack.snap @@ -89,8 +89,6 @@ pop local 1 push local 1 push local 0 eq -not -not if-goto __VM_LABEL_3 push argument 1 pop this 1 @@ -264,8 +262,6 @@ label __VM_LABEL_13 push local 0 push constant 0 eq -not -not if-goto __VM_LABEL_14 push pointer 0 push local 0 @@ -287,8 +283,6 @@ pop local 0 push local 0 push constant 0 eq -not -not if-goto __VM_LABEL_15 push local 0 call List.getData 1 @@ -333,8 +327,6 @@ label __VM_LABEL_16 push local 0 push constant 0 eq -not -not if-goto __VM_LABEL_17 push local 0 call List.getData 1 diff --git a/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__UI.jack@UI.jack.snap b/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__UI.jack@UI.jack.snap index 4497062..fb2fef6 100644 --- a/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__UI.jack@UI.jack.snap +++ b/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__UI.jack@UI.jack.snap @@ -96,8 +96,6 @@ label __VM_LABEL_1 push local 1 push constant 0 lt -not -not if-goto __VM_LABEL_2 push constant 0 not diff --git a/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__10__Square__SquareGame.jack@SquareGame.jack.snap b/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__10__Square__SquareGame.jack@SquareGame.jack.snap index 72abfe4..3fedb50 100644 --- a/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__10__Square__SquareGame.jack@SquareGame.jack.snap +++ b/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__10__Square__SquareGame.jack@SquareGame.jack.snap @@ -83,8 +83,6 @@ push constant 0 pop local 1 label __VM_LABEL_5 push local 1 -not -not if-goto __VM_LABEL_6 label __VM_LABEL_7 push local 0 @@ -169,8 +167,6 @@ label __VM_LABEL_16 push local 0 push constant 0 eq -not -not if-goto __VM_LABEL_17 call Keyboard.keyPressed 0 pop local 0 diff --git a/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__ConvertToBin__Main.jack@Main.jack.snap b/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__ConvertToBin__Main.jack@Main.jack.snap index 290861f..d3988b4 100644 --- a/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__ConvertToBin__Main.jack@Main.jack.snap +++ b/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__ConvertToBin__Main.jack@Main.jack.snap @@ -37,16 +37,12 @@ pop local 0 push local 1 push constant 16 gt -not -not if-goto __VM_LABEL_4 push argument 0 push local 0 and push constant 0 eq -not -not if-goto __VM_LABEL_6 push constant 8000 push local 1 diff --git a/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Pong__Ball.jack@Ball.jack.snap b/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Pong__Ball.jack@Ball.jack.snap index 8048bb0..12eacf2 100644 --- a/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Pong__Ball.jack@Ball.jack.snap +++ b/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Pong__Ball.jack@Ball.jack.snap @@ -249,8 +249,6 @@ label __VM_LABEL_11 push this 0 push this 10 gt -not -not if-goto __VM_LABEL_17 push constant 1 pop this 14 @@ -261,8 +259,6 @@ label __VM_LABEL_17 push this 0 push this 11 lt -not -not if-goto __VM_LABEL_18 push constant 2 pop this 14 @@ -273,8 +269,6 @@ label __VM_LABEL_18 push this 1 push this 12 gt -not -not if-goto __VM_LABEL_19 push constant 3 pop this 14 @@ -285,8 +279,6 @@ label __VM_LABEL_19 push this 1 push this 13 lt -not -not if-goto __VM_LABEL_20 push constant 4 pop this 14 diff --git a/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Pong__PongGame.jack@PongGame.jack.snap b/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Pong__PongGame.jack@PongGame.jack.snap index bf993c3..7ca368d 100644 --- a/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Pong__PongGame.jack@PongGame.jack.snap +++ b/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Pong__PongGame.jack@PongGame.jack.snap @@ -98,8 +98,6 @@ push argument 0 pop pointer 0 label __VM_LABEL_1 push this 3 -not -not if-goto __VM_LABEL_2 label __VM_LABEL_3 push local 0 @@ -261,8 +259,6 @@ lt or pop this 3 push this 3 -not -not if-goto __VM_LABEL_15 push local 4 push local 1 diff --git a/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Square__SquareGame.jack@SquareGame.jack.snap b/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Square__SquareGame.jack@SquareGame.jack.snap index 92bc6e4..42c79ee 100644 --- a/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Square__SquareGame.jack@SquareGame.jack.snap +++ b/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Square__SquareGame.jack@SquareGame.jack.snap @@ -83,8 +83,6 @@ push constant 0 pop local 1 label __VM_LABEL_5 push local 1 -not -not if-goto __VM_LABEL_6 label __VM_LABEL_7 push local 0 @@ -169,8 +167,6 @@ label __VM_LABEL_16 push local 0 push constant 0 eq -not -not if-goto __VM_LABEL_17 call Keyboard.keyPressed 0 pop local 0 From d7dcdf1f07652b66a30f9b555a1864fbcb67e856 Mon Sep 17 00:00:00 2001 From: fix-fix Date: Wed, 24 Nov 2021 00:51:12 +0500 Subject: [PATCH 4/8] compiler: drop useless gotos --- src/compiler/src/compiler.rs | 25 +++++--- src/compiler/src/optimizer/mod.rs | 6 +- .../src/optimizer/optimize_syntax_tree.rs | 64 +++++++++++++++++++ .../src/optimizer/optimize_vm_instructions.rs | 18 ++++-- src/compiler/src/parser.rs | 2 +- src/compiler/src/symbol_table.rs | 7 +- ...e example: snake__Game.jack@Game.jack.snap | 10 --- ...e example: snake__List.jack@List.jack.snap | 2 - ...example: snake__Snake.jack@Snake.jack.snap | 6 -- ... code example: snake__UI.jack@UI.jack.snap | 5 -- ...example: snake__Utils.jack@Utils.jack.snap | 1 - ...onLessSquare__Square.jack@Square.jack.snap | 6 -- ...uare__SquareGame.jack@SquareGame.jack.snap | 11 ---- ...__10__Square__Square.jack@Square.jack.snap | 6 -- ...uare__SquareGame.jack@SquareGame.jack.snap | 11 ---- ...1__ComplexArrays__Main.jack@Main.jack.snap | 1 - ...inputs__11__Pong__Ball.jack@Ball.jack.snap | 4 -- ...__inputs__11__Pong__Bat.jack@Bat.jack.snap | 2 - ...11__Pong__PongGame.jack@PongGame.jack.snap | 6 -- ...nputs__11__Seven__Main.jack@Main.jack.snap | 4 +- ...__11__Square__Square.jack@Square.jack.snap | 6 -- ...uare__SquareGame.jack@SquareGame.jack.snap | 11 ---- 22 files changed, 101 insertions(+), 113 deletions(-) create mode 100644 src/compiler/src/optimizer/optimize_syntax_tree.rs diff --git a/src/compiler/src/compiler.rs b/src/compiler/src/compiler.rs index 55847b9..fc61717 100644 --- a/src/compiler/src/compiler.rs +++ b/src/compiler/src/compiler.rs @@ -1,7 +1,7 @@ use crate::{ codegen::*, node::*, - optimizer::opimize_vm_instructions, + optimizer::{opimize_vm_instructions, optimize_syntax_tree_expression}, parser::ParseResult, symbol_table::{Entry, SubVarKind, SymbolTable}, token::Keyword, @@ -11,7 +11,7 @@ use std::{collections::HashSet, fmt::Write}; type CompilerError = Box; type Res = Result; -struct CompilerState { +pub struct CompilerState { class_name: String, label_id: usize, instructions: Vec, @@ -19,6 +19,12 @@ struct CompilerState { sym_table: SymbolTable, } +impl CompilerState { + pub fn sym_table(&self) -> &SymbolTable { + &self.sym_table + } +} + impl CompilerState { fn new(class_name: String, sym_table: SymbolTable) -> Self { Self { @@ -256,8 +262,8 @@ fn compile_statement_if( state.write_result(write_not()); state.write_result(write_if(&else_label)); compile_statements(state, context, stmt.if_statements)?; - state.write_result(write_goto(&end_label)); if let Some(else_statements) = stmt.else_statements { + state.write_result(write_goto(&end_label)); state.write_result(write_label(&else_label)); compile_statements(state, context, else_statements)?; } @@ -377,11 +383,14 @@ fn compile_expression_list( Ok(()) } -fn compile_expression( - state: &mut CompilerState, - context: &CompilerContext, - Expr(term, extra_terms): Expr, -) -> Res { +fn compile_expression(state: &mut CompilerState, context: &CompilerContext, expr: Expr) -> Res { + if let Some(results) = optimize_syntax_tree_expression(state, &expr) { + for result in results { + state.write_result(result); + } + return Ok(()); + } + let Expr(term, extra_terms) = expr; compile_term(state, context, term)?; for (op, extra_term) in extra_terms { compile_term(state, context, extra_term)?; diff --git a/src/compiler/src/optimizer/mod.rs b/src/compiler/src/optimizer/mod.rs index fe98c41..4c3a904 100644 --- a/src/compiler/src/optimizer/mod.rs +++ b/src/compiler/src/optimizer/mod.rs @@ -1,3 +1,7 @@ +mod optimize_syntax_tree; mod optimize_vm_instructions; -pub use self::optimize_vm_instructions::opimize_vm_instructions; +pub use self::{ + optimize_syntax_tree::optimize_syntax_tree_expression, + optimize_vm_instructions::opimize_vm_instructions, +}; diff --git a/src/compiler/src/optimizer/optimize_syntax_tree.rs b/src/compiler/src/optimizer/optimize_syntax_tree.rs new file mode 100644 index 0000000..ee4ec76 --- /dev/null +++ b/src/compiler/src/optimizer/optimize_syntax_tree.rs @@ -0,0 +1,64 @@ +use crate::compiler::CompilerState; + +use crate::codegen::{write_push, WriteInst}; +use crate::node::{Expr, GrammarItemType, Op, Term}; +use crate::symbol_table::{type_as_string, SymbolTable}; + +pub fn optimize_syntax_tree_expression( + state: &mut CompilerState, + expr: &Expr, +) -> Option> { + let Expr(term1, ops) = expr; + if let Some((op, term2)) = ops.get(0) { + return optimize_binop(state.sym_table(), op, term1, term2); + } + None +} + +fn optimize_binop( + sym_table: &SymbolTable, + Op(op): &Op, + term1: &Term, + term2: &Term, +) -> Option> { + let op_s = &op.as_str(); + if ["+", "-", "*", "/"].contains(op_s) { + match (term1, term2) { + // dbg!( + // term1, + // term2, + // // sym_table.lookup(term1), + // // sym_table.lookup(term2), + // ); + (Term::IntegerConstant(a), Term::IntegerConstant(b)) => { + return eval_binop(op_s, *a, *b); + } + #[allow(unreachable_code)] + (Term::VarName(va), Term::IntegerConstant(_b)) if false => { + if let Some(entry) = sym_table.lookup(va) { + if entry.typ == type_as_string(&GrammarItemType::Int) { + dbg!( + term1, + term2, + sym_table.lookup(va), + // sym_table.lookup(term2) + ); + return eval_binop(op_s, todo!(), *_b); + } + } + } + _ => {} + } + } + None +} + +fn eval_binop(op: &str, a: u16, b: u16) -> Option> { + match op { + "+" => Some(vec![write_push("constant", a + b)]), + "-" => Some(vec![write_push("constant", a - b)]), + "*" => Some(vec![write_push("constant", a * b)]), + "/" => Some(vec![write_push("constant", a / b)]), + _ => None, + } +} diff --git a/src/compiler/src/optimizer/optimize_vm_instructions.rs b/src/compiler/src/optimizer/optimize_vm_instructions.rs index 549c12c..879b8c0 100644 --- a/src/compiler/src/optimizer/optimize_vm_instructions.rs +++ b/src/compiler/src/optimizer/optimize_vm_instructions.rs @@ -1,16 +1,15 @@ -use crate::codegen::WriteInst; - use crate::instruction::Instruction; +use crate::codegen::WriteInst; + pub fn opimize_vm_instructions(instructions: &mut Vec) { let mut out = Vec::::with_capacity(instructions.len()); let mut insts_iter = instructions.iter().peekable(); - while let Some(&wi) = insts_iter.peek() { + while let Some(wi) = insts_iter.next() { let inst = wi.instruction(); match inst { Instruction::Arithmetic(op) => { - insts_iter.next(); match (op.as_str(), insts_iter.peek().map(|i| i.instruction())) { ("not", Some(Instruction::Arithmetic(op2))) if op2 == "not" => { insts_iter.next(); @@ -19,9 +18,16 @@ pub fn opimize_vm_instructions(instructions: &mut Vec) { _ => {} } } - _ => { - insts_iter.next(); + Instruction::Goto(goto_label, ..) => { + if let Some(Instruction::Label(label, ..)) = + insts_iter.peek().map(|i| i.instruction()) + { + if label == goto_label { + continue; + } + } } + _ => {} } out.push(wi.to_owned()); } diff --git a/src/compiler/src/parser.rs b/src/compiler/src/parser.rs index 80235c5..9864cb4 100644 --- a/src/compiler/src/parser.rs +++ b/src/compiler/src/parser.rs @@ -18,7 +18,7 @@ pub struct Parser<'a> { } impl<'a> Parser<'a> { - pub fn new(tokens: &'a[Token]) -> Self { + pub fn new(tokens: &'a [Token]) -> Self { Self { tokens: tokens.iter().enumerate().peekable(), tokens_seq: tokens, diff --git a/src/compiler/src/symbol_table.rs b/src/compiler/src/symbol_table.rs index 717c455..eef685d 100644 --- a/src/compiler/src/symbol_table.rs +++ b/src/compiler/src/symbol_table.rs @@ -128,12 +128,7 @@ impl SymbolTable { dict.entry_dict.insert(name.into(), entry); } - pub fn define_subroutine_var( - &mut self, - name: &str, - kind: SubVarKind, - typ: &GrammarItemType, - ) { + pub fn define_subroutine_var(&mut self, name: &str, kind: SubVarKind, typ: &GrammarItemType) { let dict = &mut self.sub; let index = dict.index_dict.entry(kind.clone()).or_insert(0); let entry = EntrySub { diff --git a/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__Game.jack@Game.jack.snap b/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__Game.jack@Game.jack.snap index f36a0d9..9990212 100644 --- a/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__Game.jack@Game.jack.snap +++ b/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__Game.jack@Game.jack.snap @@ -77,7 +77,6 @@ if-goto __VM_LABEL_1 push this 6 call Snake.dispose 1 pop temp 0 -goto __VM_LABEL_1 label __VM_LABEL_1 push constant 1 pop this 3 @@ -148,7 +147,6 @@ eq if-goto __VM_LABEL_6 push local 0 pop this 0 -goto __VM_LABEL_6 label __VM_LABEL_6 push this 0 push constant 81 @@ -162,7 +160,6 @@ push constant 0 pop this 3 push this 3 return -goto __VM_LABEL_7 label __VM_LABEL_7 push pointer 0 call Game.tickGame 1 @@ -180,7 +177,6 @@ if-goto __VM_LABEL_8 push pointer 0 call Game.endGameLoop 1 pop temp 0 -goto __VM_LABEL_8 label __VM_LABEL_8 goto __VM_LABEL_4 label __VM_LABEL_5 @@ -238,7 +234,6 @@ not if-goto __VM_LABEL_16 push constant 4 pop local 2 -goto __VM_LABEL_16 label __VM_LABEL_16 label __VM_LABEL_14 label __VM_LABEL_12 @@ -251,7 +246,6 @@ push this 6 push local 2 call Snake.setDirection 2 pop temp 0 -goto __VM_LABEL_17 label __VM_LABEL_17 push this 6 push this 4 @@ -276,7 +270,6 @@ push this 5 push constant 1 add pop this 5 -goto __VM_LABEL_18 label __VM_LABEL_18 push pointer 0 push this 6 @@ -285,7 +278,6 @@ pop this 4 push pointer 0 call Game.drawApple 1 pop temp 0 -goto __VM_LABEL_9 label __VM_LABEL_9 push constant 1000 push static 0 @@ -324,7 +316,6 @@ not if-goto __VM_LABEL_21 push constant 1 pop this 3 -goto __VM_LABEL_21 label __VM_LABEL_21 push constant 1000 push static 0 @@ -345,7 +336,6 @@ eq if-goto __VM_LABEL_22 push this 4 return -goto __VM_LABEL_22 label __VM_LABEL_22 push this 4 pop local 0 diff --git a/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__List.jack@List.jack.snap b/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__List.jack@List.jack.snap index 2ae15eb..c3ef307 100644 --- a/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__List.jack@List.jack.snap +++ b/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__List.jack@List.jack.snap @@ -72,7 +72,6 @@ if-goto __VM_LABEL_3 push this 1 call List.dispose 1 pop temp 0 -goto __VM_LABEL_3 label __VM_LABEL_3 push pointer 0 call Memory.deAlloc 1 @@ -103,7 +102,6 @@ not if-goto __VM_LABEL_4 push constant 0 return -goto __VM_LABEL_4 label __VM_LABEL_4 push local 0 pop local 1 diff --git a/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__Snake.jack@Snake.jack.snap b/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__Snake.jack@Snake.jack.snap index 228fab5..311d3b2 100644 --- a/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__Snake.jack@Snake.jack.snap +++ b/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__Snake.jack@Snake.jack.snap @@ -92,7 +92,6 @@ eq if-goto __VM_LABEL_3 push argument 1 pop this 1 -goto __VM_LABEL_3 label __VM_LABEL_3 push constant 0 return @@ -161,7 +160,6 @@ not if-goto __VM_LABEL_10 push constant 1 pop local 2 -goto __VM_LABEL_10 label __VM_LABEL_10 label __VM_LABEL_8 label __VM_LABEL_6 @@ -204,7 +202,6 @@ push temp 0 pop that 0 push this 3 return -goto __VM_LABEL_11 label __VM_LABEL_11 push argument 1 push local 1 @@ -224,7 +221,6 @@ if-goto __VM_LABEL_12 push pointer 0 call Snake.grow 1 pop temp 0 -goto __VM_LABEL_12 label __VM_LABEL_12 push this 0 push local 1 @@ -289,7 +285,6 @@ call List.getData 1 push this 1 call UI.drawSnakeHead 2 pop temp 0 -goto __VM_LABEL_15 label __VM_LABEL_15 push local 0 call List.getNext 1 @@ -337,7 +332,6 @@ if-goto __VM_LABEL_18 push constant 0 not return -goto __VM_LABEL_18 label __VM_LABEL_18 push local 0 call List.getNext 1 diff --git a/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__UI.jack@UI.jack.snap b/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__UI.jack@UI.jack.snap index fb2fef6..35e49fd 100644 --- a/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__UI.jack@UI.jack.snap +++ b/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__UI.jack@UI.jack.snap @@ -215,7 +215,6 @@ push constant 6 pop local 3 push constant 2 pop local 4 -goto __VM_LABEL_3 label __VM_LABEL_3 push argument 1 push constant 2 @@ -230,7 +229,6 @@ push constant 2 pop local 3 push constant 6 pop local 4 -goto __VM_LABEL_4 label __VM_LABEL_4 push argument 1 push constant 3 @@ -245,7 +243,6 @@ push constant 2 pop local 3 push constant 2 pop local 4 -goto __VM_LABEL_5 label __VM_LABEL_5 push argument 1 push constant 4 @@ -260,7 +257,6 @@ push constant 6 pop local 3 push constant 6 pop local 4 -goto __VM_LABEL_6 label __VM_LABEL_6 push local 0 push constant 0 @@ -528,7 +524,6 @@ not if-goto __VM_LABEL_7 push constant 0 return -goto __VM_LABEL_7 label __VM_LABEL_7 push constant 7 call String.new 1 diff --git a/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__Utils.jack@Utils.jack.snap b/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__Utils.jack@Utils.jack.snap index cd64827..2a44857 100644 --- a/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__Utils.jack@Utils.jack.snap +++ b/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__Utils.jack@Utils.jack.snap @@ -22,7 +22,6 @@ push local 0 push argument 1 add pop local 0 -goto __VM_LABEL_1 label __VM_LABEL_1 push local 0 return diff --git a/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__10__ExpressionLessSquare__Square.jack@Square.jack.snap b/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__10__ExpressionLessSquare__Square.jack@Square.jack.snap index 2b6ede2..ced16f4 100644 --- a/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__10__ExpressionLessSquare__Square.jack@Square.jack.snap +++ b/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__10__ExpressionLessSquare__Square.jack@Square.jack.snap @@ -69,7 +69,6 @@ pop this 2 push pointer 0 call Square.draw 1 pop temp 0 -goto __VM_LABEL_1 label __VM_LABEL_1 push constant 0 return @@ -87,7 +86,6 @@ pop this 2 push pointer 0 call Square.draw 1 pop temp 0 -goto __VM_LABEL_2 label __VM_LABEL_2 push constant 0 return @@ -117,7 +115,6 @@ push this 0 push this 1 call Screen.drawRectangle 4 pop temp 0 -goto __VM_LABEL_3 label __VM_LABEL_3 push constant 0 return @@ -147,7 +144,6 @@ push this 0 push this 1 call Screen.drawRectangle 4 pop temp 0 -goto __VM_LABEL_4 label __VM_LABEL_4 push constant 0 return @@ -177,7 +173,6 @@ push this 0 push this 1 call Screen.drawRectangle 4 pop temp 0 -goto __VM_LABEL_5 label __VM_LABEL_5 push constant 0 return @@ -207,7 +202,6 @@ push this 0 push this 1 call Screen.drawRectangle 4 pop temp 0 -goto __VM_LABEL_6 label __VM_LABEL_6 push constant 0 return diff --git a/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__10__ExpressionLessSquare__SquareGame.jack@SquareGame.jack.snap b/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__10__ExpressionLessSquare__SquareGame.jack@SquareGame.jack.snap index b67b5cc..86b2dbb 100644 --- a/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__10__ExpressionLessSquare__SquareGame.jack@SquareGame.jack.snap +++ b/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__10__ExpressionLessSquare__SquareGame.jack@SquareGame.jack.snap @@ -34,7 +34,6 @@ if-goto __VM_LABEL_1 push this 0 call Square.moveUp 1 pop temp 0 -goto __VM_LABEL_1 label __VM_LABEL_1 push this 1 not @@ -42,7 +41,6 @@ if-goto __VM_LABEL_2 push this 0 call Square.moveDown 1 pop temp 0 -goto __VM_LABEL_2 label __VM_LABEL_2 push this 1 not @@ -50,7 +48,6 @@ if-goto __VM_LABEL_3 push this 0 call Square.moveLeft 1 pop temp 0 -goto __VM_LABEL_3 label __VM_LABEL_3 push this 1 not @@ -58,7 +55,6 @@ if-goto __VM_LABEL_4 push this 0 call Square.moveRight 1 pop temp 0 -goto __VM_LABEL_4 label __VM_LABEL_4 push this 1 call Sys.wait 1 @@ -90,7 +86,6 @@ not if-goto __VM_LABEL_9 push local 1 pop local 1 -goto __VM_LABEL_9 label __VM_LABEL_9 push local 0 not @@ -98,7 +93,6 @@ if-goto __VM_LABEL_10 push this 0 call Square.decSize 1 pop temp 0 -goto __VM_LABEL_10 label __VM_LABEL_10 push local 0 not @@ -106,35 +100,30 @@ if-goto __VM_LABEL_11 push this 0 call Square.incSize 1 pop temp 0 -goto __VM_LABEL_11 label __VM_LABEL_11 push local 0 not if-goto __VM_LABEL_12 push local 1 pop this 1 -goto __VM_LABEL_12 label __VM_LABEL_12 push local 0 not if-goto __VM_LABEL_13 push local 0 pop this 1 -goto __VM_LABEL_13 label __VM_LABEL_13 push local 0 not if-goto __VM_LABEL_14 push this 0 pop this 1 -goto __VM_LABEL_14 label __VM_LABEL_14 push local 0 not if-goto __VM_LABEL_15 push this 1 pop this 1 -goto __VM_LABEL_15 label __VM_LABEL_15 label __VM_LABEL_16 push local 0 diff --git a/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__10__Square__Square.jack@Square.jack.snap b/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__10__Square__Square.jack@Square.jack.snap index 8ade166..9d32efb 100644 --- a/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__10__Square__Square.jack@Square.jack.snap +++ b/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__10__Square__Square.jack@Square.jack.snap @@ -90,7 +90,6 @@ pop this 2 push pointer 0 call Square.draw 1 pop temp 0 -goto __VM_LABEL_1 label __VM_LABEL_1 push constant 0 return @@ -112,7 +111,6 @@ pop this 2 push pointer 0 call Square.draw 1 pop temp 0 -goto __VM_LABEL_2 label __VM_LABEL_2 push constant 0 return @@ -159,7 +157,6 @@ push constant 1 add call Screen.drawRectangle 4 pop temp 0 -goto __VM_LABEL_3 label __VM_LABEL_3 push constant 0 return @@ -208,7 +205,6 @@ push this 2 add call Screen.drawRectangle 4 pop temp 0 -goto __VM_LABEL_4 label __VM_LABEL_4 push constant 0 return @@ -255,7 +251,6 @@ push this 2 add call Screen.drawRectangle 4 pop temp 0 -goto __VM_LABEL_5 label __VM_LABEL_5 push constant 0 return @@ -304,7 +299,6 @@ push this 2 add call Screen.drawRectangle 4 pop temp 0 -goto __VM_LABEL_6 label __VM_LABEL_6 push constant 0 return diff --git a/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__10__Square__SquareGame.jack@SquareGame.jack.snap b/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__10__Square__SquareGame.jack@SquareGame.jack.snap index 3fedb50..8912162 100644 --- a/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__10__Square__SquareGame.jack@SquareGame.jack.snap +++ b/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__10__Square__SquareGame.jack@SquareGame.jack.snap @@ -39,7 +39,6 @@ if-goto __VM_LABEL_1 push this 0 call Square.moveUp 1 pop temp 0 -goto __VM_LABEL_1 label __VM_LABEL_1 push this 1 push constant 2 @@ -49,7 +48,6 @@ if-goto __VM_LABEL_2 push this 0 call Square.moveDown 1 pop temp 0 -goto __VM_LABEL_2 label __VM_LABEL_2 push this 1 push constant 3 @@ -59,7 +57,6 @@ if-goto __VM_LABEL_3 push this 0 call Square.moveLeft 1 pop temp 0 -goto __VM_LABEL_3 label __VM_LABEL_3 push this 1 push constant 4 @@ -69,7 +66,6 @@ if-goto __VM_LABEL_4 push this 0 call Square.moveRight 1 pop temp 0 -goto __VM_LABEL_4 label __VM_LABEL_4 push constant 5 call Sys.wait 1 @@ -105,7 +101,6 @@ if-goto __VM_LABEL_9 push constant 0 not pop local 1 -goto __VM_LABEL_9 label __VM_LABEL_9 push local 0 push constant 90 @@ -115,7 +110,6 @@ if-goto __VM_LABEL_10 push this 0 call Square.decSize 1 pop temp 0 -goto __VM_LABEL_10 label __VM_LABEL_10 push local 0 push constant 88 @@ -125,7 +119,6 @@ if-goto __VM_LABEL_11 push this 0 call Square.incSize 1 pop temp 0 -goto __VM_LABEL_11 label __VM_LABEL_11 push local 0 push constant 131 @@ -134,7 +127,6 @@ not if-goto __VM_LABEL_12 push constant 1 pop this 1 -goto __VM_LABEL_12 label __VM_LABEL_12 push local 0 push constant 133 @@ -143,7 +135,6 @@ not if-goto __VM_LABEL_13 push constant 2 pop this 1 -goto __VM_LABEL_13 label __VM_LABEL_13 push local 0 push constant 130 @@ -152,7 +143,6 @@ not if-goto __VM_LABEL_14 push constant 3 pop this 1 -goto __VM_LABEL_14 label __VM_LABEL_14 push local 0 push constant 132 @@ -161,7 +151,6 @@ not if-goto __VM_LABEL_15 push constant 4 pop this 1 -goto __VM_LABEL_15 label __VM_LABEL_15 label __VM_LABEL_16 push local 0 diff --git a/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__ComplexArrays__Main.jack@Main.jack.snap b/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__ComplexArrays__Main.jack@Main.jack.snap index 483483e..2c82b89 100644 --- a/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__ComplexArrays__Main.jack@Main.jack.snap +++ b/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__ComplexArrays__Main.jack@Main.jack.snap @@ -469,7 +469,6 @@ pop temp 0 pop pointer 1 push temp 0 pop that 0 -goto __VM_LABEL_1 label __VM_LABEL_1 push constant 44 call String.new 1 diff --git a/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Pong__Ball.jack@Ball.jack.snap b/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Pong__Ball.jack@Ball.jack.snap index 12eacf2..fd91441 100644 --- a/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Pong__Ball.jack@Ball.jack.snap +++ b/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Pong__Ball.jack@Ball.jack.snap @@ -254,7 +254,6 @@ push constant 1 pop this 14 push this 10 pop this 0 -goto __VM_LABEL_17 label __VM_LABEL_17 push this 0 push this 11 @@ -264,7 +263,6 @@ push constant 2 pop this 14 push this 11 pop this 0 -goto __VM_LABEL_18 label __VM_LABEL_18 push this 1 push this 12 @@ -274,7 +272,6 @@ push constant 3 pop this 14 push this 12 pop this 1 -goto __VM_LABEL_19 label __VM_LABEL_19 push this 1 push this 13 @@ -284,7 +281,6 @@ push constant 4 pop this 14 push this 13 pop this 1 -goto __VM_LABEL_20 label __VM_LABEL_20 push pointer 0 call Ball.show 1 diff --git a/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Pong__Bat.jack@Bat.jack.snap b/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Pong__Bat.jack@Bat.jack.snap index d85d438..cd93da1 100644 --- a/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Pong__Bat.jack@Bat.jack.snap +++ b/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Pong__Bat.jack@Bat.jack.snap @@ -120,7 +120,6 @@ not if-goto __VM_LABEL_3 push constant 0 pop this 0 -goto __VM_LABEL_3 label __VM_LABEL_3 push constant 0 call Screen.setColor 1 @@ -172,7 +171,6 @@ push constant 511 push this 2 sub pop this 0 -goto __VM_LABEL_4 label __VM_LABEL_4 push constant 0 call Screen.setColor 1 diff --git a/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Pong__PongGame.jack@PongGame.jack.snap b/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Pong__PongGame.jack@PongGame.jack.snap index 7ca368d..f1c559f 100644 --- a/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Pong__PongGame.jack@PongGame.jack.snap +++ b/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Pong__PongGame.jack@PongGame.jack.snap @@ -151,7 +151,6 @@ if-goto __VM_LABEL_9 push constant 0 not pop this 3 -goto __VM_LABEL_9 label __VM_LABEL_9 label __VM_LABEL_7 label __VM_LABEL_5 @@ -209,7 +208,6 @@ push constant 114 call String.appendChar 2 call Output.printString 1 pop temp 0 -goto __VM_LABEL_12 label __VM_LABEL_12 push constant 0 return @@ -281,7 +279,6 @@ not if-goto __VM_LABEL_18 push constant 1 pop local 0 -goto __VM_LABEL_18 label __VM_LABEL_18 label __VM_LABEL_16 push this 6 @@ -303,15 +300,12 @@ pop temp 0 push this 4 call Output.printInt 1 pop temp 0 -goto __VM_LABEL_15 label __VM_LABEL_15 -goto __VM_LABEL_14 label __VM_LABEL_14 push this 1 push local 0 call Ball.bounce 2 pop temp 0 -goto __VM_LABEL_13 label __VM_LABEL_13 push constant 0 return diff --git a/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Seven__Main.jack@Main.jack.snap b/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Seven__Main.jack@Main.jack.snap index 55c30a0..9214d56 100644 --- a/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Seven__Main.jack@Main.jack.snap +++ b/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Seven__Main.jack@Main.jack.snap @@ -6,9 +6,7 @@ input_file: src/compiler/tests/inputs/11/Seven/Main.jack --- function Main.main 0 push constant 1 -push constant 2 -push constant 3 -call Math.multiply 2 +push constant 6 add call Output.printInt 1 pop temp 0 diff --git a/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Square__Square.jack@Square.jack.snap b/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Square__Square.jack@Square.jack.snap index 806337d..8988c5c 100644 --- a/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Square__Square.jack@Square.jack.snap +++ b/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Square__Square.jack@Square.jack.snap @@ -90,7 +90,6 @@ pop this 2 push pointer 0 call Square.draw 1 pop temp 0 -goto __VM_LABEL_1 label __VM_LABEL_1 push constant 0 return @@ -112,7 +111,6 @@ pop this 2 push pointer 0 call Square.draw 1 pop temp 0 -goto __VM_LABEL_2 label __VM_LABEL_2 push constant 0 return @@ -159,7 +157,6 @@ push constant 1 add call Screen.drawRectangle 4 pop temp 0 -goto __VM_LABEL_3 label __VM_LABEL_3 push constant 0 return @@ -208,7 +205,6 @@ push this 2 add call Screen.drawRectangle 4 pop temp 0 -goto __VM_LABEL_4 label __VM_LABEL_4 push constant 0 return @@ -255,7 +251,6 @@ push this 2 add call Screen.drawRectangle 4 pop temp 0 -goto __VM_LABEL_5 label __VM_LABEL_5 push constant 0 return @@ -304,7 +299,6 @@ push this 2 add call Screen.drawRectangle 4 pop temp 0 -goto __VM_LABEL_6 label __VM_LABEL_6 push constant 0 return diff --git a/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Square__SquareGame.jack@SquareGame.jack.snap b/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Square__SquareGame.jack@SquareGame.jack.snap index 42c79ee..3f65bbe 100644 --- a/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Square__SquareGame.jack@SquareGame.jack.snap +++ b/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Square__SquareGame.jack@SquareGame.jack.snap @@ -39,7 +39,6 @@ if-goto __VM_LABEL_1 push this 0 call Square.moveUp 1 pop temp 0 -goto __VM_LABEL_1 label __VM_LABEL_1 push this 1 push constant 2 @@ -49,7 +48,6 @@ if-goto __VM_LABEL_2 push this 0 call Square.moveDown 1 pop temp 0 -goto __VM_LABEL_2 label __VM_LABEL_2 push this 1 push constant 3 @@ -59,7 +57,6 @@ if-goto __VM_LABEL_3 push this 0 call Square.moveLeft 1 pop temp 0 -goto __VM_LABEL_3 label __VM_LABEL_3 push this 1 push constant 4 @@ -69,7 +66,6 @@ if-goto __VM_LABEL_4 push this 0 call Square.moveRight 1 pop temp 0 -goto __VM_LABEL_4 label __VM_LABEL_4 push constant 5 call Sys.wait 1 @@ -105,7 +101,6 @@ if-goto __VM_LABEL_9 push constant 0 not pop local 1 -goto __VM_LABEL_9 label __VM_LABEL_9 push local 0 push constant 90 @@ -115,7 +110,6 @@ if-goto __VM_LABEL_10 push this 0 call Square.decSize 1 pop temp 0 -goto __VM_LABEL_10 label __VM_LABEL_10 push local 0 push constant 88 @@ -125,7 +119,6 @@ if-goto __VM_LABEL_11 push this 0 call Square.incSize 1 pop temp 0 -goto __VM_LABEL_11 label __VM_LABEL_11 push local 0 push constant 131 @@ -134,7 +127,6 @@ not if-goto __VM_LABEL_12 push constant 1 pop this 1 -goto __VM_LABEL_12 label __VM_LABEL_12 push local 0 push constant 133 @@ -143,7 +135,6 @@ not if-goto __VM_LABEL_13 push constant 2 pop this 1 -goto __VM_LABEL_13 label __VM_LABEL_13 push local 0 push constant 130 @@ -152,7 +143,6 @@ not if-goto __VM_LABEL_14 push constant 3 pop this 1 -goto __VM_LABEL_14 label __VM_LABEL_14 push local 0 push constant 132 @@ -161,7 +151,6 @@ not if-goto __VM_LABEL_15 push constant 4 pop this 1 -goto __VM_LABEL_15 label __VM_LABEL_15 label __VM_LABEL_16 push local 0 From 6be112156b76f6de0ba253aeafe8521fc90821dc Mon Sep 17 00:00:00 2001 From: fix-fix Date: Thu, 25 Nov 2021 01:09:24 +0500 Subject: [PATCH 5/8] compiler: add term evaluation for whole expresion --- .../src/optimizer/optimize_syntax_tree.rs | 129 +++++++++++------- ...e example: snake__Game.jack@Game.jack.snap | 8 +- ...example: snake__Snake.jack@Snake.jack.snap | 8 +- ... code example: snake__UI.jack@UI.jack.snap | 12 +- ...__10__Square__Square.jack@Square.jack.snap | 20 +-- ...uare__SquareGame.jack@SquareGame.jack.snap | 4 +- ...11__ConvertToBin__Main.jack@Main.jack.snap | 4 +- ...inputs__11__Pong__Ball.jack@Ball.jack.snap | 4 +- ...__inputs__11__Pong__Bat.jack@Bat.jack.snap | 12 +- ...11__Pong__PongGame.jack@PongGame.jack.snap | 4 +- ...nputs__11__Seven__Main.jack@Main.jack.snap | 4 +- ...__11__Square__Square.jack@Square.jack.snap | 20 +-- ...uare__SquareGame.jack@SquareGame.jack.snap | 4 +- 13 files changed, 133 insertions(+), 100 deletions(-) diff --git a/src/compiler/src/optimizer/optimize_syntax_tree.rs b/src/compiler/src/optimizer/optimize_syntax_tree.rs index ee4ec76..678a4a0 100644 --- a/src/compiler/src/optimizer/optimize_syntax_tree.rs +++ b/src/compiler/src/optimizer/optimize_syntax_tree.rs @@ -1,64 +1,99 @@ use crate::compiler::CompilerState; -use crate::codegen::{write_push, WriteInst}; -use crate::node::{Expr, GrammarItemType, Op, Term}; -use crate::symbol_table::{type_as_string, SymbolTable}; +use crate::codegen::{write_arith, write_push, WriteInst}; +use crate::node::{Expr, Op, Term}; +use crate::symbol_table::SymbolTable; +use crate::token::Keyword; pub fn optimize_syntax_tree_expression( - state: &mut CompilerState, - expr: &Expr, + _state: &mut CompilerState, + Expr(term1, ops): &Expr, ) -> Option> { - let Expr(term1, ops) = expr; - if let Some((op, term2)) = ops.get(0) { - return optimize_binop(state.sym_table(), op, term1, term2); + optimize_expr(None, term1, ops) +} + +fn optimize_expr_int_inner( + _sym_table: Option<&SymbolTable>, + term1: &Term, + ops: &[(Op, Term)], +) -> Option { + // dbg!(term1, ops); + let mut term1_value = eval_term(term1); + for (Op(op), term2) in ops { + if !is_simple_arith_op(op.as_str()) { + return None; + } + let term2_value = eval_term(term2); + if let (Some(a), Some(b)) = (term1_value, term2_value) { + term1_value = eval_binop(op, a, b); + } else { + return None; + } } - None + term1_value } -fn optimize_binop( - sym_table: &SymbolTable, - Op(op): &Op, +fn is_simple_arith_op(op: &str) -> bool { + ["+", "-", "*", "/", "|", "&", "~"].contains(&op) +} + +fn optimize_expr( + sym_table: Option<&SymbolTable>, term1: &Term, - term2: &Term, + ops: &[(Op, Term)], ) -> Option> { - let op_s = &op.as_str(); - if ["+", "-", "*", "/"].contains(op_s) { - match (term1, term2) { - // dbg!( - // term1, - // term2, - // // sym_table.lookup(term1), - // // sym_table.lookup(term2), - // ); - (Term::IntegerConstant(a), Term::IntegerConstant(b)) => { - return eval_binop(op_s, *a, *b); - } - #[allow(unreachable_code)] - (Term::VarName(va), Term::IntegerConstant(_b)) if false => { - if let Some(entry) = sym_table.lookup(va) { - if entry.typ == type_as_string(&GrammarItemType::Int) { - dbg!( - term1, - term2, - sym_table.lookup(va), - // sym_table.lookup(term2) - ); - return eval_binop(op_s, todo!(), *_b); - } - } - } - _ => {} - } + // dbg!(term1, ops); + optimize_expr_int_inner(sym_table, term1, ops).map(signed_constant_to_constant_insts) +} + +fn signed_constant_to_constant_insts(value: i16) -> Vec { + let mut insts = vec![write_push("constant", value.abs() as u16)]; + if value.is_negative() { + insts.push(write_arith("neg")); } - None + insts } -fn eval_binop(op: &str, a: u16, b: u16) -> Option> { +fn eval_binop(op: &str, a: i16, b: i16) -> Option { + // dbg!(op, a, b); match op { - "+" => Some(vec![write_push("constant", a + b)]), - "-" => Some(vec![write_push("constant", a - b)]), - "*" => Some(vec![write_push("constant", a * b)]), - "/" => Some(vec![write_push("constant", a / b)]), + "+" => Some(a + b), + "-" => Some(a - b), + "*" => Some(a * b), + "/" => Some(a / b), + "|" => Some(a | b), + "&" => Some(a & b), + _ => None, + } +} + +fn eval_unop(op: &str, a: i16) -> Option { + // dbg!(op, a, b); + match op { + "-" => eval_binop(op, 0, a), + "~" => Some(if a == 0 { -1 } else { 0 }), + _ => None, + } +} + +fn eval_term(term: &Term) -> Option { + // dbg!(term); + match term { + &Term::IntegerConstant(value) => { + // dbg!(value); + Some(value.try_into().unwrap()) + } + Term::UnaryOp(Op(op), term) => match eval_term(term) { + Some(term_value) => eval_unop(op, term_value), + None => None, + }, + Term::ParenExpr(expr) => { + let Expr(termp1, ops) = &**expr; + optimize_expr_int_inner(None, termp1, ops) + } + Term::KeywordConstant(Keyword::Null) => Some(0), + Term::KeywordConstant(Keyword::True) => Some(-1), + Term::KeywordConstant(Keyword::False) => Some(0), _ => None, } } diff --git a/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__Game.jack@Game.jack.snap b/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__Game.jack@Game.jack.snap index 9990212..8346e1a 100644 --- a/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__Game.jack@Game.jack.snap +++ b/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__Game.jack@Game.jack.snap @@ -153,8 +153,8 @@ push constant 81 eq not if-goto __VM_LABEL_7 -push constant 0 -not +push constant 1 +neg pop local 1 push constant 0 pop this 3 @@ -368,8 +368,8 @@ return function Game.drawApple 0 push argument 0 pop pointer 0 -push constant 0 -not +push constant 1 +neg push this 4 call UI.drawBlockIndex 2 pop temp 0 diff --git a/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__Snake.jack@Snake.jack.snap b/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__Snake.jack@Snake.jack.snap index 311d3b2..6a77585 100644 --- a/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__Snake.jack@Snake.jack.snap +++ b/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__Snake.jack@Snake.jack.snap @@ -194,8 +194,8 @@ if-goto __VM_LABEL_11 push this 3 push constant 0 add -push constant 0 -not +push constant 1 +neg pop temp 0 pop pointer 1 push temp 0 @@ -329,8 +329,8 @@ push argument 1 eq not if-goto __VM_LABEL_18 -push constant 0 -not +push constant 1 +neg return label __VM_LABEL_18 push local 0 diff --git a/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__UI.jack@UI.jack.snap b/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__UI.jack@UI.jack.snap index 35e49fd..ed2a5c1 100644 --- a/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__UI.jack@UI.jack.snap +++ b/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__UI.jack@UI.jack.snap @@ -40,8 +40,8 @@ push static 1 push static 0 call Math.multiply 2 pop local 0 -push constant 0 -not +push constant 1 +neg call Screen.setColor 1 pop temp 0 push local 0 @@ -97,8 +97,8 @@ push local 1 push constant 0 lt if-goto __VM_LABEL_2 -push constant 0 -not +push constant 1 +neg call Screen.setColor 1 pop temp 0 push local 2 @@ -296,8 +296,8 @@ pop temp 0 push constant 0 return function UI.drawSnakePartBase 2 -push constant 0 -not +push constant 1 +neg push argument 0 call UI.drawBlockIndex 2 pop temp 0 diff --git a/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__10__Square__Square.jack@Square.jack.snap b/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__10__Square__Square.jack@Square.jack.snap index 9d32efb..4a36fe6 100644 --- a/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__10__Square__Square.jack@Square.jack.snap +++ b/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__10__Square__Square.jack@Square.jack.snap @@ -30,8 +30,8 @@ return function Square.draw 0 push argument 0 pop pointer 0 -push constant 0 -not +push constant 1 +neg call Screen.setColor 1 pop temp 0 push this 0 @@ -143,8 +143,8 @@ push this 1 push constant 2 sub pop this 1 -push constant 0 -not +push constant 1 +neg call Screen.setColor 1 pop temp 0 push this 0 @@ -187,8 +187,8 @@ push this 1 push constant 2 add pop this 1 -push constant 0 -not +push constant 1 +neg call Screen.setColor 1 pop temp 0 push this 0 @@ -237,8 +237,8 @@ push this 0 push constant 2 sub pop this 0 -push constant 0 -not +push constant 1 +neg call Screen.setColor 1 pop temp 0 push this 0 @@ -281,8 +281,8 @@ push this 0 push constant 2 add pop this 0 -push constant 0 -not +push constant 1 +neg call Screen.setColor 1 pop temp 0 push this 0 diff --git a/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__10__Square__SquareGame.jack@SquareGame.jack.snap b/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__10__Square__SquareGame.jack@SquareGame.jack.snap index 8912162..65ae248 100644 --- a/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__10__Square__SquareGame.jack@SquareGame.jack.snap +++ b/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__10__Square__SquareGame.jack@SquareGame.jack.snap @@ -98,8 +98,8 @@ push constant 81 eq not if-goto __VM_LABEL_9 -push constant 0 -not +push constant 1 +neg pop local 1 label __VM_LABEL_9 push local 0 diff --git a/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__ConvertToBin__Main.jack@Main.jack.snap b/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__ConvertToBin__Main.jack@Main.jack.snap index d3988b4..f55636f 100644 --- a/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__ConvertToBin__Main.jack@Main.jack.snap +++ b/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__ConvertToBin__Main.jack@Main.jack.snap @@ -20,8 +20,8 @@ pop temp 0 push constant 0 return function Main.convert 3 -push constant 0 -not +push constant 1 +neg pop local 2 label __VM_LABEL_1 push local 2 diff --git a/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Pong__Ball.jack@Ball.jack.snap b/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Pong__Ball.jack@Ball.jack.snap index fd91441..7b9b743 100644 --- a/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Pong__Ball.jack@Ball.jack.snap +++ b/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Pong__Ball.jack@Ball.jack.snap @@ -42,8 +42,8 @@ return function Ball.show 0 push argument 0 pop pointer 0 -push constant 0 -not +push constant 1 +neg call Screen.setColor 1 pop temp 0 push pointer 0 diff --git a/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Pong__Bat.jack@Bat.jack.snap b/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Pong__Bat.jack@Bat.jack.snap index cd93da1..63fb025 100644 --- a/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Pong__Bat.jack@Bat.jack.snap +++ b/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Pong__Bat.jack@Bat.jack.snap @@ -34,8 +34,8 @@ return function Bat.show 0 push argument 0 pop pointer 0 -push constant 0 -not +push constant 1 +neg call Screen.setColor 1 pop temp 0 push pointer 0 @@ -140,8 +140,8 @@ push this 3 add call Screen.drawRectangle 4 pop temp 0 -push constant 0 -not +push constant 1 +neg call Screen.setColor 1 pop temp 0 push this 0 @@ -187,8 +187,8 @@ push this 3 add call Screen.drawRectangle 4 pop temp 0 -push constant 0 -not +push constant 1 +neg call Screen.setColor 1 pop temp 0 push this 0 diff --git a/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Pong__PongGame.jack@PongGame.jack.snap b/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Pong__PongGame.jack@PongGame.jack.snap index f1c559f..fa42ac5 100644 --- a/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Pong__PongGame.jack@PongGame.jack.snap +++ b/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Pong__PongGame.jack@PongGame.jack.snap @@ -148,8 +148,8 @@ push constant 140 eq not if-goto __VM_LABEL_9 -push constant 0 -not +push constant 1 +neg pop this 3 label __VM_LABEL_9 label __VM_LABEL_7 diff --git a/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Seven__Main.jack@Main.jack.snap b/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Seven__Main.jack@Main.jack.snap index 9214d56..43ed84f 100644 --- a/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Seven__Main.jack@Main.jack.snap +++ b/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Seven__Main.jack@Main.jack.snap @@ -5,9 +5,7 @@ input_file: src/compiler/tests/inputs/11/Seven/Main.jack --- function Main.main 0 -push constant 1 -push constant 6 -add +push constant 7 call Output.printInt 1 pop temp 0 push constant 0 diff --git a/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Square__Square.jack@Square.jack.snap b/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Square__Square.jack@Square.jack.snap index 8988c5c..499a94a 100644 --- a/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Square__Square.jack@Square.jack.snap +++ b/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Square__Square.jack@Square.jack.snap @@ -30,8 +30,8 @@ return function Square.draw 0 push argument 0 pop pointer 0 -push constant 0 -not +push constant 1 +neg call Screen.setColor 1 pop temp 0 push this 0 @@ -143,8 +143,8 @@ push this 1 push constant 2 sub pop this 1 -push constant 0 -not +push constant 1 +neg call Screen.setColor 1 pop temp 0 push this 0 @@ -187,8 +187,8 @@ push this 1 push constant 2 add pop this 1 -push constant 0 -not +push constant 1 +neg call Screen.setColor 1 pop temp 0 push this 0 @@ -237,8 +237,8 @@ push this 0 push constant 2 sub pop this 0 -push constant 0 -not +push constant 1 +neg call Screen.setColor 1 pop temp 0 push this 0 @@ -281,8 +281,8 @@ push this 0 push constant 2 add pop this 0 -push constant 0 -not +push constant 1 +neg call Screen.setColor 1 pop temp 0 push this 0 diff --git a/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Square__SquareGame.jack@SquareGame.jack.snap b/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Square__SquareGame.jack@SquareGame.jack.snap index 3f65bbe..92d097d 100644 --- a/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Square__SquareGame.jack@SquareGame.jack.snap +++ b/src/compiler/tests/snapshots/test_output__Compiler vm code: src__compiler__tests__inputs__11__Square__SquareGame.jack@SquareGame.jack.snap @@ -98,8 +98,8 @@ push constant 81 eq not if-goto __VM_LABEL_9 -push constant 0 -not +push constant 1 +neg pop local 1 label __VM_LABEL_9 push local 0 From 51f1b24c6b008a3ccf4b9dccffa7c173245d449e Mon Sep 17 00:00:00 2001 From: fix-fix Date: Sat, 27 Nov 2021 01:47:40 +0500 Subject: [PATCH 6/8] compiler: evaluate and inline static constants --- src/compiler/src/compiler.rs | 77 ++++++++++++++++--- .../src/optimizer/optimize_syntax_tree.rs | 52 +++++++++---- src/compiler/src/symbol_table.rs | 41 ++++++++-- ...e example: snake__Game.jack@Game.jack.snap | 14 +--- ... code example: snake__UI.jack@UI.jack.snap | 36 +++------ 5 files changed, 153 insertions(+), 67 deletions(-) diff --git a/src/compiler/src/compiler.rs b/src/compiler/src/compiler.rs index fc61717..1622452 100644 --- a/src/compiler/src/compiler.rs +++ b/src/compiler/src/compiler.rs @@ -20,8 +20,8 @@ pub struct CompilerState { } impl CompilerState { - pub fn sym_table(&self) -> &SymbolTable { - &self.sym_table + pub fn sym_table(&mut self) -> &mut SymbolTable { + &mut self.sym_table } } @@ -75,8 +75,9 @@ impl CompilerState { } #[derive(Debug, Default, Clone)] -struct CompilerContext { +pub struct CompilerContext { function_variant: Option, + lhs_context: LhsContext, return_type: Option, } @@ -84,6 +85,50 @@ impl CompilerContext { fn new() -> Self { Default::default() } + + pub fn lhs_context(&self) -> LhsContext { + self.lhs_context.clone() + } + + fn set_lhs_context_static(&mut self, name: String) { + if !self.is_in_constructor() { + return; + } + self.lhs_context = Some(LhsContextInner::new_for_class_static(name.as_str())) + } + + fn reset_lhs_context_static(&mut self) { + self.lhs_context = None + } + + fn is_in_constructor(&self) -> bool { + self.function_variant == Some(GrammarSubroutineVariant::Constructor) + } +} + +#[derive(Debug, Clone)] +pub struct LhsContextClassStatic { + name: String, +} +impl LhsContextClassStatic { + pub fn name(&self) -> &str { + self.name.as_str() + } + + fn new(name: &str) -> Self { + Self { name: name.into() } + } +} +#[derive(Debug, Clone)] +pub enum LhsContextInner { + ClassStatic(LhsContextClassStatic), +} +pub type LhsContext = Option; + +impl LhsContextInner { + pub fn new_for_class_static(name: &str) -> LhsContextInner { + LhsContextInner::ClassStatic(LhsContextClassStatic::new(name)) + } } fn lookup_var(state: &mut CompilerState, context: &CompilerContext, name: String) -> Res { @@ -176,13 +221,13 @@ fn compile_subroutine_dec( .define_subroutine_var(¶m.ident, SubVarKind::Argument, ¶m.type_); } - compile_subroutine(state, &sub_context, sub, item_type)?; + compile_subroutine(state, &mut sub_context, sub, item_type)?; Ok(()) } fn compile_subroutine( state: &mut CompilerState, - context: &CompilerContext, + context: &mut CompilerContext, Subroutine(var_decs, stmts): Subroutine, _typ: GrammarSubroutineReturnType, ) -> Res { @@ -199,7 +244,7 @@ fn compile_subroutine( fn compile_statements( state: &mut CompilerState, - context: &CompilerContext, + context: &mut CompilerContext, statements: Vec, ) -> Res { for stmt in statements { @@ -208,7 +253,11 @@ fn compile_statements( Ok(()) } -fn compile_statement(state: &mut CompilerState, context: &CompilerContext, stmt: Statement) -> Res { +fn compile_statement( + state: &mut CompilerState, + context: &mut CompilerContext, + stmt: Statement, +) -> Res { match stmt { Statement::LetStatement(s) => compile_statement_let(state, context, s)?, Statement::IfStatement(s) => compile_statement_if(state, context, s)?, @@ -221,13 +270,18 @@ fn compile_statement(state: &mut CompilerState, context: &CompilerContext, stmt: fn compile_statement_let( state: &mut CompilerState, - context: &CompilerContext, + context: &mut CompilerContext, stmt: LetStatement, ) -> Res { let var = state .sym_table .lookup(&stmt.name) .ok_or(format!("Unknown var: {}", &stmt.name))?; + let is_static_var = var.kind == "static"; + if is_static_var { + context.set_lhs_context_static(stmt.name.clone()); + } + match stmt.index_expr { Some(expr) => { state.write_result(write_push(var.kind.as_str(), var.index)); @@ -244,12 +298,13 @@ fn compile_statement_let( state.write_result(write_pop(var.kind.as_str(), var.index)); } }; + context.reset_lhs_context_static(); Ok(()) } fn compile_statement_if( state: &mut CompilerState, - context: &CompilerContext, + context: &mut CompilerContext, stmt: IfStatement, ) -> Res { let end_label = state.get_label(); @@ -273,7 +328,7 @@ fn compile_statement_if( fn compile_statement_while( state: &mut CompilerState, - context: &CompilerContext, + context: &mut CompilerContext, stmt: WhileStatement, ) -> Res { let start_label = state.get_label(); @@ -384,7 +439,7 @@ fn compile_expression_list( } fn compile_expression(state: &mut CompilerState, context: &CompilerContext, expr: Expr) -> Res { - if let Some(results) = optimize_syntax_tree_expression(state, &expr) { + if let Some(results) = optimize_syntax_tree_expression(&expr, state, context) { for result in results { state.write_result(result); } diff --git a/src/compiler/src/optimizer/optimize_syntax_tree.rs b/src/compiler/src/optimizer/optimize_syntax_tree.rs index 678a4a0..f184eb2 100644 --- a/src/compiler/src/optimizer/optimize_syntax_tree.rs +++ b/src/compiler/src/optimizer/optimize_syntax_tree.rs @@ -1,35 +1,45 @@ -use crate::compiler::CompilerState; +use crate::compiler::{CompilerContext, CompilerState, LhsContext, LhsContextInner}; use crate::codegen::{write_arith, write_push, WriteInst}; -use crate::node::{Expr, Op, Term}; -use crate::symbol_table::SymbolTable; +use crate::node::{Expr, GrammarItemType, Op, Term}; +use crate::symbol_table::{type_as_string, SymbolTable}; use crate::token::Keyword; pub fn optimize_syntax_tree_expression( - _state: &mut CompilerState, Expr(term1, ops): &Expr, + state: &mut CompilerState, + context: &CompilerContext, ) -> Option> { - optimize_expr(None, term1, ops) + let lhs_context = context.lhs_context(); + optimize_expr(term1, ops, state.sym_table(), &lhs_context) } fn optimize_expr_int_inner( - _sym_table: Option<&SymbolTable>, term1: &Term, ops: &[(Op, Term)], + sym_table: &mut SymbolTable, + lhs_context: &LhsContext, ) -> Option { // dbg!(term1, ops); - let mut term1_value = eval_term(term1); + let mut term1_value = eval_term(term1, sym_table, lhs_context); for (Op(op), term2) in ops { if !is_simple_arith_op(op.as_str()) { return None; } - let term2_value = eval_term(term2); + let term2_value = eval_term(term2, sym_table, lhs_context); if let (Some(a), Some(b)) = (term1_value, term2_value) { term1_value = eval_binop(op, a, b); } else { return None; } } + + if let (Some(term_value), Some(LhsContextInner::ClassStatic(class_static))) = + (term1_value, lhs_context) + { + sym_table.add_constant_value_for_static(class_static.name(), term_value); + } + term1_value } @@ -38,12 +48,14 @@ fn is_simple_arith_op(op: &str) -> bool { } fn optimize_expr( - sym_table: Option<&SymbolTable>, term1: &Term, ops: &[(Op, Term)], + sym_table: &mut SymbolTable, + lhs_context: &LhsContext, ) -> Option> { // dbg!(term1, ops); - optimize_expr_int_inner(sym_table, term1, ops).map(signed_constant_to_constant_insts) + optimize_expr_int_inner(term1, ops, sym_table, lhs_context) + .map(signed_constant_to_constant_insts) } fn signed_constant_to_constant_insts(value: i16) -> Vec { @@ -76,24 +88,34 @@ fn eval_unop(op: &str, a: i16) -> Option { } } -fn eval_term(term: &Term) -> Option { +fn eval_term(term: &Term, sym_table: &mut SymbolTable, lhs_context: &LhsContext) -> Option { // dbg!(term); match term { - &Term::IntegerConstant(value) => { + Term::IntegerConstant(value) => { // dbg!(value); - Some(value.try_into().unwrap()) + Some((*value).try_into().unwrap()) } - Term::UnaryOp(Op(op), term) => match eval_term(term) { + Term::UnaryOp(Op(op), term) => match eval_term(term, sym_table, lhs_context) { Some(term_value) => eval_unop(op, term_value), None => None, }, Term::ParenExpr(expr) => { let Expr(termp1, ops) = &**expr; - optimize_expr_int_inner(None, termp1, ops) + optimize_expr_int_inner(termp1, ops, sym_table, lhs_context) } Term::KeywordConstant(Keyword::Null) => Some(0), Term::KeywordConstant(Keyword::True) => Some(-1), Term::KeywordConstant(Keyword::False) => Some(0), + #[allow(clippy::let_and_return)] + Term::VarName(ident) => { + let entry = sym_table.lookup(ident)?; + if entry.typ != type_as_string(&GrammarItemType::Int) { + return None; + } + let constant_value = entry.constant_value(); + // dbg!(constant_value, ident, entry); + constant_value + } _ => None, } } diff --git a/src/compiler/src/symbol_table.rs b/src/compiler/src/symbol_table.rs index eef685d..d8986fc 100644 --- a/src/compiler/src/symbol_table.rs +++ b/src/compiler/src/symbol_table.rs @@ -23,6 +23,23 @@ struct EntryClass { typ: String, kind: ClassVarKind, index: u16, + + constant_value: Option, +} + +impl EntryClass { + fn new(typ: String, kind: ClassVarKind, index: u16) -> Self { + Self { + typ, + kind, + index, + constant_value: None, + } + } + + fn set_constant_value(&mut self, term_value: i16) { + self.constant_value = Some(term_value); + } } impl From<&EntryClass> for Entry { @@ -34,6 +51,8 @@ impl From<&EntryClass> for Entry { ClassVarKind::Field => "this".to_string(), ClassVarKind::Static => "static".to_string(), }, + + constant_value: other.constant_value, } } } @@ -60,6 +79,8 @@ impl From<&EntrySub> for Entry { SubVarKind::Argument => "argument".to_string(), SubVarKind::Var => "local".to_string(), }, + + constant_value: None, } } } @@ -86,6 +107,14 @@ pub struct Entry { // What kind of memory segment pub kind: String, pub index: u16, + + constant_value: Option, +} + +impl Entry { + pub fn constant_value(&self) -> Option { + self.constant_value + } } impl SymbolTable { @@ -119,11 +148,7 @@ impl SymbolTable { ) { let dict = &mut self.class; let index = dict.index_dict.entry(kind.into()).or_insert(0); - let entry = EntryClass { - typ: type_as_string(typ), - kind: kind.into(), - index: *index, - }; + let entry = EntryClass::new(type_as_string(typ), kind.into(), *index); *index += 1; dict.entry_dict.insert(name.into(), entry); } @@ -143,6 +168,12 @@ impl SymbolTable { pub fn reset_subroutine_table(&mut self) { self.sub = Default::default(); } + + pub fn add_constant_value_for_static(&mut self, static_var: &str, term_value: i16) { + if let Some(entry) = self.class.entry_dict.get_mut(static_var) { + entry.set_constant_value(term_value); + } + } } pub fn type_as_string(typ: &GrammarItemType) -> String { diff --git a/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__Game.jack@Game.jack.snap b/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__Game.jack@Game.jack.snap index 8346e1a..9932ae7 100644 --- a/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__Game.jack@Game.jack.snap +++ b/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__Game.jack@Game.jack.snap @@ -10,9 +10,7 @@ call Memory.alloc 1 pop pointer 0 push constant 60 pop static 0 -push static 0 -push constant 30 -call Math.divide 2 +push constant 2 pop static 1 push constant 18 call String.new 1 @@ -190,7 +188,7 @@ push constant 1 add pop this 1 push this 1 -push static 1 +push constant 2 call Utils.modulo 2 push constant 0 eq @@ -279,9 +277,7 @@ push pointer 0 call Game.drawApple 1 pop temp 0 label __VM_LABEL_9 -push constant 1000 -push static 0 -call Math.divide 2 +push constant 16 call Sys.wait 1 pop temp 0 call Keyboard.keyPressed 0 @@ -317,9 +313,7 @@ if-goto __VM_LABEL_21 push constant 1 pop this 3 label __VM_LABEL_21 -push constant 1000 -push static 0 -call Math.divide 2 +push constant 16 call Sys.wait 1 pop temp 0 goto __VM_LABEL_19 diff --git a/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__UI.jack@UI.jack.snap b/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__UI.jack@UI.jack.snap index ed2a5c1..efdbd04 100644 --- a/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__UI.jack@UI.jack.snap +++ b/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__UI.jack@UI.jack.snap @@ -12,21 +12,9 @@ push constant 8 pop static 0 push constant 4 pop static 1 -push constant 512 -push static 0 -call Math.divide 2 -push constant 2 -push static 1 -call Math.multiply 2 -sub +push constant 56 pop static 2 -push constant 256 -push static 0 -call Math.divide 2 -push constant 2 -push static 1 -call Math.multiply 2 -sub +push constant 24 pop static 3 push constant 1 neg @@ -36,9 +24,7 @@ return function UI.init 1 push argument 0 pop pointer 0 -push static 1 -push static 0 -call Math.multiply 2 +push constant 32 pop local 0 push constant 1 neg @@ -169,15 +155,13 @@ pop temp 0 push constant 0 return function UI.getFieldWidth 0 -push static 2 +push constant 56 return function UI.getFieldHeight 0 -push static 3 +push constant 24 return function UI.getBoardIndexSize 0 -push static 2 -push static 3 -call Math.multiply 2 +push constant 1344 return function UI.drawBlock 0 push argument 0 @@ -307,7 +291,7 @@ pop temp 0 push argument 0 call UI.fromGameToScreen 1 pop local 1 -push static 0 +push constant 8 pop local 0 push local 1 push constant 0 @@ -454,7 +438,7 @@ push local 0 push constant 0 add push argument 0 -push static 2 +push constant 56 call Utils.modulo 2 pop temp 0 pop pointer 1 @@ -482,7 +466,7 @@ pop local 1 push local 1 push constant 0 add -push static 0 +push constant 8 push static 1 push local 0 push constant 0 @@ -498,7 +482,7 @@ pop that 0 push local 1 push constant 1 add -push static 0 +push constant 8 push static 1 push local 0 push constant 1 From 1e44d116ec40095800714c2e5b31d326dc4ee4c2 Mon Sep 17 00:00:00 2001 From: fix-fix Date: Sat, 27 Nov 2021 03:03:43 +0500 Subject: [PATCH 7/8] snake: add pause game state --- examples/snake/Game.jack | 44 +++- examples/snake/UI.jack | 6 +- ...e example: snake__Game.jack@Game.jack.snap | 197 ++++++++++++++---- ... code example: snake__UI.jack@UI.jack.snap | 16 +- 4 files changed, 202 insertions(+), 61 deletions(-) diff --git a/examples/snake/Game.jack b/examples/snake/Game.jack index 19b7043..f1a6921 100644 --- a/examples/snake/Game.jack +++ b/examples/snake/Game.jack @@ -1,6 +1,6 @@ class Game { static int FPS, FRAMES_PER_TICK; - static String msg_game_over; + static String msg_game_over, msg_game_paused; static int some_prime_num; field int key, tick, game_counter, GAME_STATE, apple_coords, score; @@ -11,6 +11,7 @@ class Game { let FPS = 60; let FRAMES_PER_TICK = FPS / 30; let msg_game_over = "=== Game Over! ==="; + let msg_game_paused = "=== Pause ==="; let GAME_STATE = 0; let score = 0; let ui = UI.new(); @@ -27,13 +28,11 @@ class Game { let GAME_STATE = 1; while (~(GAME_STATE = 0)) { - do Screen.clearScreen(); - do ui.init(); + do redraw(); let tick = 0; let score = 0; let snake = Snake.new(30, 20); let apple_coords = placeApple(snake); - do UI.drawIngameMenu(score); do run(); } return; @@ -47,6 +46,13 @@ class Game { return; } + method void redraw() { + do Screen.clearScreen(); + do ui.init(); + do UI.drawIngameMenu(score); + return; + } + method int run() { var char tempKey; // the key currently pressed by the user var boolean exit; @@ -58,10 +64,11 @@ class Game { while (~exit) { let tempKey = Keyboard.keyPressed(); - if (~(tempKey = 0)) { + if (~(tempKey = 0) & ~(tempKey = key)) { let key = tempKey; } if (key = 81) { let exit = true; let GAME_STATE = 0; return GAME_STATE; } // q key + if (key = 80) { do pauseLoop(tick); } // p key let is_over = tickGame(); do UI.updateIngameMenu(score); @@ -124,15 +131,38 @@ class Game { return; } + method void pauseLoop(int tick_initial) { + var char key; + let GAME_STATE = 3; + do UI.drawPanel(200, 100, msg_game_paused); + while (GAME_STATE = 3) { + let key = Keyboard.keyPressed(); + if ( + // p key + (key = 80) & + ((tick - tick_initial) > 10) + ) { + let GAME_STATE = 1; + let key = 0; + do Sys.wait(200); + do redraw(); + return; + } + do Sys.wait(1000 / FPS); + let tick = tick + 1; + } + return; + } + method int placeApple(Snake snake) { var int oldPlace; if (~(snake.getHead() = apple_coords)) { return apple_coords; } let oldPlace = apple_coords; - let oldPlace = Utils.modulo(oldPlace + some_prime_num, UI.getBoardIndexSize() - 1); + let oldPlace = Utils.modulo((oldPlace + some_prime_num) * tick, UI.getBoardIndexSize() - 1); while (snake.isCollided(oldPlace)) { - let oldPlace = Utils.modulo(oldPlace + some_prime_num, UI.getBoardIndexSize() - 1); + let oldPlace = Utils.modulo((oldPlace + some_prime_num) * tick, UI.getBoardIndexSize() - 1); } return oldPlace; } diff --git a/examples/snake/UI.jack b/examples/snake/UI.jack index fbd2623..ef4ed81 100644 --- a/examples/snake/UI.jack +++ b/examples/snake/UI.jack @@ -155,9 +155,6 @@ class UI { function void updateScore(int score) { var String s; - if (score = last_score) { - return; - } let s = "SCORE: "; do Output.moveCursor(0, 0); do Output.printString(s); @@ -168,6 +165,9 @@ class UI { } function void drawIngameMenu(int score) { + if (score = last_score) { + return; + } do UI.updateScore(score); return; } diff --git a/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__Game.jack@Game.jack.snap b/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__Game.jack@Game.jack.snap index 9932ae7..78d4424 100644 --- a/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__Game.jack@Game.jack.snap +++ b/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__Game.jack@Game.jack.snap @@ -51,6 +51,35 @@ call String.appendChar 2 push constant 61 call String.appendChar 2 pop static 2 +push constant 13 +call String.new 1 +push constant 61 +call String.appendChar 2 +push constant 61 +call String.appendChar 2 +push constant 61 +call String.appendChar 2 +push constant 32 +call String.appendChar 2 +push constant 80 +call String.appendChar 2 +push constant 97 +call String.appendChar 2 +push constant 117 +call String.appendChar 2 +push constant 115 +call String.appendChar 2 +push constant 101 +call String.appendChar 2 +push constant 32 +call String.appendChar 2 +push constant 61 +call String.appendChar 2 +push constant 61 +call String.appendChar 2 +push constant 61 +call String.appendChar 2 +pop static 3 push constant 0 pop this 3 push constant 0 @@ -62,7 +91,7 @@ pop this 4 push constant 0 pop this 2 push constant 2341 -pop static 3 +pop static 4 push pointer 0 return function Game.start 0 @@ -83,10 +112,8 @@ push this 3 push constant 0 eq if-goto __VM_LABEL_3 -call Screen.clearScreen 0 -pop temp 0 -push this 7 -call UI.init 1 +push pointer 0 +call Game.redraw 1 pop temp 0 push constant 0 pop this 1 @@ -100,9 +127,6 @@ push pointer 0 push this 6 call Game.placeApple 2 pop this 4 -push this 5 -call UI.drawIngameMenu 1 -pop temp 0 push pointer 0 call Game.run 1 pop temp 0 @@ -124,6 +148,19 @@ call Memory.deAlloc 1 pop temp 0 push constant 0 return +function Game.redraw 0 +push argument 0 +pop pointer 0 +call Screen.clearScreen 0 +pop temp 0 +push this 7 +call UI.init 1 +pop temp 0 +push this 5 +call UI.drawIngameMenu 1 +pop temp 0 +push constant 0 +return function Game.run 3 push argument 0 pop pointer 0 @@ -142,6 +179,13 @@ pop local 0 push local 0 push constant 0 eq +not +push local 0 +push this 0 +eq +not +and +not if-goto __VM_LABEL_6 push local 0 pop this 0 @@ -159,6 +203,16 @@ pop this 3 push this 3 return label __VM_LABEL_7 +push this 0 +push constant 80 +eq +not +if-goto __VM_LABEL_8 +push pointer 0 +push this 1 +call Game.pauseLoop 2 +pop temp 0 +label __VM_LABEL_8 push pointer 0 call Game.tickGame 1 pop local 2 @@ -171,11 +225,11 @@ or pop local 1 push local 2 not -if-goto __VM_LABEL_8 +if-goto __VM_LABEL_9 push pointer 0 call Game.endGameLoop 1 pop temp 0 -label __VM_LABEL_8 +label __VM_LABEL_9 goto __VM_LABEL_4 label __VM_LABEL_5 push this 3 @@ -193,7 +247,7 @@ call Utils.modulo 2 push constant 0 eq not -if-goto __VM_LABEL_9 +if-goto __VM_LABEL_10 push this 2 push constant 1 add @@ -202,49 +256,49 @@ push this 0 push constant 131 eq not -if-goto __VM_LABEL_11 +if-goto __VM_LABEL_12 push constant 1 pop local 2 -goto __VM_LABEL_10 -label __VM_LABEL_11 +goto __VM_LABEL_11 +label __VM_LABEL_12 push this 0 push constant 133 eq not -if-goto __VM_LABEL_13 +if-goto __VM_LABEL_14 push constant 2 pop local 2 -goto __VM_LABEL_12 -label __VM_LABEL_13 +goto __VM_LABEL_13 +label __VM_LABEL_14 push this 0 push constant 130 eq not -if-goto __VM_LABEL_15 +if-goto __VM_LABEL_16 push constant 3 pop local 2 -goto __VM_LABEL_14 -label __VM_LABEL_15 +goto __VM_LABEL_15 +label __VM_LABEL_16 push this 0 push constant 132 eq not -if-goto __VM_LABEL_16 +if-goto __VM_LABEL_17 push constant 4 pop local 2 -label __VM_LABEL_16 -label __VM_LABEL_14 -label __VM_LABEL_12 -label __VM_LABEL_10 +label __VM_LABEL_17 +label __VM_LABEL_15 +label __VM_LABEL_13 +label __VM_LABEL_11 push local 2 push constant 0 eq -if-goto __VM_LABEL_17 +if-goto __VM_LABEL_18 push this 6 push local 2 call Snake.setDirection 2 pop temp 0 -label __VM_LABEL_17 +label __VM_LABEL_18 push this 6 push this 4 call Snake.advance 2 @@ -263,12 +317,12 @@ push that 0 pop local 1 push local 1 not -if-goto __VM_LABEL_18 +if-goto __VM_LABEL_19 push this 5 push constant 1 add pop this 5 -label __VM_LABEL_18 +label __VM_LABEL_19 push pointer 0 push this 6 call Game.placeApple 2 @@ -276,7 +330,7 @@ pop this 4 push pointer 0 call Game.drawApple 1 pop temp 0 -label __VM_LABEL_9 +label __VM_LABEL_10 push constant 16 call Sys.wait 1 pop temp 0 @@ -297,27 +351,80 @@ pop temp 0 push this 6 call Snake.dispose 1 pop temp 0 -label __VM_LABEL_19 +label __VM_LABEL_20 push this 3 push constant 2 eq not -if-goto __VM_LABEL_20 +if-goto __VM_LABEL_21 call Keyboard.keyPressed 0 pop local 0 push local 0 push constant 82 eq not -if-goto __VM_LABEL_21 +if-goto __VM_LABEL_22 push constant 1 pop this 3 +label __VM_LABEL_22 +push constant 16 +call Sys.wait 1 +pop temp 0 +goto __VM_LABEL_20 label __VM_LABEL_21 +push constant 0 +return +function Game.pauseLoop 1 +push argument 0 +pop pointer 0 +push constant 3 +pop this 3 +push constant 200 +push constant 100 +push static 3 +call UI.drawPanel 3 +pop temp 0 +label __VM_LABEL_23 +push this 3 +push constant 3 +eq +not +if-goto __VM_LABEL_24 +call Keyboard.keyPressed 0 +pop local 0 +push local 0 +push constant 80 +eq +push this 1 +push argument 1 +sub +push constant 10 +gt +and +not +if-goto __VM_LABEL_25 +push constant 1 +pop this 3 +push constant 0 +pop local 0 +push constant 200 +call Sys.wait 1 +pop temp 0 +push pointer 0 +call Game.redraw 1 +pop temp 0 +push constant 0 +return +label __VM_LABEL_25 push constant 16 call Sys.wait 1 pop temp 0 -goto __VM_LABEL_19 -label __VM_LABEL_20 +push this 1 +push constant 1 +add +pop this 1 +goto __VM_LABEL_23 +label __VM_LABEL_24 push constant 0 return function Game.placeApple 1 @@ -327,36 +434,40 @@ push argument 1 call Snake.getHead 1 push this 4 eq -if-goto __VM_LABEL_22 +if-goto __VM_LABEL_26 push this 4 return -label __VM_LABEL_22 +label __VM_LABEL_26 push this 4 pop local 0 push local 0 -push static 3 +push static 4 add +push this 1 +call Math.multiply 2 call UI.getBoardIndexSize 0 push constant 1 sub call Utils.modulo 2 pop local 0 -label __VM_LABEL_23 +label __VM_LABEL_27 push argument 1 push local 0 call Snake.isCollided 2 not -if-goto __VM_LABEL_24 +if-goto __VM_LABEL_28 push local 0 -push static 3 +push static 4 add +push this 1 +call Math.multiply 2 call UI.getBoardIndexSize 0 push constant 1 sub call Utils.modulo 2 pop local 0 -goto __VM_LABEL_23 -label __VM_LABEL_24 +goto __VM_LABEL_27 +label __VM_LABEL_28 push local 0 return function Game.drawApple 0 diff --git a/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__UI.jack@UI.jack.snap b/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__UI.jack@UI.jack.snap index efdbd04..a9e7869 100644 --- a/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__UI.jack@UI.jack.snap +++ b/src/compiler/tests/snapshots/test_output__Compiler vm code example: snake__UI.jack@UI.jack.snap @@ -501,14 +501,6 @@ pop temp 0 push local 1 return function UI.updateScore 1 -push argument 0 -push static 4 -eq -not -if-goto __VM_LABEL_7 -push constant 0 -return -label __VM_LABEL_7 push constant 7 call String.new 1 push constant 83 @@ -545,6 +537,14 @@ push constant 0 return function UI.drawIngameMenu 0 push argument 0 +push static 4 +eq +not +if-goto __VM_LABEL_7 +push constant 0 +return +label __VM_LABEL_7 +push argument 0 call UI.updateScore 1 pop temp 0 push constant 0 From 8254140a238675b219ade5904c5b034f1e336af2 Mon Sep 17 00:00:00 2001 From: fix-fix Date: Sat, 27 Nov 2021 13:19:57 +0500 Subject: [PATCH 8/8] compiler: add constant value only for top let exprs --- .../src/optimizer/optimize_syntax_tree.rs | 33 +++++++++++-------- src/compiler/src/symbol_table.rs | 6 ++++ 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/src/compiler/src/optimizer/optimize_syntax_tree.rs b/src/compiler/src/optimizer/optimize_syntax_tree.rs index f184eb2..308eba2 100644 --- a/src/compiler/src/optimizer/optimize_syntax_tree.rs +++ b/src/compiler/src/optimizer/optimize_syntax_tree.rs @@ -11,36 +11,37 @@ pub fn optimize_syntax_tree_expression( context: &CompilerContext, ) -> Option> { let lhs_context = context.lhs_context(); - optimize_expr(term1, ops, state.sym_table(), &lhs_context) + optimize_expr(term1, ops, &mut Some(state.sym_table()), &lhs_context) } fn optimize_expr_int_inner( term1: &Term, ops: &[(Op, Term)], - sym_table: &mut SymbolTable, + sym_table: &mut Option<&mut SymbolTable>, lhs_context: &LhsContext, ) -> Option { // dbg!(term1, ops); - let mut term1_value = eval_term(term1, sym_table, lhs_context); + let term1_value = eval_term(term1, sym_table); + let mut full_expr_int_value = term1_value; for (Op(op), term2) in ops { if !is_simple_arith_op(op.as_str()) { return None; } - let term2_value = eval_term(term2, sym_table, lhs_context); - if let (Some(a), Some(b)) = (term1_value, term2_value) { - term1_value = eval_binop(op, a, b); + let term2_value = eval_term(term2, sym_table); + if let (Some(a), Some(b)) = (full_expr_int_value, term2_value) { + full_expr_int_value = eval_binop(op, a, b); } else { return None; } } - if let (Some(term_value), Some(LhsContextInner::ClassStatic(class_static))) = - (term1_value, lhs_context) + if let (Some(term_value), Some(sym_table), Some(LhsContextInner::ClassStatic(class_static))) = + (full_expr_int_value, sym_table, lhs_context) { sym_table.add_constant_value_for_static(class_static.name(), term_value); } - term1_value + full_expr_int_value } fn is_simple_arith_op(op: &str) -> bool { @@ -50,7 +51,7 @@ fn is_simple_arith_op(op: &str) -> bool { fn optimize_expr( term1: &Term, ops: &[(Op, Term)], - sym_table: &mut SymbolTable, + sym_table: &mut Option<&mut SymbolTable>, lhs_context: &LhsContext, ) -> Option> { // dbg!(term1, ops); @@ -88,27 +89,31 @@ fn eval_unop(op: &str, a: i16) -> Option { } } -fn eval_term(term: &Term, sym_table: &mut SymbolTable, lhs_context: &LhsContext) -> Option { +fn eval_term(term: &Term, sym_table: &mut Option<&mut SymbolTable>) -> Option { // dbg!(term); match term { Term::IntegerConstant(value) => { // dbg!(value); Some((*value).try_into().unwrap()) } - Term::UnaryOp(Op(op), term) => match eval_term(term, sym_table, lhs_context) { + Term::UnaryOp(Op(op), term) => match eval_term(term, sym_table) { Some(term_value) => eval_unop(op, term_value), None => None, }, Term::ParenExpr(expr) => { let Expr(termp1, ops) = &**expr; - optimize_expr_int_inner(termp1, ops, sym_table, lhs_context) + optimize_expr_int_inner( + termp1, ops, sym_table, + // add_constant_value_for_static only for top level expression + &None, + ) } Term::KeywordConstant(Keyword::Null) => Some(0), Term::KeywordConstant(Keyword::True) => Some(-1), Term::KeywordConstant(Keyword::False) => Some(0), #[allow(clippy::let_and_return)] Term::VarName(ident) => { - let entry = sym_table.lookup(ident)?; + let entry = sym_table.as_ref().and_then(|e| e.lookup(ident))?; if entry.typ != type_as_string(&GrammarItemType::Int) { return None; } diff --git a/src/compiler/src/symbol_table.rs b/src/compiler/src/symbol_table.rs index d8986fc..8781156 100644 --- a/src/compiler/src/symbol_table.rs +++ b/src/compiler/src/symbol_table.rs @@ -38,6 +38,12 @@ impl EntryClass { } fn set_constant_value(&mut self, term_value: i16) { + assert!( + matches!(self.constant_value, None), + "Must be written only once. Entry: {:?}\nValue:{}", + self, + term_value + ); self.constant_value = Some(term_value); } }