From 8d19767c98ae2d4532b81a18d00e0af8e6b77563 Mon Sep 17 00:00:00 2001 From: Michael Sippel Date: Sat, 18 May 2024 18:01:41 +0200 Subject: [PATCH] add export block and ability to load multiple files --- lt-stdlib/color.lt | 47 +++++++++ lt-stdlib/euclidean.lt | 28 ++++++ lt-stdlib/int.lt | 18 ++++ lt-stdlib/posint.lt | 63 ++++++++++++ lt-stdlib/ratio.lt | 45 +++++++++ lt-stdlib/stdio.lt | 12 +++ lt-stdlib/vec3i.lt | 23 +++++ main.lt | 198 ++++---------------------------------- src/expr.rs | 3 + src/main.rs | 89 +++++++++++------ src/parser.rs | 11 ++- src/procedure_compiler.rs | 78 +++++++++++---- src/symbols.rs | 69 ++++++++++--- 13 files changed, 439 insertions(+), 245 deletions(-) create mode 100644 lt-stdlib/color.lt create mode 100644 lt-stdlib/euclidean.lt create mode 100644 lt-stdlib/int.lt create mode 100644 lt-stdlib/posint.lt create mode 100644 lt-stdlib/ratio.lt create mode 100644 lt-stdlib/stdio.lt create mode 100644 lt-stdlib/vec3i.lt diff --git a/lt-stdlib/color.lt b/lt-stdlib/color.lt new file mode 100644 index 0000000..84e9bc4 --- /dev/null +++ b/lt-stdlib/color.lt @@ -0,0 +1,47 @@ +export { + let morph-rgb-to-hsv = λ{ + { + red: ℝ_0,1 ~ ℤ_256 ~ machine.UInt64; + green: ℝ_0,1 ~ ℤ_256 ~ machine.UInt64; + blue: ℝ_0,1 ~ ℤ_256 ~ machine.UInt64; + } : + ~ RGB + ~ ; + /* + ::> Color + ~ HSV + ~ { + hue: Angle + ~ Degrees + ~ ℝ_0,360 + ~ ℤ_360 + ~ machine.UInt64 ; + + saturation: ℝ_0,1 ~ ℤ_256 ~ machine.UInt64 ; + value: ℝ_0,1 ~ ℤ_256 ~ machine.UInt64 ; + } + ~ + */ + } ↦ { + let channel_max = int-max (int-max red green) blue; + let channel_min = int-min (int-min red green) blue; + + /* value */ + channel_max; + + /* saturation */ + i/ (i* 255 (i- channel_max channel_min)) channel_max; + + /* hue */ + i% (i/ (i* 60 + if( int-eq channel_max red ) { i+ (i* 0 255) (i- green blue); } + else { + if( int-eq channel_max green ) { i+ (i* 2 255) (i- blue red); } + else { i+ (i* 4 255) (i- red green); }; + } + ) + (i- channel_max channel_min) + ) + 360; + }; +} diff --git a/lt-stdlib/euclidean.lt b/lt-stdlib/euclidean.lt new file mode 100644 index 0000000..21962cf --- /dev/null +++ b/lt-stdlib/euclidean.lt @@ -0,0 +1,28 @@ + +/* Integer Math + */ + +export { + /* Euclidean Algorithm to calculate greatest common divisor + */ + let gcd = λ{ + a : ℤ ~ machine.Int64; + b : ℤ ~ machine.Int64; + } ↦ { + while( b ) { + let tmp = i% a b; + ! a b; + ! b tmp; + } + a; + }; + + /* least common multiple + */ + let lcm = λ{ + a : ℤ ~ machine.Int64; + b : ℤ ~ machine.Int64; + } ↦ i* (int-abs a) (i/ (int-abs b) (gcd a b)); + +}; + diff --git a/lt-stdlib/int.lt b/lt-stdlib/int.lt new file mode 100644 index 0000000..45e8344 --- /dev/null +++ b/lt-stdlib/int.lt @@ -0,0 +1,18 @@ + + +/* Two's complement Signed Integers + */ + +export { + let int-sign = λx:ℤ~machine.Int64 ↦ bit-and (bit-shr x 63) 1; + let int-neg = λx:ℤ~machine.Int64 ↦ i+ (bit-neg x) 1; + let int-abs = λx:ℤ~machine.Int64 ↦ if( int-sign x ) { int-neg x; } else { x; }; + let int-lt = λ{ a:ℤ~machine.Int64; b:ℤ~machine.Int64; } ↦ int-sign (i- a b); + let int-gt = λ{ a:ℤ~machine.Int64; b:ℤ~machine.Int64; } ↦ int-sign (i- b a); + let int-eq = λ{ a:ℤ~machine.Int64; b:ℤ~machine.Int64; } ↦ if (bit-xor a b) { 0; } else { 1; }; + let int-lte = λ{ a:ℤ~machine.Int64; b:ℤ~machine.Int64; } ↦ bit-or (int-lt a b) (int-eq a b); + let int-gte = λ{ a:ℤ~machine.Int64; b:ℤ~machine.Int64; } ↦ bit-or (int-gt a b) (int-eq a b); + let int-min = λ{ a:ℤ~machine.Int64; b:ℤ~machine.Int64; } ↦ if( int-lt a b ) { a; } else { b; }; + let int-max = λ{ a:ℤ~machine.Int64; b:ℤ~machine.Int64; } ↦ if( int-gt a b ) { a; } else { b; }; +}; + diff --git a/lt-stdlib/posint.lt b/lt-stdlib/posint.lt new file mode 100644 index 0000000..3b036b7 --- /dev/null +++ b/lt-stdlib/posint.lt @@ -0,0 +1,63 @@ + + +/* Positional Integer + */ +export { + let fmt-uint-radix = λ{ + radix : ℕ ~ ℤ_2^64 ~ machine.UInt64; + x : ℕ ~ ℤ_2^64 ~ machine.UInt64; + } ↦ { + if( x ) { + while( x ) { + let digit = (i% x radix); + + if( int-lt digit 10 ) { + i+ '0' digit; + } else { + i+ (i- 'a' 10) digit; + }; + ! x (i/ x radix); + } + } else { + '0'; + }; + }; + + let uint-machine-to-posint = + λ{ + radix: ℕ ~ ℤ_2^64 ~ machine.UInt64; + value: ℕ ~ ℤ_2^64 ~ machine.UInt64; + } + /* + ::> ℕ + ~ + ~ + ~ ℤ_radix + ~ ℤ_2^64 + ~ machine.UInt64> + ~ + */ + ↦ { + let len = 0; + while( value ) { + /* push digit to sequence on stack */ + i% value radix; + ! value (i/ value radix); + ! len (i+ len 1); + } + /* push length of sequence to stack */ + len; + }; + + let fmt-int-radix = λ{ + radix: ℕ ~ ℤ_2^64 ~ machine.UInt64; + x : ℤ ~ machine.Int64; + } ↦ { + fmt-uint-radix radix (int-abs x); + if( int-sign x ) { '-'; }; + }; + + let fmt-uint = λx:ℕ ↦ fmt-uint-radix 10 x; + let fmt-int = λx:ℤ ↦ fmt-int-radix 10 x; +} + diff --git a/lt-stdlib/ratio.lt b/lt-stdlib/ratio.lt new file mode 100644 index 0000000..2f7ac80 --- /dev/null +++ b/lt-stdlib/ratio.lt @@ -0,0 +1,45 @@ +export { + /* Implementation of Rational Numbers + */ + + let ratio-scale = λ{ + {p:ℕ; q:ℕ;} : ℚ ~ ; + n : ℕ ~ machine.UInt64 ; + } ↦ { + i* q n; + i* p n; + }; + + let ratio-normalize = λ{ + p: ℤ~machine.Int64; + q: ℤ~machine.Int64; + } : ℚ ~ + ↦ { + let s = gcd p q; + i/ q s; + i/ p s; + }; + + let ratio-add = λ{ + {ap:ℕ; aq:ℕ;}: ℚ ~ ; + {bp:ℕ; bq:ℕ;}: ℚ ~ ; + } ↦ { + let l = lcm aq bq; + let as = i/ l aq; + let bs = i/ l bq; + + i* aq as; + i+ (i* ap as) (i* bp bs); + }; + + let ratio-mul = λ{ + {ap:ℤ; aq:ℤ;}: ℚ ~ ; + {bp:ℤ; bq:ℤ;}: ℚ ~ ; + } ↦ ratio-normalize (i* ap bp) (i* aq bq); + + + let fmt-ratio = λ{ p:ℤ; q:ℤ; }: ℚ~ ↦ { + fmt-int q;':';fmt-int p; + }; +} + diff --git a/lt-stdlib/stdio.lt b/lt-stdlib/stdio.lt new file mode 100644 index 0000000..cfca557 --- /dev/null +++ b/lt-stdlib/stdio.lt @@ -0,0 +1,12 @@ +export { + /* output nullterminated string directly from datastack + */ + let print-nullterm = + λ{} : < Seq Char~Ascii~machine.Word > + ~ < NullTerminatedArray machine.Word > + ↦ { + while(dup) { emit; } + drop; + }; +} + diff --git a/lt-stdlib/vec3i.lt b/lt-stdlib/vec3i.lt new file mode 100644 index 0000000..09eb54c --- /dev/null +++ b/lt-stdlib/vec3i.lt @@ -0,0 +1,23 @@ + +export { + /* Vec3i + */ + let vec3i-add = λ{ + { ax:ℤ_2^64; ay:ℤ_2^64; az:ℤ_2^64; } : ; + { bx:ℤ_2^64; by:ℤ_2^64; bz:ℤ_2^64; } : ; + } ↦ { + i+ az bz; + i+ ay by; + i+ ax bx; + }; + + let fmt-vec3i = + λ{ x:ℤ_2^64; y:ℤ_2^64; z:ℤ_2^64; } : + ↦ { + '}'; + fmt-int z; '='; 'z'; ' '; ';'; + fmt-int y; '='; 'y'; ' '; ';'; + fmt-int x; '='; 'x'; '{'; + }; +} + diff --git a/main.lt b/main.lt index eb654f0..f63df59 100644 --- a/main.lt +++ b/main.lt @@ -1,182 +1,18 @@ { - /* - * Integer Operations - */ - let int-sign = λx:ℤ~machine.Int64 ↦ bit-and (bit-shr x 63) 1; - let int-neg = λx:ℤ~machine.Int64 ↦ i+ (bit-neg x) 1; - let int-abs = λx:ℤ~machine.Int64 ↦ if( int-sign x ) { int-neg x; } else { x; }; - let int-lt = λ{ a:ℤ~machine.Int64; b:ℤ~machine.Int64; } ↦ int-sign (i- a b); - let int-gt = λ{ a:ℤ~machine.Int64; b:ℤ~machine.Int64; } ↦ int-sign (i- b a); - let int-eq = λ{ a:ℤ~machine.Int64; b:ℤ~machine.Int64; } ↦ if (i- a b) { 0; } else { 1; }; - let int-lte = λ{ a:ℤ~machine.Int64; b:ℤ~machine.Int64; } ↦ bit-or (int-lt a b) (int-eq a b); - let int-gte = λ{ a:ℤ~machine.Int64; b:ℤ~machine.Int64; } ↦ bit-or (int-gt a b) (int-eq a b); - let int-min = λ{ a:ℤ~machine.Int64; b:ℤ~machine.Int64; } ↦ if( int-lt a b ) { a; } else { b; }; - let int-max = λ{ a:ℤ~machine.Int64; b:ℤ~machine.Int64; } ↦ if( int-gt a b ) { a; } else { b; }; + print-nullterm 'H''e''l''l''o'' ''W''o''r''l''d''!''\n''\0'; - /* Euclidean Algorithm to calculate greatest common divisor - */ - let gcd = λ{ - a : ℤ ~ machine.Int64; - b : ℤ ~ machine.Int64; - } ↦ { - while( b ) { - let tmp = i% a b; - ! a b; - ! b tmp; - } - a; - }; - - /* least common multiple - */ - let lcm = λ{ - a : ℤ ~ machine.Int64; - b : ℤ ~ machine.Int64; - } ↦ i* (int-abs a) (i/ (int-abs b) (gcd a b)); - - - /* Implementation of Rational Numbers - */ - let ratio-scale = λ{ - {p:ℕ; q:ℕ;} : ℚ ~ ; - n : ℕ ~ machine.UInt64 ; - } ↦ { - i* q n; - i* p n; - }; - - let ratio-normalize = λ{ - p: ℤ~machine.Int64; - q: ℤ~machine.Int64; - } : ℚ ~ - ↦ { - let s = gcd p q; - i/ q s; - i/ p s; - }; - - let ratio-add = λ{ - {ap:ℕ; aq:ℕ;}: ℚ ~ ; - {bp:ℕ; bq:ℕ;}: ℚ ~ ; - } ↦ { - let l = lcm aq bq; - let as = i/ l aq; - let bs = i/ l bq; - - i* aq as; - i+ (i* ap as) (i* bp bs); - }; - - let ratio-mul = λ{ - {ap:ℤ; aq:ℤ;}: ℚ ~ ; - {bp:ℤ; bq:ℤ;}: ℚ ~ ; - } ↦ ratio-normalize (i* ap bp) (i* aq bq); - - let morph-int-to-float = - λx: ℤ ~ machine.Int64 ~ machine.Word - ↦ { - /* todo */ - 0; - }; - - let morph-ratio-to-float = - λ{ - p : ℤ~machine.Int64; - q : ℤ~machine.Int64; - } : ℚ~ - ↦ f/ (morph-int-to-float p) (morph-int-to-float q); - - - - /* string output - */ - let print-nullterm = - λ{} : < Seq Char ~Ascii ~ machine.Word > - ~ < NullTerminatedArray machine.Word > - ↦ { - while(dup) { emit; } - drop; - }; - - print-nullterm 'H' 'a' 'l' 'l' 'o' ' ' 'W' 'e' 'l' 't' '!' '\n' '\0'; - - /* integer formatting - */ - let fmt-uint-radix = λ{ - radix : ℕ ~ ℤ_2^64 ~ machine.UInt64; - x : ℕ ~ ℤ_2^64 ~ machine.UInt64; - } ↦ { - if( x ) { - while( x ) { - let digit = (i% x radix); - - if( int-lt digit 10 ) { - i+ '0' digit; - } else { - i+ (i- 'a' 10) digit; - }; - ! x (i/ x radix); - } - } else { - '0'; - }; - }; - - let fmt-int-radix = λ{ - radix: ℕ ~ ℤ_2^64 ~ machine.UInt64; - x : ℤ ~ machine.Int64; - } ↦ { - fmt-uint-radix radix (int-abs x); - if( int-sign x ) { '-'; }; - }; - - let fmt-uint = λx:ℕ ↦ fmt-uint-radix 10 x; - let fmt-int = λx:ℤ ↦ fmt-int-radix 10 x; - - /* ratio formatting - */ - let fmt-ratio = λ{ p:ℤ; q:ℤ; } : ℚ~ ↦ { - fmt-int q;':';fmt-int p; - }; - - - - - /* test ratio - */ + /* test ratio + */ print-nullterm - (fmt-ratio { 4; int-neg 3; }) - ' ''*'' ' + (fmt-ratio { 4; int-neg 3; }) + ' ''*'' ' (fmt-ratio { 7; 4; }) - ' ''='' ' + ' ''='' ' (fmt-ratio (ratio-mul { 4; int-neg 3; } { 7; 4; })) - '\n''\0'; + '\n''\0'; - - /* Vec3i - */ - let vec3i-add = λ{ - { ax:ℤ_2^64; ay:ℤ_2^64; az:ℤ_2^64; } : ; - { bx:ℤ_2^64; by:ℤ_2^64; bz:ℤ_2^64; } : ; - } ↦ { - i+ az bz; - i+ ay by; - i+ ax bx; - }; - - let fmt-vec3i = - λ{ x:ℤ_2^64; y:ℤ_2^64; z:ℤ_2^64; } : - ↦ { - '}'; - fmt-int z; '='; 'z'; ' '; ';'; - fmt-int y; '='; 'y'; ' '; ';'; - fmt-int x; '='; 'x'; '{'; - }; - - - - /* Colors - */ + /* Colors + */ let red-u8rgb : Color ~ RGB ~ > = λ{} ↦ { 0; 0; 255; }; @@ -185,12 +21,16 @@ let blue-u8rgb = λ{} ↦ { 255; 0; 0; }; let yellow-u8rgb = λ{} ↦ { 0; 220; 220; }; - print-nullterm - (fmt-vec3i green-u8rgb) - ' ''+'' ' - (fmt-vec3i blue-u8rgb) - ' ''='' ' + print-nullterm (fmt-vec3i (morph-rgb-to-hsv yellow-u8rgb)) '\n''\0'; + + print-nullterm + (fmt-vec3i green-u8rgb) + ' ''+'' ' + (fmt-vec3i blue-u8rgb) + ' ''='' ' (fmt-vec3i (vec3i-add green-u8rgb blue-u8rgb)) - '\n''\0'; + '\n''\0'; + + uint-machine-to-posint 16 256; } diff --git a/src/expr.rs b/src/expr.rs index ed2f174..7159651 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -60,6 +60,9 @@ pub enum LTExpr { Block { statements: Vec, }, + ExportBlock { + statements: Vec, + } } impl LTExpr { diff --git a/src/main.rs b/src/main.rs index ab44e6f..e9dc49f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -76,8 +76,10 @@ fn print_diagnostic( } /* TODO: + * - export / import , load multiple files * - Compiler error reporting * - parse float literals + * - return type annotation * - write to address resulting from expression * - sized objects * - Typecheck for LTExpr::Application @@ -96,8 +98,17 @@ fn main() { /* open source file */ let args: Vec = std::env::args().collect(); - let path = &args[1]; - let iter_chars = iterate_text::file::characters::IterateFileCharacters::new(path); + + if args.len() < 2 { + eprintln!("{}", "No source files specified.".red()); + return; + } + + let mut args_iter = args.into_iter(); + args_iter.next(); + + for path in args_iter { + let iter_chars = iterate_text::file::characters::IterateFileCharacters::new(path.clone()); /* compile source file */ @@ -108,40 +119,54 @@ fn main() { }) .peekable(); - match parser::parse_expr( &typectx, &mut program_tokens ) { - Ok( ast ) => { - let bytecode = ProcedureCompiler::new(&main_scope) - .compile( &ast ) - .into_asm(&"main".into()); + match parser::parse_expr( &typectx, &mut program_tokens ) { + Ok( ast ) => { + let (exports, bytecode) = ProcedureCompiler::new(&main_scope) + .compile(&ast) + .into_asm(&path); - eprintln!("{}", "Compiled successfully.\n======================\n".green()); + eprintln!("{} {}", "Compiled".green(), path.bold()); + for (name, def) in exports.iter() { + eprintln!("export {}: {:?}", name.yellow().bold(), def); + } - /* link assembly-program to symbols - */ - linker.add_procedure("main", bytecode); + main_scope.write().unwrap().import( + exports + ); - /* load & run compiled bytecode - */ - 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 - ); + /* link assembly-program to symbols + */ + linker.add_procedure(path.as_str(), bytecode); + } + Err( (region, parse_error) ) => { + print_diagnostic( + path.as_str(), + region, + format!("{:?}", parse_error) + ); + + eprintln!("=======\nParse Error: Abort\n"); + } } - Err( (region, parse_error) ) => { - print_diagnostic( - path, - region, - format!("{:?}", parse_error) - ); - eprintln!("=======\nerror: Parse Error\n"); } - } + + /* load & run compiled bytecode + */ + let main_addr = linker + .get_link_addr(&"main.lt".into()) + .expect("'main.lt' not found"); + + let bytecode = linker.link_total().expect("Link error:"); + + eprintln!("{} ({} bytes)", "Linked bytecode.".green(), bytecode.len()); + eprintln!("================\n"); + + vm.load(bytecode); + vm.execute(main_addr); + + eprintln!( + "\n================\nVM execution finished\ndatastack = {:?}\n====", + vm.data_stack + ); } diff --git a/src/parser.rs b/src/parser.rs index 3d4d7b7..a882f9e 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -100,7 +100,7 @@ impl VariableBinding { .flatten() .collect() } - } + } } /* parse a symbol binding of the form @@ -364,7 +364,14 @@ where It: Iterator)> if_expr: Box::new(if_expr), else_expr: Box::new(else_expr), }); - } + }, + "export" => { + tokens.next(); + let block = parse_statement_block(typectx, tokens)?; + children.push(LTExpr::ExportBlock { + statements: block + }); + }, name => { children.push(parse_atom(tokens)?); } diff --git a/src/procedure_compiler.rs b/src/procedure_compiler.rs index ba3d422..85e9a92 100644 --- a/src/procedure_compiler.rs +++ b/src/procedure_compiler.rs @@ -11,7 +11,7 @@ use { }; pub struct ProcedureCompiler { - symbols: Arc>, + pub symbols: Arc>, asm: tisc::Assembler, linker: tisc::Linker, result_size: usize, @@ -27,8 +27,17 @@ impl ProcedureCompiler { } } - pub fn into_asm(mut self, proc_symbol: &String) -> Vec { - let data_frame_size = self.symbols.read().unwrap().get_frame_size() as i64; + pub fn into_asm(mut self, proc_symbol: &String) -> (Vec<(String, SymbolDef)>, Vec) { + let mut symbols = + Arc::try_unwrap(self.symbols).ok().unwrap() + .into_inner().unwrap(); + + symbols.update_link_addresses( + proc_symbol, + &self.linker + ); + + let data_frame_size = symbols.get_frame_size() as i64; let body = self.asm.build(); self.linker.add_procedure("__procedure_body__", body); @@ -36,6 +45,7 @@ impl ProcedureCompiler { .linker .get_link_addr(&"__procedure_body__".into()) .unwrap(); + let subroutines = self .linker .link_relative(&"__subroutines__".into()) @@ -58,21 +68,37 @@ impl ProcedureCompiler { superlink.add_procedure("", entry.build()); superlink.add_procedure("__subroutines__", subroutines); - let bytecode = superlink.link_relative(proc_symbol).expect("link error"); - /* - eprintln!("\n\n{}:", proc_symbol); - for (i,w) in tisc::assembler::disassemble(&bytecode).iter().enumerate() { - eprintln!("{}:\t\t{}", i, w); + symbols.update_link_addresses( + &proc_symbol, + &superlink + ); + + let mut symbol_exports = symbols.export(); + let subroutines_addr = superlink.get_link_addr(&"__subroutines__".into()).unwrap(); + for (name, def) in symbol_exports.iter_mut() { + match def { + SymbolDef::Procedure{ in_types:_, out_types:_, link_addr, export:_ } => { + match link_addr { + LinkAddr::Relative{ symbol, offset } => { + *offset += subroutines_addr; + } + LinkAddr::Absolute(addr) => { + *addr += subroutines_addr; + } + } } - */ - bytecode + _ => {} + } + } + let bytecode = superlink.link_relative(proc_symbol).expect("link error"); + (symbol_exports, bytecode) } pub fn verify(&self) { // todo } - pub fn compile_statement(mut self, statement: &Statement) -> Self { + pub fn compile_statement(mut self, statement: &Statement, enable_export: bool) -> Self { match statement { Statement::Assignment { var_id, val_expr } => { self = self.compile(val_expr); @@ -91,6 +117,7 @@ impl ProcedureCompiler { in_types, out_types, link_addr, + export }) => { self.asm = self .asm @@ -111,12 +138,23 @@ impl ProcedureCompiler { self.symbols .write() .unwrap() - .declare_proc(var_id.clone(), vec![], vec![]); - let lambda_procedure = ProcedureCompiler::new(&self.symbols) + .declare_proc(var_id.clone(), vec![], vec![], enable_export); + + let (exports, lambda_procedure) = ProcedureCompiler::new(&self.symbols) .compile(val_expr) .into_asm(var_id); self.linker.add_procedure(var_id, lambda_procedure); + + let offset = self.linker.get_link_addr(var_id).unwrap(); + + if enable_export { + for (name, def) in exports.iter() { + eprintln!("Procedure compiler: export {}", name); + } + + self.symbols.write().unwrap().import( exports ); + } } _ => { self.symbols @@ -126,7 +164,7 @@ impl ProcedureCompiler { self = self.compile_statement(&Statement::Assignment { var_id: var_id.clone(), val_expr: val_expr.clone(), - }); + }, false); } }, Statement::WhileLoop { condition, body } => { @@ -138,7 +176,7 @@ impl ProcedureCompiler { self.asm = tisc::Assembler::new(); for statement in body.into_iter() { - self = self.compile_statement(statement); + self = self.compile_statement(statement, false); } let body_asm = self.asm; @@ -168,8 +206,9 @@ impl ProcedureCompiler { in_types, out_types, link_addr, + export }) => { - self.asm = self.asm.call(symbol.as_str()); + self.asm = self.asm.call_symbol(link_addr); } None => { eprintln!("undefined symbol '{}'!", symbol); @@ -218,7 +257,12 @@ impl ProcedureCompiler { } LTExpr::Block { statements } => { for s in statements.iter() { - self = self.compile_statement(s); + self = self.compile_statement(s, false); + } + } + LTExpr::ExportBlock{ statements } => { + for s in statements.iter() { + self = self.compile_statement(s, true); } } } diff --git a/src/symbols.rs b/src/symbols.rs index 673643f..ee706ca 100644 --- a/src/symbols.rs +++ b/src/symbols.rs @@ -4,6 +4,7 @@ use { collections::HashMap, sync::{Arc, RwLock}, }, + tisc::linker::LinkAddr, }; #[derive(Clone, Debug)] @@ -19,7 +20,8 @@ pub enum SymbolDef { Procedure { in_types: Vec, out_types: Vec, - link_addr: Option, + link_addr: LinkAddr, + export: bool }, } @@ -35,6 +37,7 @@ impl SymbolDef { in_types, out_types, link_addr: _, + export: _, } => laddertypes::TypeTerm::App(vec![ typectx .write() @@ -94,6 +97,24 @@ impl Scope { Arc::new(RwLock::new(s)) } + pub fn export(self) -> Vec<(String, SymbolDef)> { + self.symbols + .into_iter() + .filter(|(name, def)| + match def { + SymbolDef::Procedure { in_types:_, out_types:_, link_addr:_, export } => *export, + _ => false + } + ) + .collect() + } + + pub fn import(&mut self, symbol_imports: Vec<(String, SymbolDef)>) { + for (name, def) in symbol_imports { + self.symbols.insert( name, def ); + } + } + pub fn get_frame_size(&self) -> usize { self.frame_size } @@ -116,20 +137,35 @@ impl Scope { } } } - /* - pub fn get_link_addr(&self, name: &str) -> Option { - match self.get(name) { - Some(SymbolDef::Procedure{ in_types:_, out_types:_, link_addr }) => { - link_addr + + /// takes the link-addresses from a Linker + /// and updates the symbol table to relative addresses + /// based on the next super-label + pub fn update_link_addresses( + &mut self, + base_symbol: &String, + linker: &tisc::Linker + ) { + for (name, def) in self.symbols.iter_mut() { + if let Some(offset) = linker.get_link_addr( name ) { + match def { + SymbolDef::Procedure { + in_types:_,out_types:_, + link_addr, + export:_ + } => { + *link_addr = LinkAddr::Relative{ + symbol: base_symbol.clone(), + offset + }; + }, + _ => {} } - Some(SymbolDef::StaticRef { typ:_, link_addr }) => { - link_addr - } - Some(SymbolDef::FrameRef { typ:_, stack_ref:_ }) => None, - None => None } - } - */ + } + } + + //<><><><><><> pub fn declare_proc_parse( @@ -165,6 +201,7 @@ impl Scope { .expect("parse typeterm") }) .collect(), + false ); } @@ -173,13 +210,15 @@ impl Scope { name: String, in_types: Vec, out_types: Vec, + export: bool ) { self.symbols.insert( - name, + name.clone(), SymbolDef::Procedure { - link_addr: None, //LinkAddr::Relative{ name, offset: 0 }, + link_addr: LinkAddr::Relative{ symbol: name, offset: 0 }, in_types, out_types, + export }, ); }