Started IR again

This commit is contained in:
Logan 2024-11-01 12:34:58 -05:00
parent 552496c0f9
commit b936901e17
15 changed files with 1070 additions and 358 deletions

View file

@ -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;

View file

@ -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>

View file

@ -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
View 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);
},
}
}
}

View file

@ -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;

View file

@ -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(())

View file

@ -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);

View file

@ -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)
}
}

View file

@ -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)
}
}

View file

@ -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 &params {
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
View 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)
}
}

View file

@ -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,

View file

@ -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(), &param_t)?;
}
e::StructLiteral { name, args, id }
},
e::Field {
namespace,
field,
uid,
} => e::Field {
namespace,
field,
uid,
},
};
Ok(expr)
}
}

View file

@ -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,
}
}
}

View file

@ -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);