Started IR again
This commit is contained in:
parent
552496c0f9
commit
b936901e17
15
demo.hal
15
demo.hal
|
@ -1,13 +1,2 @@
|
||||||
c :: C{r: 10.0};
|
a : integer : 10;
|
||||||
|
b := a + 10;
|
||||||
A :: struct {
|
|
||||||
b: B,
|
|
||||||
}
|
|
||||||
|
|
||||||
B :: struct {
|
|
||||||
c: C,
|
|
||||||
}
|
|
||||||
|
|
||||||
C :: struct {
|
|
||||||
r: real,
|
|
||||||
}
|
|
||||||
|
|
|
@ -9,5 +9,6 @@ WebAssembly.instantiateStreaming(fetch(url), { console });
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use std::{io::Write, path::Path};
|
use std::path::Path;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Parser, Tokenizer,
|
Parser, Tokenizer,
|
||||||
|
|
107
src/ir/generate.rs
Normal file
107
src/ir/generate.rs
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
use crate::{Expression, ExpressionKind, Statement, StatementKind};
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
impl Compiler {
|
||||||
|
fn statement(&mut self, stmt: Statement) {
|
||||||
|
use StatementKind as s;
|
||||||
|
match stmt.kind {
|
||||||
|
s::Declaration {
|
||||||
|
name,
|
||||||
|
type_str,
|
||||||
|
type_actual,
|
||||||
|
value,
|
||||||
|
mutable,
|
||||||
|
uid,
|
||||||
|
} => self.push(IR::New {
|
||||||
|
uid,
|
||||||
|
type_: type_actual,
|
||||||
|
}),
|
||||||
|
s::Assignment { name, value, uid } => todo!(),
|
||||||
|
s::If {
|
||||||
|
predicate,
|
||||||
|
block,
|
||||||
|
else_,
|
||||||
|
} => todo!(),
|
||||||
|
s::While { predicate, block } => todo!(),
|
||||||
|
s::Print(expression) => todo!(),
|
||||||
|
s::Expression(expression) => todo!(),
|
||||||
|
s::Block(vec) => todo!(),
|
||||||
|
s::Return(expression) => todo!(),
|
||||||
|
s::Error(diagnostic) => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn expression(&mut self, expr: Expression) {
|
||||||
|
use ExpressionKind as e;
|
||||||
|
match expr.kind {
|
||||||
|
e::Immediate(immediate) => {
|
||||||
|
let Type::Prim(p) = expr.type_ else {
|
||||||
|
unreachable!();
|
||||||
|
};
|
||||||
|
self.push(IR::Push {
|
||||||
|
value: immediate,
|
||||||
|
prim: p,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
e::Identifier(_, uid) => {
|
||||||
|
self.push(IR::Get { uid });
|
||||||
|
},
|
||||||
|
e::Binary { op, left, right } => {
|
||||||
|
self.expression(*left);
|
||||||
|
self.expression(*right);
|
||||||
|
self.push(IR::BinOp {
|
||||||
|
op,
|
||||||
|
type_: expr.type_,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
e::Unary { op, child } => {
|
||||||
|
self.expression(*child);
|
||||||
|
self.push(IR::UnOp {
|
||||||
|
op,
|
||||||
|
type_: expr.type_,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
e::Parenthesis(inner) => self.expression(*inner),
|
||||||
|
e::FunctionDef {
|
||||||
|
params,
|
||||||
|
returns_str,
|
||||||
|
returns_actual,
|
||||||
|
body,
|
||||||
|
id,
|
||||||
|
} => {
|
||||||
|
self.push(IR::StartFunc {
|
||||||
|
fid: id,
|
||||||
|
params: params.into_iter().map(|p| p.type_actual).collect(),
|
||||||
|
returns: returns_actual,
|
||||||
|
});
|
||||||
|
for s in body {
|
||||||
|
self.statement(s);
|
||||||
|
}
|
||||||
|
self.push(IR::EndFunc);
|
||||||
|
},
|
||||||
|
e::FunctionCall {
|
||||||
|
callee, args, id, ..
|
||||||
|
} => {
|
||||||
|
for arg in args {
|
||||||
|
self.expression(arg);
|
||||||
|
}
|
||||||
|
let fid = if let Type::Function(fid) = expr.type_ {
|
||||||
|
fid
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
self.push(IR::Call { fid })
|
||||||
|
},
|
||||||
|
e::StructDef(..) => {},
|
||||||
|
e::StructLiteral { name, args, id } => {},
|
||||||
|
e::Field {
|
||||||
|
namespace,
|
||||||
|
field,
|
||||||
|
uid,
|
||||||
|
} => {
|
||||||
|
self.expression(*namespace);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,28 +1,52 @@
|
||||||
|
mod generate;
|
||||||
|
pub use generate::*;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
BinaryOp, Expression, ExpressionKind, Immediate, Statement, StatementKind,
|
BinaryOp, Immediate, UnaryOp,
|
||||||
UnaryOp,
|
semantic::{FID, Primitive, Type, UID},
|
||||||
semantic::{Primitive, Type, UID},
|
|
||||||
};
|
};
|
||||||
/*
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum IR {
|
pub enum IR {
|
||||||
BinOp { op: BinaryOp, type_: Type },
|
BinOp {
|
||||||
UnOp { op: UnaryOp, type_: Type },
|
op: BinaryOp,
|
||||||
Push { prim: Primitive, value: Immediate },
|
type_: Type,
|
||||||
NewLocal { uid: UID, type_: Type },
|
},
|
||||||
AssignLocal { uid: UID },
|
UnOp {
|
||||||
GetLocal { uid: UID },
|
op: UnaryOp,
|
||||||
NewGlobal { uid: UID, type_: Type },
|
type_: Type,
|
||||||
AssignGlobal { uid: UID },
|
},
|
||||||
GetGlobal { uid: UID },
|
Push {
|
||||||
StartFunc { uid: UID },
|
prim: Primitive,
|
||||||
|
value: Immediate,
|
||||||
|
},
|
||||||
|
New {
|
||||||
|
uid: UID,
|
||||||
|
type_: Type,
|
||||||
|
},
|
||||||
|
Set {
|
||||||
|
uid: UID,
|
||||||
|
},
|
||||||
|
Get {
|
||||||
|
uid: UID,
|
||||||
|
},
|
||||||
|
StartFunc {
|
||||||
|
fid: FID,
|
||||||
|
params: Vec<Type>,
|
||||||
|
returns: Type,
|
||||||
|
},
|
||||||
EndFunc,
|
EndFunc,
|
||||||
ReturnType { type_: Type },
|
ReturnType {
|
||||||
NewParam { uid: UID, type_: Type },
|
type_: Type,
|
||||||
|
},
|
||||||
Return,
|
Return,
|
||||||
Call { uid: UID },
|
Call {
|
||||||
|
fid: FID,
|
||||||
|
},
|
||||||
Drop,
|
Drop,
|
||||||
Print,
|
Print {
|
||||||
|
type_: Type,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for IR {
|
impl std::fmt::Display for IR {
|
||||||
|
@ -32,24 +56,43 @@ impl std::fmt::Display for IR {
|
||||||
BinOp { op, type_ } => write!(f, "{op} ({type_})"),
|
BinOp { op, type_ } => write!(f, "{op} ({type_})"),
|
||||||
UnOp { op, type_ } => write!(f, "{op}, {type_}"),
|
UnOp { op, type_ } => write!(f, "{op}, {type_}"),
|
||||||
Push { prim, value } => write!(f, "push {value} ({prim})"),
|
Push { prim, value } => write!(f, "push {value} ({prim})"),
|
||||||
NewLocal { uid, type_ } => write!(f, "local ${uid} = {type_}"),
|
New { uid, type_ } => write!(f, "local ${uid} = {type_}"),
|
||||||
AssignLocal { uid } => write!(f, "pop local ${uid}"),
|
Set { uid } => write!(f, "pop local ${uid}"),
|
||||||
GetLocal { uid } => write!(f, "push local ${uid}"),
|
Get { uid } => write!(f, "push local ${uid}"),
|
||||||
NewGlobal { uid, type_ } => write!(f, "global ${uid} = {type_}"),
|
StartFunc {
|
||||||
AssignGlobal { uid } => write!(f, "pop global ${uid}"),
|
uid,
|
||||||
GetGlobal { uid } => write!(f, "push global ${uid}"),
|
params,
|
||||||
StartFunc { uid } => write!(f, "<function id=${uid}>"),
|
returns,
|
||||||
|
} => write!(
|
||||||
|
f,
|
||||||
|
"<function id=${uid} params={params:?} returns={returns}>"
|
||||||
|
),
|
||||||
EndFunc => write!(f, "</function>"),
|
EndFunc => write!(f, "</function>"),
|
||||||
NewParam { uid, type_ } => write!(f, "param ${uid} = {type_}"),
|
|
||||||
Return => write!(f, "return"),
|
Return => write!(f, "return"),
|
||||||
Call { uid } => write!(f, "call ${uid}"),
|
Call { uid } => write!(f, "call ${uid}"),
|
||||||
Drop => write!(f, "pop"),
|
Drop => write!(f, "pop"),
|
||||||
ReturnType { type_ } => write!(f, "result {type_}"),
|
ReturnType { type_ } => write!(f, "result {type_}"),
|
||||||
Print => write!(f, "print [DEBUG]"),
|
Print { type_ } => write!(f, "print {type_} [DEBUG]"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Compiler {
|
||||||
|
ir: Vec<IR>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Compiler {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self { ir: vec![] }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push(&mut self, ir: IR) {
|
||||||
|
self.ir.push(ir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
impl IR {
|
impl IR {
|
||||||
pub fn to_wat(&self) -> String {
|
pub fn to_wat(&self) -> String {
|
||||||
use BinaryOp as b;
|
use BinaryOp as b;
|
|
@ -99,13 +99,10 @@ fn typecheck(input: &'static str) -> Vec<Statement> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
/*
|
|
||||||
for s in typecheck(include_str!("../demo.hal")) {
|
for s in typecheck(include_str!("../demo.hal")) {
|
||||||
println!("{s:#?}");
|
|
||||||
println!("------------------");
|
println!("------------------");
|
||||||
|
println!("{s:#?}");
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
typecheck(include_str!("../demo.hal"));
|
|
||||||
//let module = frontend::Module::from_file("./demo.hal")?;
|
//let module = frontend::Module::from_file("./demo.hal")?;
|
||||||
//module.write_to("test");
|
//module.write_to("test");
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -67,6 +67,7 @@ pub enum ExpressionKind {
|
||||||
StructLiteral {
|
StructLiteral {
|
||||||
name: String,
|
name: String,
|
||||||
args: Vec<(String, Expression)>,
|
args: Vec<(String, Expression)>,
|
||||||
|
id: UID,
|
||||||
},
|
},
|
||||||
Field {
|
Field {
|
||||||
namespace: Box<Expression>,
|
namespace: Box<Expression>,
|
||||||
|
@ -121,7 +122,7 @@ impl std::fmt::Debug for ExpressionKind {
|
||||||
write!(f, "(fn({params:?}) -> {returns_actual:?})")
|
write!(f, "(fn({params:?}) -> {returns_actual:?})")
|
||||||
},
|
},
|
||||||
e::StructDef(params, _) => write!(f, "struct {{ {params:?} }}"),
|
e::StructDef(params, _) => write!(f, "struct {{ {params:?} }}"),
|
||||||
e::StructLiteral { name, args } => write!(f, "{name} {{ {args:?} }}"),
|
e::StructLiteral { name, args, .. } => write!(f, "{name} {{ {args:?} }}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -410,7 +411,11 @@ impl<I: Iterator<Item = Token>> Parser<I> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.eat(t::RightBrace)?;
|
self.eat(t::RightBrace)?;
|
||||||
e::StructLiteral { name, args }
|
e::StructLiteral {
|
||||||
|
name,
|
||||||
|
args,
|
||||||
|
id: "".into(),
|
||||||
|
}
|
||||||
},
|
},
|
||||||
t::Identifier(i) => {
|
t::Identifier(i) => {
|
||||||
self.skip(1);
|
self.skip(1);
|
||||||
|
|
|
@ -1,10 +1,4 @@
|
||||||
use crate::{
|
use crate::{Statement, semantic::SymbolTable};
|
||||||
Expression, ExpressionKind, Immediate, Statement, StatementKind,
|
|
||||||
err::*,
|
|
||||||
semantic::{Primitive, SymbolTable},
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::Type;
|
|
||||||
|
|
||||||
pub struct Analyzer {
|
pub struct Analyzer {
|
||||||
pub table: SymbolTable,
|
pub table: SymbolTable,
|
||||||
|
@ -18,6 +12,12 @@ impl Analyzer {
|
||||||
for s in &mut statements {
|
for s in &mut statements {
|
||||||
*s = *this.naming_pass_stmt(s.clone().into()).unwrap();
|
*s = *this.naming_pass_stmt(s.clone().into()).unwrap();
|
||||||
}
|
}
|
||||||
|
for s in &mut statements {
|
||||||
|
*s = *this.bottom_up_stmt(s.clone().into()).unwrap();
|
||||||
|
}
|
||||||
|
for s in &mut statements {
|
||||||
|
*s = *this.top_down_stmt(s.clone().into()).unwrap();
|
||||||
|
}
|
||||||
println!("-----TABLE------");
|
println!("-----TABLE------");
|
||||||
println!("{:#?}", this.table.table);
|
println!("{:#?}", this.table.table);
|
||||||
println!("-----FUNCS------");
|
println!("-----FUNCS------");
|
||||||
|
@ -26,224 +26,4 @@ impl Analyzer {
|
||||||
println!("{:#?}", this.table.structs);
|
println!("{:#?}", this.table.structs);
|
||||||
statements
|
statements
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn naming_pass_stmt(
|
|
||||||
&mut self,
|
|
||||||
mut stmt: Box<Statement>,
|
|
||||||
) -> Result<Box<Statement>> {
|
|
||||||
use StatementKind as s;
|
|
||||||
stmt.kind = match stmt.kind {
|
|
||||||
s::Declaration {
|
|
||||||
name,
|
|
||||||
type_str,
|
|
||||||
mut type_actual,
|
|
||||||
mut value,
|
|
||||||
mutable,
|
|
||||||
mut uid,
|
|
||||||
} => {
|
|
||||||
value = *self.naming_pass_expr(value.into())?;
|
|
||||||
if let Some(ref type_str) = type_str {
|
|
||||||
type_actual = self.table.reference_ident(type_str).type_;
|
|
||||||
} else {
|
|
||||||
type_actual = value.type_.clone();
|
|
||||||
}
|
|
||||||
let symbol =
|
|
||||||
self
|
|
||||||
.table
|
|
||||||
.define_ident(&name, type_actual.clone(), mutable)?;
|
|
||||||
uid = symbol.uid;
|
|
||||||
s::Declaration {
|
|
||||||
name,
|
|
||||||
type_str,
|
|
||||||
type_actual,
|
|
||||||
value,
|
|
||||||
mutable,
|
|
||||||
uid,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
s::Assignment {
|
|
||||||
name,
|
|
||||||
mut value,
|
|
||||||
mut uid,
|
|
||||||
} => {
|
|
||||||
uid = self.table.reference_ident(&name).uid;
|
|
||||||
value = *self.naming_pass_expr(value.into())?;
|
|
||||||
// Hint ident is rhs type and mutable
|
|
||||||
self.table.modify_ident(
|
|
||||||
uid.clone(),
|
|
||||||
None,
|
|
||||||
Some(value.type_.clone()),
|
|
||||||
Some(true),
|
|
||||||
false,
|
|
||||||
)?;
|
|
||||||
s::Assignment { name, value, uid }
|
|
||||||
},
|
|
||||||
s::If {
|
|
||||||
mut predicate,
|
|
||||||
mut block,
|
|
||||||
mut else_,
|
|
||||||
} => {
|
|
||||||
predicate = *self.naming_pass_expr(predicate.into())?;
|
|
||||||
self.table.start_block();
|
|
||||||
for s in &mut block {
|
|
||||||
*s = *self.naming_pass_stmt(s.clone().into())?;
|
|
||||||
}
|
|
||||||
self.table.end_block();
|
|
||||||
else_ = if let Some(else_) = else_ {
|
|
||||||
Some(self.naming_pass_stmt(else_)?)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
s::If {
|
|
||||||
predicate,
|
|
||||||
block,
|
|
||||||
else_,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
s::While {
|
|
||||||
mut predicate,
|
|
||||||
mut block,
|
|
||||||
} => {
|
|
||||||
predicate = *self.naming_pass_expr(predicate.into())?;
|
|
||||||
self.table.start_block();
|
|
||||||
for s in &mut block {
|
|
||||||
*s = *self.naming_pass_stmt(s.clone().into())?;
|
|
||||||
}
|
|
||||||
self.table.end_block();
|
|
||||||
s::While { predicate, block }
|
|
||||||
},
|
|
||||||
s::Print(mut expression) => {
|
|
||||||
expression = *self.naming_pass_expr(expression.into())?;
|
|
||||||
s::Print(expression)
|
|
||||||
},
|
|
||||||
s::Expression(mut expression) => {
|
|
||||||
expression = *self.naming_pass_expr(expression.into())?;
|
|
||||||
s::Expression(expression)
|
|
||||||
},
|
|
||||||
s::Block(mut block) => {
|
|
||||||
self.table.start_block();
|
|
||||||
for s in &mut block {
|
|
||||||
*s = *self.naming_pass_stmt(s.clone().into())?;
|
|
||||||
}
|
|
||||||
self.table.end_block();
|
|
||||||
s::Block(block)
|
|
||||||
},
|
|
||||||
s::Return(mut expression) => {
|
|
||||||
if let Some(e) = expression {
|
|
||||||
expression = Some(*self.naming_pass_expr(e.into())?);
|
|
||||||
}
|
|
||||||
s::Return(expression)
|
|
||||||
},
|
|
||||||
s::Error(diagnostic) => s::Error(diagnostic),
|
|
||||||
};
|
|
||||||
Ok(stmt)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn naming_pass_expr(
|
|
||||||
&mut self,
|
|
||||||
mut expr: Box<Expression>,
|
|
||||||
) -> Result<Box<Expression>> {
|
|
||||||
use ExpressionKind as e;
|
|
||||||
expr.kind = match expr.kind {
|
|
||||||
e::Immediate(immediate) => {
|
|
||||||
expr.type_ = Type::Prim(match &immediate {
|
|
||||||
Immediate::Integer(_, _) => Primitive::integer_ambiguous,
|
|
||||||
Immediate::Real(_) => Primitive::real_ambiguous,
|
|
||||||
Immediate::String(_) => Primitive::string,
|
|
||||||
Immediate::Glyph(_) => Primitive::glyph,
|
|
||||||
Immediate::Boolean(_) => Primitive::boolean,
|
|
||||||
});
|
|
||||||
e::Immediate(immediate)
|
|
||||||
},
|
|
||||||
e::Identifier(name, mut mangle) => {
|
|
||||||
let sym = self.table.reference_ident(&name);
|
|
||||||
mangle = sym.uid;
|
|
||||||
expr.type_ = sym.type_;
|
|
||||||
e::Identifier(name, mangle)
|
|
||||||
},
|
|
||||||
e::Binary {
|
|
||||||
op,
|
|
||||||
mut left,
|
|
||||||
mut right,
|
|
||||||
} => {
|
|
||||||
left = self.naming_pass_expr(left)?;
|
|
||||||
right = self.naming_pass_expr(right)?;
|
|
||||||
e::Binary { op, left, right }
|
|
||||||
},
|
|
||||||
e::Unary { op, mut child } => {
|
|
||||||
child = self.naming_pass_expr(child)?;
|
|
||||||
e::Unary { op, child }
|
|
||||||
},
|
|
||||||
e::Parenthesis(mut expression) => {
|
|
||||||
expression = self.naming_pass_expr(expression)?;
|
|
||||||
e::Parenthesis(expression)
|
|
||||||
},
|
|
||||||
e::FunctionDef {
|
|
||||||
params,
|
|
||||||
returns_str,
|
|
||||||
returns_actual,
|
|
||||||
mut body,
|
|
||||||
mut id,
|
|
||||||
} => {
|
|
||||||
id = self
|
|
||||||
.table
|
|
||||||
.create_function(params.clone(), returns_str.clone());
|
|
||||||
expr.type_ = Type::Function(id.clone());
|
|
||||||
self.table.start_function();
|
|
||||||
for s in &mut body {
|
|
||||||
*s = *self.naming_pass_stmt(s.clone().into())?;
|
|
||||||
}
|
|
||||||
self.table.end_function();
|
|
||||||
e::FunctionDef {
|
|
||||||
params,
|
|
||||||
returns_str,
|
|
||||||
returns_actual,
|
|
||||||
body,
|
|
||||||
id,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
e::FunctionCall {
|
|
||||||
mut callee,
|
|
||||||
mut args,
|
|
||||||
is_reference,
|
|
||||||
id,
|
|
||||||
} => {
|
|
||||||
callee = self.naming_pass_expr(callee)?;
|
|
||||||
for a in &mut args {
|
|
||||||
*a = *self.naming_pass_expr(a.clone().into())?;
|
|
||||||
}
|
|
||||||
e::FunctionCall {
|
|
||||||
callee,
|
|
||||||
args,
|
|
||||||
is_reference,
|
|
||||||
id,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
e::StructDef(params, mut sid) => {
|
|
||||||
sid = self.table.create_struct(params.clone());
|
|
||||||
expr.type_ = Type::Alias(Box::new(Type::Struct(sid)));
|
|
||||||
e::StructDef(params, sid)
|
|
||||||
},
|
|
||||||
e::StructLiteral { name, mut args } => {
|
|
||||||
self.table.reference_ident(&name);
|
|
||||||
for (_, a) in &mut args {
|
|
||||||
*a = *self.naming_pass_expr(a.clone().into())?;
|
|
||||||
}
|
|
||||||
e::StructLiteral { name, args }
|
|
||||||
},
|
|
||||||
e::Field {
|
|
||||||
mut namespace,
|
|
||||||
field,
|
|
||||||
uid,
|
|
||||||
} => {
|
|
||||||
namespace = self.naming_pass_expr(namespace)?;
|
|
||||||
e::Field {
|
|
||||||
namespace,
|
|
||||||
field,
|
|
||||||
uid,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
Ok(expr)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,25 +1,283 @@
|
||||||
use super::Analyzer;
|
use super::Analyzer;
|
||||||
use crate::{
|
use crate::{Expression, ExpressionKind, Statement, StatementKind, err::*};
|
||||||
Expression, ExpressionKind, Immediate, Statement, StatementKind,
|
|
||||||
err::*,
|
|
||||||
semantic::{Primitive, SymbolTable},
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::Type;
|
use super::Type;
|
||||||
|
|
||||||
impl Analyzer {
|
impl Analyzer {
|
||||||
pub fn stmt_bottom_up(
|
pub fn bottom_up_stmt(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut stmt: Box<Statement>,
|
mut stmt: Box<Statement>,
|
||||||
) -> Result<Box<Statement>> {
|
) -> Result<Box<Statement>> {
|
||||||
todo!()
|
use StatementKind as s;
|
||||||
|
stmt.kind = match stmt.kind {
|
||||||
|
s::Declaration {
|
||||||
|
name,
|
||||||
|
type_str,
|
||||||
|
mut type_actual,
|
||||||
|
mut value,
|
||||||
|
mutable,
|
||||||
|
uid,
|
||||||
|
} => {
|
||||||
|
value = *self.bottom_up_expr(value.into())?;
|
||||||
|
if let Some(ref uid) = type_str {
|
||||||
|
type_actual =
|
||||||
|
self.table.resolve_type(uid)?.is_alias().span(&stmt.span)?;
|
||||||
|
}
|
||||||
|
value.type_ = value
|
||||||
|
.type_
|
||||||
|
.deduce(&type_actual)
|
||||||
|
.span(&value.span)?
|
||||||
|
.promote();
|
||||||
|
type_actual = value.type_.clone();
|
||||||
|
if let Type::Ambiguous = type_actual {
|
||||||
|
return error()
|
||||||
|
.reason(format!("Cannot deduce type of {name}"))
|
||||||
|
.span(&stmt.span);
|
||||||
|
}
|
||||||
|
self.table.modify_ident(
|
||||||
|
uid.clone(),
|
||||||
|
None,
|
||||||
|
Some(type_actual.clone()),
|
||||||
|
None,
|
||||||
|
true,
|
||||||
|
)?;
|
||||||
|
s::Declaration {
|
||||||
|
name,
|
||||||
|
type_str,
|
||||||
|
type_actual,
|
||||||
|
value,
|
||||||
|
mutable,
|
||||||
|
uid,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
s::Assignment {
|
||||||
|
name,
|
||||||
|
mut value,
|
||||||
|
uid,
|
||||||
|
} => {
|
||||||
|
value = *self.bottom_up_expr(value.into())?;
|
||||||
|
self.table.modify_ident(
|
||||||
|
uid.clone(),
|
||||||
|
None,
|
||||||
|
Some(value.type_.clone()),
|
||||||
|
Some(true),
|
||||||
|
true,
|
||||||
|
)?;
|
||||||
|
s::Assignment { name, value, uid }
|
||||||
|
},
|
||||||
|
s::If {
|
||||||
|
mut predicate,
|
||||||
|
mut block,
|
||||||
|
mut else_,
|
||||||
|
} => {
|
||||||
|
predicate = *self.bottom_up_expr(predicate.into())?;
|
||||||
|
self.table.start_block();
|
||||||
|
for s in &mut block {
|
||||||
|
*s = *self.bottom_up_stmt(s.clone().into())?;
|
||||||
|
}
|
||||||
|
self.table.end_block();
|
||||||
|
else_ = if let Some(else_) = else_ {
|
||||||
|
Some(self.bottom_up_stmt(else_)?)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
s::If {
|
||||||
|
predicate,
|
||||||
|
block,
|
||||||
|
else_,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
s::While {
|
||||||
|
mut predicate,
|
||||||
|
mut block,
|
||||||
|
} => {
|
||||||
|
predicate = *self.bottom_up_expr(predicate.into())?;
|
||||||
|
self.table.start_block();
|
||||||
|
for s in &mut block {
|
||||||
|
*s = *self.bottom_up_stmt(s.clone().into())?;
|
||||||
|
}
|
||||||
|
self.table.end_block();
|
||||||
|
s::While { predicate, block }
|
||||||
|
},
|
||||||
|
s::Print(mut expression) => {
|
||||||
|
expression = *self.bottom_up_expr(expression.into())?;
|
||||||
|
s::Print(expression)
|
||||||
|
},
|
||||||
|
s::Expression(mut expression) => {
|
||||||
|
expression = *self.bottom_up_expr(expression.into())?;
|
||||||
|
s::Expression(expression)
|
||||||
|
},
|
||||||
|
s::Block(mut block) => {
|
||||||
|
for s in &mut block {
|
||||||
|
*s = *self.bottom_up_stmt(s.clone().into())?;
|
||||||
|
}
|
||||||
|
s::Block(block)
|
||||||
|
},
|
||||||
|
s::Return(mut expression) => {
|
||||||
|
expression = if let Some(e) = expression {
|
||||||
|
Some(*self.bottom_up_expr(e.into())?)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
s::Return(expression)
|
||||||
|
},
|
||||||
|
s::Error(diagnostic) => s::Error(diagnostic),
|
||||||
|
};
|
||||||
|
Ok(stmt)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bottom up type inference
|
// Bottom up type inference
|
||||||
pub fn expr_bottom_up(
|
pub fn bottom_up_expr(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut expr: Box<Expression>,
|
mut expr: Box<Expression>,
|
||||||
) -> Result<Box<Expression>> {
|
) -> Result<Box<Expression>> {
|
||||||
todo!()
|
use ExpressionKind as e;
|
||||||
|
expr.kind = match expr.kind {
|
||||||
|
// Type assigned in naming step
|
||||||
|
e::Immediate(immediate) => e::Immediate(immediate),
|
||||||
|
e::Identifier(name, mangle) => {
|
||||||
|
expr.type_ = self
|
||||||
|
.table
|
||||||
|
.resolve_type(&mangle)
|
||||||
|
.trace_span(expr.span, format!("While resolving type of '{name}'"))?;
|
||||||
|
e::Identifier(name, mangle)
|
||||||
|
},
|
||||||
|
e::Binary {
|
||||||
|
op,
|
||||||
|
mut left,
|
||||||
|
mut right,
|
||||||
|
} => {
|
||||||
|
left = self.bottom_up_expr(left)?;
|
||||||
|
right = self.bottom_up_expr(right)?;
|
||||||
|
expr.type_ =
|
||||||
|
Type::binary_op(&left.type_, op, &right.type_).span(&expr.span)?;
|
||||||
|
e::Binary { op, left, right }
|
||||||
|
},
|
||||||
|
e::Unary { op, mut child } => {
|
||||||
|
child = self.bottom_up_expr(child)?;
|
||||||
|
expr.type_ = Type::unary_op(op, &child.type_)?;
|
||||||
|
e::Unary { op, child }
|
||||||
|
},
|
||||||
|
e::Parenthesis(mut expression) => {
|
||||||
|
expression = self.bottom_up_expr(expression)?;
|
||||||
|
expr.type_ = expression.type_.clone();
|
||||||
|
e::Parenthesis(expression)
|
||||||
|
},
|
||||||
|
e::FunctionDef {
|
||||||
|
mut params,
|
||||||
|
returns_str,
|
||||||
|
mut returns_actual,
|
||||||
|
mut body,
|
||||||
|
id,
|
||||||
|
} => {
|
||||||
|
let funcdef = self.table.functions[id].clone();
|
||||||
|
self.table.start_function();
|
||||||
|
for (uid, param) in funcdef.params.iter().zip(params.iter_mut()) {
|
||||||
|
let type_ = self.table.resolve_type(uid).span(&expr.span)?;
|
||||||
|
param.type_actual = type_;
|
||||||
|
}
|
||||||
|
for s in &mut body {
|
||||||
|
*s = *self.bottom_up_stmt(s.clone().into())?;
|
||||||
|
}
|
||||||
|
self.table.end_function();
|
||||||
|
returns_actual =
|
||||||
|
self.table.resolve_type(&funcdef.returns).span(&expr.span)?;
|
||||||
|
e::FunctionDef {
|
||||||
|
params,
|
||||||
|
returns_str,
|
||||||
|
returns_actual,
|
||||||
|
body,
|
||||||
|
id,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
e::FunctionCall {
|
||||||
|
mut callee,
|
||||||
|
mut args,
|
||||||
|
is_reference,
|
||||||
|
id,
|
||||||
|
} => {
|
||||||
|
callee = self.bottom_up_expr(callee)?;
|
||||||
|
match callee.type_ {
|
||||||
|
Type::Function(fid) => {
|
||||||
|
expr.type_ = self
|
||||||
|
.table
|
||||||
|
.resolve_type(&self.table.functions[fid].returns)
|
||||||
|
.span(&callee.span)?
|
||||||
|
.is_alias()
|
||||||
|
.span(&expr.span)?
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
return error()
|
||||||
|
.reason(format!("Cannot call type {}", callee.type_))
|
||||||
|
.span(&expr.span);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for a in &mut args {
|
||||||
|
*a = *self.bottom_up_expr(a.clone().into())?;
|
||||||
|
}
|
||||||
|
e::FunctionCall {
|
||||||
|
callee,
|
||||||
|
args,
|
||||||
|
is_reference,
|
||||||
|
id,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
e::StructDef(mut params, sid) => {
|
||||||
|
let struct_ = &self.table.structs[sid].0;
|
||||||
|
for ((_, uid), p) in struct_.iter().zip(params.iter_mut()) {
|
||||||
|
p.type_actual = self
|
||||||
|
.table
|
||||||
|
.resolve_type(uid)
|
||||||
|
.trace_span(expr.span, "For struct field")?;
|
||||||
|
}
|
||||||
|
e::StructDef(params, sid)
|
||||||
|
},
|
||||||
|
e::StructLiteral { name, mut args, id } => {
|
||||||
|
expr.type_ = self
|
||||||
|
.table
|
||||||
|
.resolve_type(&id)
|
||||||
|
.span(&expr.span)?
|
||||||
|
.is_alias()
|
||||||
|
.span(&expr.span)?;
|
||||||
|
for (_name, arg) in &mut args {
|
||||||
|
*arg = *self.bottom_up_expr(arg.clone().into())?;
|
||||||
|
}
|
||||||
|
e::StructLiteral { name, args, id }
|
||||||
|
},
|
||||||
|
e::Field {
|
||||||
|
mut namespace,
|
||||||
|
field,
|
||||||
|
uid,
|
||||||
|
} => {
|
||||||
|
namespace = self.bottom_up_expr(namespace)?;
|
||||||
|
if let Type::Struct(s) = namespace.type_ {
|
||||||
|
if let e::Identifier(name, _) = &field.kind {
|
||||||
|
expr.type_ = self
|
||||||
|
.table
|
||||||
|
.get_field(s, name)
|
||||||
|
.span(&expr.span)?
|
||||||
|
.is_alias()
|
||||||
|
.reason("Expected type, found value")
|
||||||
|
.span(&expr.span)?;
|
||||||
|
} else {
|
||||||
|
return error().reason("Field must be identifier").span(&expr.span);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return error()
|
||||||
|
.reason(format!(
|
||||||
|
"Type '{}' does not contain fields",
|
||||||
|
namespace.type_
|
||||||
|
))
|
||||||
|
.span(&expr.span);
|
||||||
|
}
|
||||||
|
// TODO handle name mangle
|
||||||
|
e::Field {
|
||||||
|
namespace,
|
||||||
|
field,
|
||||||
|
uid,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
Ok(expr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
mod analyzer;
|
mod analyzer;
|
||||||
mod bottom_up;
|
mod bottom_up;
|
||||||
|
mod naming;
|
||||||
mod primitives;
|
mod primitives;
|
||||||
mod top_down;
|
mod top_down;
|
||||||
mod types;
|
mod types;
|
||||||
|
@ -11,6 +12,12 @@ pub use analyzer::*;
|
||||||
pub use primitives::*;
|
pub use primitives::*;
|
||||||
pub use types::*;
|
pub use types::*;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
enum Scope {
|
||||||
|
Block,
|
||||||
|
Function,
|
||||||
|
}
|
||||||
|
|
||||||
// Mangled name
|
// Mangled name
|
||||||
pub type UID = String;
|
pub type UID = String;
|
||||||
|
|
||||||
|
@ -23,18 +30,6 @@ pub struct Symbol {
|
||||||
mutable: Option<bool>,
|
mutable: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Symbol {
|
|
||||||
pub fn assert_is_type(&self) -> Result<Type> {
|
|
||||||
if let Type::Alias(ref t) = self.type_ {
|
|
||||||
return Ok(*t.clone());
|
|
||||||
}
|
|
||||||
error().reason(format!(
|
|
||||||
"The name '{}' refers to a value, not a type",
|
|
||||||
self.name
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
enum Definition {
|
enum Definition {
|
||||||
Ident(Symbol),
|
Ident(Symbol),
|
||||||
|
@ -86,23 +81,47 @@ impl SymbolTable {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn end_block(&mut self) {
|
pub fn end_block(&mut self) {
|
||||||
|
let mut escaped = vec![];
|
||||||
while !self.scope.is_empty() {
|
while !self.scope.is_empty() {
|
||||||
if let Some(Definition::BlockStart) = self.scope.pop() {
|
let top = self.scope.pop();
|
||||||
|
if let Some(Definition::BlockStart) = top {
|
||||||
|
self.scope.append(&mut escaped);
|
||||||
return;
|
return;
|
||||||
|
} else if let Some(Definition::Ident(s)) = top {
|
||||||
|
if !s.initialized {
|
||||||
|
escaped.push(Definition::Ident(s));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unreachable!("Cannot end global scope")
|
unreachable!("Cannot end global scope")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn resolve_type(&self, uid: &UID) -> Result<Type> {
|
||||||
|
let symbol = self.table.get(uid).unwrap();
|
||||||
|
if symbol.initialized == false {
|
||||||
|
return error().reason("Symbol was never initialized");
|
||||||
|
} else {
|
||||||
|
Ok(symbol.type_.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn start_function(&mut self) {
|
pub fn start_function(&mut self) {
|
||||||
self.nesting += 1;
|
self.nesting += 1;
|
||||||
self.scope.push(Definition::FuncStart);
|
self.scope.push(Definition::FuncStart);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn end_function(&mut self) {
|
pub fn end_function(&mut self) {
|
||||||
|
self.nesting -= 1;
|
||||||
|
let mut escaped = vec![];
|
||||||
while !self.scope.is_empty() {
|
while !self.scope.is_empty() {
|
||||||
if let Some(Definition::FuncStart) = self.scope.pop() {
|
let top = self.scope.pop();
|
||||||
|
if let Some(Definition::FuncStart) = top {
|
||||||
|
self.scope.append(&mut escaped);
|
||||||
return;
|
return;
|
||||||
|
} else if let Some(Definition::Ident(s)) = top {
|
||||||
|
if !s.initialized {
|
||||||
|
escaped.push(Definition::Ident(s));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unreachable!("Cannot end global scope")
|
unreachable!("Cannot end global scope")
|
||||||
|
@ -114,6 +133,16 @@ impl SymbolTable {
|
||||||
uid
|
uid
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_field(&self, struct_id: SID, field_name: &str) -> Result<Type> {
|
||||||
|
let struct_def = &self.structs[struct_id].0;
|
||||||
|
for (name, sid) in struct_def {
|
||||||
|
if name == field_name {
|
||||||
|
return self.resolve_type(sid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
error().reason(format!("Cannot find field '{field_name}'"))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn create_struct(&mut self, params: Vec<Parameter>) -> SID {
|
pub fn create_struct(&mut self, params: Vec<Parameter>) -> SID {
|
||||||
let sid = self.structs.len();
|
let sid = self.structs.len();
|
||||||
let mut new_params = vec![];
|
let mut new_params = vec![];
|
||||||
|
@ -129,23 +158,31 @@ impl SymbolTable {
|
||||||
&mut self,
|
&mut self,
|
||||||
params: Vec<Parameter>,
|
params: Vec<Parameter>,
|
||||||
returns: Option<String>,
|
returns: Option<String>,
|
||||||
) -> FID {
|
) -> Result<FID> {
|
||||||
let fid = self.functions.len();
|
let fid = self.functions.len();
|
||||||
let mut new_params = vec![];
|
let mut symbols = vec![];
|
||||||
for p in params {
|
for p in ¶ms {
|
||||||
let s = self.reference_ident(&p.type_str);
|
let symbol = self.reference_ident(&p.type_str);
|
||||||
new_params.push(s.uid);
|
symbols.push(symbol);
|
||||||
}
|
}
|
||||||
let returns = if let Some(s) = returns {
|
let returns = if let Some(s) = returns {
|
||||||
Some(self.reference_ident(&s).uid)
|
self.reference_ident(&s).uid
|
||||||
} else {
|
} else {
|
||||||
Some(nothing_mangle())
|
nothing_mangle()
|
||||||
};
|
};
|
||||||
|
self.start_function();
|
||||||
|
let mut new_params = vec![];
|
||||||
|
for (p, s) in params.iter().zip(symbols.iter()) {
|
||||||
|
let s = self
|
||||||
|
.define_ident(&p.name, s.type_.clone(), false)
|
||||||
|
.trace("While initializing function parameters")?;
|
||||||
|
new_params.push(s.uid);
|
||||||
|
}
|
||||||
self.functions.push(FunctionDef {
|
self.functions.push(FunctionDef {
|
||||||
params: new_params,
|
params: new_params,
|
||||||
returns,
|
returns,
|
||||||
});
|
});
|
||||||
fid
|
Ok(fid)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn modify_ident(
|
pub fn modify_ident(
|
||||||
|
@ -156,15 +193,17 @@ impl SymbolTable {
|
||||||
mutable: Option<bool>,
|
mutable: Option<bool>,
|
||||||
init: bool,
|
init: bool,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
{
|
|
||||||
let symbol = self.table.get_mut(&uid).unwrap();
|
let symbol = self.table.get_mut(&uid).unwrap();
|
||||||
if let Some(ref type_) = type_ {
|
if let Some(ref type_) = type_ {
|
||||||
symbol.type_ = symbol.type_.clone().deduce(type_)?;
|
symbol.type_ = symbol.type_.clone().deduce(type_)?;
|
||||||
}
|
}
|
||||||
if let Some(m) = mutable {
|
symbol.mutable = match (symbol.mutable, mutable) {
|
||||||
symbol.mutable = Some(m);
|
(Some(true), Some(false)) | (Some(false), Some(true)) => {
|
||||||
}
|
return error().reason("Cannot mutate immutable symbol");
|
||||||
}
|
},
|
||||||
|
_ => mutable,
|
||||||
|
};
|
||||||
|
symbol.initialized |= init;
|
||||||
|
|
||||||
let mut nesting = self.nesting;
|
let mut nesting = self.nesting;
|
||||||
for def in &mut self.scope {
|
for def in &mut self.scope {
|
||||||
|
@ -179,17 +218,21 @@ impl SymbolTable {
|
||||||
if let Some(ref type_) = type_ {
|
if let Some(ref type_) = type_ {
|
||||||
symbol.type_ = symbol.type_.clone().deduce(type_)?;
|
symbol.type_ = symbol.type_.clone().deduce(type_)?;
|
||||||
}
|
}
|
||||||
if let Some(m) = mutable {
|
symbol.mutable = match (symbol.mutable, mutable) {
|
||||||
symbol.mutable = Some(m);
|
(Some(true), Some(false)) | (Some(false), Some(true)) => {
|
||||||
}
|
return error().reason("Cannot mutate immutable symbol");
|
||||||
symbol.initialized &= init;
|
},
|
||||||
|
_ => mutable,
|
||||||
|
};
|
||||||
|
symbol.initialized |= init;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
},
|
},
|
||||||
Definition::FuncStart => nesting -= 1,
|
Definition::FuncStart => nesting -= 1,
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
panic!("Symbol {uid} does not exist")
|
Ok(())
|
||||||
|
//unreachable!("Symbol {uid} does not exist")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn define_ident(
|
pub fn define_ident(
|
||||||
|
@ -198,7 +241,15 @@ impl SymbolTable {
|
||||||
type_: Type,
|
type_: Type,
|
||||||
mutable: bool,
|
mutable: bool,
|
||||||
) -> Result<Symbol> {
|
) -> Result<Symbol> {
|
||||||
if let Ok(s) = self.lookup_this_scope(name) {
|
println!("---{name}---");
|
||||||
|
println!("{:#?}", self.lookup_block_scope(name));
|
||||||
|
if let Type::Alias(_) | Type::Function(_) = &type_ {
|
||||||
|
if mutable {
|
||||||
|
return error()
|
||||||
|
.reason("Struct and function definitions cannot be mutable");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Ok(s) = self.lookup_block_scope(name) {
|
||||||
// Re-definition error
|
// Re-definition error
|
||||||
// TODO support name shadowing
|
// TODO support name shadowing
|
||||||
if s.initialized {
|
if s.initialized {
|
||||||
|
@ -232,7 +283,7 @@ impl SymbolTable {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reference_ident(&mut self, name: &str) -> Symbol {
|
pub fn reference_ident(&mut self, name: &str) -> Symbol {
|
||||||
match self.lookup_available_scope(name) {
|
match self.lookup_function_scope(name) {
|
||||||
Ok(s) => s,
|
Ok(s) => s,
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
let uid = self.generate_uid(name);
|
let uid = self.generate_uid(name);
|
||||||
|
@ -250,24 +301,29 @@ impl SymbolTable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lookup_this_scope(&self, name: &str) -> Result<Symbol> {
|
pub fn lookup_block_scope(&self, name: &str) -> Result<Symbol> {
|
||||||
self.lookup_scope(name, false)
|
self.lookup_scope(name, Scope::Block)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lookup_available_scope(&self, name: &str) -> Result<Symbol> {
|
pub fn lookup_function_scope(&self, name: &str) -> Result<Symbol> {
|
||||||
self.lookup_scope(name, true)
|
self.lookup_scope(name, Scope::Function)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lookup_scope(&self, name: &str, with_global: bool) -> Result<Symbol> {
|
fn lookup_scope(&self, name: &str, scope: Scope) -> Result<Symbol> {
|
||||||
let mut nesting = self.nesting;
|
let mut nesting = self.nesting;
|
||||||
for def in &self.scope {
|
for def in self.scope.iter().rev() {
|
||||||
match def {
|
match def {
|
||||||
Definition::Ident(symbol)
|
Definition::Ident(symbol)
|
||||||
if (symbol.name == name)
|
if (symbol.name == name)
|
||||||
&& ((nesting == 0 && with_global) || nesting == self.nesting) =>
|
&& ((nesting == 0) || nesting == self.nesting) =>
|
||||||
{
|
{
|
||||||
return Ok(symbol.clone());
|
return Ok(symbol.clone());
|
||||||
},
|
},
|
||||||
|
Definition::FuncStart | Definition::BlockStart
|
||||||
|
if scope == Scope::Block =>
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
},
|
||||||
Definition::FuncStart => nesting -= 1,
|
Definition::FuncStart => nesting -= 1,
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
|
|
234
src/semantic/naming.rs
Normal file
234
src/semantic/naming.rs
Normal file
|
@ -0,0 +1,234 @@
|
||||||
|
use super::Analyzer;
|
||||||
|
use crate::{
|
||||||
|
Expression, ExpressionKind, Immediate, Statement, StatementKind, err::*,
|
||||||
|
semantic::Primitive,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::Type;
|
||||||
|
|
||||||
|
impl Analyzer {
|
||||||
|
pub fn naming_pass_stmt(
|
||||||
|
&mut self,
|
||||||
|
mut stmt: Box<Statement>,
|
||||||
|
) -> Result<Box<Statement>> {
|
||||||
|
use StatementKind as s;
|
||||||
|
stmt.kind = match stmt.kind {
|
||||||
|
s::Declaration {
|
||||||
|
name,
|
||||||
|
mut type_str,
|
||||||
|
type_actual,
|
||||||
|
mut value,
|
||||||
|
mutable,
|
||||||
|
mut uid,
|
||||||
|
} => {
|
||||||
|
value = *self.naming_pass_expr(value.into())?;
|
||||||
|
let type_ = if let Some(ref s) = type_str {
|
||||||
|
let s = self.table.reference_ident(s);
|
||||||
|
type_str = Some(s.uid.clone());
|
||||||
|
s.type_.is_alias().unwrap_or(Type::Ambiguous)
|
||||||
|
} else {
|
||||||
|
value.type_.clone()
|
||||||
|
};
|
||||||
|
println!("{type_:?}");
|
||||||
|
let symbol = self.table.define_ident(&name, type_, mutable)?;
|
||||||
|
uid = symbol.uid;
|
||||||
|
s::Declaration {
|
||||||
|
name,
|
||||||
|
type_str,
|
||||||
|
type_actual,
|
||||||
|
value,
|
||||||
|
mutable,
|
||||||
|
uid,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
s::Assignment {
|
||||||
|
name,
|
||||||
|
mut value,
|
||||||
|
mut uid,
|
||||||
|
} => {
|
||||||
|
uid = self.table.reference_ident(&name).uid;
|
||||||
|
value = *self.naming_pass_expr(value.into())?;
|
||||||
|
// Hint ident is rhs type and mutable
|
||||||
|
self.table.modify_ident(
|
||||||
|
uid.clone(),
|
||||||
|
None,
|
||||||
|
Some(value.type_.clone()),
|
||||||
|
Some(true),
|
||||||
|
false,
|
||||||
|
)?;
|
||||||
|
s::Assignment { name, value, uid }
|
||||||
|
},
|
||||||
|
s::If {
|
||||||
|
mut predicate,
|
||||||
|
mut block,
|
||||||
|
mut else_,
|
||||||
|
} => {
|
||||||
|
predicate = *self.naming_pass_expr(predicate.into())?;
|
||||||
|
self.table.start_block();
|
||||||
|
for s in &mut block {
|
||||||
|
*s = *self.naming_pass_stmt(s.clone().into())?;
|
||||||
|
}
|
||||||
|
self.table.end_block();
|
||||||
|
else_ = if let Some(else_) = else_ {
|
||||||
|
Some(self.naming_pass_stmt(else_)?)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
s::If {
|
||||||
|
predicate,
|
||||||
|
block,
|
||||||
|
else_,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
s::While {
|
||||||
|
mut predicate,
|
||||||
|
mut block,
|
||||||
|
} => {
|
||||||
|
predicate = *self.naming_pass_expr(predicate.into())?;
|
||||||
|
self.table.start_block();
|
||||||
|
for s in &mut block {
|
||||||
|
*s = *self.naming_pass_stmt(s.clone().into())?;
|
||||||
|
}
|
||||||
|
self.table.end_block();
|
||||||
|
s::While { predicate, block }
|
||||||
|
},
|
||||||
|
s::Print(mut expression) => {
|
||||||
|
expression = *self.naming_pass_expr(expression.into())?;
|
||||||
|
s::Print(expression)
|
||||||
|
},
|
||||||
|
s::Expression(mut expression) => {
|
||||||
|
expression = *self.naming_pass_expr(expression.into())?;
|
||||||
|
s::Expression(expression)
|
||||||
|
},
|
||||||
|
s::Block(mut block) => {
|
||||||
|
self.table.start_block();
|
||||||
|
for s in &mut block {
|
||||||
|
*s = *self.naming_pass_stmt(s.clone().into())?;
|
||||||
|
}
|
||||||
|
self.table.end_block();
|
||||||
|
s::Block(block)
|
||||||
|
},
|
||||||
|
s::Return(mut expression) => {
|
||||||
|
if let Some(e) = expression {
|
||||||
|
expression = Some(*self.naming_pass_expr(e.into())?);
|
||||||
|
}
|
||||||
|
s::Return(expression)
|
||||||
|
},
|
||||||
|
s::Error(diagnostic) => s::Error(diagnostic),
|
||||||
|
};
|
||||||
|
Ok(stmt)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn naming_pass_expr(
|
||||||
|
&mut self,
|
||||||
|
mut expr: Box<Expression>,
|
||||||
|
) -> Result<Box<Expression>> {
|
||||||
|
use ExpressionKind as e;
|
||||||
|
expr.kind = match expr.kind {
|
||||||
|
e::Immediate(immediate) => {
|
||||||
|
expr.type_ = Type::Prim(match &immediate {
|
||||||
|
Immediate::Integer(_, _) => Primitive::integer_ambiguous,
|
||||||
|
Immediate::Real(_) => Primitive::real_ambiguous,
|
||||||
|
Immediate::String(_) => Primitive::string,
|
||||||
|
Immediate::Glyph(_) => Primitive::glyph,
|
||||||
|
Immediate::Boolean(_) => Primitive::boolean,
|
||||||
|
});
|
||||||
|
e::Immediate(immediate)
|
||||||
|
},
|
||||||
|
e::Identifier(name, mut mangle) => {
|
||||||
|
let sym = self.table.reference_ident(&name);
|
||||||
|
mangle = sym.uid;
|
||||||
|
expr.type_ = sym.type_;
|
||||||
|
e::Identifier(name, mangle)
|
||||||
|
},
|
||||||
|
e::Binary {
|
||||||
|
op,
|
||||||
|
mut left,
|
||||||
|
mut right,
|
||||||
|
} => {
|
||||||
|
left = self.naming_pass_expr(left)?;
|
||||||
|
right = self.naming_pass_expr(right)?;
|
||||||
|
e::Binary { op, left, right }
|
||||||
|
},
|
||||||
|
e::Unary { op, mut child } => {
|
||||||
|
child = self.naming_pass_expr(child)?;
|
||||||
|
e::Unary { op, child }
|
||||||
|
},
|
||||||
|
e::Parenthesis(mut expression) => {
|
||||||
|
expression = self.naming_pass_expr(expression)?;
|
||||||
|
e::Parenthesis(expression)
|
||||||
|
},
|
||||||
|
e::FunctionDef {
|
||||||
|
params,
|
||||||
|
returns_str,
|
||||||
|
returns_actual,
|
||||||
|
mut body,
|
||||||
|
mut id,
|
||||||
|
} => {
|
||||||
|
// Starts function
|
||||||
|
id = self
|
||||||
|
.table
|
||||||
|
.create_function(params.clone(), returns_str.clone())
|
||||||
|
.span(&expr.span)?;
|
||||||
|
expr.type_ = Type::Function(id.clone());
|
||||||
|
for s in &mut body {
|
||||||
|
*s = *self.naming_pass_stmt(s.clone().into())?;
|
||||||
|
}
|
||||||
|
self.table.end_function();
|
||||||
|
e::FunctionDef {
|
||||||
|
params,
|
||||||
|
returns_str,
|
||||||
|
returns_actual,
|
||||||
|
body,
|
||||||
|
id,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
e::FunctionCall {
|
||||||
|
mut callee,
|
||||||
|
mut args,
|
||||||
|
is_reference,
|
||||||
|
id,
|
||||||
|
} => {
|
||||||
|
callee = self.naming_pass_expr(callee)?;
|
||||||
|
for a in &mut args {
|
||||||
|
*a = *self.naming_pass_expr(a.clone().into())?;
|
||||||
|
}
|
||||||
|
e::FunctionCall {
|
||||||
|
callee,
|
||||||
|
args,
|
||||||
|
is_reference,
|
||||||
|
id,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
e::StructDef(params, mut sid) => {
|
||||||
|
sid = self.table.create_struct(params.clone());
|
||||||
|
expr.type_ = Type::Alias(Box::new(Type::Struct(sid)));
|
||||||
|
e::StructDef(params, sid)
|
||||||
|
},
|
||||||
|
e::StructLiteral {
|
||||||
|
name,
|
||||||
|
mut args,
|
||||||
|
mut id,
|
||||||
|
} => {
|
||||||
|
id = self.table.reference_ident(&name).uid;
|
||||||
|
for (_, a) in &mut args {
|
||||||
|
*a = *self.naming_pass_expr(a.clone().into())?;
|
||||||
|
}
|
||||||
|
e::StructLiteral { name, args, id }
|
||||||
|
},
|
||||||
|
e::Field {
|
||||||
|
mut namespace,
|
||||||
|
field,
|
||||||
|
uid,
|
||||||
|
} => {
|
||||||
|
namespace = self.naming_pass_expr(namespace)?;
|
||||||
|
e::Field {
|
||||||
|
namespace,
|
||||||
|
field,
|
||||||
|
uid,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
Ok(expr)
|
||||||
|
}
|
||||||
|
}
|
|
@ -129,16 +129,22 @@ macro_rules! comparison {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Primitive {
|
impl Primitive {
|
||||||
pub fn coerce(&mut self, into: Primitive) {
|
pub fn coerce(self, expect: Primitive) -> Result<Self> {
|
||||||
use Primitive::*;
|
use Primitive::*;
|
||||||
*self = match (*self, into) {
|
match (self, expect) {
|
||||||
(
|
(
|
||||||
integer_ambiguous,
|
integer_ambiguous,
|
||||||
i8 | i16 | i32 | i64 | integer | w8 | w16 | w32 | w64 | whole,
|
a @ (i8 | i16 | i32 | i64 | integer | w8 | w16 | w32 | w64 | whole),
|
||||||
) => into,
|
)
|
||||||
(real_ambiguous, r32 | r64 | real) => into,
|
| (
|
||||||
_ => *self,
|
a @ (i8 | i16 | i32 | i64 | integer | w8 | w16 | w32 | w64 | whole),
|
||||||
};
|
integer_ambiguous,
|
||||||
|
) => Ok(a),
|
||||||
|
(real_ambiguous, a @ (r32 | r64 | real))
|
||||||
|
| (a @ (r32 | r64 | real), real_ambiguous) => Ok(a),
|
||||||
|
(t1, t2) if t1 == t2 => Ok(t1),
|
||||||
|
_ => error().reason(format!("Cannot coerce '{self}' into '{expect}'")),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_ambiguous(&self) -> bool {
|
pub fn is_ambiguous(&self) -> bool {
|
||||||
|
@ -163,9 +169,9 @@ impl Primitive {
|
||||||
) -> Result<Primitive> {
|
) -> Result<Primitive> {
|
||||||
use Primitive::*;
|
use Primitive::*;
|
||||||
if lhs.is_ambiguous() && !rhs.is_ambiguous() {
|
if lhs.is_ambiguous() && !rhs.is_ambiguous() {
|
||||||
lhs.coerce(rhs);
|
lhs = lhs.coerce(rhs)?;
|
||||||
} else if rhs.is_ambiguous() && !lhs.is_ambiguous() {
|
} else if rhs.is_ambiguous() && !lhs.is_ambiguous() {
|
||||||
rhs.coerce(lhs);
|
rhs = rhs.coerce(lhs)?;
|
||||||
}
|
}
|
||||||
selfsame_basic! {
|
selfsame_basic! {
|
||||||
lhs, op, rhs; w8, w16, w32, w64, i8, i16, i32, i64,
|
lhs, op, rhs; w8, w16, w32, w64, i8, i16, i32, i64,
|
||||||
|
|
|
@ -1,24 +1,227 @@
|
||||||
use super::{Analyzer, Type};
|
use super::{Analyzer, Type};
|
||||||
use crate::{
|
use crate::{
|
||||||
Expression, ExpressionKind, Immediate, Statement, StatementKind,
|
Expression, ExpressionKind, Statement, StatementKind, err::*,
|
||||||
err::*,
|
semantic::Primitive,
|
||||||
semantic::{Primitive, SymbolTable},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
impl Analyzer {
|
impl Analyzer {
|
||||||
pub fn stmt_top_down(
|
pub fn top_down_stmt(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut stmt: Box<Statement>,
|
mut stmt: Box<Statement>,
|
||||||
expect: &Type,
|
|
||||||
) -> Result<Box<Statement>> {
|
) -> Result<Box<Statement>> {
|
||||||
todo!()
|
use StatementKind as s;
|
||||||
|
stmt.kind = match stmt.kind {
|
||||||
|
s::Declaration {
|
||||||
|
name,
|
||||||
|
type_str,
|
||||||
|
type_actual,
|
||||||
|
mut value,
|
||||||
|
mutable,
|
||||||
|
uid,
|
||||||
|
} => {
|
||||||
|
value = *self.top_down_expr(value.into(), &type_actual)?;
|
||||||
|
s::Declaration {
|
||||||
|
name,
|
||||||
|
type_str,
|
||||||
|
type_actual,
|
||||||
|
value,
|
||||||
|
mutable,
|
||||||
|
uid,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
s::Assignment {
|
||||||
|
name,
|
||||||
|
mut value,
|
||||||
|
uid,
|
||||||
|
} => {
|
||||||
|
let type_ = self.table.resolve_type(&uid).span(&stmt.span)?;
|
||||||
|
value = *self.top_down_expr(value.into(), &type_)?;
|
||||||
|
s::Assignment { name, value, uid }
|
||||||
|
},
|
||||||
|
s::If {
|
||||||
|
mut predicate,
|
||||||
|
mut block,
|
||||||
|
mut else_,
|
||||||
|
} => {
|
||||||
|
predicate = *self
|
||||||
|
.top_down_expr(predicate.into(), &Type::Prim(Primitive::boolean))?;
|
||||||
|
for s in &mut block {
|
||||||
|
*s = *self.top_down_stmt(s.clone().into())?;
|
||||||
|
}
|
||||||
|
else_ = if let Some(else_) = else_ {
|
||||||
|
Some(self.top_down_stmt(else_)?)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
s::If {
|
||||||
|
predicate,
|
||||||
|
block,
|
||||||
|
else_,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
s::While {
|
||||||
|
mut predicate,
|
||||||
|
mut block,
|
||||||
|
} => {
|
||||||
|
predicate = *self
|
||||||
|
.top_down_expr(predicate.into(), &Type::Prim(Primitive::boolean))?;
|
||||||
|
for s in &mut block {
|
||||||
|
*s = *self.top_down_stmt(s.clone().into())?;
|
||||||
|
}
|
||||||
|
s::While { predicate, block }
|
||||||
|
},
|
||||||
|
s::Print(mut expr) => {
|
||||||
|
let expr_t = expr.type_.clone();
|
||||||
|
expr = *self.top_down_expr(expr.into(), &expr_t)?;
|
||||||
|
s::Print(expr)
|
||||||
|
},
|
||||||
|
s::Expression(mut expr) => {
|
||||||
|
let expr_t = expr.type_.clone();
|
||||||
|
expr = *self.top_down_expr(expr.into(), &expr_t)?;
|
||||||
|
s::Expression(expr)
|
||||||
|
},
|
||||||
|
s::Block(mut block) => {
|
||||||
|
for s in &mut block {
|
||||||
|
*s = *self.top_down_stmt(s.clone().into())?;
|
||||||
|
}
|
||||||
|
s::Block(block)
|
||||||
|
},
|
||||||
|
s::Return(expr) => {
|
||||||
|
if let Some(mut expr) = expr {
|
||||||
|
let expr_t = expr.type_.clone();
|
||||||
|
expr = *self.top_down_expr(expr.into(), &expr_t)?;
|
||||||
|
s::Return(Some(expr))
|
||||||
|
} else {
|
||||||
|
s::Return(None)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
s::Error(diagnostic) => s::Error(diagnostic),
|
||||||
|
};
|
||||||
|
Ok(stmt)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expr_top_down(
|
pub fn top_down_expr(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut expr: Box<Expression>,
|
mut expr: Box<Expression>,
|
||||||
expect: &Type,
|
expect: &Type,
|
||||||
) -> Result<Box<Expression>> {
|
) -> Result<Box<Expression>> {
|
||||||
todo!()
|
use ExpressionKind as e;
|
||||||
|
expr.type_ = expr.type_.coerce(expect).span(&expr.span)?;
|
||||||
|
expr.kind = match expr.kind {
|
||||||
|
e::Immediate(i) => e::Immediate(i),
|
||||||
|
e::Identifier(i, m) => e::Identifier(i, m),
|
||||||
|
e::Binary {
|
||||||
|
op,
|
||||||
|
mut left,
|
||||||
|
mut right,
|
||||||
|
} => {
|
||||||
|
left = self.top_down_expr(left, expect)?;
|
||||||
|
right = self.top_down_expr(right, expect)?;
|
||||||
|
e::Binary { op, left, right }
|
||||||
|
},
|
||||||
|
e::Unary { op, mut child } => {
|
||||||
|
child = self.top_down_expr(child, expect)?;
|
||||||
|
e::Unary { op, child }
|
||||||
|
},
|
||||||
|
e::Parenthesis(mut expression) => {
|
||||||
|
expression = self.top_down_expr(expression, expect)?;
|
||||||
|
e::Parenthesis(expression)
|
||||||
|
},
|
||||||
|
e::FunctionDef {
|
||||||
|
params,
|
||||||
|
returns_str,
|
||||||
|
returns_actual,
|
||||||
|
mut body,
|
||||||
|
id,
|
||||||
|
} => {
|
||||||
|
for s in &mut body {
|
||||||
|
*s = *self.top_down_stmt(s.clone().into())?;
|
||||||
|
}
|
||||||
|
e::FunctionDef {
|
||||||
|
params,
|
||||||
|
returns_str,
|
||||||
|
returns_actual,
|
||||||
|
body,
|
||||||
|
id,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
e::FunctionCall {
|
||||||
|
callee,
|
||||||
|
mut args,
|
||||||
|
is_reference,
|
||||||
|
id,
|
||||||
|
} => {
|
||||||
|
let func_def = if let Type::Function(fid) = callee.type_ {
|
||||||
|
self.table.functions[fid].clone()
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
if func_def.params.len() != args.len() {
|
||||||
|
return error()
|
||||||
|
.reason(format!(
|
||||||
|
"Wrong number of arguments; found {}, expected {}",
|
||||||
|
args.len(),
|
||||||
|
func_def.params.len()
|
||||||
|
))
|
||||||
|
.span(&expr.span);
|
||||||
|
}
|
||||||
|
for (param, arg) in func_def.params.iter().zip(args.iter_mut()) {
|
||||||
|
let type_ = self.table.resolve_type(param).span(&arg.span)?;
|
||||||
|
*arg = *self.top_down_expr(arg.clone().into(), &type_)?;
|
||||||
|
}
|
||||||
|
e::FunctionCall {
|
||||||
|
callee,
|
||||||
|
args,
|
||||||
|
is_reference,
|
||||||
|
id,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
e::StructDef(params, sid) => e::StructDef(params, sid),
|
||||||
|
e::StructLiteral { name, mut args, id } => {
|
||||||
|
let sid = if let Type::Struct(sid) = expr.type_ {
|
||||||
|
sid
|
||||||
|
} else {
|
||||||
|
return error()
|
||||||
|
.reason(format!("Cannot create struct from type {}", expr.type_))
|
||||||
|
.span(&expr.span);
|
||||||
|
};
|
||||||
|
if self.table.structs[sid].0.len() != args.len() {
|
||||||
|
return error()
|
||||||
|
.reason(format!(
|
||||||
|
"Wrong number of parameters; found {}, expected {}",
|
||||||
|
args.len(),
|
||||||
|
self.table.structs[sid].0.len()
|
||||||
|
))
|
||||||
|
.span(&expr.span);
|
||||||
|
}
|
||||||
|
let mut declared_params: Vec<String> = vec![];
|
||||||
|
for (name, arg) in args.iter_mut() {
|
||||||
|
if declared_params.contains(name) {
|
||||||
|
return error()
|
||||||
|
.reason(format!("Field {name} initialized more than once"))
|
||||||
|
.span(&arg.span);
|
||||||
|
}
|
||||||
|
declared_params.push(name.clone());
|
||||||
|
let param_t = self
|
||||||
|
.table
|
||||||
|
.get_field(sid, &name)
|
||||||
|
.span(&arg.span)?
|
||||||
|
.is_alias()
|
||||||
|
.span(&arg.span)?;
|
||||||
|
*arg = *self.top_down_expr(arg.clone().into(), ¶m_t)?;
|
||||||
|
}
|
||||||
|
e::StructLiteral { name, args, id }
|
||||||
|
},
|
||||||
|
e::Field {
|
||||||
|
namespace,
|
||||||
|
field,
|
||||||
|
uid,
|
||||||
|
} => e::Field {
|
||||||
|
namespace,
|
||||||
|
field,
|
||||||
|
uid,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
Ok(expr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::{BinaryOp, UnaryOp};
|
use crate::{BinaryOp, UnaryOp};
|
||||||
|
|
||||||
use super::{Symbol, UID, primitives::*};
|
use super::{UID, primitives::*};
|
||||||
use crate::err::*;
|
use crate::err::*;
|
||||||
|
|
||||||
/// Struct ID
|
/// Struct ID
|
||||||
|
@ -14,7 +14,7 @@ pub type FID = usize;
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct FunctionDef {
|
pub struct FunctionDef {
|
||||||
pub params: Vec<UID>,
|
pub params: Vec<UID>,
|
||||||
pub returns: Option<UID>,
|
pub returns: UID,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn nothing_mangle() -> UID {
|
pub fn nothing_mangle() -> UID {
|
||||||
|
@ -60,6 +60,14 @@ impl PartialEq for Type {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Type {
|
impl Type {
|
||||||
|
pub fn is_alias(&self) -> Result<Type> {
|
||||||
|
if let Type::Alias(t) = self {
|
||||||
|
Ok(*t.clone())
|
||||||
|
} else {
|
||||||
|
error().reason(format!("Expected type, found value with type {}", self))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn binary_op(lhs: &Type, op: BinaryOp, rhs: &Type) -> Result<Type> {
|
pub fn binary_op(lhs: &Type, op: BinaryOp, rhs: &Type) -> Result<Type> {
|
||||||
use Type as t;
|
use Type as t;
|
||||||
let e = error().reason(format!(
|
let e = error().reason(format!(
|
||||||
|
@ -86,17 +94,42 @@ impl Type {
|
||||||
|
|
||||||
pub fn deduce(self, hint: &Type) -> Result<Self> {
|
pub fn deduce(self, hint: &Type) -> Result<Self> {
|
||||||
use Type::*;
|
use Type::*;
|
||||||
match (hint, self) {
|
match (self, hint) {
|
||||||
(Ambiguous, t) => Ok(t),
|
(Ambiguous, t) => Ok(t.clone()),
|
||||||
(t, Ambiguous) => Ok(t.clone()),
|
(t, Ambiguous) => Ok(t),
|
||||||
(Prim(mut p1), Prim(p2)) => {
|
(Prim(mut p1), Prim(p2)) => {
|
||||||
p1.coerce(p2);
|
p1 = p1.coerce(*p2)?;
|
||||||
Ok(Prim(p1))
|
Ok(Prim(p1))
|
||||||
},
|
},
|
||||||
(t1, t2) if t1 == &t2 => Ok(t1.clone()),
|
(t1, t2) if &t1 == t2 => Ok(t1.clone()),
|
||||||
(t1, t2) => {
|
(t1, t2) => {
|
||||||
error().reason(format!("Cannot coerce type '{t2}' into '{t1}'"))
|
error().reason(format!("Cannot coerce type '{t2}' into '{t1}'"))
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn coerce(self, expect: &Type) -> Result<Self> {
|
||||||
|
use Type::*;
|
||||||
|
match (self, expect) {
|
||||||
|
(Prim(mut p1), Prim(p2)) => {
|
||||||
|
p1 = p1.coerce(*p2)?;
|
||||||
|
Ok(Prim(p1))
|
||||||
|
},
|
||||||
|
(t1, t2) if &t1 == t2 => Ok(t1.clone()),
|
||||||
|
(t1, t2) => {
|
||||||
|
error().reason(format!("Cannot coerce type '{t2}' into '{t1}'"))
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn promote(self) -> Self {
|
||||||
|
use Type::*;
|
||||||
|
match self {
|
||||||
|
Prim(mut p) => {
|
||||||
|
p.promote();
|
||||||
|
Prim(p)
|
||||||
|
},
|
||||||
|
t => t,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
10
src/token.rs
10
src/token.rs
|
@ -9,6 +9,7 @@ pub enum Base {
|
||||||
Hex = 16,
|
Hex = 16,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum TokenKind {
|
pub enum TokenKind {
|
||||||
LeftParen,
|
LeftParen,
|
||||||
|
@ -382,20 +383,19 @@ impl<I: Iterator<Item = char>> Tokenizer<I> {
|
||||||
buffer.push(c);
|
buffer.push(c);
|
||||||
let _ = self.next_char();
|
let _ = self.next_char();
|
||||||
}
|
}
|
||||||
|
buffer = buffer.to_lowercase();
|
||||||
// Determine base
|
// Determine base
|
||||||
let base = if buffer.starts_with("0b") {
|
let base = if buffer.starts_with("0b") {
|
||||||
Base::Binary
|
Base::Binary
|
||||||
} else if buffer.starts_with("0o") || buffer.starts_with("0O") {
|
} else if buffer.starts_with("0o") {
|
||||||
Base::Octal
|
Base::Octal
|
||||||
} else if buffer.starts_with("0x") || buffer.starts_with("0X") {
|
} else if buffer.starts_with("0x") {
|
||||||
Base::Hex
|
Base::Hex
|
||||||
} else {
|
} else {
|
||||||
Base::Decimal
|
Base::Decimal
|
||||||
};
|
};
|
||||||
// Determine integer or float
|
// Determine integer or float
|
||||||
if base == Base::Decimal
|
if base == Base::Decimal && (encountered_dot || buffer.contains("e")) {
|
||||||
&& (encountered_dot || buffer.contains("e") || buffer.contains("E"))
|
|
||||||
{
|
|
||||||
return t(FloatLiteral(buffer), position);
|
return t(FloatLiteral(buffer), position);
|
||||||
} else {
|
} else {
|
||||||
return t(IntegerLiteral(buffer, base), position);
|
return t(IntegerLiteral(buffer, base), position);
|
||||||
|
|
Loading…
Reference in a new issue