wip typing
This commit is contained in:
parent
c9c42d383f
commit
b8535aa772
10 changed files with 749 additions and 552 deletions
|
@ -4,11 +4,13 @@ use {
|
||||||
sync::{Arc, RwLock}
|
sync::{Arc, RwLock}
|
||||||
},
|
},
|
||||||
crate::{
|
crate::{
|
||||||
lexer::InputRegionTag
|
lexer::InputRegionTag,
|
||||||
}
|
symbols::Scope
|
||||||
|
},
|
||||||
|
tiny_ansi::TinyAnsi
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum Statement {
|
pub enum Statement {
|
||||||
Assignment {
|
Assignment {
|
||||||
name_region: InputRegionTag,
|
name_region: InputRegionTag,
|
||||||
|
@ -17,33 +19,74 @@ pub enum Statement {
|
||||||
},
|
},
|
||||||
LetAssign {
|
LetAssign {
|
||||||
name_region: InputRegionTag,
|
name_region: InputRegionTag,
|
||||||
typ: Option<TypeTag>,
|
typ: Option<laddertypes::TypeTerm>,
|
||||||
var_id: String,
|
var_id: String,
|
||||||
val_expr: LTExpr,
|
val_expr: LTExpr,
|
||||||
},
|
},
|
||||||
WhileLoop {
|
|
||||||
condition: LTExpr,
|
|
||||||
body: Vec<Statement>,
|
|
||||||
},
|
|
||||||
Return(LTExpr),
|
Return(LTExpr),
|
||||||
Expr(LTExpr),
|
Expr(LTExpr),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub enum TypeError {
|
pub enum TypeErrorKind {
|
||||||
ParseError(laddertypes::parser::ParseError),
|
// ParseError(laddertypes::parser::ParseError),
|
||||||
Mismatch {
|
AssignMismatch {
|
||||||
expected: laddertypes::TypeTerm,
|
expected: laddertypes::TypeTerm,
|
||||||
received: laddertypes::TypeTerm,
|
received: laddertypes::TypeTerm,
|
||||||
},
|
},
|
||||||
|
ArgTypeMismatch {
|
||||||
|
expected: laddertypes::TypeTerm,
|
||||||
|
received: laddertypes::TypeTerm,
|
||||||
|
},
|
||||||
|
BranchMismatch {
|
||||||
|
if_branch: laddertypes::TypeTerm,
|
||||||
|
else_branch: laddertypes::TypeTerm
|
||||||
|
},
|
||||||
|
SuperfluousArgument,
|
||||||
NoSymbol,
|
NoSymbol,
|
||||||
SuperflousArgument,
|
|
||||||
Todo
|
Todo
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type TypeTag = Result<laddertypes::TypeTerm, TypeError>;
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct TypeError {
|
||||||
|
pub region: InputRegionTag,
|
||||||
|
pub kind: TypeErrorKind
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
impl TypeErrorKind {
|
||||||
|
pub fn fmt(&self, dict: &mut impl laddertypes::TypeDict) -> String {
|
||||||
|
match self {
|
||||||
|
TypeErrorKind::BranchMismatch { if_branch, else_branch } => {
|
||||||
|
format!("Type Mismatch\nif branch\n:::{}\nelse branch\n:::{}",
|
||||||
|
if_branch.clone().sugar(dict).pretty(dict, 1),
|
||||||
|
else_branch.clone().sugar(dict).pretty(dict, 1)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
TypeErrorKind::AssignMismatch { expected, received } |
|
||||||
|
TypeErrorKind::ArgTypeMismatch { expected, received } => {
|
||||||
|
format!("Type Mismatch\n{}{}\n{}{}",
|
||||||
|
"expected\n ::: ".green(),
|
||||||
|
expected.clone().sugar(dict).pretty(dict, 1),
|
||||||
|
"received\n ::: ".green(),
|
||||||
|
received.clone().sugar(dict).pretty(dict, 1)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
TypeErrorKind::SuperfluousArgument => {
|
||||||
|
format!("Superfluous Argument")
|
||||||
|
}
|
||||||
|
TypeErrorKind::NoSymbol => {
|
||||||
|
format!("Unknown Symbol")
|
||||||
|
}
|
||||||
|
TypeErrorKind::Todo => {
|
||||||
|
format!("TODO")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type TypeTag = Result< laddertypes::TypeTerm, Vec<TypeError> >;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
pub enum LTExpr {
|
pub enum LTExpr {
|
||||||
WordLiteral {
|
WordLiteral {
|
||||||
region: InputRegionTag,
|
region: InputRegionTag,
|
||||||
|
@ -60,12 +103,12 @@ pub enum LTExpr {
|
||||||
},
|
},
|
||||||
Ascend {
|
Ascend {
|
||||||
region: InputRegionTag,
|
region: InputRegionTag,
|
||||||
typ: TypeTag,
|
typ: laddertypes::TypeTerm,
|
||||||
expr: Box<LTExpr>
|
expr: Box<LTExpr>
|
||||||
},
|
},
|
||||||
Descend {
|
Descend {
|
||||||
region: InputRegionTag,
|
region: InputRegionTag,
|
||||||
typ: TypeTag,
|
typ: laddertypes::TypeTerm,
|
||||||
expr: Box<LTExpr>
|
expr: Box<LTExpr>
|
||||||
},
|
},
|
||||||
Application {
|
Application {
|
||||||
|
@ -76,6 +119,7 @@ pub enum LTExpr {
|
||||||
},
|
},
|
||||||
Abstraction {
|
Abstraction {
|
||||||
region: InputRegionTag,
|
region: InputRegionTag,
|
||||||
|
scope: Arc<RwLock<Scope>>,
|
||||||
args: Vec<(InputRegionTag, String, Option<TypeTag>)>,
|
args: Vec<(InputRegionTag, String, Option<TypeTag>)>,
|
||||||
body: Box<LTExpr>,
|
body: Box<LTExpr>,
|
||||||
},
|
},
|
||||||
|
@ -85,12 +129,19 @@ pub enum LTExpr {
|
||||||
if_expr: Box<LTExpr>,
|
if_expr: Box<LTExpr>,
|
||||||
else_expr: Box<LTExpr>,
|
else_expr: Box<LTExpr>,
|
||||||
},
|
},
|
||||||
|
WhileLoop {
|
||||||
|
region: InputRegionTag,
|
||||||
|
condition: Box<LTExpr>,
|
||||||
|
body: Box<LTExpr>,
|
||||||
|
},
|
||||||
Block {
|
Block {
|
||||||
region: InputRegionTag,
|
region: InputRegionTag,
|
||||||
|
scope: Arc<RwLock<Scope>>,
|
||||||
statements: Vec<Statement>,
|
statements: Vec<Statement>,
|
||||||
},
|
},
|
||||||
ExportBlock {
|
ExportBlock {
|
||||||
region: InputRegionTag,
|
region: InputRegionTag,
|
||||||
|
scope: Arc<RwLock<Scope>>,
|
||||||
statements: Vec<Statement>,
|
statements: Vec<Statement>,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -98,17 +149,67 @@ pub enum LTExpr {
|
||||||
impl LTExpr {
|
impl LTExpr {
|
||||||
pub fn get_region(&self) -> InputRegionTag {
|
pub fn get_region(&self) -> InputRegionTag {
|
||||||
match self {
|
match self {
|
||||||
LTExpr::WordLiteral { region, val } => region,
|
LTExpr::WordLiteral{ region, val } => region,
|
||||||
LTExpr::StringLiteral { region, value } => region,
|
LTExpr::StringLiteral{ region, value } => region,
|
||||||
LTExpr::Symbol { region, typ, symbol } => region,
|
LTExpr::Symbol{ region, typ, symbol } => region,
|
||||||
LTExpr::Ascend { region, typ, expr } => region,
|
LTExpr::Ascend{ region, typ, expr } => region,
|
||||||
LTExpr::Descend{ region, typ, expr } => region,
|
LTExpr::Descend{ region, typ, expr } => region,
|
||||||
LTExpr::Application{ region, typ, head, body } => region,
|
LTExpr::Application{ region, typ, head, body } => region,
|
||||||
LTExpr::Abstraction{ region, args, body } => region,
|
LTExpr::Abstraction{ region, scope, args, body } => region,
|
||||||
LTExpr::Branch{ region, condition, if_expr, else_expr } => region,
|
LTExpr::Branch{ region, condition, if_expr, else_expr } => region,
|
||||||
LTExpr::Block{ region, statements } => region,
|
LTExpr::WhileLoop{ region, condition, body } => region,
|
||||||
LTExpr::ExportBlock{ region, statements } => region
|
LTExpr::Block{ region, scope, statements } => region,
|
||||||
|
LTExpr::ExportBlock{ region, scope, statements } => region
|
||||||
}.clone()
|
}.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get(&self, addr: Vec<usize>) -> Option<LTExpr> {
|
||||||
|
if addr.len() == 0 {
|
||||||
|
Some(self.clone())
|
||||||
|
} else {
|
||||||
|
let mut sub_addr = addr.clone();
|
||||||
|
let top_idx = sub_addr.remove(0);
|
||||||
|
match self {
|
||||||
|
LTExpr::Ascend{ region, typ, expr } => expr.get(addr),
|
||||||
|
LTExpr::Descend{ region, typ, expr } => expr.get(addr),
|
||||||
|
LTExpr::Application{ region, typ, head, body } => {
|
||||||
|
match top_idx {
|
||||||
|
0 => head.get(sub_addr),
|
||||||
|
i => {
|
||||||
|
if let Some(b) = body.get(i - 1) {
|
||||||
|
b.get(sub_addr)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LTExpr::Abstraction{ region, scope, args, body } => {
|
||||||
|
body.get(addr)
|
||||||
|
}
|
||||||
|
LTExpr::Branch{ region, condition, if_expr, else_expr } => {
|
||||||
|
match top_idx {
|
||||||
|
0 => condition.get(sub_addr),
|
||||||
|
1 => if_expr.get(sub_addr),
|
||||||
|
2 => else_expr.get(sub_addr),
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LTExpr::WhileLoop{ region, condition, body } => {
|
||||||
|
match top_idx {
|
||||||
|
0 => condition.get(sub_addr),
|
||||||
|
1 => body.get(sub_addr),
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LTExpr::Block{ region, scope, statements } |
|
||||||
|
LTExpr::ExportBlock{ region, scope, statements } => {
|
||||||
|
// statements.get(top_idx)?.get(sub_addr)
|
||||||
|
None
|
||||||
|
}
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
pub mod expr;
|
pub mod expr;
|
||||||
pub mod lexer;
|
pub mod lexer;
|
||||||
pub mod parser;
|
pub mod parser;
|
||||||
|
pub mod typing;
|
||||||
pub mod procedure_compiler;
|
pub mod procedure_compiler;
|
||||||
pub mod runtime;
|
pub mod runtime;
|
||||||
pub mod symbols;
|
pub mod symbols;
|
||||||
|
|
|
@ -2,6 +2,7 @@ use {
|
||||||
crate::{
|
crate::{
|
||||||
expr::{LTExpr, Statement, TypeError, TypeTag},
|
expr::{LTExpr, Statement, TypeError, TypeTag},
|
||||||
lexer::{LTIRLexer, LTIRToken, LexError, InputRegionTag},
|
lexer::{LTIRLexer, LTIRToken, LexError, InputRegionTag},
|
||||||
|
symbols::{Scope}
|
||||||
},
|
},
|
||||||
laddertypes::{
|
laddertypes::{
|
||||||
dict::TypeDict,
|
dict::TypeDict,
|
||||||
|
@ -180,7 +181,7 @@ where It: Iterator<Item = (InputRegionTag, Result<LTIRToken, LexError>)>
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_statement<It>(
|
pub fn parse_statement<It>(
|
||||||
typectx: &mut impl TypeDict,
|
super_scope: &Arc<RwLock<Scope>>,
|
||||||
tokens: &mut Peekable<It>,
|
tokens: &mut Peekable<It>,
|
||||||
) -> Result<crate::expr::Statement, (InputRegionTag, ParseError)>
|
) -> Result<crate::expr::Statement, (InputRegionTag, ParseError)>
|
||||||
where It: Iterator<Item = (InputRegionTag, Result<LTIRToken, LexError>)>
|
where It: Iterator<Item = (InputRegionTag, Result<LTIRToken, LexError>)>
|
||||||
|
@ -193,7 +194,7 @@ where It: Iterator<Item = (InputRegionTag, Result<LTIRToken, LexError>)>
|
||||||
tokens.next();
|
tokens.next();
|
||||||
// todo accept address-expression instead of symbol
|
// todo accept address-expression instead of symbol
|
||||||
let (name_region, name) = parse_symbol(tokens)?;
|
let (name_region, name) = parse_symbol(tokens)?;
|
||||||
let val_expr = parse_expr(typectx, tokens)?;
|
let val_expr = parse_expr(super_scope, tokens)?;
|
||||||
let _ = parse_expect(tokens, LTIRToken::StatementSep)?;
|
let _ = parse_expect(tokens, LTIRToken::StatementSep)?;
|
||||||
|
|
||||||
Ok(Statement::Assignment {
|
Ok(Statement::Assignment {
|
||||||
|
@ -205,49 +206,40 @@ where It: Iterator<Item = (InputRegionTag, Result<LTIRToken, LexError>)>
|
||||||
"let" => {
|
"let" => {
|
||||||
tokens.next();
|
tokens.next();
|
||||||
let (name_region, name) = parse_symbol(tokens)?;
|
let (name_region, name) = parse_symbol(tokens)?;
|
||||||
let typ = parse_type_tag(typectx, tokens)?;
|
let typ = parse_type_tag(&mut *super_scope.write().unwrap(), tokens)?;
|
||||||
|
|
||||||
/* todo
|
/* todo
|
||||||
let mut variable_bindings = parse_binding_expr(typectx, tokens)?;
|
let mut variable_bindings = parse_binding_expr(typectx, tokens)?;
|
||||||
*/
|
*/
|
||||||
let _ = parse_expect(tokens, LTIRToken::AssignValue);
|
let _ = parse_expect(tokens, LTIRToken::AssignValue);
|
||||||
let val_expr = parse_expr(typectx, tokens)?;
|
let val_expr = parse_expr(super_scope, tokens)?;
|
||||||
let _ = parse_expect(tokens, LTIRToken::StatementSep)?;
|
let _ = parse_expect(tokens, LTIRToken::StatementSep)?;
|
||||||
|
|
||||||
Ok(Statement::LetAssign {
|
Ok(Statement::LetAssign {
|
||||||
name_region,
|
name_region,
|
||||||
typ: match typ {
|
typ: match typ {
|
||||||
Some((r,t)) => Some(Ok(t)),
|
Some((r,t)) => Some(t),
|
||||||
None => None
|
None => None
|
||||||
},
|
},
|
||||||
var_id: name,
|
var_id: name,
|
||||||
val_expr,
|
val_expr,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
"while" => {
|
|
||||||
tokens.next();
|
|
||||||
let _ = parse_expect(tokens, LTIRToken::ExprOpen)?;
|
|
||||||
let cond = parse_expr(typectx, tokens)?;
|
|
||||||
let _ = parse_expect(tokens, LTIRToken::ExprClose)?;
|
|
||||||
Ok(Statement::WhileLoop {
|
|
||||||
condition: cond,
|
|
||||||
body: parse_statement_block(typectx, tokens)?,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
"return" => {
|
"return" => {
|
||||||
tokens.next();
|
tokens.next();
|
||||||
let expr = parse_expr(typectx, tokens)?;
|
let expr = parse_expr(super_scope, tokens)?;
|
||||||
let _ = parse_expect(tokens, LTIRToken::StatementSep)?;
|
let _ = parse_expect(tokens, LTIRToken::StatementSep)?;
|
||||||
Ok(Statement::Return(parse_expr(typectx, tokens)?))
|
Ok(Statement::Return(parse_expr(super_scope, tokens)?))
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let expr = parse_expr(typectx, tokens)?;
|
let expr = parse_expr(super_scope, tokens)?;
|
||||||
let _ = parse_expect(tokens, LTIRToken::StatementSep)?;
|
let _ = parse_expect(tokens, LTIRToken::StatementSep)?;
|
||||||
Ok(Statement::Expr(expr))
|
Ok(Statement::Expr(expr))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
let expr = parse_expr(typectx, tokens)?;
|
let expr = parse_expr(super_scope, tokens)?;
|
||||||
let _ = parse_expect(tokens, LTIRToken::StatementSep)?;
|
let _ = parse_expect(tokens, LTIRToken::StatementSep)?;
|
||||||
Ok(Statement::Expr(expr))
|
Ok(Statement::Expr(expr))
|
||||||
}
|
}
|
||||||
|
@ -259,7 +251,7 @@ where It: Iterator<Item = (InputRegionTag, Result<LTIRToken, LexError>)>
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_statement_block<It>(
|
pub fn parse_statement_block<It>(
|
||||||
typectx: &mut impl TypeDict,
|
scope: &Arc<RwLock<Scope>>,
|
||||||
tokens: &mut Peekable<It>,
|
tokens: &mut Peekable<It>,
|
||||||
) -> Result<Vec<Statement>, (InputRegionTag, ParseError)>
|
) -> Result<Vec<Statement>, (InputRegionTag, ParseError)>
|
||||||
where It: Iterator<Item = (InputRegionTag, Result<LTIRToken, LexError>)>
|
where It: Iterator<Item = (InputRegionTag, Result<LTIRToken, LexError>)>
|
||||||
|
@ -274,7 +266,7 @@ where It: Iterator<Item = (InputRegionTag, Result<LTIRToken, LexError>)>
|
||||||
return Ok(statements);
|
return Ok(statements);
|
||||||
}
|
}
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
statements.push(parse_statement(typectx, tokens)?);
|
statements.push(parse_statement(scope, tokens)?);
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
return Err((*region, ParseError::LexError(err.clone())));
|
return Err((*region, ParseError::LexError(err.clone())));
|
||||||
|
@ -296,13 +288,8 @@ where It: Iterator<Item = (InputRegionTag, Result<LTIRToken, LexError>)>
|
||||||
Some((region, Ok(LTIRToken::Char(c)))) => Ok(
|
Some((region, Ok(LTIRToken::Char(c)))) => Ok(
|
||||||
LTExpr::Ascend {
|
LTExpr::Ascend {
|
||||||
region: region.clone(),
|
region: region.clone(),
|
||||||
typ: match typectx.parse("Char ~ Unicode ~ ℤ_2^32") {
|
typ: typectx.parse("Char ~ Unicode ~ ℤ_2^32").unwrap(),
|
||||||
Ok(t) => Ok(t),
|
expr: Box::new(LTExpr::WordLiteral{ region, val: c as tisc::VM_Word })
|
||||||
Err(e) => Err(TypeError::ParseError(e))
|
|
||||||
},
|
|
||||||
expr: Box::new(
|
|
||||||
LTExpr::WordLiteral{ region, val: c as tisc::VM_Word }
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
Some((region, Ok(LTIRToken::Num(n)))) => Ok(LTExpr::WordLiteral{ region, val: n as tisc::VM_Word }),
|
Some((region, Ok(LTIRToken::Num(n)))) => Ok(LTExpr::WordLiteral{ region, val: n as tisc::VM_Word }),
|
||||||
|
@ -313,7 +300,7 @@ where It: Iterator<Item = (InputRegionTag, Result<LTIRToken, LexError>)>
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_expr<It>(
|
pub fn parse_expr<It>(
|
||||||
typectx: &mut impl TypeDict,
|
super_scope: &Arc<RwLock<Scope>>,
|
||||||
tokens: &mut Peekable<It>,
|
tokens: &mut Peekable<It>,
|
||||||
) -> Result<crate::expr::LTExpr, (InputRegionTag, ParseError)>
|
) -> Result<crate::expr::LTExpr, (InputRegionTag, ParseError)>
|
||||||
where It: Iterator<Item = (InputRegionTag, Result<LTIRToken, LexError>)>
|
where It: Iterator<Item = (InputRegionTag, Result<LTIRToken, LexError>)>
|
||||||
|
@ -327,12 +314,15 @@ where It: Iterator<Item = (InputRegionTag, Result<LTIRToken, LexError>)>
|
||||||
let region = region.clone();
|
let region = region.clone();
|
||||||
tokens.next();
|
tokens.next();
|
||||||
|
|
||||||
let mut variable_bindings = parse_binding_expr(typectx, tokens)?;
|
let scope = Scope::with_parent(super_scope);
|
||||||
|
|
||||||
|
let mut variable_bindings = parse_binding_expr(&mut *scope.write().unwrap(), tokens)?;
|
||||||
let _ = parse_expect(tokens, LTIRToken::MapsTo);
|
let _ = parse_expect(tokens, LTIRToken::MapsTo);
|
||||||
let body = parse_expr(typectx, tokens)?;
|
let body = parse_expr(&scope, tokens)?;
|
||||||
|
|
||||||
return Ok(LTExpr::Abstraction {
|
return Ok(LTExpr::Abstraction {
|
||||||
region,
|
region,
|
||||||
|
scope,
|
||||||
args: variable_bindings.flatten().into_iter().map(|(r,s,t)| (r,s,t.map(|t|Ok(t))) ).collect(),
|
args: variable_bindings.flatten().into_iter().map(|(r,s,t)| (r,s,t.map(|t|Ok(t))) ).collect(),
|
||||||
body: Box::new(body),
|
body: Box::new(body),
|
||||||
});
|
});
|
||||||
|
@ -350,7 +340,7 @@ where It: Iterator<Item = (InputRegionTag, Result<LTIRToken, LexError>)>
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
children.push(parse_expr(typectx, tokens)?);
|
children.push(parse_expr(super_scope, tokens)?);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(LTIRToken::ExprClose) => {
|
Ok(LTIRToken::ExprClose) => {
|
||||||
|
@ -358,10 +348,13 @@ where It: Iterator<Item = (InputRegionTag, Result<LTIRToken, LexError>)>
|
||||||
}
|
}
|
||||||
Ok(LTIRToken::BlockOpen) => {
|
Ok(LTIRToken::BlockOpen) => {
|
||||||
let region = region.clone();
|
let region = region.clone();
|
||||||
let statements = parse_statement_block(typectx, tokens)?;
|
let scope = Scope::with_parent(super_scope);
|
||||||
|
let statements = parse_statement_block(&scope, tokens)?;
|
||||||
|
|
||||||
children.push(
|
children.push(
|
||||||
LTExpr::Block {
|
LTExpr::Block {
|
||||||
region,
|
region,
|
||||||
|
scope,
|
||||||
statements
|
statements
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -379,38 +372,45 @@ where It: Iterator<Item = (InputRegionTag, Result<LTIRToken, LexError>)>
|
||||||
}
|
}
|
||||||
Ok(LTIRToken::Ascend(type_str)) => {
|
Ok(LTIRToken::Ascend(type_str)) => {
|
||||||
let mut region = region.clone();
|
let mut region = region.clone();
|
||||||
let typ =
|
let typ = super_scope.write().unwrap().parse(type_str);
|
||||||
match typectx.parse(type_str) {
|
|
||||||
Ok(t) => Ok(t),
|
|
||||||
Err(e) => Err(TypeError::ParseError(e))
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(expr) = children.pop() {
|
if let Some(expr) = children.pop() {
|
||||||
region.begin = expr.get_region().begin;
|
region.begin = expr.get_region().begin;
|
||||||
|
|
||||||
|
match typ {
|
||||||
|
Ok(typ) => {
|
||||||
children.push(LTExpr::Ascend {
|
children.push(LTExpr::Ascend {
|
||||||
region: region.clone(),
|
region: region.clone(),
|
||||||
typ,
|
typ,
|
||||||
expr: Box::new(expr)
|
expr: Box::new(expr)
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
return Err((region, ParseError::TypeParseError(e)));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tokens.next();
|
tokens.next();
|
||||||
}
|
}
|
||||||
Ok(LTIRToken::Descend(type_str)) => {
|
Ok(LTIRToken::Descend(type_str)) => {
|
||||||
let region = region.clone();
|
let region = region.clone();
|
||||||
let typ =
|
let typ = super_scope.write().unwrap().parse(type_str);
|
||||||
match typectx.parse(type_str) {
|
|
||||||
Ok(t) => Ok(t),
|
|
||||||
Err(e) => Err(TypeError::ParseError(e))
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(expr) = children.pop() {
|
if let Some(expr) = children.pop() {
|
||||||
|
match typ {
|
||||||
|
Ok(typ) => {
|
||||||
children.push(LTExpr::Descend {
|
children.push(LTExpr::Descend {
|
||||||
region,
|
region,
|
||||||
typ,
|
typ,
|
||||||
expr: Box::new(expr)
|
expr: Box::new(expr)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Err(e) => {
|
||||||
|
return Err((region, ParseError::TypeParseError(e)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tokens.next();
|
tokens.next();
|
||||||
}
|
}
|
||||||
|
@ -419,18 +419,21 @@ where It: Iterator<Item = (InputRegionTag, Result<LTIRToken, LexError>)>
|
||||||
let region = region.clone();
|
let region = region.clone();
|
||||||
tokens.next();
|
tokens.next();
|
||||||
let _ = parse_expect(tokens, LTIRToken::ExprOpen)?;
|
let _ = parse_expect(tokens, LTIRToken::ExprOpen)?;
|
||||||
let cond = parse_expr(typectx, tokens)?;
|
let cond = parse_expr(super_scope, tokens)?;
|
||||||
let _ = parse_expect(tokens, LTIRToken::ExprClose)?;
|
let _ = parse_expect(tokens, LTIRToken::ExprClose)?;
|
||||||
|
|
||||||
let if_statements = parse_statement_block(typectx, tokens)?;
|
let if_statements = parse_statement_block(super_scope, tokens)?;
|
||||||
let if_expr = LTExpr::Block{ region: region.clone(), statements: if_statements };
|
|
||||||
let mut else_expr = LTExpr::Block{ region: InputRegionTag::default(), statements: vec![] };
|
let scope = super_scope.clone();
|
||||||
|
let if_expr = LTExpr::Block{ region: region.clone(), scope, statements: if_statements };
|
||||||
|
let scope = super_scope.clone();
|
||||||
|
let mut else_expr = LTExpr::Block{ region: InputRegionTag::default(), scope, statements: vec![] };
|
||||||
|
|
||||||
if let Some((region, peektok)) = tokens.peek() {
|
if let Some((region, peektok)) = tokens.peek() {
|
||||||
if let Ok(LTIRToken::Symbol(name)) = peektok {
|
if let Ok(LTIRToken::Symbol(name)) = peektok {
|
||||||
if name == "else" {
|
if name == "else" {
|
||||||
tokens.next();
|
tokens.next();
|
||||||
else_expr = parse_expr(typectx, tokens)?;
|
else_expr = parse_expr(super_scope, tokens)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -442,21 +445,35 @@ where It: Iterator<Item = (InputRegionTag, Result<LTIRToken, LexError>)>
|
||||||
else_expr: Box::new(else_expr),
|
else_expr: Box::new(else_expr),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
"while" => {
|
||||||
|
let region = region.clone();
|
||||||
|
tokens.next();
|
||||||
|
let _ = parse_expect(tokens, LTIRToken::ExprOpen)?;
|
||||||
|
let cond = parse_expr(super_scope, tokens)?;
|
||||||
|
let _ = parse_expect(tokens, LTIRToken::ExprClose)?;
|
||||||
|
children.push(LTExpr::WhileLoop {
|
||||||
|
region,
|
||||||
|
condition: Box::new(cond),
|
||||||
|
body: Box::new(parse_expr(super_scope, tokens)?),
|
||||||
|
});
|
||||||
|
}
|
||||||
"export" => {
|
"export" => {
|
||||||
let region = region.clone();
|
let region = region.clone();
|
||||||
tokens.next();
|
tokens.next();
|
||||||
let block = parse_statement_block(typectx, tokens)?;
|
let scope = Scope::with_parent(super_scope);
|
||||||
|
let block = parse_statement_block(&scope, tokens)?;
|
||||||
children.push(LTExpr::ExportBlock {
|
children.push(LTExpr::ExportBlock {
|
||||||
region,
|
region,
|
||||||
|
scope,
|
||||||
statements: block
|
statements: block
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
name => {
|
name => {
|
||||||
children.push(parse_atom(typectx, tokens)?);
|
children.push(parse_atom(&mut *super_scope.write().unwrap(), tokens)?);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Ok(atom) => {
|
Ok(atom) => {
|
||||||
children.push(parse_atom(typectx, tokens)?);
|
children.push(parse_atom(&mut *super_scope.write().unwrap(), tokens)?);
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
return Err((*region, ParseError::LexError(err.clone())));
|
return Err((*region, ParseError::LexError(err.clone())));
|
||||||
|
|
|
@ -17,404 +17,81 @@ use {
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct ProcedureCompiler {
|
pub struct ProcedureCompiler {
|
||||||
pub symbols: Arc<RwLock<Scope>>,
|
proc_symbol: String,
|
||||||
|
scope: Arc<RwLock<Scope>>,
|
||||||
asm: tisc::Assembler,
|
asm: tisc::Assembler,
|
||||||
linker: tisc::Linker,
|
subroutines: Vec<tisc::assembler::AssemblyWord>,
|
||||||
result_size: usize,
|
pub linker: tisc::Linker,
|
||||||
|
|
||||||
pub diagnostics: Vec<( InputRegionTag, String )>
|
pub diagnostics: Vec<( InputRegionTag, String )>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProcedureCompiler {
|
impl ProcedureCompiler {
|
||||||
pub fn new(parent_scope: &Arc<RwLock<Scope>>) -> Self {
|
pub fn new(proc_symbol: String, scope: Arc<RwLock<Scope>>) -> Self {
|
||||||
ProcedureCompiler {
|
ProcedureCompiler {
|
||||||
symbols: Scope::with_parent(parent_scope),
|
proc_symbol,
|
||||||
|
scope,
|
||||||
|
subroutines: Vec::new(),
|
||||||
asm: tisc::Assembler::new(),
|
asm: tisc::Assembler::new(),
|
||||||
linker: tisc::Linker::new(),
|
linker: tisc::Linker::new(),
|
||||||
result_size: 0,
|
|
||||||
|
|
||||||
diagnostics: Vec::new()
|
diagnostics: Vec::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
pub fn export_symbols(&self) -> Vec<(String, SymbolDef)> {
|
||||||
|
let mut scope = self.scope.write().unwrap();
|
||||||
|
scope.update_link_addresses(&self.proc_symbol, &self.linker);
|
||||||
|
scope.export()
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
pub fn get_bytecode(mut self, ret: bool) -> (
|
||||||
|
Vec<(String, SymbolDef)>,
|
||||||
|
Vec<tisc::assembler::AssemblyWord>
|
||||||
|
) {
|
||||||
|
let frame_size = self.scope.read().unwrap().get_frame_size();
|
||||||
|
if frame_size > 0 {
|
||||||
|
let alloc_asm = tisc::Assembler::new()
|
||||||
|
.lit(frame_size as tisc::VM_Word).call("data-frame-alloc");
|
||||||
|
let drop_asm = tisc::Assembler::new()
|
||||||
|
.lit(frame_size as tisc::VM_Word).call("data-frame-drop");
|
||||||
|
|
||||||
pub fn into_asm(mut self, proc_symbol: &String) -> (Vec<(String, SymbolDef)>, Vec<(InputRegionTag, String)>, Vec<tisc::assembler::AssemblyWord>) {
|
self.asm = alloc_asm.join( self.asm ).join( drop_asm );
|
||||||
let mut symbols =
|
}
|
||||||
Arc::try_unwrap(self.symbols).ok().unwrap()
|
|
||||||
.into_inner().unwrap();
|
|
||||||
|
|
||||||
symbols.update_link_addresses(
|
let main_section = self.asm.build();
|
||||||
proc_symbol,
|
|
||||||
|
//self.linker.add_procedure( &self.proc_symbol, main_section );
|
||||||
|
// ^--- this would insert the asm section at the end,
|
||||||
|
// we however need it an the beginning of the bytecode
|
||||||
|
|
||||||
|
// insert section at front
|
||||||
|
self.linker.next_addr += main_section.len() as i64;
|
||||||
|
for (name,section) in self.linker.symbols.iter_mut() {
|
||||||
|
section.addr += main_section.len() as i64;
|
||||||
|
}
|
||||||
|
self.linker.symbols.insert(
|
||||||
|
self.proc_symbol.clone(),
|
||||||
|
tisc::linker::Section { addr: 0, data: main_section }
|
||||||
|
);
|
||||||
|
|
||||||
|
// replace all symbol definitions from subroutines
|
||||||
|
// with relative LinkAddr`s
|
||||||
|
self.scope.write().unwrap().update_link_addresses(
|
||||||
|
&self.proc_symbol,
|
||||||
&self.linker
|
&self.linker
|
||||||
);
|
);
|
||||||
|
|
||||||
let data_frame_size = symbols.get_frame_size() as i64;
|
(
|
||||||
|
self.scope.read().unwrap().export(),
|
||||||
let body = self.asm.build();
|
self.linker.link_relative( &self.proc_symbol ).expect("link error")
|
||||||
self.linker.add_procedure("__procedure_body__", body);
|
)
|
||||||
let body_addr = self
|
|
||||||
.linker
|
|
||||||
.get_link_addr(&"__procedure_body__".into())
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let subroutines = self
|
|
||||||
.linker
|
|
||||||
.link_relative(&"__subroutines__".into())
|
|
||||||
.expect("link error");
|
|
||||||
|
|
||||||
let mut entry = tisc::Assembler::new();
|
|
||||||
if data_frame_size > 0 {
|
|
||||||
entry = entry.lit(data_frame_size).call("data-frame-alloc");
|
|
||||||
}
|
|
||||||
entry = entry.call_symbol(LinkAddr::Relative {
|
|
||||||
symbol: "__subroutines__".into(),
|
|
||||||
offset: body_addr,
|
|
||||||
});
|
|
||||||
|
|
||||||
if data_frame_size > 0 {
|
|
||||||
entry = entry.lit(data_frame_size).call("data-frame-drop");
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut superlink = tisc::Linker::new();
|
|
||||||
superlink.add_procedure("", entry.build());
|
|
||||||
superlink.add_procedure("__subroutines__", subroutines);
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let bytecode = superlink.link_relative(proc_symbol).expect("link error");
|
|
||||||
(symbol_exports, self.diagnostics, bytecode)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn parse_type(&self, s: &str) -> laddertypes::TypeTerm {
|
|
||||||
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 {
|
||||||
match statement {
|
match statement {
|
||||||
Statement::Assignment { name_region, var_id, val_expr } => {
|
Statement::Assignment { name_region, var_id, val_expr } => {
|
||||||
self = self.compile(val_expr);
|
self = self.compile_expr(val_expr);
|
||||||
|
|
||||||
match self.symbols.read().unwrap().get(var_id) {
|
match self.scope.read().unwrap().get(var_id) {
|
||||||
Some(SymbolDef::FrameRef { typ, stack_ref }) => {
|
Some(SymbolDef::FrameRef { typ, stack_ref }) => {
|
||||||
self.asm = self.asm.lit(stack_ref).call("data-frame-set");
|
self.asm = self.asm.lit(stack_ref).call("data-frame-set");
|
||||||
}
|
}
|
||||||
|
@ -430,8 +107,7 @@ impl ProcedureCompiler {
|
||||||
link_addr,
|
link_addr,
|
||||||
export
|
export
|
||||||
}) => {
|
}) => {
|
||||||
self.asm = self
|
self.asm = self.asm
|
||||||
.asm
|
|
||||||
.call(var_id.as_str())
|
.call(var_id.as_str())
|
||||||
.inst(tisc::VM_Instruction::Store);
|
.inst(tisc::VM_Instruction::Store);
|
||||||
}
|
}
|
||||||
|
@ -448,23 +124,40 @@ impl ProcedureCompiler {
|
||||||
typ,
|
typ,
|
||||||
var_id,
|
var_id,
|
||||||
val_expr,
|
val_expr,
|
||||||
} => match val_expr {
|
} => {
|
||||||
LTExpr::Abstraction { region:_, args: _, body: _ } => {
|
let val_type = self.scope.read().unwrap()
|
||||||
let (exports, mut diagnostics, lambda_procedure) = ProcedureCompiler::new(&self.symbols)
|
.get(var_id).unwrap()
|
||||||
.compile(val_expr)
|
.get_type(&mut self.scope.clone());
|
||||||
.into_asm(var_id);
|
let val_type = val_type.sugar(&mut self.scope.clone());
|
||||||
|
match val_type {
|
||||||
|
laddertypes::SugaredTypeTerm::Func(mut f_types) => {
|
||||||
|
let mut c = ProcedureCompiler::new(
|
||||||
|
var_id.clone(),
|
||||||
|
self.scope.clone()
|
||||||
|
);
|
||||||
|
c = c.compile_expr( val_expr );
|
||||||
|
self.diagnostics.append(&mut c.diagnostics);
|
||||||
|
|
||||||
self.diagnostics.append(&mut diagnostics);
|
let (symbols,code) = c.get_bytecode( true );
|
||||||
|
eprintln!("LET assign compiled {}", var_id);
|
||||||
self.linker.add_procedure(var_id, lambda_procedure);
|
for (i,l) in tisc::assembler::disassemble( &code ).iter().enumerate() {
|
||||||
|
eprintln!("{}+{} ... {}", var_id, i, l);
|
||||||
let offset = self.linker.get_link_addr(var_id).unwrap();
|
|
||||||
|
|
||||||
// forward already exported symbols
|
|
||||||
if enable_export {
|
|
||||||
self.symbols.write().unwrap().import( exports );
|
|
||||||
}
|
}
|
||||||
|
self.linker.add_procedure(var_id, code);
|
||||||
|
|
||||||
|
/*
|
||||||
|
let out_types = vec![ f_types.pop().unwrap().desugar(&mut self.scope.clone()) ];
|
||||||
|
let in_types = f_types.into_iter().map(|t| t.desugar(&mut self.scope.clone())).collect();
|
||||||
|
|
||||||
|
self.scope.write().unwrap().declare_proc(
|
||||||
|
var_id.clone(),
|
||||||
|
in_types,
|
||||||
|
out_types,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
self = self.compile_statement(&Statement::Assignment {
|
self = self.compile_statement(&Statement::Assignment {
|
||||||
name_region: *name_region,
|
name_region: *name_region,
|
||||||
|
@ -472,36 +165,21 @@ impl ProcedureCompiler {
|
||||||
val_expr: val_expr.clone(),
|
val_expr: val_expr.clone(),
|
||||||
}, false);
|
}, false);
|
||||||
}
|
}
|
||||||
},
|
|
||||||
Statement::WhileLoop { condition, body } => {
|
|
||||||
let asm = self.asm;
|
|
||||||
|
|
||||||
self.asm = tisc::Assembler::new();
|
|
||||||
self = self.compile(condition);
|
|
||||||
let cond_asm = self.asm;
|
|
||||||
|
|
||||||
self.asm = tisc::Assembler::new();
|
|
||||||
for statement in body.into_iter() {
|
|
||||||
self = self.compile_statement(statement, false);
|
|
||||||
}
|
}
|
||||||
let body_asm = self.asm;
|
|
||||||
|
|
||||||
self.asm = asm;
|
|
||||||
self.asm = self.asm.while_loop(cond_asm, body_asm);
|
|
||||||
}
|
}
|
||||||
Statement::Expr(expr) => {
|
Statement::Expr(expr) => {
|
||||||
self = self.compile(expr);
|
self = self.compile_expr(expr);
|
||||||
}
|
}
|
||||||
Statement::Return(expr) => {
|
Statement::Return(expr) => {
|
||||||
self = self.compile(expr);
|
self = self.compile_expr(expr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn compile(mut self, expr: <Expr) -> Self {
|
pub fn compile_expr(mut self, expr: <Expr) -> Self {
|
||||||
match expr {
|
match expr {
|
||||||
LTExpr::Symbol { region, typ, symbol } => match self.symbols.read().unwrap().get(symbol) {
|
LTExpr::Symbol { region, typ, symbol } => match self.scope.read().unwrap().get(symbol) {
|
||||||
Some(SymbolDef::FrameRef { typ, stack_ref }) => {
|
Some(SymbolDef::FrameRef { typ, stack_ref }) => {
|
||||||
self.asm = self.asm.lit(stack_ref).call("data-frame-get");
|
self.asm = self.asm.lit(stack_ref).call("data-frame-get");
|
||||||
}
|
}
|
||||||
|
@ -532,34 +210,10 @@ impl ProcedureCompiler {
|
||||||
self.asm = self.asm.lit(*val);
|
self.asm = self.asm.lit(*val);
|
||||||
}
|
}
|
||||||
LTExpr::Ascend { region, typ, expr } => {
|
LTExpr::Ascend { region, typ, expr } => {
|
||||||
self = self.compile(expr);
|
self = self.compile_expr(expr);
|
||||||
}
|
}
|
||||||
LTExpr::Descend { region, typ, expr } => {
|
LTExpr::Descend { region, typ, expr } => {
|
||||||
self = self.compile(expr);
|
self = self.compile_expr(expr);
|
||||||
}
|
|
||||||
LTExpr::Application { region, typ, head, body } => {
|
|
||||||
for arg in body.iter().rev() {
|
|
||||||
self = self.compile(arg);
|
|
||||||
}
|
|
||||||
self = self.compile(head);
|
|
||||||
}
|
|
||||||
LTExpr::Abstraction { region, args, body } => {
|
|
||||||
for (region, arg_name, arg_type) in args.iter() {
|
|
||||||
if let Some(Ok(typeterm)) = arg_type {
|
|
||||||
let id = self
|
|
||||||
.symbols
|
|
||||||
.write()
|
|
||||||
.unwrap()
|
|
||||||
.declare_var(arg_name.clone(), typeterm.clone());
|
|
||||||
self.asm = self.asm.lit(id).call("data-frame-set");
|
|
||||||
} else {
|
|
||||||
self.diagnostics.push((
|
|
||||||
region.clone(),
|
|
||||||
format!("invalid type {:?} for argument {}", arg_type, arg_name)
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self = self.compile(body);
|
|
||||||
}
|
}
|
||||||
LTExpr::Branch {
|
LTExpr::Branch {
|
||||||
region,
|
region,
|
||||||
|
@ -567,29 +221,112 @@ impl ProcedureCompiler {
|
||||||
if_expr,
|
if_expr,
|
||||||
else_expr,
|
else_expr,
|
||||||
} => {
|
} => {
|
||||||
self = self.compile(condition);
|
self = self.compile_expr(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_expr(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_expr(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);
|
||||||
}
|
}
|
||||||
LTExpr::Block { region, statements } => {
|
LTExpr::WhileLoop { region, condition, body } => {
|
||||||
for s in statements.iter() {
|
let asm = self.asm;
|
||||||
self = self.compile_statement(s, false);
|
|
||||||
|
self.asm = tisc::Assembler::new();
|
||||||
|
self = self.compile_expr(condition);
|
||||||
|
let cond_asm = self.asm;
|
||||||
|
|
||||||
|
self.asm = tisc::Assembler::new();
|
||||||
|
self = self.compile_expr(body);
|
||||||
|
let body_asm = self.asm;
|
||||||
|
|
||||||
|
self.asm = asm;
|
||||||
|
self.asm = self.asm.while_loop(cond_asm, body_asm);
|
||||||
|
}
|
||||||
|
LTExpr::Application { region, typ, head, body } => {
|
||||||
|
for arg in body.iter().rev() {
|
||||||
|
self = self.compile_expr(arg);
|
||||||
|
}
|
||||||
|
self = self.compile_expr(head);
|
||||||
|
}
|
||||||
|
LTExpr::Abstraction { region, scope, args, body } => {
|
||||||
|
let mut abs_compiler = ProcedureCompiler::new("__abs__".into(), scope.clone());
|
||||||
|
|
||||||
|
for (region, arg_name, arg_type) in args.iter() {
|
||||||
|
match scope.read().unwrap().get(arg_name) {
|
||||||
|
Some(SymbolDef::FrameRef{ typ, stack_ref }) => {
|
||||||
|
eprintln!("Arg {} stack ref = {}", arg_name, stack_ref);
|
||||||
|
|
||||||
|
// TODO: aknowledge actual size of arguments
|
||||||
|
// let arg_size = typ.get_size()
|
||||||
|
let arg_size = 1;
|
||||||
|
|
||||||
|
for i in 0..arg_size {
|
||||||
|
abs_compiler.asm = abs_compiler.asm
|
||||||
|
.lit(stack_ref + i)
|
||||||
|
.call("data-frame-set");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LTExpr::ExportBlock{ region, statements } => {
|
_ => {
|
||||||
for s in statements.iter() {
|
self.diagnostics.push(
|
||||||
self = self.compile_statement(s, true);
|
(region.clone(),
|
||||||
|
format!("argument variable is not a frame-ref"))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abs_compiler = abs_compiler.compile_expr( body );
|
||||||
|
let (abs_symbols, mut abs_code) = abs_compiler.get_bytecode( false );
|
||||||
|
|
||||||
|
for (s,def) in abs_symbols.iter() {
|
||||||
|
eprintln!("{} = {:?}", s, def);
|
||||||
|
}
|
||||||
|
for (i, l) in tisc::assembler::disassemble(&abs_code).into_iter().enumerate() {
|
||||||
|
eprintln!("__abs__+{} .. {}", i, l);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.asm.words.append( &mut abs_code );
|
||||||
|
/*
|
||||||
|
self.linker.add_procedure(
|
||||||
|
"__abs__".into(),
|
||||||
|
abs_code
|
||||||
|
);*/
|
||||||
|
}
|
||||||
|
LTExpr::Block { region, scope, statements } => {
|
||||||
|
let mut block_compiler = ProcedureCompiler::new(
|
||||||
|
"__block__".into(),
|
||||||
|
scope.clone()
|
||||||
|
);
|
||||||
|
|
||||||
|
for stmnt in statements.iter() {
|
||||||
|
block_compiler = block_compiler.compile_statement( stmnt, true );
|
||||||
|
}
|
||||||
|
|
||||||
|
let (block_symbols, mut block_code) = block_compiler.get_bytecode( true );
|
||||||
|
|
||||||
|
eprintln!("BLOCK compiler:");
|
||||||
|
for (s,def) in block_symbols.iter() {
|
||||||
|
eprintln!("{} = {:?}", s, def);
|
||||||
|
}
|
||||||
|
for (i,l) in tisc::assembler::disassemble( &block_code ).into_iter().enumerate() {
|
||||||
|
eprintln!("block+{} .. {}", i, l);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.linker.
|
||||||
|
self.scope.write().unwrap().import(
|
||||||
|
block_symbols
|
||||||
|
);
|
||||||
|
self.asm.words.append(&mut block_code);
|
||||||
|
}
|
||||||
|
LTExpr::ExportBlock{ region, scope, statements } => {
|
||||||
|
}
|
||||||
|
}
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -73,6 +73,7 @@ impl SymbolDef {
|
||||||
|
|
||||||
/* Describes a lexical scope of symbols
|
/* Describes a lexical scope of symbols
|
||||||
*/
|
*/
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
pub struct Scope {
|
pub struct Scope {
|
||||||
/* definition of runtime symbols
|
/* definition of runtime symbols
|
||||||
*/
|
*/
|
||||||
|
@ -147,15 +148,16 @@ impl Scope {
|
||||||
s
|
s
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn export(self) -> Vec<(String, SymbolDef)> {
|
pub fn export(&self) -> Vec<(String, SymbolDef)> {
|
||||||
self.symbols
|
self.symbols
|
||||||
.into_iter()
|
.iter()
|
||||||
.filter(|(name, def)|
|
.filter(|(name, def)|
|
||||||
match def {
|
match def {
|
||||||
SymbolDef::Procedure { in_types:_, out_types:_, link_addr:_, export } => *export,
|
SymbolDef::Procedure { in_types:_, out_types:_, link_addr:_, export } => *export,
|
||||||
_ => false
|
_ => false
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
.map(|(n,d)| (n.clone(), d.clone()))
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
319
lib-ltcore/src/typing.rs
Normal file
319
lib-ltcore/src/typing.rs
Normal file
|
@ -0,0 +1,319 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
lexer::InputRegionTag,
|
||||||
|
expr::{LTExpr, Statement, TypeTag, TypeError, TypeErrorKind},
|
||||||
|
symbols::{Scope, SymbolDef},
|
||||||
|
},
|
||||||
|
std::{
|
||||||
|
ops::Deref,
|
||||||
|
sync::{Arc, RwLock},
|
||||||
|
},
|
||||||
|
laddertypes::{
|
||||||
|
parser::ParseLadderType,
|
||||||
|
unparser::UnparseLadderType,
|
||||||
|
dict::TypeDict
|
||||||
|
},
|
||||||
|
tisc::{assembler::AssemblyWord, linker::LinkAddr},
|
||||||
|
tiny_ansi::TinyAnsi
|
||||||
|
};
|
||||||
|
|
||||||
|
impl LTExpr {
|
||||||
|
/*
|
||||||
|
pub fn get_type(&self) -> TypeTag {
|
||||||
|
Err(TypeError::Todo)
|
||||||
|
}*/
|
||||||
|
|
||||||
|
pub fn infer_type(&self, scope: &Arc<RwLock<Scope>>) -> TypeTag
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
LTExpr::WordLiteral{ region, val } => {
|
||||||
|
Ok(scope.write().unwrap().parse(
|
||||||
|
"ℤ_2^64 ~ machine.UInt64 ~ machine.Word"
|
||||||
|
).unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
LTExpr::StringLiteral{ region, value } => {
|
||||||
|
Ok(scope.write().unwrap().parse(
|
||||||
|
"<Seq Char ~ Unicode ~ ℤ_2^32 ~ ℤ_2^64 ~ machine.UInt64>
|
||||||
|
~ <TermArray 0 machine.UInt64 ~ machine.Word>"
|
||||||
|
).unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
LTExpr::Symbol { region, typ, symbol } => {
|
||||||
|
let mut s = scope.write().unwrap();
|
||||||
|
if let Some(sdef) = s.get(symbol) {
|
||||||
|
Ok(sdef.get_type(&mut *s))
|
||||||
|
} else {
|
||||||
|
let region = region.clone();
|
||||||
|
Err(vec![ TypeError{ region, kind: TypeErrorKind::NoSymbol } ])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LTExpr::Ascend { region, typ, expr } => {
|
||||||
|
let expr_type = expr.infer_type( scope )?;
|
||||||
|
let sub_type = typ.clone();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* todo: check potential overlap of typ with expr_type
|
||||||
|
*/
|
||||||
|
if let Ok(i) = sub_type.is_syntactic_subtype_of(&expr_type) {
|
||||||
|
let mut lnf = expr_type.get_lnf_vec();
|
||||||
|
let mut sub_lnf = sub_type.get_lnf_vec();
|
||||||
|
|
||||||
|
for x in 0..i {
|
||||||
|
lnf.insert(x, sub_lnf.remove(0));
|
||||||
|
}
|
||||||
|
let result_type = laddertypes::TypeTerm::Ladder(lnf);
|
||||||
|
Ok(result_type)
|
||||||
|
} else {
|
||||||
|
Ok(laddertypes::TypeTerm::Ladder(vec![
|
||||||
|
sub_type,
|
||||||
|
expr_type
|
||||||
|
]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LTExpr::Descend { region, typ, expr } => {
|
||||||
|
let expr_type = expr.infer_type(scope)?;
|
||||||
|
let super_type = typ.clone();
|
||||||
|
|
||||||
|
if let Ok(i) = expr_type.is_syntactic_subtype_of(&super_type) {
|
||||||
|
let lnf = expr_type.get_lnf_vec();
|
||||||
|
let result_type = laddertypes::TypeTerm::Ladder(lnf[i..].into_iter().cloned().collect());
|
||||||
|
Ok(result_type)
|
||||||
|
} else {
|
||||||
|
return Err(vec![ TypeError{
|
||||||
|
region: region.clone(),
|
||||||
|
kind: TypeErrorKind::ArgTypeMismatch {
|
||||||
|
expected: expr_type,
|
||||||
|
received: super_type
|
||||||
|
}
|
||||||
|
} ]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LTExpr::Abstraction { region, scope, args, body } => {
|
||||||
|
let mut f = Vec::new();
|
||||||
|
|
||||||
|
for (region, name, typ) in args {
|
||||||
|
if let Some(typ) = typ {
|
||||||
|
let typ = typ.clone()?;
|
||||||
|
let sugar_typ = typ.clone().sugar(&mut *scope.write().unwrap());
|
||||||
|
f.push( sugar_typ );
|
||||||
|
|
||||||
|
scope.write().unwrap().declare_var(name.clone(), typ.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let body_type = body.infer_type( scope )?;
|
||||||
|
f.push( body_type.sugar(&mut *scope.write().unwrap()) );
|
||||||
|
|
||||||
|
Ok(laddertypes::SugaredTypeTerm::Func(f).desugar( &mut *scope.write().unwrap() ))
|
||||||
|
}
|
||||||
|
|
||||||
|
LTExpr::Application{ region, typ, head, body } => {
|
||||||
|
let mut head_type = head.infer_type(scope)?;
|
||||||
|
let mut args = body.into_iter();
|
||||||
|
|
||||||
|
let mut result_type = head_type;
|
||||||
|
let mut sugared_result_type = result_type.sugar(&mut *scope.write().unwrap());
|
||||||
|
|
||||||
|
let mut errors = Vec::new();
|
||||||
|
|
||||||
|
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 = expected_arg_type.clone().desugar(&mut *scope.write().unwrap());
|
||||||
|
|
||||||
|
// check subtype
|
||||||
|
let received_arg_type = arg.infer_type(scope)?;
|
||||||
|
if ! received_arg_type.is_syntactic_subtype_of(&expected_arg_type).is_ok() {
|
||||||
|
errors.push(TypeError{
|
||||||
|
region: arg.get_region(),
|
||||||
|
kind: TypeErrorKind::ArgTypeMismatch {
|
||||||
|
expected: expected_arg_type,
|
||||||
|
received: received_arg_type
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// partial application.
|
||||||
|
f_types.push(sugared_result_type);
|
||||||
|
sugared_result_type = laddertypes::SugaredTypeTerm::Func(
|
||||||
|
f_types[argi .. ].into_iter().cloned().collect()
|
||||||
|
);
|
||||||
|
|
||||||
|
// todo examine stack ..
|
||||||
|
|
||||||
|
return
|
||||||
|
if errors.len() == 0 {
|
||||||
|
result_type = sugared_result_type.desugar(&mut *scope.write().unwrap());
|
||||||
|
Ok(result_type)
|
||||||
|
} else {
|
||||||
|
Err(errors)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while let Some(arg) = args.next() {
|
||||||
|
errors.push(TypeError{
|
||||||
|
region: arg.get_region(),
|
||||||
|
kind: TypeErrorKind::SuperfluousArgument
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if errors.len() == 0 {
|
||||||
|
result_type = sugared_result_type.desugar(&mut *scope.write().unwrap());
|
||||||
|
Ok(result_type)
|
||||||
|
} else {
|
||||||
|
Err(errors)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LTExpr::Branch { region, condition, if_expr, else_expr } => {
|
||||||
|
let received_cond_type = condition.infer_type(scope)?;
|
||||||
|
let expected_cond_type = scope.write().unwrap().parse("Bool ~ machine.Word").unwrap();
|
||||||
|
|
||||||
|
if received_cond_type.is_syntactic_subtype_of(&expected_cond_type).is_ok() {
|
||||||
|
|
||||||
|
let if_expr_type = if_expr.infer_type(scope)?;
|
||||||
|
let else_expr_type = else_expr.infer_type(scope)?;
|
||||||
|
|
||||||
|
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 {
|
||||||
|
Err(vec![TypeError{
|
||||||
|
region: region.clone(),
|
||||||
|
kind: TypeErrorKind::BranchMismatch {
|
||||||
|
if_branch: if_expr_type,
|
||||||
|
else_branch: else_expr_type
|
||||||
|
}
|
||||||
|
}])
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err(vec![ TypeError{
|
||||||
|
region: condition.get_region(),
|
||||||
|
kind: TypeErrorKind::ArgTypeMismatch {
|
||||||
|
expected: expected_cond_type,
|
||||||
|
received: received_cond_type
|
||||||
|
}
|
||||||
|
}])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LTExpr::WhileLoop { region, condition, body } => {
|
||||||
|
let received_cond_type = condition.infer_type(scope)?;
|
||||||
|
let expected_cond_type = scope.write().unwrap().parse("Bool ~ machine.Word").unwrap();
|
||||||
|
|
||||||
|
if received_cond_type.is_syntactic_subtype_of(&expected_cond_type).is_ok() {
|
||||||
|
let body_type = body.infer_type(scope)?;
|
||||||
|
let body_type = body_type.sugar(&mut scope.clone());
|
||||||
|
let loop_type = laddertypes::SugaredTypeTerm::Seq(vec![ body_type ]);
|
||||||
|
Ok(loop_type.desugar(&mut scope.clone()))
|
||||||
|
} else {
|
||||||
|
return Err(vec![ TypeError{
|
||||||
|
region: condition.get_region(),
|
||||||
|
kind: TypeErrorKind::ArgTypeMismatch {
|
||||||
|
expected: expected_cond_type,
|
||||||
|
received: received_cond_type
|
||||||
|
}
|
||||||
|
}]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LTExpr::ExportBlock{ region, scope, statements } |
|
||||||
|
LTExpr::Block{ region, scope, statements } => {
|
||||||
|
let mut types = Vec::new();
|
||||||
|
|
||||||
|
for s in statements {
|
||||||
|
match s.infer_type(scope) {
|
||||||
|
Ok(Some(t)) => {
|
||||||
|
if !t.is_empty() {
|
||||||
|
types.insert(0, t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(None) => {}
|
||||||
|
Err(e) => {
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(
|
||||||
|
if types.len() == 1 { types.pop().unwrap() }
|
||||||
|
else { laddertypes::SugaredTypeTerm::Struct(types) }
|
||||||
|
.desugar(&mut scope.clone())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Statement {
|
||||||
|
pub fn infer_type(&self, scope: &Arc<RwLock<Scope>>) -> Result< Option<laddertypes::SugaredTypeTerm> , Vec<TypeError> > {
|
||||||
|
match self {
|
||||||
|
Statement::LetAssign{ name_region, typ, var_id, val_expr } => {
|
||||||
|
let typ = val_expr.infer_type( scope )?;
|
||||||
|
|
||||||
|
match typ.clone().sugar( &mut scope.clone() ) {
|
||||||
|
laddertypes::SugaredTypeTerm::Func(mut args) => {
|
||||||
|
let out_type = args.pop().unwrap();
|
||||||
|
let out_types =
|
||||||
|
match out_type.clone() {
|
||||||
|
laddertypes::SugaredTypeTerm::Struct(oa) => oa.into_iter().map(|t|t.desugar(&mut scope.clone())).collect(),
|
||||||
|
_ => vec![ out_type.desugar(&mut scope.clone()) ]
|
||||||
|
};
|
||||||
|
let in_types = args.into_iter().map(|t| t.desugar(&mut scope.clone())).collect();
|
||||||
|
|
||||||
|
scope.write().unwrap()
|
||||||
|
.declare_proc(
|
||||||
|
var_id.clone(),
|
||||||
|
in_types,
|
||||||
|
out_types,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let id = scope.write().unwrap().declare_var(var_id.clone(), typ);
|
||||||
|
eprintln!("TYPING declare var = {}", id);
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Statement::Return(expr) |
|
||||||
|
Statement::Expr(expr) => {
|
||||||
|
let t = expr.infer_type(scope)?;
|
||||||
|
|
||||||
|
if t != laddertypes::TypeTerm::App(vec![]) {
|
||||||
|
let st = t.sugar(&mut scope.clone());
|
||||||
|
Ok(Some(st))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Statement::Assignment { name_region, var_id, val_expr } => {
|
||||||
|
let received_type = val_expr.infer_type(scope)?;
|
||||||
|
let expected_type = scope.write().unwrap().get_type(var_id).unwrap();
|
||||||
|
if ! received_type.is_syntactic_subtype_of(&expected_type).is_ok() {
|
||||||
|
return Err(vec![ TypeError{
|
||||||
|
region: val_expr.get_region(),
|
||||||
|
kind: TypeErrorKind::AssignMismatch {
|
||||||
|
expected: expected_type,
|
||||||
|
received: received_type
|
||||||
|
}
|
||||||
|
}]);
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -51,23 +51,35 @@ 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 mut compiler = ProcedureCompiler::new(&main_scope);
|
let mut compiler = ProcedureCompiler::new(path.clone(), main_scope.clone());
|
||||||
|
|
||||||
match compiler.infer_type(&mut ast) {
|
match ast.infer_type(&main_scope) {
|
||||||
Ok(mut t) => {
|
Ok(mut t) => {
|
||||||
|
eprintln!("Typecheck {}", "OK".green().bold());
|
||||||
t = t.normalize();
|
t = t.normalize();
|
||||||
t = t.param_normalize();
|
t = t.param_normalize();
|
||||||
let mut tc = compiler.symbols.clone();
|
let mut tc = main_scope.clone();
|
||||||
eprintln!("Expr has type:\n================\n{}\n================\n", t.sugar(&mut tc).pretty(&mut tc, 0));
|
eprintln!( "{}", t.sugar(&mut tc).pretty(&tc,0) );
|
||||||
|
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(type_errs) => {
|
||||||
eprintln!("{} [{:?}]", "Type Error".red(), e);
|
for e in type_errs.iter() {
|
||||||
|
crate::diagnostic::print_diagnostic(
|
||||||
|
path.as_str(),
|
||||||
|
e.region,
|
||||||
|
e.kind.fmt(&mut main_scope.clone())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
eprintln!("----------------------------------");
|
||||||
|
eprintln!("{} ({} errors)", "Typecheck failed".bright_red().bold(), type_errs.len());
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let (exports, diagnostics, proc_code) = compiler
|
compiler = compiler.compile_expr(&ast);
|
||||||
.compile(&ast)
|
let diagnostics = compiler.diagnostics.clone();
|
||||||
.into_asm(&path);
|
let (exports, proc_code) = compiler.get_bytecode(false);
|
||||||
|
|
||||||
for (region, message) in diagnostics {
|
for (region, message) in diagnostics {
|
||||||
crate::diagnostic::print_diagnostic(
|
crate::diagnostic::print_diagnostic(
|
||||||
|
@ -77,6 +89,7 @@ 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());
|
eprintln!("export {}:", name.yellow().bold());
|
||||||
|
@ -93,6 +106,10 @@ fn main() {
|
||||||
|
|
||||||
/* link assembly-program to symbols
|
/* link assembly-program to symbols
|
||||||
*/
|
*/
|
||||||
|
eprintln!("generated bytecode ({})", proc_code.len() );
|
||||||
|
for (i,l) in tisc::assembler::disassemble(&proc_code).iter().enumerate() {
|
||||||
|
eprintln!("{} .... {}", i,l);
|
||||||
|
}
|
||||||
linker.add_procedure(path.as_str(), proc_code);
|
linker.add_procedure(path.as_str(), proc_code);
|
||||||
}
|
}
|
||||||
Err( (region, parse_error) ) => {
|
Err( (region, parse_error) ) => {
|
||||||
|
|
1
ltcc/test.lt
Normal file
1
ltcc/test.lt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
|
BIN
ltcc/test.lt.o
Normal file
BIN
ltcc/test.lt.o
Normal file
Binary file not shown.
|
@ -35,8 +35,10 @@ fn main() {
|
||||||
linker.import( source_path, bincode::deserialize_from( input ).expect("") );
|
linker.import( source_path, bincode::deserialize_from( input ).expect("") );
|
||||||
}
|
}
|
||||||
|
|
||||||
let entry_addr = linker.get_link_addr(&args.entry)
|
let entry_addr = linker.get_link_addr(&args.entry).unwrap_or(0);
|
||||||
|
/*
|
||||||
.expect(&format!("cant find entry symbol '{}'", args.entry));
|
.expect(&format!("cant find entry symbol '{}'", args.entry));
|
||||||
|
*/
|
||||||
let bytecode = linker.link_total().expect("Link error:");
|
let bytecode = linker.link_total().expect("Link error:");
|
||||||
|
|
||||||
eprintln!("{} ({} bytes)", "Loaded bytecode.".green(), bytecode.len());
|
eprintln!("{} ({} bytes)", "Loaded bytecode.".green(), bytecode.len());
|
||||||
|
|
Loading…
Reference in a new issue