started ir

This commit is contained in:
Logan Gatlin 2024-10-22 21:44:30 -05:00
parent 47c6ccfa6b
commit 6175f976a3
5 changed files with 172 additions and 142 deletions

View file

@ -1,3 +1,2 @@
Point :: struct {x: integer};
a : integer : 10;
p :: Point{x: a};
a : i32 = 10;
b := 20 + a;

17
src/ir.rs Normal file
View file

@ -0,0 +1,17 @@
use crate::{semantic::Type, BinaryOp, Immediate, UnaryOp};
#[derive(Debug, Clone)]
pub enum IR {
BinOp { op: BinaryOp, type_: Type },
UnOp { op: UnaryOp, type_: Type },
Imm(Immediate),
NewLocal { uid: usize, type_: Type },
AssignLocal { uid: usize },
AccessLocal { uid: usize },
NewGlobal { uid: usize, type_: Type },
AssignGlobal { uid: usize },
AccessGlobal { uid: usize },
StartFunc { uid: usize },
NewParam { uid: usize, type_: Type },
EndFunc,
}

View file

@ -1,5 +1,6 @@
mod err;
mod frontend;
mod ir;
mod lookahead;
mod parse;
mod semantic;

View file

@ -1,5 +1,80 @@
mod primitives;
mod types;
use crate::err::*;
pub use primitives::*;
pub use types::*;
#[derive(Debug, Clone)]
pub enum Symbol {
Var(String, Type, bool),
Type(String, Type),
BlockStart,
FuncStart,
}
#[derive(Debug, Clone)]
pub struct SymbolTable {
syms: Vec<Symbol>,
}
impl SymbolTable {
fn define_var(&mut self, name: String, type_: Type, mutable: bool) {
self.syms.push(Symbol::Var(name, type_, mutable));
}
fn define_type(&mut self, name: String, type_: Type) {
self.syms.push(Symbol::Type(name, type_));
}
fn start_func(&mut self) {
self.syms.push(Symbol::FuncStart);
}
fn end_func(&mut self) {
while !self.syms.is_empty() {
if let Some(Symbol::FuncStart) = self.syms.pop() {
return;
}
}
unreachable!("Tried to exit global scope in symbol table")
}
fn start_block(&mut self) {
self.syms.push(Symbol::BlockStart);
}
fn end_block(&mut self) {
while !self.syms.is_empty() {
if let Some(Symbol::BlockStart) = self.syms.pop() {
return;
}
}
unreachable!("Tried to exit global scope in symbol table")
}
fn get_var(&self, name: &str) -> Result<(Type, bool)> {
for s in self.syms.iter().rev() {
if let Symbol::Var(name2, type_, mutable) = s {
if name == name2 {
return Ok((type_.clone(), *mutable));
}
}
}
error().reason(format!("Identifier {name} is not defined"))
}
fn get_type(&self, name: &str) -> Result<Type> {
for s in self.syms.iter().rev() {
if let Symbol::Type(name2, t) = s {
if name == name2 {
return Ok(t.clone());
}
}
}
if let Some(p) = Primitive::from_string(name) {
return Ok(Type::Prim(p));
}
error().reason(format!("Type {name} is not defined"))
}
}

View file

@ -1,5 +1,5 @@
use crate::{
BinaryOp, Expression, ExpressionKind, Immediate, Parameter, Statement,
semantic::SymbolTable, BinaryOp, Expression, ExpressionKind, Immediate, Parameter, Statement,
StatementKind, UnaryOp,
};
@ -45,14 +45,6 @@ impl PartialEq for Type {
}
impl Type {
pub fn from_string(value: &str) -> Self {
if let Some(p) = Primitive::from_string(value) {
Type::Prim(p)
} else {
Type::Ambiguous
}
}
pub fn binary_op(lhs: &Type, op: BinaryOp, rhs: &Type) -> Result<Type> {
use Type as t;
let e = error().reason(format!(
@ -62,7 +54,7 @@ impl Type {
(t::Prim(a), t::Prim(b)) => {
let p = Primitive::binary_op(*a, op, *b)?;
Ok(t::Prim(p))
},
}
_ => e,
}
}
@ -87,73 +79,17 @@ impl Type {
(Ambiguous, t) => Some(t.clone()),
(Prim(p1), Prim(p2)) => {
let (p1, p2) = Primitive::coerce_ambiguous(*p1, *p2);
if p1 != p2 { None } else { Some(Type::Prim(p1)) }
},
if p1 != p2 {
None
} else {
Some(Type::Prim(p1))
}
}
_ => None,
}
}
}
#[derive(Debug, Clone)]
enum Symbol {
Var(String, Type, bool),
Type(String, Type),
BlockStart,
}
#[derive(Debug, Clone)]
struct SymbolTable {
syms: Vec<Symbol>,
}
impl SymbolTable {
fn define_var(&mut self, name: String, type_: Type, mutable: bool) {
self.syms.push(Symbol::Var(name, type_, mutable));
}
fn define_type(&mut self, name: String, type_: Type) {
self.syms.push(Symbol::Type(name, type_));
}
fn start_block(&mut self) {
self.syms.push(Symbol::BlockStart);
}
fn end_block(&mut self) {
while !self.syms.is_empty() {
if let Some(Symbol::BlockStart) = self.syms.pop() {
return;
}
}
unreachable!("Tried to exit global scope in symbol table")
}
fn get_var(&self, name: &str) -> Result<(Type, bool)> {
for s in self.syms.iter().rev() {
if let Symbol::Var(name2, type_, mutable) = s {
if name == name2 {
return Ok((type_.clone(), *mutable));
}
}
}
error().reason(format!("Identifier {name} is not defined"))
}
fn get_type(&self, name: &str) -> Result<Type> {
for s in self.syms.iter().rev() {
if let Symbol::Type(name2, t) = s {
if name == name2 {
return Ok(t.clone());
}
}
}
if let Some(p) = Primitive::from_string(name) {
return Ok(Type::Prim(p));
}
error().reason(format!("Type {name} is not defined"))
}
}
pub fn typecheck(program: Vec<Statement>) -> Vec<Statement> {
use StatementKind as s;
let mut table = SymbolTable { syms: vec![] };
@ -171,10 +107,7 @@ pub fn typecheck(program: Vec<Statement>) -> Vec<Statement> {
ret
}
fn statement(
mut stmt: Box<Statement>,
table: &mut SymbolTable,
) -> Result<Box<Statement>> {
fn statement(mut stmt: Box<Statement>, table: &mut SymbolTable) -> Result<Box<Statement>> {
use Primitive as p;
use StatementKind as s;
match stmt.kind {
@ -190,8 +123,7 @@ fn statement(
None => Type::Ambiguous,
};
let value = expression(value.into(), table)?;
let type_actual =
Type::coerce(&type_expect, &value.type_).reason(format!(
let type_actual = Type::coerce(&type_expect, &value.type_).reason(format!(
"Expected type '{:?}', found type '{:?}'",
type_expect, value.type_
))?;
@ -222,7 +154,7 @@ fn statement(
value: *value,
mutable,
};
},
}
s::Assignment { name, value } => {
let (type_, mutable) = table.get_var(&name).span(&stmt.span)?;
// Check that it is mutable
@ -240,7 +172,7 @@ fn statement(
));
}
stmt.kind = s::Assignment { name, value };
},
}
s::If {
predicate,
block,
@ -271,7 +203,7 @@ fn statement(
else_,
};
table.end_block();
},
}
s::While { predicate, block } => {
table.start_block();
let predicate = *expression(predicate.into(), table)?;
@ -292,10 +224,10 @@ fn statement(
block: new_block,
};
table.end_block();
},
}
s::Print(e) => {
stmt.kind = s::Print(*expression(e.into(), table)?);
},
}
s::Expression(mut e) => {
use ExpressionKind as e;
let is_func = if let e::Function { params, .. } = &mut e.kind {
@ -313,7 +245,7 @@ fn statement(
if is_func {
table.end_block();
}
},
}
s::Block(block) => {
table.start_block();
let mut new_block = vec![];
@ -322,16 +254,13 @@ fn statement(
}
stmt.kind = s::Block(new_block);
table.end_block();
},
}
s::Error(e) => return Err(e),
}
Ok(stmt)
}
fn expression(
mut expr: Box<Expression>,
table: &SymbolTable,
) -> Result<Box<Expression>> {
fn expression(mut expr: Box<Expression>, table: &SymbolTable) -> Result<Box<Expression>> {
use ExpressionKind as e;
use Immediate as i;
use Primitive as p;
@ -349,19 +278,19 @@ fn expression(
let type_ = Type::binary_op(&left.type_, op, &right.type_)?;
expr.kind = e::Binary { left, right, op };
type_
},
}
e::Unary { op, child } => {
let child = expression(child, table)?;
let type_ = Type::unary_op(op, &child.type_)?;
expr.kind = e::Unary { child, op };
type_
},
}
e::Parenthesis(inner) => {
let inner = expression(inner, table)?;
let type_ = inner.type_.clone();
expr.kind = e::Parenthesis(inner);
type_
},
}
e::Function {
mut params,
returns_str,
@ -385,15 +314,57 @@ fn expression(
params: params.into_iter().map(|p| p.type_actual).collect(),
returns: returns_actual.into(),
}
},
}
e::Call { callee, mut args } => {
let callee = expression(callee, table)?;
// Check that this is actually a function
let Type::Function {
ref params,
ref returns,
} = callee.type_
else {
return error()
.reason(format!("Cannot call type {:?}", callee.type_))
.span(&callee.span);
};
// Check for correct number of args
if params.len() != args.len() {
return error()
.reason(format!(
"Wrong number of arguments, function expects {}, found {}",
params.len(),
args.len()
))
.span(&callee.span);
}
// Check for correct arg types
for (expect, actual) in params.iter().zip(args.iter_mut()) {
*actual = *expression(actual.clone().into(), table)?;
let coerced_type = Type::coerce(expect, &actual.type_);
println!("{:?}, {:?}, {coerced_type:?}", expect, actual.type_);
if let Some(t) = coerced_type {
actual.type_ = t;
} else {
return error()
.reason(format!(
"Expected type {expect:?}, found {:?}",
actual.type_
))
.span(&actual.span);
}
}
let returns = *returns.clone();
expr.kind = e::Call { callee, args };
returns
}
e::Struct(mut params) => {
for p in &mut params {
p.type_actual = table.get_type(&p.type_str).span(&expr.span)?;
}
expr.kind = e::Struct(params.clone());
Type::Struct(params)
},
e::StructLiteral { name, mut args } => {
}
e::StructLiteral { name, args } => {
let type_ = table.get_type(&name).span(&expr.span)?;
let Type::Struct(params) = type_ else {
return error().reason(format!(
@ -403,7 +374,7 @@ fn expression(
};
if args.len() != params.len() {
return error().reason(format!(
"Incorrect number of parameters for struct '{}', expected {} and \
"Incorrect number of parameters for struct '{}'; expected {}, \
found {}",
name,
params.len(),
@ -430,9 +401,12 @@ fn expression(
.span(&argexpr.span);
}
let argspan = argexpr.span;
let arg = *expression(argexpr.clone().into(), table)
let mut arg = *expression(argexpr.clone().into(), table)
.trace_span(expr.span, "while parsing struct literal")?;
if &arg.type_ != ptype {
let coerced_type = Type::coerce(ptype, &arg.type_);
if let Some(t) = coerced_type {
arg.type_ = t;
} else {
return error()
.reason(format!(
"In struct literal, expected type '{ptype:?}', found '{:?}",
@ -447,43 +421,7 @@ fn expression(
args: new_args,
};
Type::Struct(params)
},
e::Call { callee, args } => {
let callee = expression(callee, table)?;
// Check that this is actually a function
let Type::Function {
ref params,
ref returns,
} = callee.type_
else {
return error()
.reason(format!("Cannot call type {:?}", callee.type_))
.span(&callee.span);
};
// Check for correct number of args
if params.len() != args.len() {
return error()
.reason(format!(
"Wrong number of arguments, function expects {}",
params.len()
))
.span(&callee.span);
}
// Check for correct arg types
for (expect, actual) in params.iter().zip(args.iter()) {
if *expect != actual.type_ {
return error()
.reason(format!(
"Expected type {expect:?}, found {:?}",
actual.type_
))
.span(&actual.span);
}
}
let returns = *returns.clone();
expr.kind = e::Call { callee, args };
returns
},
e::Field { namespace, field } => {
let namespace = expression(namespace, table)?;
// Check that namespace is struct
@ -515,7 +453,7 @@ fn expression(
.span(&field.span)?;
expr.kind = e::Field { namespace, field };
type_
},
}
};
expr.type_ = type_;
Ok(expr)