initial structure impl
This commit is contained in:
@@ -37,7 +37,10 @@ impl PType {
|
||||
output: &mut CompilerOutput,
|
||||
span: FileSpan,
|
||||
) -> Type {
|
||||
match namespace.get(&self.name).and_then(|ids| ids.ty) {
|
||||
let Some(name) = self.name.as_ref() else {
|
||||
return Type::Error;
|
||||
};
|
||||
match namespace.get(&name).and_then(|ids| ids.ty) {
|
||||
Some(id) => {
|
||||
if self.args.is_empty() {
|
||||
Type::Concrete(id)
|
||||
@@ -51,10 +54,10 @@ impl PType {
|
||||
}
|
||||
}
|
||||
None => {
|
||||
if let Ok(num) = self.name.parse::<u32>() {
|
||||
if let Ok(num) = name.parse::<u32>() {
|
||||
Type::Bits(num)
|
||||
} else {
|
||||
match self.name.as_str() {
|
||||
match name.as_str() {
|
||||
"slice" => {
|
||||
let inner = self.args[0].lower(namespace, output);
|
||||
Type::Slice(Box::new(inner))
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
use super::{func::FnLowerCtx, FnLowerable, PExpr, UnaryOp};
|
||||
use crate::ir::{DataDef, IRUInstruction, Origin, Type, VarInst};
|
||||
use crate::{
|
||||
ir::{DataDef, IRUInstruction, Origin, Type, VarInst},
|
||||
parser::PInfixOp,
|
||||
};
|
||||
|
||||
impl FnLowerable for PExpr {
|
||||
type Output = VarInst;
|
||||
@@ -13,7 +16,7 @@ impl FnLowerable for PExpr {
|
||||
DataDef {
|
||||
ty: Type::Bits(8).arr(data.len() as u32),
|
||||
origin: Origin::File(l.span),
|
||||
label: format!("string \"{}\"", s.replace("\n", "\\n"))
|
||||
label: format!("string \"{}\"", s.replace("\n", "\\n")),
|
||||
},
|
||||
data,
|
||||
);
|
||||
@@ -42,7 +45,7 @@ impl FnLowerable for PExpr {
|
||||
DataDef {
|
||||
ty,
|
||||
origin: Origin::File(l.span),
|
||||
label: format!("num {n:?}")
|
||||
label: format!("num {n:?}"),
|
||||
},
|
||||
n.whole.parse::<i64>().unwrap().to_le_bytes().to_vec(),
|
||||
);
|
||||
@@ -56,15 +59,39 @@ impl FnLowerable for PExpr {
|
||||
PExpr::Ident(i) => ctx.get_var(i)?,
|
||||
PExpr::BinaryOp(op, e1, e2) => {
|
||||
let res1 = e1.lower(ctx)?;
|
||||
let res2 = e2.lower(ctx)?;
|
||||
op.traitt();
|
||||
todo!();
|
||||
if *op == PInfixOp::Access {
|
||||
let sty = &ctx.map.get_var(res1.id).ty;
|
||||
let Type::Concrete(tid) = sty else {
|
||||
ctx.err(format!("Type {:?} has no fields", ctx.map.type_name(sty)));
|
||||
return None;
|
||||
};
|
||||
let struc = ctx.map.get_struct(*tid);
|
||||
let Some(box PExpr::Ident(ident)) = &e2.inner else {
|
||||
ctx.err(format!("Field accesses must be identifiers",));
|
||||
return None;
|
||||
};
|
||||
let fname = &ident.as_ref()?.0;
|
||||
let Some(field) = struc.fields.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
|
||||
} else {
|
||||
let res2 = e2.lower(ctx)?;
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
PExpr::UnaryOp(op, e) => {
|
||||
let res = e.lower(ctx)?;
|
||||
match op {
|
||||
UnaryOp::Ref => {
|
||||
let temp = ctx.temp(ctx.map.get_var(res.id).ty.clone());
|
||||
let temp = ctx.temp(ctx.map.get_var(res.id).ty.clone().rf());
|
||||
ctx.push(IRUInstruction::Ref {
|
||||
dest: temp,
|
||||
src: res,
|
||||
@@ -120,7 +147,7 @@ impl FnLowerable for PExpr {
|
||||
temp
|
||||
}
|
||||
PExpr::Group(e) => e.lower(ctx)?,
|
||||
PExpr::Construct(c) => todo!(),
|
||||
PExpr::Construct(c) => c.lower(ctx)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ use super::{CompilerMsg, CompilerOutput, FileSpan, FnLowerable, Node, PFunction}
|
||||
use crate::{
|
||||
ir::{
|
||||
FnDef, FnID, IRInstructions, IRUFunction, IRUInstruction, Idents, NamespaceGuard, Origin,
|
||||
Type, VarDef, VarID, VarInst,
|
||||
Type, VarDef, VarInst,
|
||||
},
|
||||
parser,
|
||||
};
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
mod arch;
|
||||
mod asm;
|
||||
mod block;
|
||||
mod def;
|
||||
mod expr;
|
||||
mod func;
|
||||
mod module;
|
||||
mod arch;
|
||||
mod struc;
|
||||
|
||||
use super::*;
|
||||
|
||||
|
||||
@@ -4,6 +4,9 @@ use super::{PModule, CompilerOutput};
|
||||
|
||||
impl PModule {
|
||||
pub fn lower(&self, map: &mut NamespaceGuard, output: &mut CompilerOutput) {
|
||||
for s in &self.structs {
|
||||
s.lower(map, output);
|
||||
}
|
||||
let mut fns = Vec::new();
|
||||
for f in &self.functions {
|
||||
if let Some(id) = f.lower_header(map, output) {
|
||||
|
||||
96
src/parser/v3/lower/struc.rs
Normal file
96
src/parser/v3/lower/struc.rs
Normal file
@@ -0,0 +1,96 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::{
|
||||
common::{CompilerMsg, CompilerOutput, FileSpan},
|
||||
ir::{IRUInstruction, NamespaceGuard, Origin, StructDef, StructField, VarInst},
|
||||
parser::{Node, PConstruct, PConstructFields, PStruct, PStructFields},
|
||||
};
|
||||
|
||||
use super::{FnLowerCtx, FnLowerable};
|
||||
|
||||
impl FnLowerable for PConstruct {
|
||||
type Output = VarInst;
|
||||
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<VarInst> {
|
||||
let ty = self.name.lower(ctx.map, ctx.output);
|
||||
let fields = match &self.fields {
|
||||
PConstructFields::Named(nodes) => nodes
|
||||
.iter()
|
||||
.flat_map(|n| {
|
||||
let def = n.as_ref()?;
|
||||
let name = def.name.as_ref()?.to_string();
|
||||
let expr = def.val.as_ref()?.lower(ctx)?;
|
||||
Some((name, expr))
|
||||
})
|
||||
.collect(),
|
||||
PConstructFields::Tuple(nodes) => nodes
|
||||
.iter()
|
||||
.enumerate()
|
||||
.flat_map(|(i, n)| {
|
||||
let expr = n.as_ref()?.lower(ctx)?;
|
||||
Some((format!("{i}"), expr))
|
||||
})
|
||||
.collect(),
|
||||
PConstructFields::None => HashMap::new(),
|
||||
};
|
||||
let id = ctx.temp(ty);
|
||||
ctx.push(IRUInstruction::Construct { dest: id, fields });
|
||||
Some(id)
|
||||
}
|
||||
}
|
||||
|
||||
impl PStruct {
|
||||
pub fn lower(
|
||||
&self,
|
||||
map: &mut NamespaceGuard,
|
||||
output: &mut CompilerOutput,
|
||||
span: FileSpan,
|
||||
) -> Option<()> {
|
||||
let mut offset = 0;
|
||||
let fields = match &self.fields {
|
||||
PStructFields::Named(nodes) => nodes
|
||||
.iter()
|
||||
.flat_map(|n| {
|
||||
let def = n.as_ref()?;
|
||||
let name = def.name.as_ref()?.to_string();
|
||||
let tynode = def.ty.as_ref()?;
|
||||
let ty = tynode.lower(map, output);
|
||||
let size = map.size_of_type(&ty).unwrap_or_else(|| {
|
||||
output.err(CompilerMsg {
|
||||
msg: format!("Size of type '{}' unknown", map.type_name(&ty)),
|
||||
spans: vec![tynode.span],
|
||||
});
|
||||
0
|
||||
});
|
||||
let res = Some((name, StructField { ty, offset }));
|
||||
offset += size;
|
||||
res
|
||||
})
|
||||
.collect(),
|
||||
PStructFields::Tuple(nodes) => nodes
|
||||
.iter()
|
||||
.enumerate()
|
||||
.flat_map(|(i, n)| {
|
||||
let ty = n.as_ref()?.lower(map, output, span);
|
||||
let size = map.size_of_type(&ty)?;
|
||||
let res = Some((format!("{i}"), StructField { ty, offset }));
|
||||
offset += size;
|
||||
res
|
||||
})
|
||||
.collect(),
|
||||
PStructFields::None => HashMap::new(),
|
||||
};
|
||||
map.def_type(StructDef {
|
||||
name: self.name.as_ref()?.to_string(),
|
||||
origin: Origin::File(span),
|
||||
size: offset,
|
||||
fields,
|
||||
});
|
||||
Some(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Node<PStruct> {
|
||||
pub fn lower(&self, map: &mut NamespaceGuard, output: &mut CompilerOutput) {
|
||||
self.as_ref().map(|i| i.lower(map, output, self.span));
|
||||
}
|
||||
}
|
||||
@@ -14,3 +14,6 @@ pub use node::*;
|
||||
pub use nodes::*;
|
||||
pub use parse::*;
|
||||
pub use token::*;
|
||||
|
||||
// idea: create generic "map" and "tuple" types which are used for function calls, tuples, struct
|
||||
// creation, etc. instead of specializing at the parsing level
|
||||
|
||||
@@ -23,6 +23,12 @@ impl<T> Node<T> {
|
||||
span: self.span,
|
||||
}
|
||||
}
|
||||
pub fn map<T2, F: Fn(T) -> T2>(self, f: F) -> Node<T2> {
|
||||
Node {
|
||||
inner: self.inner.map(f),
|
||||
span: self.span,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Deref for Node<T> {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use std::fmt::Debug;
|
||||
|
||||
use super::{
|
||||
MaybeParsable, Node, PExpr, PIdent, PType, Parsable, ParseResult, ParserCtx, Symbol,
|
||||
Token, CompilerMsg
|
||||
CompilerMsg, MaybeParsable, Node, PExpr, PIdent, PType, Parsable, ParseResult, ParserCtx,
|
||||
Symbol, Token,
|
||||
};
|
||||
|
||||
pub struct PVarDef {
|
||||
@@ -18,27 +18,30 @@ pub struct PFieldDef {
|
||||
impl Parsable for PVarDef {
|
||||
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||
let name = ctx.parse()?;
|
||||
if ctx.peek().is_some_and(|n| n.is_symbol(Symbol::Colon)) {
|
||||
ParseResult::Ok(if ctx.peek().is_some_and(|n| n.is_symbol(Symbol::Colon)) {
|
||||
ctx.next();
|
||||
ctx.parse().map(|ty| Self { name, ty: Some(ty) })
|
||||
Self {
|
||||
name,
|
||||
ty: Some(ctx.parse()?),
|
||||
}
|
||||
} else {
|
||||
ParseResult::Ok(Self { name, ty: None })
|
||||
}
|
||||
Self { name, ty: None }
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Parsable for PFieldDef {
|
||||
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||
let name = ctx.parse()?;
|
||||
if ctx.peek().is_some_and(|n| n.is_symbol(Symbol::Colon)) {
|
||||
ParseResult::Ok(if ctx.peek().is_some_and(|n| n.is_symbol(Symbol::Colon)) {
|
||||
ctx.next();
|
||||
ctx.parse().map(|ty| Self {
|
||||
Self {
|
||||
name,
|
||||
val: Some(ty),
|
||||
})
|
||||
val: Some(ctx.parse()?),
|
||||
}
|
||||
} else {
|
||||
ParseResult::Ok(Self { name, val: None })
|
||||
}
|
||||
Self { name, val: None }
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
use std::fmt::{Debug, Write};
|
||||
|
||||
use super::{
|
||||
op::{PInfixOp, UnaryOp}, util::parse_list, Keyword, Node, NodeParsable, PAsmBlock, PBlock, PConstruct, PIdent, PLiteral, Parsable, ParseResult, ParserCtx, Symbol, CompilerMsg
|
||||
op::{PInfixOp, UnaryOp},
|
||||
util::parse_list,
|
||||
CompilerMsg, Keyword, Node, NodeParsable, PAsmBlock, PBlock, PConstruct, PIdent, PLiteral,
|
||||
Parsable, ParseResult, ParserCtx, Symbol,
|
||||
};
|
||||
|
||||
type BoxNode = Node<Box<PExpr>>;
|
||||
@@ -53,12 +56,21 @@ impl Parsable for PExpr {
|
||||
Self::UnaryOp(op, n)
|
||||
}
|
||||
});
|
||||
} else if let Some(val) = Node::maybe_parse(ctx) {
|
||||
} else if let Some(val) = ctx.maybe_parse() {
|
||||
Self::Lit(val)
|
||||
} else {
|
||||
let res = ctx.parse();
|
||||
if res.node.is_some() {
|
||||
Self::Ident(res.node)
|
||||
// TODO: this is extremely limiting
|
||||
// maybe parse generically and then during lowering figure out what's a function vs
|
||||
// struct vs etc like mentioned in main.rs
|
||||
if let Some(next) = ctx.peek()
|
||||
&& next.is_symbol(Symbol::OpenCurly)
|
||||
{
|
||||
Self::Construct(ctx.parse_with(res.node)?)
|
||||
} else {
|
||||
Self::Ident(res.node)
|
||||
}
|
||||
} else {
|
||||
let next = ctx.expect_peek()?;
|
||||
return ParseResult::Err(CompilerMsg::unexpected_token(next, "an expression"));
|
||||
|
||||
@@ -5,7 +5,7 @@ use std::{
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct PIdent(String);
|
||||
pub struct PIdent(pub String);
|
||||
|
||||
impl Parsable for PIdent {
|
||||
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
use std::fmt::Debug;
|
||||
|
||||
use crate::parser::ParsableWith;
|
||||
|
||||
use super::{
|
||||
util::parse_list, Keyword, Node, PExpr, PFieldDef, PIdent, PType, PVarDef, Parsable,
|
||||
ParseResult, ParserCtx, CompilerMsg, Symbol,
|
||||
util::parse_list, CompilerMsg, Keyword, Node, PExpr, PFieldDef, PIdent, PType, PVarDef,
|
||||
Parsable, ParseResult, ParserCtx, Symbol,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -13,7 +15,7 @@ pub struct PStruct {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PConstruct {
|
||||
pub name: Node<PIdent>,
|
||||
pub name: Node<PType>,
|
||||
pub fields: PConstructFields,
|
||||
}
|
||||
|
||||
@@ -57,11 +59,20 @@ impl Parsable for PStruct {
|
||||
}
|
||||
}
|
||||
|
||||
impl Parsable for PConstruct {
|
||||
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||
ctx.expect_kw(Keyword::Struct)?;
|
||||
let name = ctx.parse()?;
|
||||
impl ParsableWith for PConstruct {
|
||||
type Data = Node<PIdent>;
|
||||
fn parse(ctx: &mut ParserCtx, name_node: Self::Data) -> ParseResult<Self> {
|
||||
let next = ctx.expect_peek()?;
|
||||
// TODO: this is not correct span; type should also span generics, which aren't even in
|
||||
// here yet
|
||||
let span = name_node.span;
|
||||
let name = Node::new(
|
||||
PType {
|
||||
name: name_node,
|
||||
args: Vec::new(),
|
||||
},
|
||||
span,
|
||||
);
|
||||
let fields = if next.is_symbol(Symbol::Semicolon) {
|
||||
ctx.next();
|
||||
PConstructFields::None
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
use std::fmt::Debug;
|
||||
|
||||
use super::{util::parse_list, Node, Parsable, ParseResult, ParserCtx, CompilerMsg, Symbol, Token};
|
||||
use super::{
|
||||
util::parse_list, CompilerMsg, Node, PIdent, Parsable, ParseResult, ParserCtx, Symbol, Token,
|
||||
};
|
||||
|
||||
pub struct PType {
|
||||
pub name: String,
|
||||
pub name: Node<PIdent>,
|
||||
pub args: Vec<Node<PType>>,
|
||||
}
|
||||
|
||||
@@ -11,18 +13,15 @@ impl Parsable for PType {
|
||||
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||
let next = ctx.expect_peek()?;
|
||||
let res = if next.is_symbol(Symbol::Ampersand) {
|
||||
let name = Node::new(PIdent("&".to_string()), next.span);
|
||||
ctx.next();
|
||||
let arg = ctx.parse()?;
|
||||
Self {
|
||||
name: "&".to_string(),
|
||||
name,
|
||||
args: vec![arg],
|
||||
}
|
||||
} else {
|
||||
let Token::Word(name) = &next.token else {
|
||||
return ParseResult::Err(CompilerMsg::unexpected_token(next, "a type identifier"));
|
||||
};
|
||||
let n = name.to_string();
|
||||
ctx.next();
|
||||
let n = ctx.parse()?;
|
||||
let mut args = Vec::new();
|
||||
if let Some(next) = ctx.peek() {
|
||||
if next.is_symbol(Symbol::OpenAngle) {
|
||||
@@ -38,8 +37,8 @@ impl Parsable for PType {
|
||||
|
||||
impl Debug for PType {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.name)?;
|
||||
if self.name == "&" {
|
||||
write!(f, "{:?}", self.name)?;
|
||||
if self.name.as_ref().is_some_and(|n| n.0 == "&") {
|
||||
write!(f, "{:?}", self.args[0])?;
|
||||
} else if !self.args.is_empty() {
|
||||
write!(f, "<{:?}>", self.args)?;
|
||||
|
||||
Reference in New Issue
Block a user