implement scoped variable allocation & assignment

This commit is contained in:
Michael Sippel 2024-05-08 13:09:49 +02:00
parent 94ca9ca69f
commit 09e9e063ae
Signed by: senvas
GPG key ID: F96CF119C34B64A6
5 changed files with 747 additions and 386 deletions

View file

@ -6,35 +6,30 @@ use {
}
};
#[derive(Debug)]
#[derive(Clone, Debug)]
pub enum Statement {
Assignment {
var_id: String,
val_expr: LTExpr
},
WhileLoop {
condition: Box<LTExpr>,
condition: LTExpr,
body: Vec<Statement>
},
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<LTExpr>,
body: Vec<LTExpr>
@ -44,6 +39,11 @@ pub enum LTExpr {
arg_type: laddertypes::TypeTerm,
val_expr: Box<LTExpr>
},
Let {
name: String,
val: Box<LTExpr>,
body: Box<LTExpr>
},
Branch {
condition: Box<LTExpr>,
if_expr: Box<LTExpr>,
@ -55,28 +55,15 @@ pub enum LTExpr {
}
impl LTExpr {
pub fn var_symbol(typectx: &Arc<RwLock<laddertypes::TypeDict>>, str: &str) -> Self {
LTExpr::SymbolLiteral {
pub fn symbol(typectx: &Arc<RwLock<laddertypes::TypeDict>>, str: &str) -> Self {
LTExpr::Symbol {
typ: typectx.write().unwrap().parse("<Ref memory::Word>~Symbol~<Seq Char>").expect("parse typeterm"),
symbol: String::from(str)
}
}
pub fn call_symbol(
typectx: &Arc<RwLock<laddertypes::TypeDict>>,
//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<RwLock<laddertypes::TypeDict>>, 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<RwLock<laddertypes::TypeDict>>, 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<LTExpr>) -> Self {
LTExpr::Application {
head: Box::new( head ),
@ -107,7 +102,7 @@ impl LTExpr {
impl Statement {
pub fn while_loop(cond: LTExpr, body: Vec<Statement>) -> Self {
Statement::WhileLoop {
condition: Box::new(cond),
condition: cond,
body
}
}

View file

@ -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",
"<Seq Char
~Ascii
~machine::Word>
~<NullTerminatedSeq machine::Word>"
);
// 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![ "<MutRef T~machine::Word>~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![
"<MutRef T~machine::Word>~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(
&LTExpr::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 : <Ptr machine::Word>~machine::Address~machine::Word = 0x80;
*/
symbols.define(&mut vm, &typectx,
"glob1",
main_scope.write().unwrap()
.declare_proc_parse(
"print-nullterm",
vec![],
vec![
"<Ref machine::Word>~<Ptr machine::Word>~machine::Address~machine::Word"
"<Ref <Seq Char~Ascii~machine::Word>~<NullTerminatedSeq 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(
&LTExpr::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![
"<Ref <Seq Char~Ascii~machine::Word>~<LengthPrefixedSeq machine::Word>>
~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);
}

View file

@ -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<RwLock<Scope>>,
asm: tisc::Assembler,
result_size: usize
linker: tisc::Linker,
result_size: usize,
}
impl ProcedureCompiler {
pub fn new() -> Self {
pub fn new(parent_scope: &Arc<RwLock<Scope>>) -> 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: &LTExpr) -> 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 {
}
}

306
src/runtime.rs Normal file
View file

@ -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<RwLock<Scope>> {
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![ "<MutRef T~machine::Word>~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![
"<MutRef T~machine::Word>~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(
&LTExpr::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",
"<MutRef <Seq machine::Word>>~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",
"<RefMut 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!["<Ref T~machine::Word>~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
}

View file

@ -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<RwLock<laddertypes::dict::TypeDict>>) -> 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<RwLock<laddertypes::TypeDict>>,
/* number of words required for
* the stack frame of this scope
*/
frame_size: usize,
/* parent scope whose all
* symbols are inherited
*/
parent: Option< Arc<RwLock<Scope>> >
}
impl Scope {
pub fn new() -> Arc<RwLock<Self>> {
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<RwLock<laddertypes::TypeDict>>, 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<RwLock<Scope>>) -> Arc<RwLock<Self>> {
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<RwLock<laddertypes::TypeDict>>,
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<SymbolDef> {
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<tisc::VM_Word> {
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
});
}
}