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 { pub enum Statement {
Assignment { Assignment {
var_id: String, var_id: String,
val_expr: LTExpr val_expr: LTExpr
}, },
WhileLoop { WhileLoop {
condition: Box<LTExpr>, condition: LTExpr,
body: Vec<Statement> body: Vec<Statement>
}, },
Return(LTExpr), Return(LTExpr),
Expr(LTExpr) Expr(LTExpr)
} }
#[derive(Debug)] #[derive(Clone, Debug)]
pub enum LTExpr { pub enum LTExpr {
SymbolLiteral { Literal {
typ: laddertypes::TypeTerm,
val: tisc::VM_Word
},
Symbol {
typ: laddertypes::TypeTerm, typ: laddertypes::TypeTerm,
symbol: String, symbol: String,
}, },
WordLiteral {
typ: laddertypes::TypeTerm,
val: tisc::VM_Word
},
CallLiteral {
typ: laddertypes::TypeTerm,
result_size: usize,
val: tisc::VM_Word
},
Application { Application {
head: Box<LTExpr>, head: Box<LTExpr>,
body: Vec<LTExpr> body: Vec<LTExpr>
@ -44,6 +39,11 @@ pub enum LTExpr {
arg_type: laddertypes::TypeTerm, arg_type: laddertypes::TypeTerm,
val_expr: Box<LTExpr> val_expr: Box<LTExpr>
}, },
Let {
name: String,
val: Box<LTExpr>,
body: Box<LTExpr>
},
Branch { Branch {
condition: Box<LTExpr>, condition: Box<LTExpr>,
if_expr: Box<LTExpr>, if_expr: Box<LTExpr>,
@ -55,28 +55,15 @@ pub enum LTExpr {
} }
impl LTExpr { impl LTExpr {
pub fn var_symbol(typectx: &Arc<RwLock<laddertypes::TypeDict>>, str: &str) -> Self { pub fn symbol(typectx: &Arc<RwLock<laddertypes::TypeDict>>, str: &str) -> Self {
LTExpr::SymbolLiteral { LTExpr::Symbol {
typ: typectx.write().unwrap().parse("<Ref memory::Word>~Symbol~<Seq Char>").expect("parse typeterm"), typ: typectx.write().unwrap().parse("<Ref memory::Word>~Symbol~<Seq Char>").expect("parse typeterm"),
symbol: String::from(str) 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 { 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"), typ: typectx.write().unwrap().parse("_2^64~machine::UInt64~machine::Word").expect("parse typeterm"),
val: val as tisc::VM_Word 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 { pub fn application(head: LTExpr, body: Vec<LTExpr>) -> Self {
LTExpr::Application { LTExpr::Application {
head: Box::new( head ), head: Box::new( head ),
@ -107,7 +102,7 @@ impl LTExpr {
impl Statement { impl Statement {
pub fn while_loop(cond: LTExpr, body: Vec<Statement>) -> Self { pub fn while_loop(cond: LTExpr, body: Vec<Statement>) -> Self {
Statement::WhileLoop { Statement::WhileLoop {
condition: Box::new(cond), condition: cond,
body body
} }
} }

View file

@ -7,290 +7,173 @@ use {
mod expr; mod expr;
mod symbols; mod symbols;
mod procedure_compiler; mod procedure_compiler;
mod runtime;
use crate::{ use crate::{
expr::{LTExpr, Statement}, expr::{LTExpr, Statement},
symbols::{SymbolTable}, symbols::{Scope},
procedure_compiler::ProcedureCompiler procedure_compiler::ProcedureCompiler
}; };
fn main() { 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 // create virtual machine with 4096 words of memory
let mut vm = tisc::VM::new(0x1000); let mut vm = tisc::VM::new(0x1000);
// store function types & link addresses let mut linker = tisc::Linker::new();
let mut symbols = SymbolTable::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, let typectx = main_scope.read().unwrap().typectx.clone();
* and whatever type this word has is preserved
/* define type of the symbol
*/ */
symbols.define(&mut vm, &typectx, main_scope.write().unwrap()
"dup", .declare_static_parse(
"hello-string",
"<Seq Char
~Ascii
~machine::Word>
~<NullTerminatedSeq machine::Word>"
);
// input type main_scope.write().unwrap()
vec![ "T~machine::Word" ], .declare_proc_parse(
"print-nullterm",
// 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",
vec![], vec![],
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) /* link assembly-program to symbol
);
/*
* let main = {
* (! glob1 10);
* while (@ glob1) {
* (! glob1 (subi (@ glob1) 1));
* (emit 42);
* }
* };
*/ */
symbols.define(&mut vm, &typectx, linker.add_procedure(
"main", "main",
vec![], ProcedureCompiler::new(&main_scope)
vec![],
ProcedureCompiler::new()
.compile( .compile(
&LTExpr::block(vec![ &LTExpr::block(vec![
Statement::Expr(LTExpr::application( Statement::Expr(
symbols.call_symbol(&typectx, "!"),
vec![
symbols.call_symbol(&typectx, "glob1"),
LTExpr::lit_uint(&typectx, 10)
]
)),
Statement::while_loop(
LTExpr::application( LTExpr::application(
symbols.call_symbol(&typectx, "@"), LTExpr::abstraction(
vec![ &typectx,
symbols.call_symbol(&typectx, "glob1") "c",
] "Char",
), LTExpr::block(vec![
vec![ Statement::Expr(LTExpr::application(
Statement::Expr(LTExpr::application( LTExpr::symbol(&typectx, "emit"),
symbols.call_symbol(&typectx, "!"),
vec![
symbols.call_symbol(&typectx, "glob1"),
LTExpr::application(
symbols.call_symbol(&typectx, "subi"),
vec![ vec![
LTExpr::lit_uint(&typectx, 1), LTExpr::symbol(&typectx, "c")
LTExpr::application(
symbols.call_symbol(&typectx, "@"),
vec![
symbols.call_symbol(&typectx, "glob1")
]
),
] ]
), )),
] Statement::Assignment{
)), var_id: "c".into(),
val_expr: LTExpr::application(
Statement::Expr(LTExpr::application( LTExpr::symbol(&typectx, "i+"),
symbols.call_symbol(&typectx, "emit"), vec![
vec![ LTExpr::lit_uint(&typectx, 42) ] 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() .into_asm()
.build()
); );
vm.execute( symbols.get_link_addr("main").unwrap() ); linker.add_static("hello-string",
eprintln!("\nvm.stack = {:?}", vm.data_stack); "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 { use {
crate::expr::{LTExpr, Statement} std::{
sync::{Arc, RwLock},
ops::Deref,
},
crate::{
expr::{LTExpr, Statement},
symbols::{Scope, SymbolDef}
}
}; };
pub struct ProcedureCompiler { pub struct ProcedureCompiler {
locals: Vec< String >, symbols: Arc<RwLock<Scope>>,
asm: tisc::Assembler, asm: tisc::Assembler,
result_size: usize linker: tisc::Linker,
result_size: usize,
} }
impl ProcedureCompiler { impl ProcedureCompiler {
pub fn new() -> Self { pub fn new(parent_scope: &Arc<RwLock<Scope>>) -> Self {
ProcedureCompiler { ProcedureCompiler {
locals: Vec::new(), symbols: Scope::with_parent(parent_scope),
asm: tisc::Assembler::new(), asm: tisc::Assembler::new(),
result_size: 0 linker: tisc::Linker::new(),
result_size: 0,
} }
} }
pub fn into_asm(self) -> tisc::Assembler { 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) { pub fn verify(&self) {
// todo
} }
pub fn compile_statement(mut self, statement: &Statement) -> Self { pub fn compile_statement(mut self, statement: &Statement) -> Self {
match statement { match statement {
Statement::Assignment{ var_id, val_expr } => { 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 } => { Statement::WhileLoop { condition, body } => {
let asm = self.asm; let asm = self.asm;
self.asm = tisc::Assembler::new(); self.asm = tisc::Assembler::new();
self = self.compile( &condition ); self = self.compile( condition );
let cond_asm = self.asm; let cond_asm = self.asm;
self.asm = tisc::Assembler::new(); self.asm = tisc::Assembler::new();
for statement in body.iter() { for statement in body.into_iter() {
self = self.compile_statement( statement ); self = self.compile_statement( statement );
} }
let body_asm = self.asm; let body_asm = self.asm;
@ -59,61 +94,70 @@ impl ProcedureCompiler {
pub fn compile(mut self, expr: &LTExpr) -> Self { pub fn compile(mut self, expr: &LTExpr) -> Self {
match expr { match expr {
LTExpr::SymbolLiteral { typ, symbol } => { LTExpr::Symbol { typ, symbol } => {
// todo: check type match self.symbols.read().unwrap().get(symbol) {
Some(SymbolDef::FrameRef{ typ, stack_ref }) => {
// search locals self.asm = self.asm
let mut id = None; .lit( stack_ref )
.call("data-frame-get");
for (i, l) in self.locals.iter().enumerate() { }
if l == symbol { Some(SymbolDef::StaticRef{ typ, link_addr }) => {
id = Some(self.locals.len()-i); self.asm = self.asm.static_ref( symbol.as_str() );
break; }
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 ); 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 } => { LTExpr::Application { head, body } => {
for arg in body.iter().rev() { for arg in body.iter().rev() {
self = self.compile(arg); self = self.compile(arg);
} }
self = self.compile(&head); self = self.compile(head);
}, },
LTExpr::Abstraction { arg_id, arg_type, val_expr } => { LTExpr::Let { name, val, body } => {
self.locals.push(arg_id.clone()); self.symbols.write().unwrap()
self = self.compile(val_expr); .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 self.asm = self.asm
.lit( self.result_size as tisc::VM_Word + 1 ) .lit( id )
.instruction(tisc::VM_Instruction::Roll) .call("data-frame-set");
.instruction(tisc::VM_Instruction::Drop);
self.locals.pop(); self = self.compile(val_expr);
}, },
LTExpr::Branch { condition, if_expr, else_expr } => { LTExpr::Branch { condition, if_expr, else_expr } => {
self = self.compile(&condition); self = self.compile(condition);
let asm = self.asm; let asm = self.asm;
self.asm = tisc::Assembler::new(); self.asm = tisc::Assembler::new();
self = self.compile( &if_expr ); self = self.compile( if_expr );
let if_asm = self.asm; let if_asm = self.asm;
self.asm = tisc::Assembler::new(); self.asm = tisc::Assembler::new();
self = self.compile( &else_expr ); self = self.compile( else_expr );
let else_asm = self.asm; let else_asm = self.asm;
self.asm = asm; self.asm = asm;
self.asm = self.asm.branch( if_asm, else_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 { use {
std::{
collections::HashMap,
sync::{Arc, RwLock},
},
crate::expr::LTExpr crate::expr::LTExpr
}; };
pub struct SymbolEntry { #[derive(Clone, Debug)]
link_addr: tisc::VM_Word, pub enum SymbolDef {
FrameRef {
in_types: Vec< laddertypes::TypeTerm >, typ: laddertypes::TypeTerm,
out_types: Vec< 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 { impl SymbolDef {
symbols: HashMap< String, SymbolEntry >, pub fn get_type(&self, typectx: &Arc<RwLock<laddertypes::dict::TypeDict>>) -> laddertypes::TypeTerm {
linker: tisc::Linker match self {
} SymbolDef::FrameRef { typ, stack_ref:_ } => typ.clone(),
SymbolDef::StaticRef { typ, link_addr:_ } => typ.clone(),
impl SymbolTable { SymbolDef::Procedure { in_types, out_types, link_addr: _ } => {
pub fn new() -> Self { laddertypes::TypeTerm::App(vec![
SymbolTable { typectx.write().unwrap().parse("Fn").expect("parse typeterm"),
symbols: HashMap::new(), laddertypes::TypeTerm::App( in_types.clone() ),
linker: tisc::Linker::new(0x100) laddertypes::TypeTerm::App( out_types.clone() )
])
}
} }
} }
}
pub fn get_link_addr(&self, symbol: &str) -> Option< tisc::VM_Word > { /* Describes a lexical scope of symbols
self.symbols.get(&String::from(symbol)).map(|e| e.link_addr) */
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 { pub fn with_parent(parent: &Arc<RwLock<Scope>>) -> Arc<RwLock<Self>> {
let entry = self.symbols.get(&String::from(symbol)).unwrap(); let s = Scope {
LTExpr::call_symbol( symbols: HashMap::new(),
/*
&laddertypes::TypeTerm::App(vec![ // todo: create proper child scope
typectx.write().unwrap().parse("Fn").expect("parse typeterm"), typectx: parent.read().unwrap().typectx.clone(),
laddertypes::TypeTerm::App( entry.in_types.clone() ),
laddertypes::TypeTerm::App( entry.out_types.clone() ) frame_size: 0,
]), parent: Some(parent.clone()),
*/ };
typectx,
entry.out_types.len(), Arc::new(RwLock::new(s))
entry.link_addr
)
} }
pub fn define( pub fn get_frame_size(&self) -> usize {
&mut self, self.frame_size
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() );
self.symbols.insert( pub fn get(&self, name: &str) -> Option<SymbolDef> {
String::from(symbol), match self.symbols.get(name) {
SymbolEntry { Some(def) => Some(def.clone()),
link_addr: self.linker.resolve_symbol(&String::from(symbol)).expect("cant find symbol"), None => {
in_types: in_types.into_iter().map(|t| typectx.write().unwrap().parse(t).expect("parse typeterm")).collect(), if let Some(parent) = self.parent.as_ref() {
out_types: out_types.into_iter().map(|t| typectx.write().unwrap().parse(t).expect("parse typeterm")).collect() 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
});
}
} }