diff --git a/src/expr.rs b/src/expr.rs index 4d50569..9afc91e 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -6,35 +6,30 @@ use { } }; -#[derive(Debug)] +#[derive(Clone, Debug)] pub enum Statement { Assignment { var_id: String, val_expr: LTExpr }, WhileLoop { - condition: Box, + condition: LTExpr, body: Vec }, Return(LTExpr), Expr(LTExpr) } -#[derive(Debug)] +#[derive(Clone, Debug)] pub enum LTExpr { - SymbolLiteral { + Literal { + typ: laddertypes::TypeTerm, + val: tisc::VM_Word + }, + Symbol { typ: laddertypes::TypeTerm, symbol: String, }, - WordLiteral { - typ: laddertypes::TypeTerm, - val: tisc::VM_Word - }, - CallLiteral { - typ: laddertypes::TypeTerm, - result_size: usize, - val: tisc::VM_Word - }, Application { head: Box, body: Vec @@ -44,6 +39,11 @@ pub enum LTExpr { arg_type: laddertypes::TypeTerm, val_expr: Box }, + Let { + name: String, + val: Box, + body: Box + }, Branch { condition: Box, if_expr: Box, @@ -55,28 +55,15 @@ pub enum LTExpr { } impl LTExpr { - pub fn var_symbol(typectx: &Arc>, str: &str) -> Self { - LTExpr::SymbolLiteral { + pub fn symbol(typectx: &Arc>, str: &str) -> Self { + LTExpr::Symbol { typ: typectx.write().unwrap().parse("~Symbol~").expect("parse typeterm"), symbol: String::from(str) } } - pub fn call_symbol( - typectx: &Arc>, - //typ: laddertypes::TypeTerm, - result_size: usize, - addr: tisc::VM_Word - ) -> Self { - LTExpr::CallLiteral { - typ: typectx.write().unwrap().parse("machine::Word").expect("parse typeterm"), - result_size, - val: addr - } - } - pub fn lit_uint(typectx: &Arc>, val: u64) -> Self { - LTExpr::WordLiteral { + LTExpr::Literal { typ: typectx.write().unwrap().parse("ℤ_2^64~machine::UInt64~machine::Word").expect("parse typeterm"), val: val as tisc::VM_Word } @@ -90,6 +77,14 @@ impl LTExpr { } } + pub fn let_expr(typectx: &Arc>, name: &str, val: LTExpr, body: LTExpr) -> Self { + LTExpr::Let { + name: String::from(name), + val: Box::new(val), + body: Box::new(body) + } + } + pub fn application(head: LTExpr, body: Vec) -> Self { LTExpr::Application { head: Box::new( head ), @@ -107,7 +102,7 @@ impl LTExpr { impl Statement { pub fn while_loop(cond: LTExpr, body: Vec) -> Self { Statement::WhileLoop { - condition: Box::new(cond), + condition: cond, body } } diff --git a/src/main.rs b/src/main.rs index 5c28587..794d7c9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,290 +7,173 @@ use { mod expr; mod symbols; mod procedure_compiler; +mod runtime; use crate::{ expr::{LTExpr, Statement}, - symbols::{SymbolTable}, + symbols::{Scope}, procedure_compiler::ProcedureCompiler }; fn main() { - let mut typectx = Arc::new( RwLock::new( laddertypes::dict::TypeDict::new() )); - - // define 'T' to be a type-variable in all type-terms - typectx.write().unwrap().add_varname("T".into()); - // create virtual machine with 4096 words of memory let mut vm = tisc::VM::new(0x1000); - // store function types & link addresses - let mut symbols = SymbolTable::new(); + let mut linker = tisc::Linker::new(); + let root_scope = crate::runtime::init_runtime(&mut linker); + let main_scope = Scope::with_parent(&root_scope); - /* Duplicate the top item on the stack, - * and whatever type this word has is preserved + let typectx = main_scope.read().unwrap().typectx.clone(); + + /* define type of the symbol */ - symbols.define(&mut vm, &typectx, - "dup", + main_scope.write().unwrap() + .declare_static_parse( + "hello-string", + " + ~" + ); - // input type - vec![ "T~machine::Word" ], - - // output type - vec![ "T~machine::Word", - "T~machine::Word" ], - - tisc::Assembler::new().instruction( tisc::VM_Instruction::Dup ) - ); - - /* The top two items must be native u64 integers, - * which are replaced by their sum. - * We do not know wheter a sum of two integers actually - * preserves the semantics of a more abstract type - */ - symbols.define(&mut vm, &typectx, - "addi", - - // input type - vec![ "ℤ_2^64~machine::UInt64~machine::Word", - "ℤ_2^64~machine::UInt64~machine::Word" ], - - // output type - vec![ "ℤ_2^64~machine::UInt64~machine::Word" ], - - tisc::Assembler::new().instruction( tisc::VM_Instruction::Add ) - ); - - symbols.define(&mut vm, &typectx, - "subi", - - // input type - vec![ "ℤ_2^64~machine::UInt64~machine::Word", - "ℤ_2^64~machine::UInt64~machine::Word" ], - - // output type - vec![ "ℤ_2^64~machine::UInt64~machine::Word" ], - - tisc::Assembler::new() - .instruction(tisc::VM_Instruction::BitwiseNot) - .lit(1) - .instruction(tisc::VM_Instruction::Add) - .instruction(tisc::VM_Instruction::Add) - ); - - /* Put a single Ascii character on stdout - */ - symbols.define(&mut vm, &typectx, - "emit", - - // input type - vec![ "Char~Ascii~machine::Word" ], - - // output type - vec![], - - tisc::Assembler::new().instruction( tisc::VM_Instruction::Emit ) - ); - - /* Fetch memory address - */ - symbols.define(&mut vm, &typectx, - "@", - - // input type - vec![ "~machine::Address~machine::Word" ], - - // output type - vec![ "T~machine::Word" ], - - tisc::Assembler::new().instruction( tisc::VM_Instruction::Fetch ) - ); - - /* Store to memory - */ - symbols.define(&mut vm, &typectx, - "!", - - // input type - vec![ - "~machine::Address~machine::Word", - "T~machine::Word" - ], - - // output type - vec![], - - tisc::Assembler::new().instruction( tisc::VM_Instruction::Store ) - ); - - /* - * let double = λx.(addi x x); - */ - symbols.define(&mut vm, &typectx, - "double", - - // input type - vec![ "ℤ_2^64~machine::UInt64~machine::Word" ], - - // output type - vec![ "ℤ_2^64~machine::UInt64~machine::Word" ], - - ProcedureCompiler::new() - .compile( - <Expr::abstraction( - &typectx, - "x", - "ℤ_2^64~machine::UInt64~machine::Word", - - LTExpr::application( - symbols.call_symbol(&typectx, "addi"), - vec![ - LTExpr::var_symbol(&typectx, "x"), - LTExpr::var_symbol(&typectx, "x") - ] - ) - ) - ) - .into_asm() - ); - - /* - * let muli = λa.λb.{ - * let mut sum = 0; - * while( b != 0 ) { - * sum := (addi sum a); - * b := (subi b 1); - * } - * sum - * }; - */ - symbols.define(&mut vm, &typectx, - "muli", - - // input type - vec![ "ℤ_2^64~machine::UInt64~machine::Word", - "ℤ_2^64~machine::UInt64~machine::Word" ], - - // output type - vec![ "ℤ_2^64~machine::UInt64~machine::Word" ], - - tisc::Assembler::new() - .lit(0) // [ a b ] -- [ a b sum ] - - .while_loop( - // condition - tisc::Assembler::new() - // [ a b sum ] -- [ a b sum b ] - .lit( 2 ) - .instruction( tisc::VM_Instruction::Pick ), - - // body - tisc::Assembler::new() - // [ a b sum ] -- [ a b sum a ] - .lit( 3 ) - .instruction( tisc::VM_Instruction::Pick ) - - // [ a b sum a -- a b (sum+a) ] - .instruction( tisc::VM_Instruction::Add ) - - // [ a b sum -- a sum b ] - .instruction( tisc::VM_Instruction::Swap ) - - // [ a sum b -- a sum b 1 ] - .lit( 1 ) - - // [ a sum b -- a sum (b-1) ] - .call( symbols.get_link_addr("subi").expect("subi not linked") ) - - // [ a sum b -- a b sum ] - .instruction( tisc::VM_Instruction::Swap ) - ) - - // [ a b sum -- a sum b ] - .lit(2).instruction(tisc::VM_Instruction::Roll) - // [ a sum b -- a sum ] - .instruction(tisc::VM_Instruction::Drop) - - // [ a sum -- sum a ] - .lit(2).instruction(tisc::VM_Instruction::Roll) - // [ sum a -- sum ] - .instruction(tisc::VM_Instruction::Drop) - ); - - /* - * glob1 : ~machine::Address~machine::Word = 0x80; - */ - symbols.define(&mut vm, &typectx, - "glob1", + main_scope.write().unwrap() + .declare_proc_parse( + "print-nullterm", vec![], vec![ - "~~machine::Address~machine::Word" + "~> + ~machine::Address + ~machine::Word" ], + vec![]); - tisc::Assembler::new().lit(0x80) - ); - - /* - * let main = { - * (! glob1 10); - * while (@ glob1) { - * (! glob1 (subi (@ glob1) 1)); - * (emit 42); - * } - * }; + /* link assembly-program to symbol */ - symbols.define(&mut vm, &typectx, + linker.add_procedure( "main", - vec![], - vec![], - ProcedureCompiler::new() + ProcedureCompiler::new(&main_scope) .compile( <Expr::block(vec![ - Statement::Expr(LTExpr::application( - symbols.call_symbol(&typectx, "!"), - vec![ - symbols.call_symbol(&typectx, "glob1"), - LTExpr::lit_uint(&typectx, 10) - ] - )), - Statement::while_loop( + Statement::Expr( LTExpr::application( - symbols.call_symbol(&typectx, "@"), - vec![ - symbols.call_symbol(&typectx, "glob1") - ] - ), - vec![ - Statement::Expr(LTExpr::application( - symbols.call_symbol(&typectx, "!"), - vec![ - symbols.call_symbol(&typectx, "glob1"), - - LTExpr::application( - symbols.call_symbol(&typectx, "subi"), + LTExpr::abstraction( + &typectx, + "c", + "Char", + LTExpr::block(vec![ + Statement::Expr(LTExpr::application( + LTExpr::symbol(&typectx, "emit"), vec![ - LTExpr::lit_uint(&typectx, 1), - LTExpr::application( - symbols.call_symbol(&typectx, "@"), - vec![ - symbols.call_symbol(&typectx, "glob1") - ] - ), + LTExpr::symbol(&typectx, "c") ] - ), - ] - )), - - Statement::Expr(LTExpr::application( - symbols.call_symbol(&typectx, "emit"), - vec![ LTExpr::lit_uint(&typectx, 42) ] - )) - ] - ), + )), + Statement::Assignment{ + var_id: "c".into(), + val_expr: LTExpr::application( + LTExpr::symbol(&typectx, "i+"), + vec![ + LTExpr::symbol(&typectx, "c"), + LTExpr::lit_uint(&typectx, 1) + ] + ) + }, + Statement::Expr(LTExpr::application( + LTExpr::symbol(&typectx, "emit"), + vec![ + LTExpr::symbol(&typectx, "c") + ] + )) + ]) + ), + vec![ + LTExpr::lit_uint(&typectx, 42) + ] + )), + Statement::Expr( + LTExpr::application( + LTExpr::symbol(&typectx, "emit"), + vec![ + LTExpr::lit_uint(&typectx, 10) + ] + )) ]) ) .into_asm() + .build() ); - vm.execute( symbols.get_link_addr("main").unwrap() ); - eprintln!("\nvm.stack = {:?}", vm.data_stack); + linker.add_static("hello-string", + "Hallo Welt!\n\0" + .chars() + .map(|c| (c as u8) as tisc::VM_Word) + .collect()); + + linker.add_procedure( + "print-nullterm", + tisc::Assembler::new() + .while_loop( + tisc::Assembler::new() + .inst( tisc::VM_Instruction::Dup ) + .inst( tisc::VM_Instruction::Fetch ) + .inst( tisc::VM_Instruction::Dup ), + + tisc::Assembler::new() + .inst( tisc::VM_Instruction::Emit ) + .lit( 1 ) + .inst( tisc::VM_Instruction::Add ) + ) + .inst( tisc::VM_Instruction::Drop ) + .inst( tisc::VM_Instruction::Drop ) + .build() + ); + + main_scope.write().unwrap().declare_proc_parse( + "print-lenprefix", + vec![], + vec![ + "~> + ~machine::Address + ~machine::Word" + ], + vec![]); + + linker.add_procedure( + "print-lenprefix", + tisc::Assembler::new() + // calculate stop address + .inst( tisc::VM_Instruction::Dup ) + .inst( tisc::VM_Instruction::Dup ) + .inst( tisc::VM_Instruction::Fetch ) + .lit(1) + .inst( tisc::VM_Instruction::Add ) + .inst( tisc::VM_Instruction::Add ) + .inst( tisc::VM_Instruction::Swap ) + + // emit until address == start address + .while_loop( + tisc::Assembler::new() + .lit( 2 ) + .inst( tisc::VM_Instruction::Pick ) + .lit( 2 ) + .inst( tisc::VM_Instruction::Pick ) + .call("i-"), + + tisc::Assembler::new() + .inst( tisc::VM_Instruction::Dup ) + .inst( tisc::VM_Instruction::Fetch ) + .inst( tisc::VM_Instruction::Emit ) + .lit( 1 ) + .inst( tisc::VM_Instruction::Add ) + ) + .inst( tisc::VM_Instruction::Drop ) + .inst( tisc::VM_Instruction::Drop ) + .build() + ); + + let main_addr = linker.get_link_addr(&"main".into()).expect("'main' not linked"); + vm.load( linker.link_total().expect("could not link") ); + vm.execute( main_addr ); + + eprintln!("\n====\nVM execution finished\ndatastack = {:?}\n====", vm.data_stack); } + diff --git a/src/procedure_compiler.rs b/src/procedure_compiler.rs index 3667d40..730b6a9 100644 --- a/src/procedure_compiler.rs +++ b/src/procedure_compiler.rs @@ -1,45 +1,80 @@ use { - crate::expr::{LTExpr, Statement} + std::{ + sync::{Arc, RwLock}, + ops::Deref, + }, + crate::{ + expr::{LTExpr, Statement}, + symbols::{Scope, SymbolDef} + } }; pub struct ProcedureCompiler { - locals: Vec< String >, + symbols: Arc>, asm: tisc::Assembler, - result_size: usize + linker: tisc::Linker, + result_size: usize, } impl ProcedureCompiler { - pub fn new() -> Self { + pub fn new(parent_scope: &Arc>) -> Self { ProcedureCompiler { - locals: Vec::new(), + symbols: Scope::with_parent(parent_scope), asm: tisc::Assembler::new(), - result_size: 0 + linker: tisc::Linker::new(), + result_size: 0, } } pub fn into_asm(self) -> tisc::Assembler { - self.asm + let data_frame_size = self.symbols.read().unwrap().get_frame_size() as i64; + tisc::Assembler::new() + .lit(data_frame_size) + .call("data-frame-alloc") + .join(self.asm) + .lit(data_frame_size) + .call("data-frame-drop") } pub fn verify(&self) { - + // todo } pub fn compile_statement(mut self, statement: &Statement) -> Self { match statement { Statement::Assignment{ var_id, val_expr } => { - + self = self.compile(val_expr); + match self.symbols.read().unwrap().get(var_id) { + Some(SymbolDef::FrameRef{ typ, stack_ref }) => { + self.asm = self.asm + .lit(stack_ref) + .call("data-frame-set"); + } + Some(SymbolDef::StaticRef{ typ, link_addr }) => { + self.asm = self.asm + .static_ref( var_id.as_str() ) + .inst( tisc::VM_Instruction::Store ); + } + Some(SymbolDef::Procedure{ in_types, out_types, link_addr }) => { + self.asm = self.asm + .call( var_id.as_str() ) + .inst( tisc::VM_Instruction::Store ); + } + None => { + eprintln!("cannot assign undefined symbol '{}'!", var_id); + } + } } Statement::WhileLoop { condition, body } => { let asm = self.asm; self.asm = tisc::Assembler::new(); - self = self.compile( &condition ); + self = self.compile( condition ); let cond_asm = self.asm; self.asm = tisc::Assembler::new(); - for statement in body.iter() { + for statement in body.into_iter() { self = self.compile_statement( statement ); } let body_asm = self.asm; @@ -59,61 +94,70 @@ impl ProcedureCompiler { pub fn compile(mut self, expr: <Expr) -> Self { match expr { - LTExpr::SymbolLiteral { typ, symbol } => { - // todo: check type - - // search locals - let mut id = None; - - for (i, l) in self.locals.iter().enumerate() { - if l == symbol { - id = Some(self.locals.len()-i); - break; + LTExpr::Symbol { typ, symbol } => { + match self.symbols.read().unwrap().get(symbol) { + Some(SymbolDef::FrameRef{ typ, stack_ref }) => { + self.asm = self.asm + .lit( stack_ref ) + .call("data-frame-get"); + } + Some(SymbolDef::StaticRef{ typ, link_addr }) => { + self.asm = self.asm.static_ref( symbol.as_str() ); + } + Some(SymbolDef::Procedure{ in_types, out_types, link_addr }) => { + self.asm = self.asm.call( symbol.as_str() ); + } + None => { + eprintln!("undefined symbol '{}'!", symbol); } } - - if let Some(id) = id { - self.asm = self.asm - .lit(id as i64) - .instruction(tisc::VM_Instruction::Pick); - } else { - eprintln!("unknown symbol '{}'", symbol); - } }, - LTExpr::WordLiteral { typ, val } => { + LTExpr::Literal { typ, val } => { self.asm = self.asm.lit( *val ); } - LTExpr::CallLiteral { typ, result_size, val } => { - self.result_size += result_size; - self.asm = self.asm.call( *val ); - } LTExpr::Application { head, body } => { for arg in body.iter().rev() { self = self.compile(arg); } - self = self.compile(&head); + self = self.compile(head); }, - LTExpr::Abstraction { arg_id, arg_type, val_expr } => { - self.locals.push(arg_id.clone()); - self = self.compile(val_expr); + LTExpr::Let { name, val, body } => { + self.symbols.write().unwrap() + .declare_var( + name.clone(), + laddertypes::TypeTerm::unit() + ); + + self = self.compile_statement( + &Statement::Assignment { + var_id: name.clone(), + val_expr: val.deref().clone() + } + ); + self = self.compile(&body.deref().clone()); + }, + LTExpr::Abstraction { arg_id: arg_name, arg_type, val_expr } => { + let id = self.symbols + .write().unwrap() + .declare_var( + arg_name.clone(), + laddertypes::TypeTerm::unit()); - // drop locals self.asm = self.asm - .lit( self.result_size as tisc::VM_Word + 1 ) - .instruction(tisc::VM_Instruction::Roll) - .instruction(tisc::VM_Instruction::Drop); + .lit( id ) + .call("data-frame-set"); - self.locals.pop(); + self = self.compile(val_expr); }, LTExpr::Branch { condition, if_expr, else_expr } => { - self = self.compile(&condition); + self = self.compile(condition); let asm = self.asm; self.asm = tisc::Assembler::new(); - self = self.compile( &if_expr ); + self = self.compile( if_expr ); let if_asm = self.asm; self.asm = tisc::Assembler::new(); - self = self.compile( &else_expr ); + self = self.compile( else_expr ); let else_asm = self.asm; self.asm = asm; self.asm = self.asm.branch( if_asm, else_asm ); @@ -128,4 +172,3 @@ impl ProcedureCompiler { } } - diff --git a/src/runtime.rs b/src/runtime.rs new file mode 100644 index 0000000..40328e1 --- /dev/null +++ b/src/runtime.rs @@ -0,0 +1,306 @@ +use { + std::sync::{Arc, RwLock}, + crate::{ + expr::LTExpr, + symbols::Scope, + procedure_compiler::ProcedureCompiler + }, + tisc::linker::Linker +}; + +pub fn init_runtime(linker: &mut Linker) -> Arc> { + let symbols = Scope::new(); + let typectx = symbols.read().unwrap().typectx.clone(); + + /* Duplicate the top item on the stack, + * and whatever type this word has is preserved + */ + symbols.write().unwrap().declare_proc_parse( + "dup", + vec![ "T" ], + vec![ "T~machine::Word" ], + vec![ "T~machine::Word", + "T~machine::Word" ] + ); + + linker.add_procedure("dup", tisc::Assembler::new().inst( tisc::VM_Instruction::Dup ).build()); + + + /* Put a single Ascii character on stdout + */ + symbols.write().unwrap().declare_proc_parse( + "emit", + vec![], + vec![ "Char~Ascii~machine::Word" ], + vec![] + ); + + linker.add_procedure("emit", tisc::Assembler::new().inst( tisc::VM_Instruction::Emit ).build()); + + + /* The top two items must be native u64 integers, + * which are replaced by their sum. + * We do not know wheter a sum of two integers actually + * preserves the semantics of a more abstract type + */ + symbols.write().unwrap().declare_proc_parse( + "i+", + vec![], + vec![ "ℤ_2^64~machine::UInt64~machine::Word", + "ℤ_2^64~machine::UInt64~machine::Word" ], + vec![ "ℤ_2^64~machine::UInt64~machine::Word" ] + ); + + linker.add_procedure( + "i+", + tisc::Assembler::new() + .inst( tisc::VM_Instruction::Add ) + .build() + ); + + + /* Floating-point Additionu + */ + symbols.write().unwrap().declare_proc_parse( + "f+", + vec![], + vec![ "ℝ~machine::f64~machine::Word", + "ℝ~machine::f64~machine::Word" ], + vec![ "ℝ~machine::f64~machine::Word" ] + ); + + linker.add_procedure( + "f+", + tisc::Assembler::new() + .inst( tisc::VM_Instruction::Addf ) + .build() + ); + + + /* Integer Subtraction + */ + symbols.write().unwrap().declare_proc_parse( + "i-", + vec![], + vec![ "ℤ_2^64~machine::UInt64~machine::Word", + "ℤ_2^64~machine::UInt64~machine::Word" ], + vec![ "ℤ_2^64~machine::UInt64~machine::Word" ] + ); + linker.add_procedure( + "i-", + tisc::Assembler::new() + .inst(tisc::VM_Instruction::BitwiseNot) + .lit(1) + .inst(tisc::VM_Instruction::Add) + .inst(tisc::VM_Instruction::Add) + .build() + ); + + + /* Fetch memory address + */ + symbols.write().unwrap().declare_proc_parse("@", + vec![], + vec![ "~machine::Address~machine::Word" ], + vec![ "T~machine::Word" ] + ); + linker.add_procedure( + "@", + tisc::Assembler::new() + .inst( tisc::VM_Instruction::Fetch ) + .build() + ); + + + /* Store to memory + */ + symbols.write().unwrap().declare_proc_parse("!", + vec![], + vec![ + "~machine::Address~machine::Word", + "T~machine::Word" + ], + vec![] + ); + linker.add_procedure( + "!", + tisc::Assembler::new() + .inst( tisc::VM_Instruction::Store ) + .build() + ); + + /* + * let muli = λa.λb.{ + * let mut sum = 0; + * while( b != 0 ) { + * sum := (addi sum a); + * b := (subi b 1); + * } + * sum + * }; + */ + symbols.write().unwrap().declare_proc_parse( + "i*", + vec![], + vec![ "ℤ_2^64~machine::UInt64~machine::Word", + "ℤ_2^64~machine::UInt64~machine::Word" ], + vec![ "ℤ_2^64~machine::UInt64~machine::Word" ]); + + linker.add_procedure( + "i*", + tisc::Assembler::new() + .lit(0) // [ a b ] -- [ a b sum ] + + .while_loop( + // condition + tisc::Assembler::new() + // [ a b sum ] -- [ a b sum b ] + .lit( 2 ) + .inst( tisc::VM_Instruction::Pick ), + + // body + tisc::Assembler::new() + // [ a b sum ] -- [ a b sum a ] + .lit( 3 ) + .inst( tisc::VM_Instruction::Pick ) + + // [ a b sum a -- a b (sum+a) ] + .inst( tisc::VM_Instruction::Add ) + + // [ a b sum -- a sum b ] + .inst( tisc::VM_Instruction::Swap ) + + // [ a sum b -- a sum b 1 ] + .lit( 1 ) + + // [ a sum b -- a sum (b-1) ] + .call( "i-" ) + + // [ a sum b -- a b sum ] + .inst( tisc::VM_Instruction::Swap ) + ) + + // [ a b sum -- a sum b ] + .lit(2).inst(tisc::VM_Instruction::Roll) + // [ a sum b -- a sum ] + .inst(tisc::VM_Instruction::Drop) + + // [ a sum -- sum a ] + .lit(2).inst(tisc::VM_Instruction::Roll) + // [ sum a -- sum ] + .inst(tisc::VM_Instruction::Drop) + + .build() + ); + + + /* + * let isquare = λx.(i* x x); + */ + symbols.write().unwrap().declare_proc_parse( + "isquare", + vec![], + vec![ "ℤ_2^64~machine::UInt64~machine::Word" ], + vec![ "ℤ_2^64~machine::UInt64~machine::Word" ]); + + linker.add_procedure( + "isquare", + ProcedureCompiler::new(&symbols) + .compile( + <Expr::abstraction( + &typectx, + "x", + "ℤ_2^64~machine::UInt64~machine::Word", + + LTExpr::application( + LTExpr::symbol(&typectx, "i*"), + vec![ + LTExpr::symbol(&typectx, "x"), + LTExpr::symbol(&typectx, "x") + ] + ) + ) + ) + .into_asm() + .build() + ); + + symbols.write().unwrap().declare_static_parse( + "data-frame-ptr", + ">~machine::Address~machine::Word" + ); + linker.add_static("data-frame-ptr", vec![ 0x1000 ]); + + symbols.write().unwrap().declare_proc_parse( + "data-frame-set", + vec!["T"], + vec!["T~machine::Word", + "~LocalVariableId~machine::UInt64~machine::Word"], + vec![]); + + linker.add_procedure( + "data-frame-set", + tisc::Assembler::new() + .static_ref("data-frame-ptr") + .inst( tisc::VM_Instruction::Fetch ) + .inst( tisc::VM_Instruction::Add ) + .inst( tisc::VM_Instruction::Store ) + .build() + ); + + + symbols.write().unwrap().declare_proc_parse( + "data-frame-get", + vec!["T"], + vec!["~DataFrameRef~machine::UInt64~machine::Word"], + vec!["T~machine::Word"] + ); + linker.add_procedure( + "data-frame-get", + tisc::Assembler::new() + .static_ref("data-frame-ptr") + .inst( tisc::VM_Instruction::Fetch ) + .inst( tisc::VM_Instruction::Add ) + .inst( tisc::VM_Instruction::Fetch ) + .build() + ); + + + symbols.write().unwrap().declare_proc_parse( + "data-frame-alloc", + vec![], + vec![], + vec![]); + + linker.add_procedure( + "data-frame-alloc", + tisc::Assembler::new() + .static_ref("data-frame-ptr") + .inst( tisc::VM_Instruction::Fetch ) + .inst( tisc::VM_Instruction::Swap ) + .call("i-") + .static_ref("data-frame-ptr") + .inst( tisc::VM_Instruction::Store ) + .build() + ); + + symbols.write().unwrap().declare_proc_parse( + "data-frame-drop", + vec![], + vec![], + vec![]); + + linker.add_procedure( + "data-frame-drop", + tisc::Assembler::new() + .static_ref("data-frame-ptr") + .inst( tisc::VM_Instruction::Fetch ) + .call("i+") + .static_ref("data-frame-ptr") + .inst( tisc::VM_Instruction::Store ) + .build() + ); + + symbols +} + diff --git a/src/symbols.rs b/src/symbols.rs index 7f0a1d9..34a2669 100644 --- a/src/symbols.rs +++ b/src/symbols.rs @@ -1,71 +1,205 @@ -use std::{ - collections::HashMap, - sync::{Arc, RwLock}, -}; - use { + std::{ + collections::HashMap, + sync::{Arc, RwLock}, + }, crate::expr::LTExpr }; -pub struct SymbolEntry { - link_addr: tisc::VM_Word, - - in_types: Vec< laddertypes::TypeTerm >, - out_types: Vec< laddertypes::TypeTerm > +#[derive(Clone, Debug)] +pub enum SymbolDef { + FrameRef { + typ: laddertypes::TypeTerm, + stack_ref: tisc::VM_Word, + }, + StaticRef { + typ: laddertypes::TypeTerm, + link_addr: Option< tisc::VM_Word > + }, + Procedure { + in_types: Vec< laddertypes::TypeTerm >, + out_types: Vec< laddertypes::TypeTerm >, + link_addr: Option< tisc::VM_Word > + } } -pub struct SymbolTable { - symbols: HashMap< String, SymbolEntry >, - linker: tisc::Linker -} - -impl SymbolTable { - pub fn new() -> Self { - SymbolTable { - symbols: HashMap::new(), - linker: tisc::Linker::new(0x100) +impl SymbolDef { + pub fn get_type(&self, typectx: &Arc>) -> laddertypes::TypeTerm { + match self { + SymbolDef::FrameRef { typ, stack_ref:_ } => typ.clone(), + SymbolDef::StaticRef { typ, link_addr:_ } => typ.clone(), + SymbolDef::Procedure { in_types, out_types, link_addr: _ } => { + laddertypes::TypeTerm::App(vec![ + typectx.write().unwrap().parse("Fn").expect("parse typeterm"), + laddertypes::TypeTerm::App( in_types.clone() ), + laddertypes::TypeTerm::App( out_types.clone() ) + ]) + } } } +} - pub fn get_link_addr(&self, symbol: &str) -> Option< tisc::VM_Word > { - self.symbols.get(&String::from(symbol)).map(|e| e.link_addr) +/* Describes a lexical scope of symbols + */ +pub struct Scope { + /* definition of runtime symbols + */ + symbols: HashMap< String, SymbolDef >, + + /* type symbols + */ + pub typectx: Arc>, + + /* number of words required for + * the stack frame of this scope + */ + frame_size: usize, + + /* parent scope whose all + * symbols are inherited + */ + parent: Option< Arc> > +} + +impl Scope { + pub fn new() -> Arc> { + Arc::new(RwLock::new(Scope { + symbols: HashMap::new(), + typectx: Arc::new(RwLock::new( laddertypes::dict::TypeDict::new() )), + frame_size: 0, + parent: None + })) } - pub fn call_symbol(&self, typectx: &Arc>, symbol: &str) -> LTExpr { - let entry = self.symbols.get(&String::from(symbol)).unwrap(); - LTExpr::call_symbol( - /* - &laddertypes::TypeTerm::App(vec![ - typectx.write().unwrap().parse("Fn").expect("parse typeterm"), - laddertypes::TypeTerm::App( entry.in_types.clone() ), - laddertypes::TypeTerm::App( entry.out_types.clone() ) - ]), - */ - typectx, - entry.out_types.len(), - entry.link_addr - ) + pub fn with_parent(parent: &Arc>) -> Arc> { + let s = Scope { + symbols: HashMap::new(), + + // todo: create proper child scope + typectx: parent.read().unwrap().typectx.clone(), + + frame_size: 0, + parent: Some(parent.clone()), + }; + + Arc::new(RwLock::new(s)) } - pub fn define( - &mut self, - vm: &mut tisc::VM, - typectx: &Arc>, - symbol: &str, - in_types: Vec<&str>, - out_types: Vec<&str>, - asm: tisc::Assembler - ) { - self.linker.link( vm, String::from(symbol), asm.build() ); + pub fn get_frame_size(&self) -> usize { + self.frame_size + } - self.symbols.insert( - String::from(symbol), - SymbolEntry { - link_addr: self.linker.resolve_symbol(&String::from(symbol)).expect("cant find symbol"), - in_types: in_types.into_iter().map(|t| typectx.write().unwrap().parse(t).expect("parse typeterm")).collect(), - out_types: out_types.into_iter().map(|t| typectx.write().unwrap().parse(t).expect("parse typeterm")).collect() + pub fn get(&self, name: &str) -> Option { + match self.symbols.get(name) { + Some(def) => Some(def.clone()), + None => { + if let Some(parent) = self.parent.as_ref() { + match parent.read().unwrap().get( name ) { + Some(SymbolDef::FrameRef { + typ, stack_ref + }) => Some(SymbolDef::FrameRef { + typ: typ.clone(), stack_ref: stack_ref + self.get_frame_size() as i64 + }), + x => x.clone() + } + } else { + None + } } + } + } +/* + pub fn get_link_addr(&self, name: &str) -> Option { + match self.get(name) { + Some(SymbolDef::Procedure{ in_types:_, out_types:_, link_addr }) => { + link_addr + } + Some(SymbolDef::StaticRef { typ:_, link_addr }) => { + link_addr + } + Some(SymbolDef::FrameRef { typ:_, stack_ref:_ }) => None, + None => None + } + } +*/ + //<><><><><><> + + pub fn declare_proc_parse(&mut self, + name: &str, + type_vars: Vec<&str>, + in_types: Vec<&str>, + out_types: Vec<&str> + ) { + for v in type_vars { + self.typectx.write().unwrap().add_varname(v.into()); + } + + self.declare_proc( + String::from(name), + in_types.into_iter().map(|t| self.typectx.write().unwrap().parse(t).expect("parse typeterm")).collect(), + out_types.into_iter().map(|t| self.typectx.write().unwrap().parse(t).expect("parse typeterm")).collect() ); } + + pub fn declare_proc(&mut self, + name: String, + in_types: Vec< laddertypes::TypeTerm >, + out_types: Vec< laddertypes::TypeTerm > + ) { + self.symbols.insert(name, SymbolDef::Procedure { + link_addr: None,//LinkAddr::Relative{ name, offset: 0 }, + in_types, + out_types + }); + } + + //<><><><><> + + pub fn declare_var_parse(&mut self, + name: &str, + typ: &str + ) { + let typ = self.typectx.write().unwrap().parse(typ).expect("parse typeterm"); + self.declare_var( + String::from(name), + typ + ); + } + + pub fn declare_var(&mut self, name: String, typ: laddertypes::TypeTerm) -> tisc::VM_Word { + let stack_ref = self.frame_size as tisc::VM_Word; + self.frame_size += 1; + + self.symbols.insert(name, SymbolDef::FrameRef { + typ, + stack_ref + }); + + stack_ref + } + + //<><><><><><> + + pub fn declare_static_parse( + &mut self, + name: &str, + typ: &str + ) { + let typ = self.typectx + .write().unwrap() + .parse(typ).expect("parse typeterm"); + self.declare_static(String::from(name), typ); + } + + pub fn declare_static( + &mut self, + name: String, + typ: laddertypes::TypeTerm + ) { + self.symbols.insert(name, SymbolDef::StaticRef { + typ, + link_addr: None + }); + } }