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 :: struct {
|
||||
b: B,
|
||||
}
|
||||
|
||||
B :: struct {
|
||||
c: C,
|
||||
}
|
||||
|
||||
C :: struct {
|
||||
r: real,
|
||||
}
|
||||
a : integer : 10;
|
||||
b := a + 10;
|
||||
|
|
|
@ -4,10 +4,11 @@
|
|||
</head>
|
||||
|
||||
<script>
|
||||
const url = '/test.wasm';
|
||||
WebAssembly.instantiateStreaming(fetch(url), { console });
|
||||
const url = '/test.wasm';
|
||||
WebAssembly.instantiateStreaming(fetch(url), { console });
|
||||
</script>
|
||||
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use std::{io::Write, path::Path};
|
||||
use std::path::Path;
|
||||
|
||||
use crate::{
|
||||
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::{
|
||||
BinaryOp, Expression, ExpressionKind, Immediate, Statement, StatementKind,
|
||||
UnaryOp,
|
||||
semantic::{Primitive, Type, UID},
|
||||
BinaryOp, Immediate, UnaryOp,
|
||||
semantic::{FID, Primitive, Type, UID},
|
||||
};
|
||||
/*
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum IR {
|
||||
BinOp { op: BinaryOp, type_: Type },
|
||||
UnOp { op: UnaryOp, type_: Type },
|
||||
Push { prim: Primitive, value: Immediate },
|
||||
NewLocal { uid: UID, type_: Type },
|
||||
AssignLocal { uid: UID },
|
||||
GetLocal { uid: UID },
|
||||
NewGlobal { uid: UID, type_: Type },
|
||||
AssignGlobal { uid: UID },
|
||||
GetGlobal { uid: UID },
|
||||
StartFunc { uid: UID },
|
||||
BinOp {
|
||||
op: BinaryOp,
|
||||
type_: Type,
|
||||
},
|
||||
UnOp {
|
||||
op: UnaryOp,
|
||||
type_: Type,
|
||||
},
|
||||
Push {
|
||||
prim: Primitive,
|
||||
value: Immediate,
|
||||
},
|
||||
New {
|
||||
uid: UID,
|
||||
type_: Type,
|
||||
},
|
||||
Set {
|
||||
uid: UID,
|
||||
},
|
||||
Get {
|
||||
uid: UID,
|
||||
},
|
||||
StartFunc {
|
||||
fid: FID,
|
||||
params: Vec<Type>,
|
||||
returns: Type,
|
||||
},
|
||||
EndFunc,
|
||||
ReturnType { type_: Type },
|
||||
NewParam { uid: UID, type_: Type },
|
||||
ReturnType {
|
||||
type_: Type,
|
||||
},
|
||||
Return,
|
||||
Call { uid: UID },
|
||||
Call {
|
||||
fid: FID,
|
||||
},
|
||||
Drop,
|
||||
Print,
|
||||
Print {
|
||||
type_: Type,
|
||||
},
|
||||
}
|
||||
|
||||
impl std::fmt::Display for IR {
|
||||
|
@ -32,24 +56,43 @@ impl std::fmt::Display for IR {
|
|||
BinOp { op, type_ } => write!(f, "{op} ({type_})"),
|
||||
UnOp { op, type_ } => write!(f, "{op}, {type_}"),
|
||||
Push { prim, value } => write!(f, "push {value} ({prim})"),
|
||||
NewLocal { uid, type_ } => write!(f, "local ${uid} = {type_}"),
|
||||
AssignLocal { uid } => write!(f, "pop local ${uid}"),
|
||||
GetLocal { uid } => write!(f, "push local ${uid}"),
|
||||
NewGlobal { uid, type_ } => write!(f, "global ${uid} = {type_}"),
|
||||
AssignGlobal { uid } => write!(f, "pop global ${uid}"),
|
||||
GetGlobal { uid } => write!(f, "push global ${uid}"),
|
||||
StartFunc { uid } => write!(f, "<function id=${uid}>"),
|
||||
New { uid, type_ } => write!(f, "local ${uid} = {type_}"),
|
||||
Set { uid } => write!(f, "pop local ${uid}"),
|
||||
Get { uid } => write!(f, "push local ${uid}"),
|
||||
StartFunc {
|
||||
uid,
|
||||
params,
|
||||
returns,
|
||||
} => write!(
|
||||
f,
|
||||
"<function id=${uid} params={params:?} returns={returns}>"
|
||||
),
|
||||
EndFunc => write!(f, "</function>"),
|
||||
NewParam { uid, type_ } => write!(f, "param ${uid} = {type_}"),
|
||||
Return => write!(f, "return"),
|
||||
Call { uid } => write!(f, "call ${uid}"),
|
||||
Drop => write!(f, "pop"),
|
||||
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 {
|
||||
pub fn to_wat(&self) -> String {
|
||||
use BinaryOp as b;
|
|
@ -99,13 +99,10 @@ fn typecheck(input: &'static str) -> Vec<Statement> {
|
|||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
/*
|
||||
for s in typecheck(include_str!("../demo.hal")) {
|
||||
println!("{s:#?}");
|
||||
println!("------------------");
|
||||
println!("{s:#?}");
|
||||
}
|
||||
*/
|
||||
typecheck(include_str!("../demo.hal"));
|
||||
//let module = frontend::Module::from_file("./demo.hal")?;
|
||||
//module.write_to("test");
|
||||
Ok(())
|
||||
|
|
|
@ -67,6 +67,7 @@ pub enum ExpressionKind {
|
|||
StructLiteral {
|
||||
name: String,
|
||||
args: Vec<(String, Expression)>,
|
||||
id: UID,
|
||||
},
|
||||
Field {
|
||||
namespace: Box<Expression>,
|
||||
|
@ -121,7 +122,7 @@ impl std::fmt::Debug for ExpressionKind {
|
|||
write!(f, "(fn({params:?}) -> {returns_actual:?})")
|
||||
},
|
||||
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)?;
|
||||
e::StructLiteral { name, args }
|
||||
e::StructLiteral {
|
||||
name,
|
||||
args,
|
||||
id: "".into(),
|
||||
}
|
||||
},
|
||||
t::Identifier(i) => {
|
||||
self.skip(1);
|
||||
|
|
|
@ -1,10 +1,4 @@
|
|||
use crate::{
|
||||
Expression, ExpressionKind, Immediate, Statement, StatementKind,
|
||||
err::*,
|
||||
semantic::{Primitive, SymbolTable},
|
||||
};
|
||||
|
||||
use super::Type;
|
||||
use crate::{Statement, semantic::SymbolTable};
|
||||
|
||||
pub struct Analyzer {
|
||||
pub table: SymbolTable,
|
||||
|
@ -18,6 +12,12 @@ impl Analyzer {
|
|||
for s in &mut statements {
|
||||
*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!("{:#?}", this.table.table);
|
||||
println!("-----FUNCS------");
|
||||
|
@ -26,224 +26,4 @@ impl Analyzer {
|
|||
println!("{:#?}", this.table.structs);
|
||||
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 crate::{
|
||||
Expression, ExpressionKind, Immediate, Statement, StatementKind,
|
||||
err::*,
|
||||
semantic::{Primitive, SymbolTable},
|
||||
};
|
||||
use crate::{Expression, ExpressionKind, Statement, StatementKind, err::*};
|
||||
|
||||
use super::Type;
|
||||
|
||||
impl Analyzer {
|
||||
pub fn stmt_bottom_up(
|
||||
pub fn bottom_up_stmt(
|
||||
&mut self,
|
||||
mut stmt: 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
|
||||
pub fn expr_bottom_up(
|
||||
pub fn bottom_up_expr(
|
||||
&mut self,
|
||||
mut expr: 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 bottom_up;
|
||||
mod naming;
|
||||
mod primitives;
|
||||
mod top_down;
|
||||
mod types;
|
||||
|
@ -11,6 +12,12 @@ pub use analyzer::*;
|
|||
pub use primitives::*;
|
||||
pub use types::*;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
enum Scope {
|
||||
Block,
|
||||
Function,
|
||||
}
|
||||
|
||||
// Mangled name
|
||||
pub type UID = String;
|
||||
|
||||
|
@ -23,18 +30,6 @@ pub struct Symbol {
|
|||
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)]
|
||||
enum Definition {
|
||||
Ident(Symbol),
|
||||
|
@ -86,23 +81,47 @@ impl SymbolTable {
|
|||
}
|
||||
|
||||
pub fn end_block(&mut self) {
|
||||
let mut escaped = vec![];
|
||||
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;
|
||||
} else if let Some(Definition::Ident(s)) = top {
|
||||
if !s.initialized {
|
||||
escaped.push(Definition::Ident(s));
|
||||
}
|
||||
}
|
||||
}
|
||||
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) {
|
||||
self.nesting += 1;
|
||||
self.scope.push(Definition::FuncStart);
|
||||
}
|
||||
|
||||
pub fn end_function(&mut self) {
|
||||
self.nesting -= 1;
|
||||
let mut escaped = vec![];
|
||||
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;
|
||||
} else if let Some(Definition::Ident(s)) = top {
|
||||
if !s.initialized {
|
||||
escaped.push(Definition::Ident(s));
|
||||
}
|
||||
}
|
||||
}
|
||||
unreachable!("Cannot end global scope")
|
||||
|
@ -114,6 +133,16 @@ impl SymbolTable {
|
|||
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 {
|
||||
let sid = self.structs.len();
|
||||
let mut new_params = vec![];
|
||||
|
@ -129,23 +158,31 @@ impl SymbolTable {
|
|||
&mut self,
|
||||
params: Vec<Parameter>,
|
||||
returns: Option<String>,
|
||||
) -> FID {
|
||||
) -> Result<FID> {
|
||||
let fid = self.functions.len();
|
||||
let mut new_params = vec![];
|
||||
for p in params {
|
||||
let s = self.reference_ident(&p.type_str);
|
||||
new_params.push(s.uid);
|
||||
let mut symbols = vec![];
|
||||
for p in ¶ms {
|
||||
let symbol = self.reference_ident(&p.type_str);
|
||||
symbols.push(symbol);
|
||||
}
|
||||
let returns = if let Some(s) = returns {
|
||||
Some(self.reference_ident(&s).uid)
|
||||
self.reference_ident(&s).uid
|
||||
} 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 {
|
||||
params: new_params,
|
||||
returns,
|
||||
});
|
||||
fid
|
||||
Ok(fid)
|
||||
}
|
||||
|
||||
pub fn modify_ident(
|
||||
|
@ -156,15 +193,17 @@ impl SymbolTable {
|
|||
mutable: Option<bool>,
|
||||
init: bool,
|
||||
) -> Result<()> {
|
||||
{
|
||||
let symbol = self.table.get_mut(&uid).unwrap();
|
||||
if let Some(ref type_) = type_ {
|
||||
symbol.type_ = symbol.type_.clone().deduce(type_)?;
|
||||
}
|
||||
if let Some(m) = mutable {
|
||||
symbol.mutable = Some(m);
|
||||
}
|
||||
let symbol = self.table.get_mut(&uid).unwrap();
|
||||
if let Some(ref type_) = type_ {
|
||||
symbol.type_ = symbol.type_.clone().deduce(type_)?;
|
||||
}
|
||||
symbol.mutable = match (symbol.mutable, mutable) {
|
||||
(Some(true), Some(false)) | (Some(false), Some(true)) => {
|
||||
return error().reason("Cannot mutate immutable symbol");
|
||||
},
|
||||
_ => mutable,
|
||||
};
|
||||
symbol.initialized |= init;
|
||||
|
||||
let mut nesting = self.nesting;
|
||||
for def in &mut self.scope {
|
||||
|
@ -179,17 +218,21 @@ impl SymbolTable {
|
|||
if let Some(ref type_) = type_ {
|
||||
symbol.type_ = symbol.type_.clone().deduce(type_)?;
|
||||
}
|
||||
if let Some(m) = mutable {
|
||||
symbol.mutable = Some(m);
|
||||
}
|
||||
symbol.initialized &= init;
|
||||
symbol.mutable = match (symbol.mutable, mutable) {
|
||||
(Some(true), Some(false)) | (Some(false), Some(true)) => {
|
||||
return error().reason("Cannot mutate immutable symbol");
|
||||
},
|
||||
_ => mutable,
|
||||
};
|
||||
symbol.initialized |= init;
|
||||
return Ok(());
|
||||
},
|
||||
Definition::FuncStart => nesting -= 1,
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
panic!("Symbol {uid} does not exist")
|
||||
Ok(())
|
||||
//unreachable!("Symbol {uid} does not exist")
|
||||
}
|
||||
|
||||
pub fn define_ident(
|
||||
|
@ -198,7 +241,15 @@ impl SymbolTable {
|
|||
type_: Type,
|
||||
mutable: bool,
|
||||
) -> 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
|
||||
// TODO support name shadowing
|
||||
if s.initialized {
|
||||
|
@ -232,7 +283,7 @@ impl SymbolTable {
|
|||
}
|
||||
|
||||
pub fn reference_ident(&mut self, name: &str) -> Symbol {
|
||||
match self.lookup_available_scope(name) {
|
||||
match self.lookup_function_scope(name) {
|
||||
Ok(s) => s,
|
||||
Err(_) => {
|
||||
let uid = self.generate_uid(name);
|
||||
|
@ -250,24 +301,29 @@ impl SymbolTable {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn lookup_this_scope(&self, name: &str) -> Result<Symbol> {
|
||||
self.lookup_scope(name, false)
|
||||
pub fn lookup_block_scope(&self, name: &str) -> Result<Symbol> {
|
||||
self.lookup_scope(name, Scope::Block)
|
||||
}
|
||||
|
||||
pub fn lookup_available_scope(&self, name: &str) -> Result<Symbol> {
|
||||
self.lookup_scope(name, true)
|
||||
pub fn lookup_function_scope(&self, name: &str) -> Result<Symbol> {
|
||||
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;
|
||||
for def in &self.scope {
|
||||
for def in self.scope.iter().rev() {
|
||||
match def {
|
||||
Definition::Ident(symbol)
|
||||
if (symbol.name == name)
|
||||
&& ((nesting == 0 && with_global) || nesting == self.nesting) =>
|
||||
&& ((nesting == 0) || nesting == self.nesting) =>
|
||||
{
|
||||
return Ok(symbol.clone());
|
||||
},
|
||||
Definition::FuncStart | Definition::BlockStart
|
||||
if scope == Scope::Block =>
|
||||
{
|
||||
break;
|
||||
},
|
||||
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 {
|
||||
pub fn coerce(&mut self, into: Primitive) {
|
||||
pub fn coerce(self, expect: Primitive) -> Result<Self> {
|
||||
use Primitive::*;
|
||||
*self = match (*self, into) {
|
||||
match (self, expect) {
|
||||
(
|
||||
integer_ambiguous,
|
||||
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),
|
||||
)
|
||||
| (
|
||||
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 {
|
||||
|
@ -163,9 +169,9 @@ impl Primitive {
|
|||
) -> Result<Primitive> {
|
||||
use Primitive::*;
|
||||
if lhs.is_ambiguous() && !rhs.is_ambiguous() {
|
||||
lhs.coerce(rhs);
|
||||
lhs = lhs.coerce(rhs)?;
|
||||
} else if rhs.is_ambiguous() && !lhs.is_ambiguous() {
|
||||
rhs.coerce(lhs);
|
||||
rhs = rhs.coerce(lhs)?;
|
||||
}
|
||||
selfsame_basic! {
|
||||
lhs, op, rhs; w8, w16, w32, w64, i8, i16, i32, i64,
|
||||
|
|
|
@ -1,24 +1,227 @@
|
|||
use super::{Analyzer, Type};
|
||||
use crate::{
|
||||
Expression, ExpressionKind, Immediate, Statement, StatementKind,
|
||||
err::*,
|
||||
semantic::{Primitive, SymbolTable},
|
||||
Expression, ExpressionKind, Statement, StatementKind, err::*,
|
||||
semantic::Primitive,
|
||||
};
|
||||
|
||||
impl Analyzer {
|
||||
pub fn stmt_top_down(
|
||||
pub fn top_down_stmt(
|
||||
&mut self,
|
||||
mut stmt: Box<Statement>,
|
||||
expect: &Type,
|
||||
) -> 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 expr: Box<Expression>,
|
||||
expect: &Type,
|
||||
) -> 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 super::{Symbol, UID, primitives::*};
|
||||
use super::{UID, primitives::*};
|
||||
use crate::err::*;
|
||||
|
||||
/// Struct ID
|
||||
|
@ -14,7 +14,7 @@ pub type FID = usize;
|
|||
#[derive(Debug, Clone)]
|
||||
pub struct FunctionDef {
|
||||
pub params: Vec<UID>,
|
||||
pub returns: Option<UID>,
|
||||
pub returns: UID,
|
||||
}
|
||||
|
||||
pub fn nothing_mangle() -> UID {
|
||||
|
@ -60,6 +60,14 @@ impl PartialEq for 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> {
|
||||
use Type as t;
|
||||
let e = error().reason(format!(
|
||||
|
@ -86,17 +94,42 @@ impl Type {
|
|||
|
||||
pub fn deduce(self, hint: &Type) -> Result<Self> {
|
||||
use Type::*;
|
||||
match (hint, self) {
|
||||
(Ambiguous, t) => Ok(t),
|
||||
(t, Ambiguous) => Ok(t.clone()),
|
||||
match (self, hint) {
|
||||
(Ambiguous, t) => Ok(t.clone()),
|
||||
(t, Ambiguous) => Ok(t),
|
||||
(Prim(mut p1), Prim(p2)) => {
|
||||
p1.coerce(p2);
|
||||
p1 = p1.coerce(*p2)?;
|
||||
Ok(Prim(p1))
|
||||
},
|
||||
(t1, t2) if t1 == &t2 => Ok(t1.clone()),
|
||||
(t1, t2) if &t1 == t2 => Ok(t1.clone()),
|
||||
(t1, t2) => {
|
||||
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,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum TokenKind {
|
||||
LeftParen,
|
||||
|
@ -382,20 +383,19 @@ impl<I: Iterator<Item = char>> Tokenizer<I> {
|
|||
buffer.push(c);
|
||||
let _ = self.next_char();
|
||||
}
|
||||
buffer = buffer.to_lowercase();
|
||||
// Determine base
|
||||
let base = if buffer.starts_with("0b") {
|
||||
Base::Binary
|
||||
} else if buffer.starts_with("0o") || buffer.starts_with("0O") {
|
||||
} else if buffer.starts_with("0o") {
|
||||
Base::Octal
|
||||
} else if buffer.starts_with("0x") || buffer.starts_with("0X") {
|
||||
} else if buffer.starts_with("0x") {
|
||||
Base::Hex
|
||||
} else {
|
||||
Base::Decimal
|
||||
};
|
||||
// Determine integer or float
|
||||
if base == Base::Decimal
|
||||
&& (encountered_dot || buffer.contains("e") || buffer.contains("E"))
|
||||
{
|
||||
if base == Base::Decimal && (encountered_dot || buffer.contains("e")) {
|
||||
return t(FloatLiteral(buffer), position);
|
||||
} else {
|
||||
return t(IntegerLiteral(buffer, base), position);
|
||||
|
|
Loading…
Reference in a new issue