structs r a lot more sane in code, can now actually assign & stuff
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
use crate::ir::{IRUInstruction, VarInst};
|
||||
use crate::ir::{IRUInstruction, Type, VarInst};
|
||||
|
||||
use super::{FnLowerCtx, FnLowerable, PBlock, PStatement};
|
||||
|
||||
@@ -9,7 +9,7 @@ impl FnLowerable for PBlock {
|
||||
for statement in &self.statements {
|
||||
statement.lower(ctx);
|
||||
}
|
||||
let res = self.result.as_ref().map(|r| r.lower(ctx)).flatten();
|
||||
let res = self.result.as_ref().and_then(|r| r.lower(ctx));
|
||||
ctx.program.pop();
|
||||
res
|
||||
}
|
||||
@@ -28,8 +28,13 @@ impl FnLowerable for PStatement {
|
||||
None
|
||||
}
|
||||
super::PStatement::Return(e) => {
|
||||
let src = e.lower(ctx)?;
|
||||
ctx.push_at(IRUInstruction::Ret { src }, src.span);
|
||||
if let Some(e) = e {
|
||||
let src = e.lower(ctx)?;
|
||||
ctx.push_at(IRUInstruction::Ret { src }, src.span);
|
||||
} else {
|
||||
let src = ctx.temp(Type::Unit);
|
||||
ctx.push_at(IRUInstruction::Ret { src }, src.span);
|
||||
}
|
||||
None
|
||||
}
|
||||
super::PStatement::Expr(e) => e.lower(ctx),
|
||||
|
||||
@@ -13,6 +13,7 @@ impl Node<PVarDef> {
|
||||
Some(VarDef {
|
||||
name,
|
||||
ty,
|
||||
parent: None,
|
||||
origin: self.span,
|
||||
})
|
||||
}
|
||||
@@ -36,18 +37,14 @@ impl PType {
|
||||
let Some(name) = self.name.as_ref() else {
|
||||
return Type::Error;
|
||||
};
|
||||
match namespace.get(&name).and_then(|ids| ids.ty) {
|
||||
match namespace.get(&name).and_then(|ids| ids.struc) {
|
||||
Some(id) => {
|
||||
if self.args.is_empty() {
|
||||
Type::Concrete(id)
|
||||
} else {
|
||||
let args = self
|
||||
.args
|
||||
.iter()
|
||||
.map(|n| n.lower(namespace, output))
|
||||
.collect();
|
||||
Type::Generic { base: id, args }
|
||||
}
|
||||
let args = self
|
||||
.args
|
||||
.iter()
|
||||
.map(|n| n.lower(namespace, output))
|
||||
.collect();
|
||||
Type::Struct { id, args }
|
||||
}
|
||||
None => {
|
||||
if let Ok(num) = name.parse::<u32>() {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use super::{func::FnLowerCtx, FnLowerable, PExpr, UnaryOp};
|
||||
use crate::{
|
||||
ir::{DataDef, IRUInstruction, Type, VarInst},
|
||||
ir::{DataDef, FieldRef, IRUInstruction, Type, VarInst},
|
||||
parser::PInfixOp,
|
||||
};
|
||||
|
||||
@@ -61,30 +61,36 @@ impl FnLowerable for PExpr {
|
||||
let res1 = e1.lower(ctx)?;
|
||||
if *op == PInfixOp::Access {
|
||||
let sty = &ctx.program.get_var(res1.id).ty;
|
||||
let Type::Concrete(tid) = sty else {
|
||||
let Type::Struct {
|
||||
id: struct_id,
|
||||
args,
|
||||
} = sty
|
||||
else {
|
||||
ctx.err(format!(
|
||||
"Type {:?} has no fields",
|
||||
ctx.program.type_name(sty)
|
||||
));
|
||||
return None;
|
||||
};
|
||||
let struc = ctx.program.get_struct(*tid);
|
||||
let struc = ctx.program.get_struct(*struct_id);
|
||||
let Some(box PExpr::Ident(ident)) = &e2.inner else {
|
||||
ctx.err(format!("Field accesses must be identifiers",));
|
||||
ctx.err("Field accesses must be identifiers".to_string());
|
||||
return None;
|
||||
};
|
||||
let fname = &ident.as_ref()?.0;
|
||||
let Some(field) = struc.fields.get(fname) else {
|
||||
let Some(&field) = struc.field_map.get(fname) else {
|
||||
ctx.err(format!("Field '{fname}' not in struct"));
|
||||
return None;
|
||||
};
|
||||
let temp = ctx.temp(field.ty.clone());
|
||||
ctx.push(IRUInstruction::Access {
|
||||
dest: temp,
|
||||
src: res1,
|
||||
field: fname.to_string(),
|
||||
});
|
||||
temp
|
||||
let fdef = struc.field(field);
|
||||
ctx.temp_subvar(
|
||||
fdef.ty.clone(),
|
||||
FieldRef {
|
||||
var: res1.id,
|
||||
struc: *struct_id,
|
||||
field,
|
||||
},
|
||||
)
|
||||
} else {
|
||||
let res2 = e2.lower(ctx)?;
|
||||
match op {
|
||||
@@ -186,6 +192,10 @@ impl FnLowerable for PExpr {
|
||||
ctx.push(IRUInstruction::Break);
|
||||
return None;
|
||||
}
|
||||
PExpr::Continue => {
|
||||
ctx.push(IRUInstruction::Continue);
|
||||
return None;
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use super::{CompilerMsg, CompilerOutput, FileSpan, FnLowerable, Node, PFunction};
|
||||
use crate::{
|
||||
ir::{
|
||||
FnDef, FnID, IRUFunction, IRUInstrInst, IRUInstruction, IRUProgram, Idents, Origin, Type,
|
||||
VarDef, VarInst,
|
||||
FnDef, FnID, IRUFunction, IRUInstrInst, IRUInstruction, IRUProgram, Idents, Type, VarDef,
|
||||
VarInst, FieldRef,
|
||||
},
|
||||
parser,
|
||||
};
|
||||
@@ -32,6 +32,7 @@ impl PFunction {
|
||||
a.lower(map, output).unwrap_or(VarDef {
|
||||
name: "{error}".to_string(),
|
||||
origin: a.span,
|
||||
parent: None,
|
||||
ty: Type::Error,
|
||||
})
|
||||
})
|
||||
@@ -117,6 +118,9 @@ impl FnLowerCtx<'_> {
|
||||
pub fn temp(&mut self, ty: Type) -> VarInst {
|
||||
self.program.temp_var(self.span, ty)
|
||||
}
|
||||
pub fn temp_subvar(&mut self, ty: Type, parent: FieldRef) -> VarInst {
|
||||
self.program.temp_subvar(self.span, ty, parent)
|
||||
}
|
||||
pub fn push(&mut self, i: IRUInstruction) {
|
||||
self.instructions.push(IRUInstrInst { i, span: self.span });
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::{
|
||||
common::{CompilerMsg, CompilerOutput, FileSpan},
|
||||
ir::{IRUInstruction, IRUProgram, Origin, StructDef, StructField, VarInst},
|
||||
common::{CompilerOutput, FileSpan},
|
||||
ir::{FieldID, IRUInstruction, IRUProgram, StructDef, StructField, Type, VarInst},
|
||||
parser::{Node, PConstruct, PConstructFields, PStruct, PStructFields},
|
||||
};
|
||||
|
||||
@@ -12,6 +12,18 @@ impl FnLowerable for PConstruct {
|
||||
type Output = VarInst;
|
||||
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<VarInst> {
|
||||
let ty = self.name.lower(ctx.program, ctx.output);
|
||||
let field_map = match ty {
|
||||
Type::Struct { id, .. } => ctx.program.get_struct(id),
|
||||
_ => {
|
||||
ctx.err(format!(
|
||||
"Type {} cannot be constructed",
|
||||
ctx.program.type_name(&ty)
|
||||
));
|
||||
return None;
|
||||
}
|
||||
}
|
||||
.field_map
|
||||
.clone();
|
||||
let fields = match &self.fields {
|
||||
PConstructFields::Named(nodes) => nodes
|
||||
.iter()
|
||||
@@ -19,7 +31,15 @@ impl FnLowerable for PConstruct {
|
||||
let def = n.as_ref()?;
|
||||
let name = def.name.as_ref()?.to_string();
|
||||
let expr = def.val.as_ref()?.lower(ctx)?;
|
||||
Some((name, expr))
|
||||
let Some(&field) = field_map.get(&name) else {
|
||||
ctx.err(format!(
|
||||
"Struct {} has no field {}",
|
||||
ctx.program.type_name(&ty),
|
||||
name
|
||||
));
|
||||
return None;
|
||||
};
|
||||
Some((field, expr))
|
||||
})
|
||||
.collect(),
|
||||
PConstructFields::Tuple(nodes) => nodes
|
||||
@@ -27,10 +47,19 @@ impl FnLowerable for PConstruct {
|
||||
.enumerate()
|
||||
.flat_map(|(i, n)| {
|
||||
let expr = n.as_ref()?.lower(ctx)?;
|
||||
Some((format!("{i}"), expr))
|
||||
let name = format!("{i}");
|
||||
let Some(&field) = field_map.get(&name) else {
|
||||
ctx.err(format!(
|
||||
"Struct {} has no field {}",
|
||||
ctx.program.type_name(&ty),
|
||||
name
|
||||
));
|
||||
return None;
|
||||
};
|
||||
Some((field, expr))
|
||||
})
|
||||
.collect(),
|
||||
PConstructFields::None => HashMap::new(),
|
||||
PConstructFields::None => Default::default(),
|
||||
};
|
||||
let id = ctx.temp(ty);
|
||||
ctx.push(IRUInstruction::Construct { dest: id, fields });
|
||||
@@ -45,7 +74,7 @@ impl PStruct {
|
||||
output: &mut CompilerOutput,
|
||||
span: FileSpan,
|
||||
) -> Option<()> {
|
||||
let mut offset = 0;
|
||||
let mut field_map = HashMap::new();
|
||||
let fields = match &self.fields {
|
||||
PStructFields::Named(nodes) => nodes
|
||||
.iter()
|
||||
@@ -54,16 +83,7 @@ impl PStruct {
|
||||
let name = def.name.as_ref()?.to_string();
|
||||
let tynode = def.ty.as_ref()?;
|
||||
let ty = tynode.lower(p, output);
|
||||
let size = p.size_of_type(&ty).unwrap_or_else(|| {
|
||||
output.err(CompilerMsg {
|
||||
msg: format!("Size of type '{}' unknown", p.type_name(&ty)),
|
||||
spans: vec![tynode.span],
|
||||
});
|
||||
0
|
||||
});
|
||||
let res = Some((name, StructField { ty, offset }));
|
||||
offset += size;
|
||||
res
|
||||
Some((name, ty))
|
||||
})
|
||||
.collect(),
|
||||
PStructFields::Tuple(nodes) => nodes
|
||||
@@ -71,18 +91,23 @@ impl PStruct {
|
||||
.enumerate()
|
||||
.flat_map(|(i, n)| {
|
||||
let ty = n.as_ref()?.lower(p, output, span);
|
||||
let size = p.size_of_type(&ty)?;
|
||||
let res = Some((format!("{i}"), StructField { ty, offset }));
|
||||
offset += size;
|
||||
res
|
||||
Some((format!("{i}"), ty))
|
||||
})
|
||||
.collect(),
|
||||
PStructFields::None => HashMap::new(),
|
||||
};
|
||||
p.def_type(StructDef {
|
||||
PStructFields::None => vec![],
|
||||
}
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(i, (name, ty))| {
|
||||
let id = FieldID(i);
|
||||
field_map.insert(name.clone(), id);
|
||||
StructField { name, ty }
|
||||
})
|
||||
.collect();
|
||||
p.def_struct(StructDef {
|
||||
name: self.name.as_ref()?.to_string(),
|
||||
origin: span,
|
||||
size: offset,
|
||||
field_map,
|
||||
fields,
|
||||
});
|
||||
Some(())
|
||||
|
||||
@@ -22,6 +22,7 @@ pub enum PExpr {
|
||||
If(BoxNode, BoxNode),
|
||||
Loop(BoxNode),
|
||||
Break,
|
||||
Continue,
|
||||
}
|
||||
|
||||
impl Parsable for PExpr {
|
||||
@@ -57,6 +58,9 @@ impl Parsable for PExpr {
|
||||
} else if next.is_keyword(Keyword::Break) {
|
||||
ctx.next();
|
||||
Self::Break
|
||||
} else if next.is_keyword(Keyword::Continue) {
|
||||
ctx.next();
|
||||
Self::Continue
|
||||
} else if next.is_keyword(Keyword::Asm) {
|
||||
ctx.next();
|
||||
Self::AsmBlock(ctx.parse()?)
|
||||
@@ -165,6 +169,7 @@ impl Debug for PExpr {
|
||||
PExpr::If(cond, res) => write!(f, "if {cond:?} then {res:?}")?,
|
||||
PExpr::Loop(res) => write!(f, "loop -> {res:?}")?,
|
||||
PExpr::Break => write!(f, "break")?,
|
||||
PExpr::Continue => write!(f, "continue")?,
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use super::{PExpr, Keyword, Node, Parsable, ParseResult, ParserCtx, Symbol, Token, PVarDef};
|
||||
use super::{Keyword, Node, PExpr, PVarDef, Parsable, ParseResult, ParserCtx, Symbol, Token};
|
||||
|
||||
pub enum PStatement {
|
||||
Let(Node<PVarDef>, Node<PExpr>),
|
||||
Return(Node<PExpr>),
|
||||
Return(Option<Node<PExpr>>),
|
||||
Expr(Node<PExpr>),
|
||||
}
|
||||
|
||||
@@ -18,7 +18,11 @@ impl Parsable for PStatement {
|
||||
}
|
||||
Token::Keyword(Keyword::Return) => {
|
||||
ctx.next();
|
||||
ctx.parse().map(Self::Return)
|
||||
if ctx.peek().is_some_and(|t| t.is_symbol(Symbol::Semicolon)) {
|
||||
ParseResult::Ok(Self::Return(None))
|
||||
} else {
|
||||
ctx.parse().map(|res| Self::Return(Some(res)))
|
||||
}
|
||||
}
|
||||
_ => ctx.parse().map(Self::Expr),
|
||||
}
|
||||
|
||||
@@ -4,8 +4,9 @@ pub enum Keyword {
|
||||
Let,
|
||||
If,
|
||||
Return,
|
||||
Break,
|
||||
Loop,
|
||||
Break,
|
||||
Continue,
|
||||
Struct,
|
||||
Trait,
|
||||
Impl,
|
||||
@@ -24,6 +25,7 @@ impl Keyword {
|
||||
"for" => Self::For,
|
||||
"return" => Self::Return,
|
||||
"break" => Self::Break,
|
||||
"continue" => Self::Continue,
|
||||
"loop" => Self::Loop,
|
||||
"trait" => Self::Trait,
|
||||
"impl" => Self::Impl,
|
||||
|
||||
Reference in New Issue
Block a user