initial structure impl
This commit is contained in:
@@ -1,11 +1,24 @@
|
|||||||
|
struct Test {
|
||||||
|
a: 64,
|
||||||
|
b: 64,
|
||||||
|
}
|
||||||
|
|
||||||
fn start() {
|
fn start() {
|
||||||
println("Helld!");
|
println("Helld!");
|
||||||
println("Hello World!!!!!");
|
println("Hello World!!!!!");
|
||||||
thinger();
|
thinger();
|
||||||
println("what");
|
println("what");
|
||||||
print(tester());
|
print(tester());
|
||||||
|
let test = Test {
|
||||||
|
a: 10,
|
||||||
|
b: 9,
|
||||||
|
};
|
||||||
arger("a", "b", "c");
|
arger("a", "b", "c");
|
||||||
exit(mul(sub(add(5, 9), 1), 3));
|
let z = sub(test.a, 10);
|
||||||
|
exit(add(mul(sub(add(5, test.b), 1), 3), z));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn structer(test: Test) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn thinger() {
|
fn thinger() {
|
||||||
|
|||||||
@@ -88,7 +88,23 @@ pub fn compile(program: &IRLProgram) -> UnlinkedProgram<LI> {
|
|||||||
for i in &f.instructions {
|
for i in &f.instructions {
|
||||||
irli.push((v.len(), format!("{i:?}")));
|
irli.push((v.len(), format!("{i:?}")));
|
||||||
match i {
|
match i {
|
||||||
IRI::Mv { dest, src } => todo!(),
|
IRI::Mv {
|
||||||
|
dest,
|
||||||
|
dest_offset,
|
||||||
|
src,
|
||||||
|
src_offset,
|
||||||
|
} => {
|
||||||
|
let s = align(&f.stack[src]) as u32;
|
||||||
|
mov_mem(
|
||||||
|
&mut v,
|
||||||
|
sp,
|
||||||
|
stack[src] + align(src_offset),
|
||||||
|
sp,
|
||||||
|
stack[dest] + align(dest_offset),
|
||||||
|
t0,
|
||||||
|
s,
|
||||||
|
);
|
||||||
|
}
|
||||||
IRI::Ref { dest, src } => todo!(),
|
IRI::Ref { dest, src } => todo!(),
|
||||||
IRI::LoadAddr { dest, offset, src } => {
|
IRI::LoadAddr { dest, offset, src } => {
|
||||||
v.extend([
|
v.extend([
|
||||||
|
|||||||
@@ -16,7 +16,9 @@ pub struct IRLFunction {
|
|||||||
pub enum IRLInstruction {
|
pub enum IRLInstruction {
|
||||||
Mv {
|
Mv {
|
||||||
dest: VarID,
|
dest: VarID,
|
||||||
|
dest_offset: Size,
|
||||||
src: VarID,
|
src: VarID,
|
||||||
|
src_offset: Size,
|
||||||
},
|
},
|
||||||
Ref {
|
Ref {
|
||||||
dest: VarID,
|
dest: VarID,
|
||||||
|
|||||||
@@ -41,7 +41,9 @@ impl IRLProgram {
|
|||||||
}
|
}
|
||||||
instrs.push(IRLInstruction::Mv {
|
instrs.push(IRLInstruction::Mv {
|
||||||
dest: dest.id,
|
dest: dest.id,
|
||||||
|
dest_offset: 0,
|
||||||
src: src.id,
|
src: src.id,
|
||||||
|
src_offset: 0,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
IRUInstruction::Ref { dest, src } => {
|
IRUInstruction::Ref { dest, src } => {
|
||||||
@@ -83,7 +85,10 @@ impl IRLProgram {
|
|||||||
src: sym,
|
src: sym,
|
||||||
});
|
});
|
||||||
|
|
||||||
let sym = builder.anon_ro_data(&(*len as u64).to_le_bytes(), Some(format!("len: {}", len)));
|
let sym = builder.anon_ro_data(
|
||||||
|
&(*len as u64).to_le_bytes(),
|
||||||
|
Some(format!("len: {}", len)),
|
||||||
|
);
|
||||||
instrs.push(IRLInstruction::LoadData {
|
instrs.push(IRLInstruction::LoadData {
|
||||||
dest: dest.id,
|
dest: dest.id,
|
||||||
offset: 8,
|
offset: 8,
|
||||||
@@ -129,6 +134,46 @@ impl IRLProgram {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
IRUInstruction::Ret { src } => instrs.push(IRLInstruction::Ret { src: src.id }),
|
IRUInstruction::Ret { src } => instrs.push(IRLInstruction::Ret { src: src.id }),
|
||||||
|
IRUInstruction::Construct { dest, fields } => {
|
||||||
|
if alloc_stack(dest.id) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let ty = &p.get_var(dest.id).ty;
|
||||||
|
let Type::Concrete(id) = ty else {
|
||||||
|
return Err(format!("Failed to contruct type {}", p.type_name(ty)));
|
||||||
|
};
|
||||||
|
let struc = p.get_struct(*id);
|
||||||
|
for (name, var) in fields {
|
||||||
|
instrs.push(IRLInstruction::Mv {
|
||||||
|
dest: dest.id,
|
||||||
|
src: var.id,
|
||||||
|
dest_offset: struc.fields[name].offset,
|
||||||
|
src_offset: 0,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IRUInstruction::Access { dest, src, field } => {
|
||||||
|
if alloc_stack(dest.id) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let ty = &p.get_var(src.id).ty;
|
||||||
|
let Type::Concrete(id) = ty else {
|
||||||
|
return Err(format!(
|
||||||
|
"Failed to access field of struct {}",
|
||||||
|
p.type_name(ty)
|
||||||
|
));
|
||||||
|
};
|
||||||
|
let struc = p.get_struct(*id);
|
||||||
|
let Some(field) = struc.fields.get(field) else {
|
||||||
|
return Err(format!("No field {field} in struct {}", p.type_name(ty)));
|
||||||
|
};
|
||||||
|
instrs.push(IRLInstruction::Mv {
|
||||||
|
dest: dest.id,
|
||||||
|
src: src.id,
|
||||||
|
src_offset: field.offset,
|
||||||
|
dest_offset: 0,
|
||||||
|
})
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
builder.write_fn(
|
builder.write_fn(
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use crate::common::FileSpan;
|
use crate::{common::FileSpan, ir::{Len, Size}};
|
||||||
|
|
||||||
use super::Type;
|
use super::Type;
|
||||||
use std::fmt::Debug;
|
use std::{collections::HashMap, fmt::Debug};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct FnDef {
|
pub struct FnDef {
|
||||||
@@ -12,9 +12,16 @@ pub struct FnDef {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct TypeDef {
|
pub struct StructField {
|
||||||
|
pub ty: Type,
|
||||||
|
pub offset: Len,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct StructDef {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub args: usize,
|
pub fields: HashMap<String, StructField>,
|
||||||
|
pub size: Size,
|
||||||
pub origin: Origin,
|
pub origin: Origin,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
use std::fmt::Write;
|
use std::{collections::HashMap, fmt::Write};
|
||||||
|
|
||||||
use super::{arch::riscv64::RV64Instruction, inst::VarInst, DataID, FnID, IRUInstrInst, Type, VarID};
|
use super::{
|
||||||
|
arch::riscv64::RV64Instruction, inst::VarInst, DataID, FnID, IRUInstrInst, Type, VarID,
|
||||||
|
};
|
||||||
use crate::{common::FileSpan, compiler::arch::riscv::Reg, util::Padder};
|
use crate::{common::FileSpan, compiler::arch::riscv::Reg, util::Padder};
|
||||||
|
|
||||||
pub struct IRUFunction {
|
pub struct IRUFunction {
|
||||||
@@ -31,6 +33,11 @@ pub enum IRUInstruction {
|
|||||||
dest: VarInst,
|
dest: VarInst,
|
||||||
src: FnID,
|
src: FnID,
|
||||||
},
|
},
|
||||||
|
Access {
|
||||||
|
dest: VarInst,
|
||||||
|
src: VarInst,
|
||||||
|
field: String,
|
||||||
|
},
|
||||||
Call {
|
Call {
|
||||||
dest: VarInst,
|
dest: VarInst,
|
||||||
f: VarInst,
|
f: VarInst,
|
||||||
@@ -43,6 +50,10 @@ pub enum IRUInstruction {
|
|||||||
Ret {
|
Ret {
|
||||||
src: VarInst,
|
src: VarInst,
|
||||||
},
|
},
|
||||||
|
Construct {
|
||||||
|
dest: VarInst,
|
||||||
|
fields: HashMap<String, VarInst>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct IRInstructions {
|
pub struct IRInstructions {
|
||||||
@@ -84,6 +95,8 @@ impl std::fmt::Debug for IRUInstruction {
|
|||||||
} => write!(f, "{dest:?} <- {func:?}({args:?})"),
|
} => write!(f, "{dest:?} <- {func:?}({args:?})"),
|
||||||
Self::AsmBlock { args, instructions } => write!(f, "asm {args:?} {instructions:#?}"),
|
Self::AsmBlock { args, instructions } => write!(f, "asm {args:?} {instructions:#?}"),
|
||||||
Self::Ret { src } => f.debug_struct("Ret").field("src", src).finish(),
|
Self::Ret { src } => f.debug_struct("Ret").field("src", src).finish(),
|
||||||
|
Self::Construct { dest, fields } => write!(f, "{dest:?} <- {fields:?}"),
|
||||||
|
Self::Access { dest, src, field } => write!(f, "{dest:?} <- {src:?}.{field}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ use super::{inst::VarInst, *};
|
|||||||
pub struct IRUProgram {
|
pub struct IRUProgram {
|
||||||
pub fn_defs: Vec<FnDef>,
|
pub fn_defs: Vec<FnDef>,
|
||||||
pub var_defs: Vec<VarDef>,
|
pub var_defs: Vec<VarDef>,
|
||||||
pub type_defs: Vec<TypeDef>,
|
pub type_defs: Vec<StructDef>,
|
||||||
pub data_defs: Vec<DataDef>,
|
pub data_defs: Vec<DataDef>,
|
||||||
pub fns: Vec<Option<IRUFunction>>,
|
pub fns: Vec<Option<IRUFunction>>,
|
||||||
pub data: Vec<Vec<u8>>,
|
pub data: Vec<Vec<u8>>,
|
||||||
@@ -59,7 +59,7 @@ impl IRUProgram {
|
|||||||
pub fn get_fn_var(&self, id: VarID) -> Option<&FnDef> {
|
pub fn get_fn_var(&self, id: VarID) -> Option<&FnDef> {
|
||||||
Some(&self.fn_defs[self.fn_map.get(&id)?.0])
|
Some(&self.fn_defs[self.fn_map.get(&id)?.0])
|
||||||
}
|
}
|
||||||
pub fn get_type(&self, id: TypeID) -> &TypeDef {
|
pub fn get_struct(&self, id: TypeID) -> &StructDef {
|
||||||
&self.type_defs[id.0]
|
&self.type_defs[id.0]
|
||||||
}
|
}
|
||||||
pub fn alias_fn(&mut self, name: &str, id: FnID) {
|
pub fn alias_fn(&mut self, name: &str, id: FnID) {
|
||||||
@@ -82,10 +82,7 @@ impl IRUProgram {
|
|||||||
pub fn size_of_type(&self, ty: &Type) -> Option<Size> {
|
pub fn size_of_type(&self, ty: &Type) -> Option<Size> {
|
||||||
// TODO: target matters
|
// TODO: target matters
|
||||||
Some(match ty {
|
Some(match ty {
|
||||||
Type::Concrete(id) => {
|
Type::Concrete(id) => self.type_defs[id.0].size,
|
||||||
let def = &self.type_defs[id.0];
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
Type::Bits(b) => *b,
|
Type::Bits(b) => *b,
|
||||||
Type::Generic { base, args } => todo!(),
|
Type::Generic { base, args } => todo!(),
|
||||||
Type::Fn { args, ret } => todo!(),
|
Type::Fn { args, ret } => todo!(),
|
||||||
@@ -131,7 +128,7 @@ impl IRUProgram {
|
|||||||
|
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
pub fn def_type(&mut self, def: TypeDef) -> TypeID {
|
pub fn def_type(&mut self, def: StructDef) -> TypeID {
|
||||||
let i = self.type_defs.len();
|
let i = self.type_defs.len();
|
||||||
let id = TypeID(i);
|
let id = TypeID(i);
|
||||||
self.insert(&def.name, Ident::Type(id));
|
self.insert(&def.name, Ident::Type(id));
|
||||||
@@ -148,10 +145,10 @@ impl IRUProgram {
|
|||||||
let mut str = String::new();
|
let mut str = String::new();
|
||||||
match ty {
|
match ty {
|
||||||
Type::Concrete(t) => {
|
Type::Concrete(t) => {
|
||||||
str += &self.get_type(*t).name;
|
str += &self.get_struct(*t).name;
|
||||||
}
|
}
|
||||||
Type::Generic { base, args } => {
|
Type::Generic { base, args } => {
|
||||||
str += &self.get_type(*base).name;
|
str += &self.get_struct(*base).name;
|
||||||
if let Some(arg) = args.first() {
|
if let Some(arg) = args.first() {
|
||||||
str = str + "<" + &self.type_name(arg);
|
str = str + "<" + &self.type_name(arg);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use super::{IRUInstruction, IRUProgram, Len, TypeID};
|
use super::{IRUProgram, Len, TypeID};
|
||||||
|
|
||||||
#[derive(Clone, PartialEq)]
|
#[derive(Clone, PartialEq)]
|
||||||
pub enum Type {
|
pub enum Type {
|
||||||
@@ -30,14 +30,7 @@ pub fn resolve_types(ns: &IRUProgram) {
|
|||||||
for (i, f) in ns.iter_fns() {
|
for (i, f) in ns.iter_fns() {
|
||||||
for inst in &f.instructions {
|
for inst in &f.instructions {
|
||||||
match &inst.i {
|
match &inst.i {
|
||||||
IRUInstruction::Mv { dest, src } => todo!(),
|
_ => todo!(),
|
||||||
IRUInstruction::Ref { dest, src } => todo!(),
|
|
||||||
IRUInstruction::LoadData { dest, src } => todo!(),
|
|
||||||
IRUInstruction::LoadSlice { dest, src } => todo!(),
|
|
||||||
IRUInstruction::LoadFn { dest, src } => todo!(),
|
|
||||||
IRUInstruction::Call { dest, f, args } => todo!(),
|
|
||||||
IRUInstruction::AsmBlock { instructions, args } => todo!(),
|
|
||||||
IRUInstruction::Ret { src } => todo!(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// TODO: move this into ir, not parser
|
// TODO: move this into ir, not parser
|
||||||
use super::{IRUProgram, Type};
|
use super::{IRUInstruction, IRUProgram, Type};
|
||||||
use crate::common::{CompilerMsg, CompilerOutput};
|
use crate::common::{CompilerMsg, CompilerOutput};
|
||||||
|
|
||||||
impl IRUProgram {
|
impl IRUProgram {
|
||||||
@@ -8,18 +8,18 @@ impl IRUProgram {
|
|||||||
for (f, fd) in self.fns.iter().flatten().zip(&self.fn_defs) {
|
for (f, fd) in self.fns.iter().flatten().zip(&self.fn_defs) {
|
||||||
for i in &f.instructions {
|
for i in &f.instructions {
|
||||||
match &i.i {
|
match &i.i {
|
||||||
super::IRUInstruction::Mv { dest, src } => {
|
IRUInstruction::Mv { dest, src } => {
|
||||||
let dest = self.get_var(dest.id);
|
let dest = self.get_var(dest.id);
|
||||||
let src = self.get_var(src.id);
|
let src = self.get_var(src.id);
|
||||||
output.check_assign(self, &src.ty, &dest.ty, i.span);
|
output.check_assign(self, &src.ty, &dest.ty, i.span);
|
||||||
}
|
}
|
||||||
super::IRUInstruction::Ref { dest, src } => todo!(),
|
IRUInstruction::Ref { dest, src } => todo!(),
|
||||||
super::IRUInstruction::LoadData { dest, src } => {
|
IRUInstruction::LoadData { dest, src } => {
|
||||||
let dest = self.get_var(dest.id);
|
let dest = self.get_var(dest.id);
|
||||||
let src = self.get_data(*src);
|
let src = self.get_data(*src);
|
||||||
output.check_assign(self, &src.ty, &dest.ty, i.span);
|
output.check_assign(self, &src.ty, &dest.ty, i.span);
|
||||||
}
|
}
|
||||||
super::IRUInstruction::LoadSlice { dest, src } => {
|
IRUInstruction::LoadSlice { dest, src } => {
|
||||||
let dest = self.get_var(dest.id);
|
let dest = self.get_var(dest.id);
|
||||||
let src = self.get_data(*src);
|
let src = self.get_data(*src);
|
||||||
let Type::Array(srcty, ..) = &src.ty else {
|
let Type::Array(srcty, ..) = &src.ty else {
|
||||||
@@ -27,8 +27,8 @@ impl IRUProgram {
|
|||||||
};
|
};
|
||||||
output.check_assign(self, &Type::Slice(srcty.clone()), &dest.ty, i.span);
|
output.check_assign(self, &Type::Slice(srcty.clone()), &dest.ty, i.span);
|
||||||
}
|
}
|
||||||
super::IRUInstruction::LoadFn { dest, src } => todo!(),
|
IRUInstruction::LoadFn { dest, src } => todo!(),
|
||||||
super::IRUInstruction::Call { dest, f, args } => {
|
IRUInstruction::Call { dest, f, args } => {
|
||||||
let destty = &self.get_var(dest.id).ty;
|
let destty = &self.get_var(dest.id).ty;
|
||||||
let f = self.get_var(f.id);
|
let f = self.get_var(f.id);
|
||||||
let Type::Fn { args: argtys, ret } = &f.ty else {
|
let Type::Fn { args: argtys, ret } = &f.ty else {
|
||||||
@@ -46,13 +46,66 @@ impl IRUProgram {
|
|||||||
output.check_assign(self, argt, &dest.ty, argv.span);
|
output.check_assign(self, argt, &dest.ty, argv.span);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
super::IRUInstruction::AsmBlock { instructions, args } => {
|
IRUInstruction::AsmBlock { instructions, args } => {
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
super::IRUInstruction::Ret { src } => {
|
IRUInstruction::Ret { src } => {
|
||||||
let srcty = &self.get_var(src.id).ty;
|
let srcty = &self.get_var(src.id).ty;
|
||||||
output.check_assign(self, srcty, &fd.ret, src.span);
|
output.check_assign(self, srcty, &fd.ret, src.span);
|
||||||
},
|
}
|
||||||
|
IRUInstruction::Construct { dest, fields } => {
|
||||||
|
let dest_def = self.get_var(dest.id);
|
||||||
|
let tyid = match dest_def.ty {
|
||||||
|
Type::Concrete(id) => id,
|
||||||
|
_ => {
|
||||||
|
output.err(CompilerMsg {
|
||||||
|
msg: "uhh type is not struct".to_string(),
|
||||||
|
spans: vec![dest.span],
|
||||||
|
});
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let def = self.get_struct(tyid);
|
||||||
|
for (name, field) in &def.fields {
|
||||||
|
if let Some(var) = fields.get(name) {
|
||||||
|
let ety = &self.get_var(var.id).ty;
|
||||||
|
output.check_assign(self, &field.ty, ety, var.span);
|
||||||
|
} else {
|
||||||
|
output.err(CompilerMsg {
|
||||||
|
msg: format!("field '{name}' missing from struct"),
|
||||||
|
spans: vec![dest.span],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for name in fields.keys() {
|
||||||
|
if !def.fields.contains_key(name) {
|
||||||
|
output.err(CompilerMsg {
|
||||||
|
msg: format!("field '{name}' not in struct"),
|
||||||
|
spans: vec![dest.span],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IRUInstruction::Access { dest, src, field } => {
|
||||||
|
let dest_def = self.get_var(dest.id);
|
||||||
|
let src_def = self.get_var(src.id);
|
||||||
|
let tyid = match src_def.ty {
|
||||||
|
Type::Concrete(id) => id,
|
||||||
|
_ => {
|
||||||
|
output.err(CompilerMsg {
|
||||||
|
msg: "uhh type is not struct".to_string(),
|
||||||
|
spans: vec![dest.span],
|
||||||
|
});
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let def = self.get_struct(tyid);
|
||||||
|
let field = def.fields.get(field).expect(
|
||||||
|
"already validated during parse lowering... probably shouldn't be?",
|
||||||
|
);
|
||||||
|
output.check_assign(self, &field.ty, &dest_def.ty, i.span);
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
#![feature(box_patterns)]
|
#![feature(box_patterns)]
|
||||||
#![feature(try_trait_v2)]
|
#![feature(try_trait_v2)]
|
||||||
#![feature(trait_alias)]
|
#![feature(trait_alias)]
|
||||||
|
#![feature(let_chains)]
|
||||||
|
// dawg what
|
||||||
|
#![feature(str_as_str)]
|
||||||
|
|
||||||
use ir::{IRLProgram, IRUProgram};
|
use ir::{IRLProgram, IRUProgram};
|
||||||
use parser::{NodeParsable, PModule, PStatement, ParserCtx};
|
use parser::{NodeParsable, PModule, PStatement, ParserCtx};
|
||||||
@@ -17,10 +20,10 @@ mod compiler;
|
|||||||
mod ir;
|
mod ir;
|
||||||
mod parser;
|
mod parser;
|
||||||
mod util;
|
mod util;
|
||||||
use common::*;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let file = std::env::args_os().nth(1);
|
let file = std::env::args_os().nth(1);
|
||||||
|
// TODO: professional arg parsing
|
||||||
let gdb = std::env::args().nth(2).is_some_and(|a| a == "--debug");
|
let gdb = std::env::args().nth(2).is_some_and(|a| a == "--debug");
|
||||||
let asm = std::env::args().nth(2).is_some_and(|a| a == "--asm");
|
let asm = std::env::args().nth(2).is_some_and(|a| a == "--asm");
|
||||||
if let Some(path) = file {
|
if let Some(path) = file {
|
||||||
|
|||||||
@@ -37,7 +37,10 @@ impl PType {
|
|||||||
output: &mut CompilerOutput,
|
output: &mut CompilerOutput,
|
||||||
span: FileSpan,
|
span: FileSpan,
|
||||||
) -> Type {
|
) -> 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) => {
|
Some(id) => {
|
||||||
if self.args.is_empty() {
|
if self.args.is_empty() {
|
||||||
Type::Concrete(id)
|
Type::Concrete(id)
|
||||||
@@ -51,10 +54,10 @@ impl PType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
if let Ok(num) = self.name.parse::<u32>() {
|
if let Ok(num) = name.parse::<u32>() {
|
||||||
Type::Bits(num)
|
Type::Bits(num)
|
||||||
} else {
|
} else {
|
||||||
match self.name.as_str() {
|
match name.as_str() {
|
||||||
"slice" => {
|
"slice" => {
|
||||||
let inner = self.args[0].lower(namespace, output);
|
let inner = self.args[0].lower(namespace, output);
|
||||||
Type::Slice(Box::new(inner))
|
Type::Slice(Box::new(inner))
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
use super::{func::FnLowerCtx, FnLowerable, PExpr, UnaryOp};
|
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 {
|
impl FnLowerable for PExpr {
|
||||||
type Output = VarInst;
|
type Output = VarInst;
|
||||||
@@ -13,7 +16,7 @@ impl FnLowerable for PExpr {
|
|||||||
DataDef {
|
DataDef {
|
||||||
ty: Type::Bits(8).arr(data.len() as u32),
|
ty: Type::Bits(8).arr(data.len() as u32),
|
||||||
origin: Origin::File(l.span),
|
origin: Origin::File(l.span),
|
||||||
label: format!("string \"{}\"", s.replace("\n", "\\n"))
|
label: format!("string \"{}\"", s.replace("\n", "\\n")),
|
||||||
},
|
},
|
||||||
data,
|
data,
|
||||||
);
|
);
|
||||||
@@ -42,7 +45,7 @@ impl FnLowerable for PExpr {
|
|||||||
DataDef {
|
DataDef {
|
||||||
ty,
|
ty,
|
||||||
origin: Origin::File(l.span),
|
origin: Origin::File(l.span),
|
||||||
label: format!("num {n:?}")
|
label: format!("num {n:?}"),
|
||||||
},
|
},
|
||||||
n.whole.parse::<i64>().unwrap().to_le_bytes().to_vec(),
|
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::Ident(i) => ctx.get_var(i)?,
|
||||||
PExpr::BinaryOp(op, e1, e2) => {
|
PExpr::BinaryOp(op, e1, e2) => {
|
||||||
let res1 = e1.lower(ctx)?;
|
let res1 = e1.lower(ctx)?;
|
||||||
|
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)?;
|
let res2 = e2.lower(ctx)?;
|
||||||
op.traitt();
|
todo!()
|
||||||
todo!();
|
}
|
||||||
}
|
}
|
||||||
PExpr::UnaryOp(op, e) => {
|
PExpr::UnaryOp(op, e) => {
|
||||||
let res = e.lower(ctx)?;
|
let res = e.lower(ctx)?;
|
||||||
match op {
|
match op {
|
||||||
UnaryOp::Ref => {
|
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 {
|
ctx.push(IRUInstruction::Ref {
|
||||||
dest: temp,
|
dest: temp,
|
||||||
src: res,
|
src: res,
|
||||||
@@ -120,7 +147,7 @@ impl FnLowerable for PExpr {
|
|||||||
temp
|
temp
|
||||||
}
|
}
|
||||||
PExpr::Group(e) => e.lower(ctx)?,
|
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::{
|
use crate::{
|
||||||
ir::{
|
ir::{
|
||||||
FnDef, FnID, IRInstructions, IRUFunction, IRUInstruction, Idents, NamespaceGuard, Origin,
|
FnDef, FnID, IRInstructions, IRUFunction, IRUInstruction, Idents, NamespaceGuard, Origin,
|
||||||
Type, VarDef, VarID, VarInst,
|
Type, VarDef, VarInst,
|
||||||
},
|
},
|
||||||
parser,
|
parser,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
|
mod arch;
|
||||||
mod asm;
|
mod asm;
|
||||||
mod block;
|
mod block;
|
||||||
mod def;
|
mod def;
|
||||||
mod expr;
|
mod expr;
|
||||||
mod func;
|
mod func;
|
||||||
mod module;
|
mod module;
|
||||||
mod arch;
|
mod struc;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,9 @@ use super::{PModule, CompilerOutput};
|
|||||||
|
|
||||||
impl PModule {
|
impl PModule {
|
||||||
pub fn lower(&self, map: &mut NamespaceGuard, output: &mut CompilerOutput) {
|
pub fn lower(&self, map: &mut NamespaceGuard, output: &mut CompilerOutput) {
|
||||||
|
for s in &self.structs {
|
||||||
|
s.lower(map, output);
|
||||||
|
}
|
||||||
let mut fns = Vec::new();
|
let mut fns = Vec::new();
|
||||||
for f in &self.functions {
|
for f in &self.functions {
|
||||||
if let Some(id) = f.lower_header(map, output) {
|
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 nodes::*;
|
||||||
pub use parse::*;
|
pub use parse::*;
|
||||||
pub use token::*;
|
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,
|
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> {
|
impl<T> Deref for Node<T> {
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
MaybeParsable, Node, PExpr, PIdent, PType, Parsable, ParseResult, ParserCtx, Symbol,
|
CompilerMsg, MaybeParsable, Node, PExpr, PIdent, PType, Parsable, ParseResult, ParserCtx,
|
||||||
Token, CompilerMsg
|
Symbol, Token,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct PVarDef {
|
pub struct PVarDef {
|
||||||
@@ -18,27 +18,30 @@ pub struct PFieldDef {
|
|||||||
impl Parsable for PVarDef {
|
impl Parsable for PVarDef {
|
||||||
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||||
let name = ctx.parse()?;
|
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.next();
|
||||||
ctx.parse().map(|ty| Self { name, ty: Some(ty) })
|
Self {
|
||||||
} else {
|
name,
|
||||||
ParseResult::Ok(Self { name, ty: None })
|
ty: Some(ctx.parse()?),
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
Self { name, ty: None }
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parsable for PFieldDef {
|
impl Parsable for PFieldDef {
|
||||||
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||||
let name = ctx.parse()?;
|
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.next();
|
||||||
ctx.parse().map(|ty| Self {
|
Self {
|
||||||
name,
|
name,
|
||||||
val: Some(ty),
|
val: Some(ctx.parse()?),
|
||||||
})
|
|
||||||
} else {
|
|
||||||
ParseResult::Ok(Self { name, val: None })
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
Self { name, val: None }
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
use std::fmt::{Debug, Write};
|
use std::fmt::{Debug, Write};
|
||||||
|
|
||||||
use super::{
|
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>>;
|
type BoxNode = Node<Box<PExpr>>;
|
||||||
@@ -53,12 +56,21 @@ impl Parsable for PExpr {
|
|||||||
Self::UnaryOp(op, n)
|
Self::UnaryOp(op, n)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else if let Some(val) = Node::maybe_parse(ctx) {
|
} else if let Some(val) = ctx.maybe_parse() {
|
||||||
Self::Lit(val)
|
Self::Lit(val)
|
||||||
} else {
|
} else {
|
||||||
let res = ctx.parse();
|
let res = ctx.parse();
|
||||||
if res.node.is_some() {
|
if res.node.is_some() {
|
||||||
|
// 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)
|
Self::Ident(res.node)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
let next = ctx.expect_peek()?;
|
let next = ctx.expect_peek()?;
|
||||||
return ParseResult::Err(CompilerMsg::unexpected_token(next, "an expression"));
|
return ParseResult::Err(CompilerMsg::unexpected_token(next, "an expression"));
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct PIdent(String);
|
pub struct PIdent(pub String);
|
||||||
|
|
||||||
impl Parsable for PIdent {
|
impl Parsable for PIdent {
|
||||||
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
use crate::parser::ParsableWith;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
util::parse_list, Keyword, Node, PExpr, PFieldDef, PIdent, PType, PVarDef, Parsable,
|
util::parse_list, CompilerMsg, Keyword, Node, PExpr, PFieldDef, PIdent, PType, PVarDef,
|
||||||
ParseResult, ParserCtx, CompilerMsg, Symbol,
|
Parsable, ParseResult, ParserCtx, Symbol,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -13,7 +15,7 @@ pub struct PStruct {
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct PConstruct {
|
pub struct PConstruct {
|
||||||
pub name: Node<PIdent>,
|
pub name: Node<PType>,
|
||||||
pub fields: PConstructFields,
|
pub fields: PConstructFields,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,11 +59,20 @@ impl Parsable for PStruct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parsable for PConstruct {
|
impl ParsableWith for PConstruct {
|
||||||
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
type Data = Node<PIdent>;
|
||||||
ctx.expect_kw(Keyword::Struct)?;
|
fn parse(ctx: &mut ParserCtx, name_node: Self::Data) -> ParseResult<Self> {
|
||||||
let name = ctx.parse()?;
|
|
||||||
let next = ctx.expect_peek()?;
|
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) {
|
let fields = if next.is_symbol(Symbol::Semicolon) {
|
||||||
ctx.next();
|
ctx.next();
|
||||||
PConstructFields::None
|
PConstructFields::None
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
use std::fmt::Debug;
|
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 struct PType {
|
||||||
pub name: String,
|
pub name: Node<PIdent>,
|
||||||
pub args: Vec<Node<PType>>,
|
pub args: Vec<Node<PType>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -11,18 +13,15 @@ impl Parsable for PType {
|
|||||||
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||||
let next = ctx.expect_peek()?;
|
let next = ctx.expect_peek()?;
|
||||||
let res = if next.is_symbol(Symbol::Ampersand) {
|
let res = if next.is_symbol(Symbol::Ampersand) {
|
||||||
|
let name = Node::new(PIdent("&".to_string()), next.span);
|
||||||
ctx.next();
|
ctx.next();
|
||||||
let arg = ctx.parse()?;
|
let arg = ctx.parse()?;
|
||||||
Self {
|
Self {
|
||||||
name: "&".to_string(),
|
name,
|
||||||
args: vec![arg],
|
args: vec![arg],
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let Token::Word(name) = &next.token else {
|
let n = ctx.parse()?;
|
||||||
return ParseResult::Err(CompilerMsg::unexpected_token(next, "a type identifier"));
|
|
||||||
};
|
|
||||||
let n = name.to_string();
|
|
||||||
ctx.next();
|
|
||||||
let mut args = Vec::new();
|
let mut args = Vec::new();
|
||||||
if let Some(next) = ctx.peek() {
|
if let Some(next) = ctx.peek() {
|
||||||
if next.is_symbol(Symbol::OpenAngle) {
|
if next.is_symbol(Symbol::OpenAngle) {
|
||||||
@@ -38,8 +37,8 @@ impl Parsable for PType {
|
|||||||
|
|
||||||
impl Debug for PType {
|
impl Debug for PType {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(f, "{}", self.name)?;
|
write!(f, "{:?}", self.name)?;
|
||||||
if self.name == "&" {
|
if self.name.as_ref().is_some_and(|n| n.0 == "&") {
|
||||||
write!(f, "{:?}", self.args[0])?;
|
write!(f, "{:?}", self.args[0])?;
|
||||||
} else if !self.args.is_empty() {
|
} else if !self.args.is_empty() {
|
||||||
write!(f, "<{:?}>", self.args)?;
|
write!(f, "<{:?}>", self.args)?;
|
||||||
|
|||||||
Reference in New Issue
Block a user