wip infer_type
This commit is contained in:
parent
2ac69a7b12
commit
d295243dd0
3 changed files with 331 additions and 16 deletions
|
@ -4,7 +4,7 @@ version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
laddertypes = { path = "../../lib-laddertypes" }
|
laddertypes = { path = "../../lib-laddertypes", features = ["pretty"] }
|
||||||
tisc = { path = "../../lib-tisc" }
|
tisc = { path = "../../lib-tisc" }
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
tiny-ansi = "0.1.0"
|
||||||
|
|
|
@ -8,7 +8,12 @@ use {
|
||||||
ops::Deref,
|
ops::Deref,
|
||||||
sync::{Arc, RwLock},
|
sync::{Arc, RwLock},
|
||||||
},
|
},
|
||||||
|
laddertypes::{
|
||||||
|
parser::ParseLadderType,
|
||||||
|
unparser::UnparseLadderType
|
||||||
|
},
|
||||||
tisc::{assembler::AssemblyWord, linker::LinkAddr},
|
tisc::{assembler::AssemblyWord, linker::LinkAddr},
|
||||||
|
tiny_ansi::TinyAnsi
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct ProcedureCompiler {
|
pub struct ProcedureCompiler {
|
||||||
|
@ -99,8 +104,309 @@ impl ProcedureCompiler {
|
||||||
(symbol_exports, self.diagnostics, bytecode)
|
(symbol_exports, self.diagnostics, bytecode)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn verify(&self) {
|
pub fn parse_type(&self, s: &str) -> laddertypes::TypeTerm {
|
||||||
// todo
|
self.symbols.write().unwrap().parse(s).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unparse_type(&self, t: &laddertypes::TypeTerm) -> String {
|
||||||
|
self.symbols.write().unwrap().unparse(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sugar_type(&self, t: laddertypes::TypeTerm) -> laddertypes::SugaredTypeTerm {
|
||||||
|
let mut symbols = self.symbols.clone();
|
||||||
|
t.sugar( &mut symbols )
|
||||||
|
}
|
||||||
|
pub fn desugar_type(&self, t: laddertypes::SugaredTypeTerm) -> laddertypes::TypeTerm {
|
||||||
|
let mut symbols = self.symbols.clone();
|
||||||
|
t.desugar( &mut symbols )
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn infer_type(&mut self,
|
||||||
|
expr: &mut LTExpr,
|
||||||
|
) -> TypeTag {
|
||||||
|
match expr {
|
||||||
|
LTExpr::Ascend { region, typ, expr } => {
|
||||||
|
let expr_type = self.infer_type(expr)?;
|
||||||
|
let sub_type = typ.clone()?;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* todo: check potential overlap of typ with expr_type
|
||||||
|
*/
|
||||||
|
|
||||||
|
Ok(laddertypes::TypeTerm::Ladder(vec![
|
||||||
|
sub_type,
|
||||||
|
expr_type
|
||||||
|
]))
|
||||||
|
}
|
||||||
|
LTExpr::Descend { region, typ, expr } => {
|
||||||
|
let expr_type = self.infer_type(expr)?;
|
||||||
|
let super_type = typ.clone()?;
|
||||||
|
|
||||||
|
if expr_type.is_syntactic_subtype_of(&super_type).is_ok() {
|
||||||
|
Ok(super_type)
|
||||||
|
} else {
|
||||||
|
self.diagnostics.push(
|
||||||
|
(expr.get_region(),
|
||||||
|
format!("Type Error (descend):\n expected\n==> {}\n received\n==> {}\n",
|
||||||
|
self.unparse_type(&super_type),
|
||||||
|
self.unparse_type(&expr_type)
|
||||||
|
)));
|
||||||
|
return Err(TypeError::Mismatch {
|
||||||
|
expected: expr_type,
|
||||||
|
received: super_type
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LTExpr::WordLiteral{ region, val } => {
|
||||||
|
Ok(self.parse_type(
|
||||||
|
"ℤ_2^64 ~ machine.UInt64 ~ machine.Word"
|
||||||
|
))
|
||||||
|
}
|
||||||
|
LTExpr::StringLiteral{ region, value } => {
|
||||||
|
Ok(self.parse_type(
|
||||||
|
"<Seq Char ~ Unicode ~ ℤ_2^32 ~ machine.UInt64>
|
||||||
|
~ <TermArray 0 machine.UInt64 ~ machine.Word>"
|
||||||
|
))
|
||||||
|
}
|
||||||
|
LTExpr::Symbol { region, typ, symbol } => {
|
||||||
|
let scope = self.symbols.read().unwrap();
|
||||||
|
if let Some(sdef) = scope.get(symbol) {
|
||||||
|
drop(scope);
|
||||||
|
Ok(sdef.get_type(&mut self.symbols.clone()))
|
||||||
|
} else {
|
||||||
|
Err(TypeError::NoSymbol)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LTExpr::Abstraction { region, args, body } => {
|
||||||
|
let mut f = Vec::new();
|
||||||
|
|
||||||
|
let mut body_scope = Scope::with_parent( &self.symbols );
|
||||||
|
|
||||||
|
for (region, name, typ) in args {
|
||||||
|
if let Some(typ) = typ {
|
||||||
|
let typ = typ.clone()?;
|
||||||
|
let sugar_typ = typ.clone().sugar(&mut body_scope);
|
||||||
|
f.push( sugar_typ );
|
||||||
|
|
||||||
|
body_scope.write().unwrap().declare_var(name.clone(), typ.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let body_type = self.infer_type(body)?;
|
||||||
|
f.push( self.sugar_type(body_type) );
|
||||||
|
|
||||||
|
Ok(self.desugar_type(
|
||||||
|
laddertypes::SugaredTypeTerm::Func(f)
|
||||||
|
))
|
||||||
|
}
|
||||||
|
LTExpr::Application { region, typ, head, body } => {
|
||||||
|
let mut head_type = self.infer_type(head)?;
|
||||||
|
let mut args = body.into_iter();
|
||||||
|
|
||||||
|
let mut result_type = head_type;
|
||||||
|
let mut sugared_result_type = self.sugar_type(result_type);
|
||||||
|
while let laddertypes::SugaredTypeTerm::Func(mut f_types) = sugared_result_type {
|
||||||
|
sugared_result_type = f_types.pop().unwrap();
|
||||||
|
|
||||||
|
for (argi, expected_arg_type) in f_types.iter().enumerate() {
|
||||||
|
if let Some(arg) = args.next() {
|
||||||
|
|
||||||
|
let expected_arg_type = self.desugar_type(expected_arg_type.clone());
|
||||||
|
|
||||||
|
// check subtype
|
||||||
|
let received_arg_type = self.infer_type(arg)?;
|
||||||
|
if ! received_arg_type.is_syntactic_subtype_of(&expected_arg_type).is_ok() {
|
||||||
|
self.diagnostics.push(
|
||||||
|
(arg.get_region(),
|
||||||
|
format!("Type Error (arg {}):\n{}{}\n{}{}\n",
|
||||||
|
argi,
|
||||||
|
"expected\n::: ".bright_white(),
|
||||||
|
expected_arg_type.clone().sugar(&mut self.symbols.clone()).pretty(&mut self.symbols.clone(), 1),
|
||||||
|
"received\n::: ".bright_white(),
|
||||||
|
received_arg_type.clone().sugar(&mut self.symbols.clone()).pretty(&mut self.symbols.clone(), 1)
|
||||||
|
)));
|
||||||
|
|
||||||
|
return Err(TypeError::Mismatch {
|
||||||
|
expected: expected_arg_type,
|
||||||
|
received: received_arg_type
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// partial application.
|
||||||
|
f_types.push(sugared_result_type);
|
||||||
|
result_type = self.desugar_type(laddertypes::SugaredTypeTerm::Func(f_types[argi..].into_iter().cloned().collect()));
|
||||||
|
return Ok(result_type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result_type = self.desugar_type(sugared_result_type);
|
||||||
|
Ok(result_type)
|
||||||
|
}
|
||||||
|
LTExpr::Branch { region, condition, if_expr, else_expr } => {
|
||||||
|
let received_cond_type = self.infer_type(condition)?;
|
||||||
|
let expected_cond_type = self.symbols.parse("Bool ~ machine.Word").unwrap();
|
||||||
|
|
||||||
|
if received_cond_type.is_syntactic_subtype_of(&expected_cond_type).is_ok() {
|
||||||
|
|
||||||
|
let if_expr_type = self.infer_type(if_expr)?;
|
||||||
|
let else_expr_type = self.infer_type(else_expr)?;
|
||||||
|
|
||||||
|
if if_expr_type.is_syntactic_subtype_of(&else_expr_type).is_ok() {
|
||||||
|
Ok(else_expr_type)
|
||||||
|
} else if else_expr_type.is_syntactic_subtype_of(&if_expr_type).is_ok() {
|
||||||
|
Ok(if_expr_type)
|
||||||
|
} else {
|
||||||
|
|
||||||
|
self.diagnostics.push(
|
||||||
|
(region.clone(),
|
||||||
|
format!("Type Error (if/else):\n{}{}\n{}{}\n",
|
||||||
|
"if branch\n::: ".bright_white(),
|
||||||
|
if_expr_type.clone().sugar(&mut self.symbols.clone()).pretty(&mut self.symbols.clone(), 1),
|
||||||
|
"else branch\n::: ".bright_white(),
|
||||||
|
else_expr_type.clone().sugar(&mut self.symbols.clone()).pretty(&mut self.symbols.clone(), 1)))
|
||||||
|
);
|
||||||
|
|
||||||
|
Err(TypeError::Mismatch {
|
||||||
|
expected: if_expr_type,
|
||||||
|
received: else_expr_type
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.diagnostics.push(
|
||||||
|
(condition.get_region(),
|
||||||
|
format!("Type Error (condition):\n{}{}\n{}{}\n",
|
||||||
|
"expected\n::: ".bright_white(),
|
||||||
|
expected_cond_type.clone().sugar(&mut self.symbols.clone()).pretty(&mut self.symbols.clone(), 1),
|
||||||
|
"received\n::: ".bright_white(),
|
||||||
|
received_cond_type.clone().sugar(&mut self.symbols.clone()).pretty(&mut self.symbols.clone(), 1)))
|
||||||
|
);
|
||||||
|
|
||||||
|
Err(TypeError::Mismatch {
|
||||||
|
expected: expected_cond_type,
|
||||||
|
received: received_cond_type
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LTExpr::ExportBlock{ region, statements } |
|
||||||
|
LTExpr::Block{ region, statements } => {
|
||||||
|
let mut types = Vec::new();
|
||||||
|
|
||||||
|
for s in statements {
|
||||||
|
match s {
|
||||||
|
Statement::LetAssign{ name_region, typ, var_id, val_expr } => {
|
||||||
|
let typ = self.infer_type(val_expr)?;
|
||||||
|
|
||||||
|
match typ {
|
||||||
|
laddertypes::TypeTerm::App(mut args) => {
|
||||||
|
if args.len() > 1 {
|
||||||
|
if args[0] == self.parse_type("Func") {
|
||||||
|
args.remove(0);
|
||||||
|
let out_type = args.pop().unwrap();
|
||||||
|
let out_types = match out_type.clone() {
|
||||||
|
laddertypes::TypeTerm::App(mut oa) => {
|
||||||
|
if oa.len() > 1 {
|
||||||
|
if oa.remove(0) == self.parse_type("Struct") {
|
||||||
|
oa
|
||||||
|
} else {
|
||||||
|
vec![ out_type ]
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
vec![ out_type ]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
vec![ out_type ]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let in_types = args;
|
||||||
|
|
||||||
|
self.symbols.write().unwrap()
|
||||||
|
.declare_proc(
|
||||||
|
var_id.clone(),
|
||||||
|
in_types,
|
||||||
|
out_types,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// eprintln!("DEFINE a VARIABLE! (1)");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// eprintln!("DEFINE A VARIABLE (2)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t => {
|
||||||
|
// eprintln!("DEFINE A VARIABLE (3)");
|
||||||
|
let id = self
|
||||||
|
.symbols
|
||||||
|
.write()
|
||||||
|
.unwrap()
|
||||||
|
.declare_var(var_id.clone(), t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Statement::Return(expr) |
|
||||||
|
Statement::Expr(expr) => {
|
||||||
|
let t = self.infer_type(expr)?;
|
||||||
|
let st = self.sugar_type(t);
|
||||||
|
|
||||||
|
if st != laddertypes::SugaredTypeTerm::Struct(vec![]) {
|
||||||
|
types.push(st);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Statement::WhileLoop { condition, body } => {
|
||||||
|
let received_cond_type = self.infer_type(condition)?;
|
||||||
|
let expected_cond_type = self.symbols.parse("Bool ~ machine.Word").unwrap();
|
||||||
|
|
||||||
|
if received_cond_type.is_syntactic_subtype_of(&expected_cond_type).is_ok() {
|
||||||
|
let body_type = self.infer_type(&mut LTExpr::Block{ region: InputRegionTag::default(), statements: body.clone() })?;
|
||||||
|
let st = self.sugar_type(body_type);
|
||||||
|
if st != laddertypes::SugaredTypeTerm::Struct(vec![]) {
|
||||||
|
types.push(st);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.diagnostics.push(
|
||||||
|
(condition.get_region(),
|
||||||
|
format!("Type Error (condition):\n{}{}\n{}{}\n",
|
||||||
|
"expected\n::: ".bright_white(),
|
||||||
|
expected_cond_type.clone().sugar(&mut self.symbols.clone()).pretty(&mut self.symbols.clone(), 1),
|
||||||
|
"received\n::: ".bright_white(),
|
||||||
|
received_cond_type.clone().sugar(&mut self.symbols.clone()).pretty(&mut self.symbols.clone(), 1)))
|
||||||
|
);
|
||||||
|
|
||||||
|
return Err(TypeError::Mismatch {
|
||||||
|
expected: expected_cond_type,
|
||||||
|
received: received_cond_type
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Statement::Assignment { name_region, var_id, val_expr } => {
|
||||||
|
let received_type = self.infer_type(val_expr)?;
|
||||||
|
let expected_type = self.symbols.write().unwrap().get_type(var_id).unwrap();
|
||||||
|
|
||||||
|
if ! received_type.is_syntactic_subtype_of(&expected_type).is_ok() {
|
||||||
|
self.diagnostics.push(
|
||||||
|
(name_region.clone(),
|
||||||
|
format!("Type Error (assign):\n{}{}\n{}{}\n",
|
||||||
|
"expected\n::: ".bright_white(),
|
||||||
|
expected_type.clone().sugar(&mut self.symbols.clone()).pretty(&mut self.symbols.clone(), 1),
|
||||||
|
"received\n::: ".bright_white(),
|
||||||
|
received_type.clone().sugar(&mut self.symbols.clone()).pretty(&mut self.symbols.clone(), 1)))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if types.len() == 1 {
|
||||||
|
Ok(self.desugar_type(types.pop().unwrap()))
|
||||||
|
} else {
|
||||||
|
Ok(self.desugar_type(laddertypes::SugaredTypeTerm::Struct(types)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn compile_statement(mut self, statement: &Statement, enable_export: bool) -> Self {
|
pub fn compile_statement(mut self, statement: &Statement, enable_export: bool) -> Self {
|
||||||
|
@ -144,11 +450,6 @@ impl ProcedureCompiler {
|
||||||
val_expr,
|
val_expr,
|
||||||
} => match val_expr {
|
} => match val_expr {
|
||||||
LTExpr::Abstraction { region:_, args: _, body: _ } => {
|
LTExpr::Abstraction { region:_, args: _, body: _ } => {
|
||||||
self.symbols
|
|
||||||
.write()
|
|
||||||
.unwrap()
|
|
||||||
.declare_proc(var_id.clone(), vec![], vec![], enable_export);
|
|
||||||
|
|
||||||
let (exports, mut diagnostics, lambda_procedure) = ProcedureCompiler::new(&self.symbols)
|
let (exports, mut diagnostics, lambda_procedure) = ProcedureCompiler::new(&self.symbols)
|
||||||
.compile(val_expr)
|
.compile(val_expr)
|
||||||
.into_asm(var_id);
|
.into_asm(var_id);
|
||||||
|
@ -165,11 +466,6 @@ impl ProcedureCompiler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
self.symbols
|
|
||||||
.write()
|
|
||||||
.unwrap()
|
|
||||||
.declare_var(var_id.clone(), laddertypes::TypeTerm::unit());
|
|
||||||
|
|
||||||
self = self.compile_statement(&Statement::Assignment {
|
self = self.compile_statement(&Statement::Assignment {
|
||||||
name_region: *name_region,
|
name_region: *name_region,
|
||||||
var_id: var_id.clone(),
|
var_id: var_id.clone(),
|
||||||
|
|
|
@ -51,7 +51,21 @@ fn main() {
|
||||||
|
|
||||||
match ltcore::parser::parse_expr( &mut main_scope, &mut program_tokens ) {
|
match ltcore::parser::parse_expr( &mut main_scope, &mut program_tokens ) {
|
||||||
Ok( mut ast ) => {
|
Ok( mut ast ) => {
|
||||||
let (exports, diagnostics, proc_code) = ProcedureCompiler::new(&main_scope)
|
let mut compiler = ProcedureCompiler::new(&main_scope);
|
||||||
|
|
||||||
|
match compiler.infer_type(&mut ast) {
|
||||||
|
Ok(mut t) => {
|
||||||
|
t = t.normalize();
|
||||||
|
t = t.param_normalize();
|
||||||
|
let mut tc = compiler.symbols.clone();
|
||||||
|
eprintln!("Expr has type:\n================\n{}\n================\n", t.sugar(&mut tc).pretty(&mut tc, 0));
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("{} [{:?}]", "Type Error".red(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let (exports, diagnostics, proc_code) = compiler
|
||||||
.compile(&ast)
|
.compile(&ast)
|
||||||
.into_asm(&path);
|
.into_asm(&path);
|
||||||
|
|
||||||
|
@ -65,7 +79,12 @@ fn main() {
|
||||||
|
|
||||||
eprintln!("{} {}", "Compiled".green(), path.bold());
|
eprintln!("{} {}", "Compiled".green(), path.bold());
|
||||||
for (name, def) in exports.iter() {
|
for (name, def) in exports.iter() {
|
||||||
eprintln!("export {}: {:?}", name.yellow().bold(), def);
|
eprintln!("export {}:", name.yellow().bold());
|
||||||
|
let mut t = def.get_type(&mut main_scope);
|
||||||
|
t = t.normalize();
|
||||||
|
t = t.param_normalize();
|
||||||
|
let mut tc = main_scope.clone();
|
||||||
|
eprintln!( "{}", t.sugar(&mut tc).pretty(&tc,0) );
|
||||||
}
|
}
|
||||||
|
|
||||||
main_scope.write().unwrap().import(
|
main_scope.write().unwrap().import(
|
||||||
|
|
Loading…
Reference in a new issue