INITIAL GENERICS IMPL
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -1,6 +1,6 @@
|
|||||||
# This file is automatically @generated by Cargo.
|
# This file is automatically @generated by Cargo.
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
version = 4
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lang"
|
name = "lang"
|
||||||
|
|||||||
@@ -2,7 +2,3 @@
|
|||||||
name = "lang"
|
name = "lang"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ fn start() {
|
|||||||
print("test: 0x");
|
print("test: 0x");
|
||||||
print_hex(31);
|
print_hex(31);
|
||||||
println("");
|
println("");
|
||||||
|
generic();
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,6 +75,23 @@ fn structer(test: Test) {
|
|||||||
println("");
|
println("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct GTest<T, U> {
|
||||||
|
a: T,
|
||||||
|
b: U,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generic() {
|
||||||
|
let gt = GTest {
|
||||||
|
a: 39,
|
||||||
|
b: "hello",
|
||||||
|
};
|
||||||
|
print("generic: ");
|
||||||
|
print_dec(gt.a);
|
||||||
|
print(", ");
|
||||||
|
print(gt.b);
|
||||||
|
println("");
|
||||||
|
}
|
||||||
|
|
||||||
fn thinger() {
|
fn thinger() {
|
||||||
print("estamos jugando\n");
|
print("estamos jugando\n");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::ir::{AsmBlockArgType, UInstrInst, Size, SymbolSpace, UFunc, VarOffset};
|
use crate::ir::{AsmBlockArgType, Size, SymbolSpace, UFunc, UInstrInst, VarOffset};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
IRLFunction, LInstruction, Len, Symbol, SymbolSpaceBuilder, Type, UInstruction, UProgram,
|
IRLFunction, LInstruction, Len, Symbol, SymbolSpaceBuilder, Type, UInstruction, UProgram, VarID,
|
||||||
VarID,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct LProgram {
|
pub struct LProgram {
|
||||||
@@ -43,12 +42,37 @@ impl LProgram {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct StructInst {
|
||||||
|
offsets: Vec<Len>,
|
||||||
|
order: HashMap<String, usize>,
|
||||||
|
size: Size,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct LFunctionBuilder<'a> {
|
pub struct LFunctionBuilder<'a> {
|
||||||
|
data: LFunctionBuilderData<'a>,
|
||||||
program: &'a UProgram,
|
program: &'a UProgram,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> LFunctionBuilderData<'a> {
|
||||||
|
pub fn new(builder: &'a mut SymbolSpaceBuilder) -> Self {
|
||||||
|
Self {
|
||||||
|
instrs: Vec::new(),
|
||||||
|
struct_insts: HashMap::new(),
|
||||||
|
stack: HashMap::new(),
|
||||||
|
subvar_map: HashMap::new(),
|
||||||
|
makes_call: false,
|
||||||
|
builder,
|
||||||
|
loopp: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct LFunctionBuilderData<'a> {
|
||||||
builder: &'a mut SymbolSpaceBuilder,
|
builder: &'a mut SymbolSpaceBuilder,
|
||||||
instrs: Vec<LInstruction>,
|
instrs: Vec<LInstruction>,
|
||||||
stack: HashMap<VarID, Size>,
|
stack: HashMap<VarID, Size>,
|
||||||
subvar_map: HashMap<VarID, VarOffset>,
|
subvar_map: HashMap<VarID, VarOffset>,
|
||||||
|
struct_insts: HashMap<Type, StructInst>,
|
||||||
makes_call: bool,
|
makes_call: bool,
|
||||||
loopp: Option<LoopCtx>,
|
loopp: Option<LoopCtx>,
|
||||||
}
|
}
|
||||||
@@ -62,29 +86,32 @@ pub struct LoopCtx {
|
|||||||
impl<'a> LFunctionBuilder<'a> {
|
impl<'a> LFunctionBuilder<'a> {
|
||||||
pub fn new(program: &'a UProgram, builder: &'a mut SymbolSpaceBuilder) -> Self {
|
pub fn new(program: &'a UProgram, builder: &'a mut SymbolSpaceBuilder) -> Self {
|
||||||
Self {
|
Self {
|
||||||
instrs: Vec::new(),
|
data: LFunctionBuilderData::new(builder),
|
||||||
stack: HashMap::new(),
|
|
||||||
subvar_map: HashMap::new(),
|
|
||||||
makes_call: false,
|
|
||||||
program,
|
program,
|
||||||
builder,
|
|
||||||
loopp: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn alloc_stack(&mut self, i: VarID) -> Option<()> {
|
pub fn alloc_stack(&mut self, i: VarID) -> Option<()> {
|
||||||
if self.program.size_of_var(i).expect("unsized type") == 0 {
|
if self
|
||||||
|
.data
|
||||||
|
.size_of_var(self.program, i)
|
||||||
|
.expect("unsized type")
|
||||||
|
== 0
|
||||||
|
{
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
self.map_subvar(i);
|
self.map_subvar(i);
|
||||||
let var = self.program.var_offset(i).expect("var offset");
|
let var = self.data.var_offset(self.program, i).expect("var offset");
|
||||||
*self
|
if let None = self.stack.get(&var.id) {
|
||||||
.stack
|
let size = self
|
||||||
.entry(var.id)
|
.data
|
||||||
.or_insert(self.program.size_of_var(var.id).expect("unsized type"));
|
.size_of_var(self.program, var.id)
|
||||||
|
.expect("unsized type");
|
||||||
|
self.data.stack.insert(var.id, size);
|
||||||
|
}
|
||||||
Some(())
|
Some(())
|
||||||
}
|
}
|
||||||
pub fn map_subvar(&mut self, i: VarID) {
|
pub fn map_subvar(&mut self, i: VarID) {
|
||||||
let off = self.program.var_offset(i).expect("var offset");
|
let off = self.data.var_offset(self.program, i).expect("var offset");
|
||||||
if off.id != i {
|
if off.id != i {
|
||||||
self.subvar_map.insert(i, off);
|
self.subvar_map.insert(i, off);
|
||||||
}
|
}
|
||||||
@@ -112,7 +139,7 @@ impl<'a> LFunctionBuilder<'a> {
|
|||||||
UInstruction::LoadData { dest, src } => {
|
UInstruction::LoadData { dest, src } => {
|
||||||
self.alloc_stack(dest.id)?;
|
self.alloc_stack(dest.id)?;
|
||||||
let data = self.program.expect(*src);
|
let data = self.program.expect(*src);
|
||||||
let sym = self.builder.ro_data(
|
let sym = self.data.builder.ro_data(
|
||||||
src,
|
src,
|
||||||
&data.content,
|
&data.content,
|
||||||
Some(self.program.names.get(dest.id).to_string()),
|
Some(self.program.names.get(dest.id).to_string()),
|
||||||
@@ -133,7 +160,7 @@ impl<'a> LFunctionBuilder<'a> {
|
|||||||
self.program.type_name(&data.ty)
|
self.program.type_name(&data.ty)
|
||||||
)));
|
)));
|
||||||
};
|
};
|
||||||
let sym = self.builder.ro_data(
|
let sym = self.data.builder.ro_data(
|
||||||
src,
|
src,
|
||||||
&data.content,
|
&data.content,
|
||||||
Some(self.program.names.get(dest.id).to_string()),
|
Some(self.program.names.get(dest.id).to_string()),
|
||||||
@@ -168,7 +195,10 @@ impl<'a> LFunctionBuilder<'a> {
|
|||||||
self.makes_call = true;
|
self.makes_call = true;
|
||||||
let fid = &self.program.fn_map[&f.id];
|
let fid = &self.program.fn_map[&f.id];
|
||||||
let sym = self.builder.func(fid);
|
let sym = self.builder.func(fid);
|
||||||
let ret_size = self.program.size_of_var(dest.id).expect("unsized type");
|
let ret_size = self
|
||||||
|
.data
|
||||||
|
.size_of_var(self.program, dest.id)
|
||||||
|
.expect("unsized type");
|
||||||
let dest = if ret_size > 0 {
|
let dest = if ret_size > 0 {
|
||||||
Some((dest.id, ret_size))
|
Some((dest.id, ret_size))
|
||||||
} else {
|
} else {
|
||||||
@@ -181,7 +211,12 @@ impl<'a> LFunctionBuilder<'a> {
|
|||||||
.iter()
|
.iter()
|
||||||
.map(|a| {
|
.map(|a| {
|
||||||
self.map_subvar(a.id);
|
self.map_subvar(a.id);
|
||||||
(a.id, self.program.size_of_var(a.id).expect("unsized type"))
|
(
|
||||||
|
a.id,
|
||||||
|
self.data
|
||||||
|
.size_of_var(self.program, a.id)
|
||||||
|
.expect("unsized type"),
|
||||||
|
)
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
};
|
};
|
||||||
@@ -210,31 +245,32 @@ impl<'a> LFunctionBuilder<'a> {
|
|||||||
}
|
}
|
||||||
UInstruction::Ret { src } => {
|
UInstruction::Ret { src } => {
|
||||||
self.map_subvar(src.id);
|
self.map_subvar(src.id);
|
||||||
self.instrs.push(LInstruction::Ret {
|
let src = if self
|
||||||
src: if self.program.size_of_var(src.id).expect("unsized var") == 0 {
|
.data
|
||||||
|
.size_of_var(self.program, src.id)
|
||||||
|
.expect("unsized var")
|
||||||
|
== 0
|
||||||
|
{
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(src.id)
|
Some(src.id)
|
||||||
},
|
};
|
||||||
})
|
self.data.instrs.push(LInstruction::Ret { src })
|
||||||
}
|
}
|
||||||
UInstruction::Construct { dest, fields } => {
|
UInstruction::Construct { dest, fields } => {
|
||||||
self.alloc_stack(dest.id)?;
|
self.alloc_stack(dest.id)?;
|
||||||
let ty = &self.program.expect(dest.id).ty;
|
for (field, var) in fields {
|
||||||
let &Type::Struct { id, ref args } = ty else {
|
|
||||||
return Some(Some(format!(
|
|
||||||
"Failed to contruct type {}",
|
|
||||||
self.program.type_name(ty)
|
|
||||||
)));
|
|
||||||
};
|
|
||||||
for (&fid, var) in fields {
|
|
||||||
self.map_subvar(var.id);
|
self.map_subvar(var.id);
|
||||||
self.instrs.push(LInstruction::Mv {
|
let i = LInstruction::Mv {
|
||||||
dest: dest.id,
|
dest: dest.id,
|
||||||
src: var.id,
|
src: var.id,
|
||||||
dest_offset: self.program.field_offset(id, fid).expect("field offset"),
|
dest_offset: self
|
||||||
|
.data
|
||||||
|
.field_offset(self.program, dest.id, field)
|
||||||
|
.expect("field offset"),
|
||||||
src_offset: 0,
|
src_offset: 0,
|
||||||
})
|
};
|
||||||
|
self.instrs.push(i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
UInstruction::If { cond, body } => {
|
UInstruction::If { cond, body } => {
|
||||||
@@ -266,35 +302,146 @@ impl<'a> LFunctionBuilder<'a> {
|
|||||||
self.loopp = old;
|
self.loopp = old;
|
||||||
}
|
}
|
||||||
UInstruction::Break => {
|
UInstruction::Break => {
|
||||||
self.instrs.push(LInstruction::Jump(
|
self.data.instrs.push(LInstruction::Jump(
|
||||||
self.loopp.expect("Tried to break outside of loop").bot,
|
self.data.loopp.expect("Tried to break outside of loop").bot,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
UInstruction::Continue => {
|
UInstruction::Continue => {
|
||||||
self.instrs.push(LInstruction::Jump(
|
self.data.instrs.push(LInstruction::Jump(
|
||||||
self.loopp.expect("Tried to break outside of loop").top,
|
self.data.loopp.expect("Tried to break outside of loop").top,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Some(None)
|
Some(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn finish(self, f: &UFunc) -> IRLFunction {
|
pub fn finish(mut self, f: &UFunc) -> IRLFunction {
|
||||||
IRLFunction {
|
IRLFunction {
|
||||||
instructions: self.instrs,
|
|
||||||
makes_call: self.makes_call,
|
|
||||||
args: f
|
args: f
|
||||||
.args
|
.args
|
||||||
.iter()
|
.iter()
|
||||||
.map(|a| (*a, self.program.size_of_var(*a).expect("unsized type")))
|
.map(|a| {
|
||||||
|
(
|
||||||
|
*a,
|
||||||
|
self.data
|
||||||
|
.size_of_var(self.program, *a)
|
||||||
|
.expect("unsized type"),
|
||||||
|
)
|
||||||
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
ret_size: self.program.size_of_type(&f.ret).expect("unsized type"),
|
ret_size: self
|
||||||
stack: self.stack,
|
.data
|
||||||
subvar_map: self.subvar_map,
|
.size_of_type(self.program, &f.ret)
|
||||||
|
.expect("unsized type"),
|
||||||
|
instructions: self.data.instrs,
|
||||||
|
makes_call: self.data.makes_call,
|
||||||
|
stack: self.data.stack,
|
||||||
|
subvar_map: self.data.subvar_map,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl LFunctionBuilderData<'_> {
|
||||||
|
pub fn var_offset(&mut self, p: &UProgram, var: VarID) -> Option<VarOffset> {
|
||||||
|
let mut current = VarOffset { id: var, offset: 0 };
|
||||||
|
while let Some(parent) = &p.get(current.id)?.parent {
|
||||||
|
current.id = parent.var;
|
||||||
|
current.offset += self.field_offset(p, parent.var, &parent.field)?;
|
||||||
|
}
|
||||||
|
Some(current)
|
||||||
|
}
|
||||||
|
pub fn addr_size(&self) -> Size {
|
||||||
|
64
|
||||||
|
}
|
||||||
|
pub fn struct_inst(&mut self, p: &UProgram, ty: &Type) -> Option<&StructInst> {
|
||||||
|
// normally I'd let Some(..) here and return, but polonius does not exist :grief:
|
||||||
|
if self.struct_insts.get(ty).is_none() {
|
||||||
|
let Type::Struct { id, args } = ty else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
let struc = p.get(*id)?;
|
||||||
|
let mut sizes = struc
|
||||||
|
.fields
|
||||||
|
.iter()
|
||||||
|
.map(|(n, f)| {
|
||||||
|
let ty = if let Type::Generic { id } = &f.ty {
|
||||||
|
struc
|
||||||
|
.generics
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.find_map(|(i, g)| if *g == *id { args.get(i) } else { None })
|
||||||
|
.unwrap_or(&f.ty)
|
||||||
|
} else {
|
||||||
|
&f.ty
|
||||||
|
};
|
||||||
|
(n, self.size_of_type(p, ty).expect("unsized type"))
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
sizes.sort_by(|(n1, s1, ..), (n2, s2, ..)| s1.cmp(s2).then_with(|| n1.cmp(n2)));
|
||||||
|
let mut offset = 0;
|
||||||
|
let mut offsets = Vec::new();
|
||||||
|
let mut order = HashMap::new();
|
||||||
|
for (i, (name, size)) in sizes.iter().rev().enumerate() {
|
||||||
|
// TODO: alignment!!!
|
||||||
|
order.insert(name.to_string(), i);
|
||||||
|
offsets.push(offset);
|
||||||
|
offset += size;
|
||||||
|
}
|
||||||
|
self.struct_insts.insert(
|
||||||
|
ty.clone(),
|
||||||
|
StructInst {
|
||||||
|
offsets,
|
||||||
|
order,
|
||||||
|
size: offset,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
self.struct_insts.get(ty)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn field_offset(&mut self, p: &UProgram, var: VarID, field: &str) -> Option<Len> {
|
||||||
|
let ty = &p.get(var)?.ty;
|
||||||
|
let inst = self.struct_inst(p, ty)?;
|
||||||
|
let i = *inst.order.get(field)?;
|
||||||
|
Some(*inst.offsets.get(i)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn size_of_type(&mut self, p: &UProgram, ty: &Type) -> Option<Size> {
|
||||||
|
// TODO: target matters
|
||||||
|
Some(match ty {
|
||||||
|
Type::Bits(b) => *b,
|
||||||
|
Type::Struct { id, args } => self.struct_inst(p, ty)?.size,
|
||||||
|
Type::Generic { id } => return None,
|
||||||
|
Type::Fn { args, ret } => todo!(),
|
||||||
|
Type::Ref(_) => self.addr_size(),
|
||||||
|
Type::Array(ty, len) => self.size_of_type(p, ty)? * len,
|
||||||
|
Type::Slice(_) => self.addr_size() * 2,
|
||||||
|
Type::Infer => return None,
|
||||||
|
Type::Error => return None,
|
||||||
|
Type::Unit => 0,
|
||||||
|
Type::Placeholder => return None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn size_of_var(&mut self, p: &UProgram, var: VarID) -> Option<Size> {
|
||||||
|
self.size_of_type(p, &p.get(var)?.ty)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> std::ops::Deref for LFunctionBuilder<'a> {
|
||||||
|
type Target = LFunctionBuilderData<'a>;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> std::ops::DerefMut for LFunctionBuilder<'a> {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl std::ops::Deref for LProgram {
|
impl std::ops::Deref for LProgram {
|
||||||
type Target = SymbolSpace;
|
type Target = SymbolSpace;
|
||||||
|
|
||||||
|
|||||||
@@ -3,9 +3,12 @@ use crate::common::{CompilerMsg, CompilerOutput, FileSpan};
|
|||||||
use super::{Type, UProgram};
|
use super::{Type, UProgram};
|
||||||
|
|
||||||
impl CompilerOutput {
|
impl CompilerOutput {
|
||||||
pub fn check_assign(&mut self, p: &UProgram, src: &Type, dest: &Type, span: FileSpan) -> bool {
|
pub fn check_assign(&mut self, p: &UProgram, src: &Type, dest: &Type, span: FileSpan) {
|
||||||
// TODO: spans
|
// TODO: spans
|
||||||
if src != dest {
|
if src != dest {
|
||||||
|
if !src.is_real() || !dest.is_real() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
self.err(CompilerMsg {
|
self.err(CompilerMsg {
|
||||||
msg: format!(
|
msg: format!(
|
||||||
"Cannot assign type '{}' to '{}'",
|
"Cannot assign type '{}' to '{}'",
|
||||||
@@ -14,9 +17,6 @@ impl CompilerOutput {
|
|||||||
),
|
),
|
||||||
spans: vec![span],
|
spans: vec![span],
|
||||||
});
|
});
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use std::{collections::HashMap, fmt::Write};
|
use std::{collections::HashMap, fmt::Write};
|
||||||
|
|
||||||
use super::{arch::riscv64::RV64Instruction, inst::VarInst, DataID, FnID, UInstrInst, UFunc};
|
use super::{arch::riscv64::RV64Instruction, inst::VarInst, DataID, FnID, UFunc, UInstrInst};
|
||||||
use crate::{compiler::arch::riscv::Reg, ir::FieldID, util::Padder};
|
use crate::{compiler::arch::riscv::Reg, util::Padder};
|
||||||
|
|
||||||
pub enum UInstruction {
|
pub enum UInstruction {
|
||||||
Mv {
|
Mv {
|
||||||
@@ -38,7 +38,7 @@ pub enum UInstruction {
|
|||||||
},
|
},
|
||||||
Construct {
|
Construct {
|
||||||
dest: VarInst,
|
dest: VarInst,
|
||||||
fields: HashMap<FieldID, VarInst>,
|
fields: HashMap<String, VarInst>,
|
||||||
},
|
},
|
||||||
If {
|
If {
|
||||||
cond: VarInst,
|
cond: VarInst,
|
||||||
|
|||||||
@@ -3,11 +3,9 @@ use crate::{
|
|||||||
ir::{Len, Named, ID},
|
ir::{Len, Named, ID},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{Type, UInstrInst, UProgram};
|
use super::{Type, UInstrInst, UInstruction, UProgram};
|
||||||
use std::{collections::HashMap, fmt::Debug};
|
use std::{collections::HashMap, fmt::Debug};
|
||||||
|
|
||||||
pub const NAMED_KINDS: usize = 4;
|
|
||||||
|
|
||||||
pub struct UFunc {
|
pub struct UFunc {
|
||||||
pub args: Vec<VarID>,
|
pub args: Vec<VarID>,
|
||||||
pub ret: Type,
|
pub ret: Type,
|
||||||
@@ -17,17 +15,19 @@ pub struct UFunc {
|
|||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct StructField {
|
pub struct StructField {
|
||||||
pub name: String,
|
|
||||||
pub ty: Type,
|
pub ty: Type,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct UStruct {
|
pub struct UStruct {
|
||||||
pub fields: Vec<StructField>,
|
pub fields: HashMap<String, StructField>,
|
||||||
pub field_map: HashMap<String, FieldID>,
|
pub generics: Vec<GenericID>,
|
||||||
pub origin: Origin,
|
pub origin: Origin,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct UGeneric {}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct UVar {
|
pub struct UVar {
|
||||||
pub parent: Option<FieldRef>,
|
pub parent: Option<FieldRef>,
|
||||||
@@ -41,13 +41,10 @@ pub struct VarOffset {
|
|||||||
pub offset: Len,
|
pub offset: Len,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
|
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
|
||||||
pub struct FieldRef {
|
pub struct FieldRef {
|
||||||
pub var: VarID,
|
pub var: VarID,
|
||||||
// this is technically redundant bc you can get it from the var...
|
pub field: String,
|
||||||
// but it makes things a lot easier, and you'd have to recheck the fields anyways
|
|
||||||
pub struc: StructID,
|
|
||||||
pub field: FieldID,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@@ -70,84 +67,68 @@ impl UFunc {
|
|||||||
ret: Box::new(self.ret.clone()),
|
ret: Box::new(self.ret.clone()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
pub fn flat_iter(&self) -> impl Iterator<Item = &UInstrInst> {
|
||||||
|
InstrIter::new(self.instructions.iter())
|
||||||
impl UStruct {
|
|
||||||
pub fn field(&self, id: FieldID) -> &StructField {
|
|
||||||
&self.fields[id.0]
|
|
||||||
}
|
|
||||||
pub fn get_field(&self, name: &str) -> Option<&StructField> {
|
|
||||||
self.field_map.get(name).map(|id| self.field(*id))
|
|
||||||
}
|
|
||||||
pub fn iter_fields(&self) -> impl Iterator<Item = (FieldID, &StructField)> {
|
|
||||||
self.fields
|
|
||||||
.iter()
|
|
||||||
.enumerate()
|
|
||||||
.map(|(i, f)| (FieldID::new(i), f))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type StructID = ID<UStruct>;
|
pub struct InstrIter<'a> {
|
||||||
pub type VarID = ID<UVar>;
|
iters: Vec<core::slice::Iter<'a, UInstrInst>>,
|
||||||
pub type DataID = ID<UData>;
|
}
|
||||||
pub type FieldID = ID<StructField>;
|
|
||||||
|
impl<'a> InstrIter<'a> {
|
||||||
|
pub fn new(iter: core::slice::Iter<'a, UInstrInst>) -> Self {
|
||||||
|
Self { iters: vec![iter] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Iterator for InstrIter<'a> {
|
||||||
|
type Item = &'a UInstrInst;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
let iter = self.iters.last_mut()?;
|
||||||
|
let Some(next) = iter.next() else {
|
||||||
|
self.iters.pop();
|
||||||
|
return self.next();
|
||||||
|
};
|
||||||
|
match &next.i {
|
||||||
|
UInstruction::Loop { body } => self.iters.push(body.iter()),
|
||||||
|
UInstruction::If { cond: _, body } => self.iters.push(body.iter()),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
Some(next)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_kind {
|
||||||
|
($struc:ty, $idx:expr, $field:ident, $name:expr) => {
|
||||||
|
impl Kind for $struc {
|
||||||
|
const INDEX: usize = $idx;
|
||||||
|
fn from_program_mut(program: &mut UProgram) -> &mut Vec<Option<Self>> {
|
||||||
|
&mut program.$field
|
||||||
|
}
|
||||||
|
fn from_program(program: &UProgram) -> &Vec<Option<Self>> {
|
||||||
|
&program.$field
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Named for $struc {
|
||||||
|
const NAME: &str = $name;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_kind!(UFunc, 0, fns, "func");
|
||||||
|
impl_kind!(UVar, 1, vars, "var");
|
||||||
|
impl_kind!(UStruct, 2, structs, "struct");
|
||||||
|
impl_kind!(UGeneric, 3, types, "type");
|
||||||
|
impl_kind!(UData, 4, data, "data");
|
||||||
|
pub const NAMED_KINDS: usize = 5;
|
||||||
|
|
||||||
pub type FnID = ID<UFunc>;
|
pub type FnID = ID<UFunc>;
|
||||||
|
pub type VarID = ID<UVar>;
|
||||||
impl Kind for UFunc {
|
pub type StructID = ID<UStruct>;
|
||||||
const INDEX: usize = 0;
|
pub type DataID = ID<UData>;
|
||||||
fn from_program_mut(program: &mut UProgram) -> &mut Vec<Option<Self>> {
|
pub type GenericID = ID<UGeneric>;
|
||||||
&mut program.fns
|
|
||||||
}
|
|
||||||
fn from_program(program: &UProgram) -> &Vec<Option<Self>> {
|
|
||||||
&program.fns
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Named for UFunc {
|
|
||||||
const NAME: &str = "func";
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Kind for UVar {
|
|
||||||
const INDEX: usize = 1;
|
|
||||||
fn from_program_mut(program: &mut UProgram) -> &mut Vec<Option<Self>> {
|
|
||||||
&mut program.vars
|
|
||||||
}
|
|
||||||
fn from_program(program: &UProgram) -> &Vec<Option<Self>> {
|
|
||||||
&program.vars
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Named for UVar {
|
|
||||||
const NAME: &str = "var";
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Kind for UStruct {
|
|
||||||
const INDEX: usize = 2;
|
|
||||||
fn from_program_mut(program: &mut UProgram) -> &mut Vec<Option<Self>> {
|
|
||||||
&mut program.structs
|
|
||||||
}
|
|
||||||
fn from_program(program: &UProgram) -> &Vec<Option<Self>> {
|
|
||||||
&program.structs
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Named for UStruct {
|
|
||||||
const NAME: &str = "struct";
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Kind for UData {
|
|
||||||
const INDEX: usize = 3;
|
|
||||||
fn from_program_mut(program: &mut UProgram) -> &mut Vec<Option<Self>> {
|
|
||||||
&mut program.data
|
|
||||||
}
|
|
||||||
fn from_program(program: &UProgram) -> &Vec<Option<Self>> {
|
|
||||||
&program.data
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Named for UData {
|
|
||||||
const NAME: &str = "data";
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Named for StructField {
|
|
||||||
const NAME: &str = "field";
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait Kind {
|
pub trait Kind {
|
||||||
const INDEX: usize;
|
const INDEX: usize;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ pub struct UProgram {
|
|||||||
pub fns: Vec<Option<UFunc>>,
|
pub fns: Vec<Option<UFunc>>,
|
||||||
pub vars: Vec<Option<UVar>>,
|
pub vars: Vec<Option<UVar>>,
|
||||||
pub structs: Vec<Option<UStruct>>,
|
pub structs: Vec<Option<UStruct>>,
|
||||||
|
pub types: Vec<Option<UGeneric>>,
|
||||||
pub data: Vec<Option<UData>>,
|
pub data: Vec<Option<UData>>,
|
||||||
pub start: Option<FnID>,
|
pub start: Option<FnID>,
|
||||||
pub names: NameMap,
|
pub names: NameMap,
|
||||||
@@ -46,6 +47,7 @@ impl UProgram {
|
|||||||
fns: Vec::new(),
|
fns: Vec::new(),
|
||||||
vars: Vec::new(),
|
vars: Vec::new(),
|
||||||
structs: Vec::new(),
|
structs: Vec::new(),
|
||||||
|
types: Vec::new(),
|
||||||
data: Vec::new(),
|
data: Vec::new(),
|
||||||
start: None,
|
start: None,
|
||||||
names: NameMap::new(),
|
names: NameMap::new(),
|
||||||
@@ -87,27 +89,6 @@ impl UProgram {
|
|||||||
pub fn get_fn_var(&self, id: VarID) -> Option<&UFunc> {
|
pub fn get_fn_var(&self, id: VarID) -> Option<&UFunc> {
|
||||||
self.fns[self.fn_map.get(&id)?.0].as_ref()
|
self.fns[self.fn_map.get(&id)?.0].as_ref()
|
||||||
}
|
}
|
||||||
pub fn size_of_type(&self, ty: &Type) -> Option<Size> {
|
|
||||||
// TODO: target matters
|
|
||||||
Some(match ty {
|
|
||||||
Type::Bits(b) => *b,
|
|
||||||
Type::Struct { id, args } => self.structs[id.0]
|
|
||||||
.as_ref()?
|
|
||||||
.fields
|
|
||||||
.iter()
|
|
||||||
.try_fold(0, |sum, f| Some(sum + self.size_of_type(&f.ty)?))?,
|
|
||||||
Type::Fn { args, ret } => todo!(),
|
|
||||||
Type::Ref(_) => 64,
|
|
||||||
Type::Array(ty, len) => self.size_of_type(ty)? * len,
|
|
||||||
Type::Slice(_) => 128,
|
|
||||||
Type::Infer => return None,
|
|
||||||
Type::Error => return None,
|
|
||||||
Type::Unit => 0,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
pub fn size_of_var(&self, var: VarID) -> Option<Size> {
|
|
||||||
self.size_of_type(&self.get(var)?.ty)
|
|
||||||
}
|
|
||||||
pub fn temp_subvar(&mut self, origin: Origin, ty: Type, parent: FieldRef) -> VarInst {
|
pub fn temp_subvar(&mut self, origin: Origin, ty: Type, parent: FieldRef) -> VarInst {
|
||||||
self.temp_var_inner(origin, ty, Some(parent))
|
self.temp_var_inner(origin, ty, Some(parent))
|
||||||
}
|
}
|
||||||
@@ -145,6 +126,22 @@ impl UProgram {
|
|||||||
id
|
id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn field_type<'a>(&'a self, sty: &'a Type, field: &str) -> Option<&'a Type> {
|
||||||
|
let Type::Struct { id, args } = sty else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
let struc = self.get(*id)?;
|
||||||
|
let field = struc.fields.get(field)?;
|
||||||
|
if let Type::Generic { id } = field.ty {
|
||||||
|
for (i, g) in struc.generics.iter().enumerate() {
|
||||||
|
if *g == id {
|
||||||
|
return Some(&args[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(&field.ty)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn type_name(&self, ty: &Type) -> String {
|
pub fn type_name(&self, ty: &Type) -> String {
|
||||||
let mut str = String::new();
|
let mut str = String::new();
|
||||||
match ty {
|
match ty {
|
||||||
@@ -176,10 +173,12 @@ impl UProgram {
|
|||||||
}
|
}
|
||||||
Type::Error => str += "{error}",
|
Type::Error => str += "{error}",
|
||||||
Type::Infer => str += "{inferred}",
|
Type::Infer => str += "{inferred}",
|
||||||
|
Type::Generic { id } => str += self.names.get(*id),
|
||||||
Type::Bits(size) => str += &format!("b{}", size),
|
Type::Bits(size) => str += &format!("b{}", size),
|
||||||
Type::Array(t, len) => str += &format!("[{}; {len}]", self.type_name(t)),
|
Type::Array(t, len) => str += &format!("[{}; {len}]", self.type_name(t)),
|
||||||
Type::Unit => str += "()",
|
Type::Unit => str += "()",
|
||||||
Type::Slice(t) => str += &format!("&[{}]", self.type_name(t)),
|
Type::Slice(t) => str += &format!("&[{}]", self.type_name(t)),
|
||||||
|
Type::Placeholder => str += "{placeholder}",
|
||||||
}
|
}
|
||||||
str
|
str
|
||||||
}
|
}
|
||||||
@@ -192,22 +191,6 @@ impl UProgram {
|
|||||||
last.insert(name, Idents::new(id.into()));
|
last.insert(name, Idents::new(id.into()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn var_offset(&self, var: VarID) -> Option<VarOffset> {
|
|
||||||
let mut current = VarOffset { id: var, offset: 0 };
|
|
||||||
while let Some(parent) = self.get(current.id)?.parent {
|
|
||||||
current.id = parent.var;
|
|
||||||
current.offset += self.field_offset(parent.struc, parent.field)?;
|
|
||||||
}
|
|
||||||
Some(current)
|
|
||||||
}
|
|
||||||
pub fn field_offset(&self, struct_id: StructID, field: FieldID) -> Option<Len> {
|
|
||||||
let struc = self.get(struct_id)?;
|
|
||||||
let mut offset = 0;
|
|
||||||
for i in 0..field.0 {
|
|
||||||
offset += self.size_of_type(&struc.fields[i].ty)?;
|
|
||||||
}
|
|
||||||
Some(offset)
|
|
||||||
}
|
|
||||||
pub fn iter_vars(&self) -> impl Iterator<Item = (VarID, &UVar)> {
|
pub fn iter_vars(&self) -> impl Iterator<Item = (VarID, &UVar)> {
|
||||||
self.vars
|
self.vars
|
||||||
.iter()
|
.iter()
|
||||||
|
|||||||
@@ -1,15 +1,19 @@
|
|||||||
use super::{Len, StructID, UInstruction, UProgram, UVar, VarID};
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
#[derive(Clone, PartialEq)]
|
use super::{GenericID, Len, StructID, UInstruction, UProgram, UVar, VarID};
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||||
pub enum Type {
|
pub enum Type {
|
||||||
Bits(u32),
|
Bits(u32),
|
||||||
Struct { id: StructID, args: Vec<Type> },
|
Struct { id: StructID, args: Vec<Type> },
|
||||||
|
Generic { id: GenericID },
|
||||||
Fn { args: Vec<Type>, ret: Box<Type> },
|
Fn { args: Vec<Type>, ret: Box<Type> },
|
||||||
Ref(Box<Type>),
|
Ref(Box<Type>),
|
||||||
Slice(Box<Type>),
|
Slice(Box<Type>),
|
||||||
Array(Box<Type>, Len),
|
Array(Box<Type>, Len),
|
||||||
Infer,
|
Infer,
|
||||||
Error,
|
Error,
|
||||||
|
Placeholder,
|
||||||
Unit,
|
Unit,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -23,44 +27,95 @@ impl Type {
|
|||||||
pub fn slice(self) -> Self {
|
pub fn slice(self) -> Self {
|
||||||
Self::Slice(Box::new(self))
|
Self::Slice(Box::new(self))
|
||||||
}
|
}
|
||||||
|
pub fn is_real(&self) -> bool {
|
||||||
|
!matches!(self, Self::Error | Self::Placeholder | Self::Infer)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UProgram {
|
impl UProgram {
|
||||||
pub fn resolve_types(&mut self) {
|
pub fn resolve_types(&mut self) {
|
||||||
// I LOVE RUST
|
// I LOVE RUST
|
||||||
let mut vars = self.vars.clone();
|
let mut vars = self.vars.clone();
|
||||||
for f in self.fns.iter().flatten() {
|
for (i, f) in self.iter_fns() {
|
||||||
for i in &f.instructions {
|
let mut redo_iter = Vec::new();
|
||||||
self.resolve_instr_types(&mut vars, &i.i);
|
let mut ph_vars = Vec::new();
|
||||||
|
let mut redo_new = Vec::new();
|
||||||
|
for i in f.flat_iter() {
|
||||||
|
if let Err(id) = self.resolve_instr_types(&mut vars, &i.i) {
|
||||||
|
redo_iter.push(i);
|
||||||
|
ph_vars.push(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while !redo_iter.is_empty() {
|
||||||
|
let mut new_ph = Vec::new();
|
||||||
|
for id in &ph_vars {
|
||||||
|
let i = id.0;
|
||||||
|
let Some(var) = &vars[i] else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
if var.ty == Type::Placeholder
|
||||||
|
&& let Some(parent) = var.parent.as_ref()
|
||||||
|
{
|
||||||
|
let pty = &vars[parent.var.0].as_ref().unwrap().ty;
|
||||||
|
if let Some(ft) = self.field_type(pty, &parent.field) {
|
||||||
|
vars[i].as_mut().unwrap().ty = ft.clone();
|
||||||
|
} else {
|
||||||
|
new_ph.push(parent.var);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ph_vars = new_ph;
|
||||||
|
for &i in &redo_iter {
|
||||||
|
if let Err(id) = self.resolve_instr_types(&mut vars, &i.i) {
|
||||||
|
redo_new.push(i);
|
||||||
|
ph_vars.push(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::mem::swap(&mut redo_iter, &mut redo_new);
|
||||||
|
redo_new.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.vars = vars;
|
self.vars = vars;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolve_instr_types(&self, vars: &mut Vec<Option<UVar>>, i: &UInstruction) {
|
pub fn resolve_instr_types(
|
||||||
|
&self,
|
||||||
|
vars: &mut Vec<Option<UVar>>,
|
||||||
|
i: &UInstruction,
|
||||||
|
) -> Result<(), VarID> {
|
||||||
|
'outer: {
|
||||||
match &i {
|
match &i {
|
||||||
UInstruction::Call { dest, f, args } => {
|
UInstruction::Call { dest, f, args } => {
|
||||||
let ret = self.get_fn_var(f.id).expect("bruh").ret.clone();
|
let fun = self.get_fn_var(f.id).expect("bruh");
|
||||||
vars[dest.id.0].as_mut().expect("bruh").ty = ret;
|
vars[dest.id.0].as_mut().expect("bruh").ty = fun.ret.clone();
|
||||||
|
for (src, &dest) in args.iter().zip(&fun.args) {
|
||||||
|
let dest_ty = get(vars, dest)?;
|
||||||
|
let src_ty = get(vars, src.id)?;
|
||||||
|
if let Some(ty) = match_types(dest_ty, src_ty) {
|
||||||
|
set(vars, dest, ty.clone());
|
||||||
|
set(vars, src.id, ty);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
UInstruction::Mv { dest, src } => {
|
UInstruction::Mv { dest, src } => {
|
||||||
let dest_ty = get(vars, dest.id);
|
let dest_ty = get(vars, dest.id)?;
|
||||||
let src_ty = get(vars, src.id);
|
let src_ty = get(vars, src.id)?;
|
||||||
if let Some(ty) = match_types(dest_ty, src_ty) {
|
if let Some(ty) = match_types(dest_ty, src_ty) {
|
||||||
set(vars, dest.id, ty.clone());
|
set(vars, dest.id, ty.clone());
|
||||||
set(vars, src.id, ty);
|
set(vars, src.id, ty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
UInstruction::Ref { dest, src } => {
|
UInstruction::Ref { dest, src } => {
|
||||||
let dest_ty = get(vars, dest.id);
|
let dest_ty = get(vars, dest.id)?;
|
||||||
let src_ty = get(vars, src.id);
|
let src_ty = get(vars, src.id)?;
|
||||||
if let Type::Ref(dest_ty) = dest_ty {
|
let Type::Ref(dest_ty) = dest_ty else {
|
||||||
|
break 'outer;
|
||||||
|
};
|
||||||
if let Some(ty) = match_types(dest_ty, src_ty) {
|
if let Some(ty) = match_types(dest_ty, src_ty) {
|
||||||
set(vars, dest.id, ty.clone().rf());
|
set(vars, dest.id, ty.clone().rf());
|
||||||
set(vars, src.id, ty);
|
set(vars, src.id, ty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
UInstruction::LoadData { dest, src } => {
|
UInstruction::LoadData { dest, src } => {
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
@@ -75,29 +130,60 @@ impl UProgram {
|
|||||||
}
|
}
|
||||||
UInstruction::Ret { .. } => {}
|
UInstruction::Ret { .. } => {}
|
||||||
UInstruction::Construct { dest, fields } => {
|
UInstruction::Construct { dest, fields } => {
|
||||||
// TODO
|
let dest_ty = get(vars, dest.id)?;
|
||||||
|
let Type::Struct { id, args } = dest_ty else {
|
||||||
|
break 'outer;
|
||||||
|
};
|
||||||
|
let id = *id;
|
||||||
|
let Some(struc) = self.get(id) else {
|
||||||
|
break 'outer;
|
||||||
|
};
|
||||||
|
let mut new = HashMap::new();
|
||||||
|
for (name, field) in &struc.fields {
|
||||||
|
let Some(src) = fields.get(name) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
let src_ty = get(vars, src.id)?;
|
||||||
|
if let Some(ty) = match_types(&field.ty, src_ty) {
|
||||||
|
if let Type::Generic { id } = field.ty {
|
||||||
|
new.insert(id, ty.clone());
|
||||||
}
|
}
|
||||||
UInstruction::If { cond, body } => {
|
set(vars, src.id, ty);
|
||||||
for i in body {
|
|
||||||
self.resolve_instr_types(vars, &i.i);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
UInstruction::Loop { body } => {
|
let mut args: Vec<_> = struc
|
||||||
for i in body {
|
.generics
|
||||||
self.resolve_instr_types(vars, &i.i);
|
.iter()
|
||||||
|
.map(|&id| Type::Generic { id })
|
||||||
|
.collect();
|
||||||
|
for (i, g) in struc.generics.iter().enumerate() {
|
||||||
|
if let Some(ty) = new.remove(g) {
|
||||||
|
args[i] = ty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// for arg in &args {
|
||||||
|
// println!("{:?}", self.type_name(arg));
|
||||||
|
// }
|
||||||
|
set(vars, dest.id, Type::Struct { id, args });
|
||||||
|
}
|
||||||
|
UInstruction::If { cond, body } => {}
|
||||||
|
UInstruction::Loop { body } => {}
|
||||||
UInstruction::Break => {}
|
UInstruction::Break => {}
|
||||||
UInstruction::Continue => {}
|
UInstruction::Continue => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(vars: &[Option<UVar>], id: VarID) -> &Type {
|
pub fn get(vars: &[Option<UVar>], id: VarID) -> Result<&Type, VarID> {
|
||||||
&vars[id.0]
|
let var = vars[id.0]
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.expect("PARTIAL BORROWING WOULD BE REALLY COOL")
|
.expect("PARTIAL BORROWING WOULD BE REALLY COOL");
|
||||||
.ty
|
if var.ty == Type::Placeholder {
|
||||||
|
return Err(id);
|
||||||
|
}
|
||||||
|
Ok(&var.ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set(vars: &mut [Option<UVar>], id: VarID, ty: Type) {
|
pub fn set(vars: &mut [Option<UVar>], id: VarID, ty: Type) {
|
||||||
@@ -112,8 +198,11 @@ pub fn match_types(dest: &Type, src: &Type) -> Option<Type> {
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
match (dest, src) {
|
match (dest, src) {
|
||||||
(Type::Error, x) | (x, Type::Error) => None,
|
(Type::Error, _) | (_, Type::Error) => None,
|
||||||
|
(Type::Placeholder, _) | (_, Type::Placeholder) => None,
|
||||||
(Type::Infer, x) | (x, Type::Infer) => Some(x.clone()),
|
(Type::Infer, x) | (x, Type::Infer) => Some(x.clone()),
|
||||||
|
// TODO: handle constraints?
|
||||||
|
(Type::Generic { id }, x) | (x, Type::Generic { id }) => Some(x.clone()),
|
||||||
(
|
(
|
||||||
Type::Struct {
|
Type::Struct {
|
||||||
id: dest_id,
|
id: dest_id,
|
||||||
|
|||||||
@@ -21,6 +21,23 @@ impl UProgram {
|
|||||||
spans: vec![var.origin],
|
spans: vec![var.origin],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if var.ty == Type::Placeholder {
|
||||||
|
output.err(CompilerMsg {
|
||||||
|
msg: format!("Var {:?} still placeholder!", id),
|
||||||
|
spans: vec![var.origin],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if let Some(parent) = &var.parent {
|
||||||
|
let pty = &self.get(parent.var).unwrap().ty;
|
||||||
|
if let Some(ft) = self.field_type(pty, &parent.field) {
|
||||||
|
output.check_assign(self, &var.ty, ft, var.origin);
|
||||||
|
} else {
|
||||||
|
output.err(CompilerMsg {
|
||||||
|
msg: format!("invalid parent!"),
|
||||||
|
spans: vec![var.origin],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
output
|
output
|
||||||
}
|
}
|
||||||
@@ -81,14 +98,15 @@ impl UProgram {
|
|||||||
}
|
}
|
||||||
UInstruction::AsmBlock { instructions, args } => {
|
UInstruction::AsmBlock { instructions, args } => {
|
||||||
for arg in args {
|
for arg in args {
|
||||||
if let Some(size) = self.size_of_var(arg.var.id)
|
// TODO: validate size with enabled targets
|
||||||
&& size != 64
|
// if let Some(size) = self.size_of_var(arg.var.id)
|
||||||
{
|
// && size != 64
|
||||||
output.err(CompilerMsg {
|
// {
|
||||||
msg: format!("asm block args must be size 64, is size {}", size),
|
// output.err(CompilerMsg {
|
||||||
spans: vec![arg.var.span],
|
// msg: format!("asm block args must be size 64, is size {}", size),
|
||||||
});
|
// spans: vec![arg.var.span],
|
||||||
}
|
// });
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
UInstruction::Ret { src } => {
|
UInstruction::Ret { src } => {
|
||||||
@@ -98,24 +116,35 @@ impl UProgram {
|
|||||||
}
|
}
|
||||||
UInstruction::Construct { dest, fields } => {
|
UInstruction::Construct { dest, fields } => {
|
||||||
let dest_def = self.expect(dest.id);
|
let dest_def = self.expect(dest.id);
|
||||||
let tyid = match &dest_def.ty {
|
let (tyid, args) = match &dest_def.ty {
|
||||||
Type::Struct { id, args } => *id,
|
Type::Struct { id, args } => (*id, args),
|
||||||
_ => {
|
_ => {
|
||||||
output.err(CompilerMsg {
|
output.err(CompilerMsg {
|
||||||
msg: "uhh type is not struct".to_string(),
|
msg: format!(
|
||||||
|
"Type {} cannot be constructed",
|
||||||
|
self.type_name(&dest_def.ty)
|
||||||
|
),
|
||||||
spans: vec![dest.span],
|
spans: vec![dest.span],
|
||||||
});
|
});
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let def = self.expect(tyid);
|
let def = self.expect(tyid);
|
||||||
for (id, field) in def.iter_fields() {
|
for (name, field) in &def.fields {
|
||||||
if let Some(var) = fields.get(&id) {
|
if let Some(var) = fields.get(name) {
|
||||||
|
let mut sty = &field.ty;
|
||||||
|
if let Type::Generic { id } = sty {
|
||||||
|
for (g, a) in def.generics.iter().zip(args) {
|
||||||
|
if *g == *id {
|
||||||
|
sty = a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
let ety = &self.expect(var.id).ty;
|
let ety = &self.expect(var.id).ty;
|
||||||
output.check_assign(self, &field.ty, ety, var.span);
|
output.check_assign(self, ety, sty, var.span);
|
||||||
} else {
|
} else {
|
||||||
output.err(CompilerMsg {
|
output.err(CompilerMsg {
|
||||||
msg: format!("field '{}' missing from struct", field.name),
|
msg: format!("field '{}' missing from struct", name),
|
||||||
spans: vec![dest.span],
|
spans: vec![dest.span],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use crate::ir::{Type, UProgram, UStruct, UVar, VarInst};
|
use crate::ir::{Type, UProgram, UVar, VarInst};
|
||||||
|
|
||||||
use super::{CompilerMsg, CompilerOutput, FileSpan, Node, PType, PVarDef};
|
use super::{CompilerOutput, Node, PVarDef};
|
||||||
|
|
||||||
impl Node<PVarDef> {
|
impl Node<PVarDef> {
|
||||||
pub fn lower(&self, program: &mut UProgram, output: &mut CompilerOutput) -> Option<VarInst> {
|
pub fn lower(&self, program: &mut UProgram, output: &mut CompilerOutput) -> Option<VarInst> {
|
||||||
@@ -27,54 +27,3 @@ impl Node<PVarDef> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Node<PType> {
|
|
||||||
pub fn lower(&self, namespace: &mut UProgram, output: &mut CompilerOutput) -> Type {
|
|
||||||
self.as_ref()
|
|
||||||
.map(|t| t.lower(namespace, output, self.span))
|
|
||||||
.unwrap_or(Type::Error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PType {
|
|
||||||
pub fn lower(
|
|
||||||
&self,
|
|
||||||
namespace: &mut UProgram,
|
|
||||||
output: &mut CompilerOutput,
|
|
||||||
span: FileSpan,
|
|
||||||
) -> Type {
|
|
||||||
let Some(name) = self.name.as_ref() else {
|
|
||||||
return Type::Error;
|
|
||||||
};
|
|
||||||
match namespace
|
|
||||||
.get_idents(name)
|
|
||||||
.and_then(|ids| ids.get::<UStruct>())
|
|
||||||
{
|
|
||||||
Some(id) => {
|
|
||||||
let args = self
|
|
||||||
.args
|
|
||||||
.iter()
|
|
||||||
.map(|n| n.lower(namespace, output))
|
|
||||||
.collect();
|
|
||||||
Type::Struct { id, args }
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
if let Ok(num) = name.parse::<u32>() {
|
|
||||||
Type::Bits(num)
|
|
||||||
} else {
|
|
||||||
match name.as_str() {
|
|
||||||
"slice" => {
|
|
||||||
let inner = self.args[0].lower(namespace, output);
|
|
||||||
Type::Slice(Box::new(inner))
|
|
||||||
}
|
|
||||||
"_" => Type::Infer,
|
|
||||||
_ => {
|
|
||||||
output.err(CompilerMsg::from_span(span, "Type not found".to_string()));
|
|
||||||
Type::Error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -58,35 +58,16 @@ impl FnLowerable for PExpr {
|
|||||||
PExpr::BinaryOp(op, e1, e2) => {
|
PExpr::BinaryOp(op, e1, e2) => {
|
||||||
let res1 = e1.lower(ctx)?;
|
let res1 = e1.lower(ctx)?;
|
||||||
if *op == PInfixOp::Access {
|
if *op == PInfixOp::Access {
|
||||||
let sty = &ctx.program.expect(res1.id).ty;
|
|
||||||
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.expect(*struct_id);
|
|
||||||
let Some(box PExpr::Ident(ident)) = &e2.inner else {
|
let Some(box PExpr::Ident(ident)) = &e2.inner else {
|
||||||
ctx.err("Field accesses must be identifiers".to_string());
|
ctx.err("Field accessors must be identifiers".to_string());
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
let fname = &ident.as_ref()?.0;
|
let fname = ident.as_ref()?.0.clone();
|
||||||
let Some(&field) = struc.field_map.get(fname) else {
|
|
||||||
ctx.err(format!("Field '{fname}' not in struct"));
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
let fdef = struc.field(field);
|
|
||||||
ctx.temp_subvar(
|
ctx.temp_subvar(
|
||||||
fdef.ty.clone(),
|
Type::Placeholder,
|
||||||
FieldRef {
|
FieldRef {
|
||||||
var: res1.id,
|
var: res1.id,
|
||||||
struc: *struct_id,
|
field: fname,
|
||||||
field,
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
@@ -147,7 +128,7 @@ impl FnLowerable for PExpr {
|
|||||||
.program
|
.program
|
||||||
.get_fn_var(fe.id)
|
.get_fn_var(fe.id)
|
||||||
.map(|f| f.ret.clone())
|
.map(|f| f.ret.clone())
|
||||||
.unwrap_or(Type::Error);
|
.unwrap_or(Type::Placeholder);
|
||||||
let temp = ctx.temp(ty);
|
let temp = ctx.temp(ty);
|
||||||
ctx.push(UInstruction::Call {
|
ctx.push(UInstruction::Call {
|
||||||
dest: temp,
|
dest: temp,
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
use super::{CompilerMsg, CompilerOutput, FileSpan, FnLowerable, Node, PFunction};
|
use super::{CompilerMsg, CompilerOutput, FileSpan, FnLowerable, Node, PFunction};
|
||||||
use crate::{
|
use crate::{
|
||||||
ir::{FieldRef, FnID, Idents, Type, UFunc, UInstrInst, UInstruction, UProgram, UVar, VarInst},
|
ir::{
|
||||||
|
FieldRef, FnID, Idents, InstrIter, Type, UFunc, UInstrInst, UInstruction, UProgram, UVar,
|
||||||
|
VarInst,
|
||||||
|
},
|
||||||
parser,
|
parser,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -24,8 +27,7 @@ impl PFunction {
|
|||||||
name.to_string(),
|
name.to_string(),
|
||||||
Some(UVar {
|
Some(UVar {
|
||||||
parent: None,
|
parent: None,
|
||||||
// this gets replaced with the correct type later
|
ty: Type::Placeholder,
|
||||||
ty: Type::Error,
|
|
||||||
origin: self.header.span,
|
origin: self.header.span,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
@@ -62,11 +64,12 @@ impl PFunction {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
let origin = self.header.span;
|
let origin = self.header.span;
|
||||||
|
let instructions = ctx.instructions;
|
||||||
let f = UFunc {
|
let f = UFunc {
|
||||||
origin,
|
origin,
|
||||||
args,
|
args,
|
||||||
ret,
|
ret,
|
||||||
instructions: ctx.instructions,
|
instructions,
|
||||||
};
|
};
|
||||||
p.expect_mut(p.inv_fn_map[id.0]).ty = f.ty(p);
|
p.expect_mut(p.inv_fn_map[id.0]).ty = f.ty(p);
|
||||||
p.write(id, f)
|
p.write(id, f)
|
||||||
@@ -115,7 +118,7 @@ impl FnLowerCtx<'_> {
|
|||||||
self.program.temp_subvar(self.span, ty, parent)
|
self.program.temp_subvar(self.span, ty, parent)
|
||||||
}
|
}
|
||||||
pub fn push(&mut self, i: UInstruction) {
|
pub fn push(&mut self, i: UInstruction) {
|
||||||
self.instructions.push(UInstrInst { i, span: self.span });
|
self.push_at(i, self.span);
|
||||||
}
|
}
|
||||||
pub fn push_at(&mut self, i: UInstruction, span: FileSpan) {
|
pub fn push_at(&mut self, i: UInstruction, span: FileSpan) {
|
||||||
self.instructions.push(UInstrInst { i, span });
|
self.instructions.push(UInstrInst { i, span });
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ mod expr;
|
|||||||
mod func;
|
mod func;
|
||||||
mod module;
|
mod module;
|
||||||
mod struc;
|
mod struc;
|
||||||
|
mod ty;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
common::{CompilerOutput, FileSpan},
|
common::{CompilerOutput, FileSpan},
|
||||||
ir::{FieldID, StructField, StructID, Type, UInstruction, UProgram, UStruct, VarInst},
|
ir::{StructField, StructID, UInstruction, UProgram, UStruct, VarInst},
|
||||||
parser::{Node, PConstruct, PConstructFields, PStruct, PStructFields},
|
parser::{Node, PConstruct, PConstructFields, PStruct, PStructFields},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -12,18 +10,6 @@ impl FnLowerable for PConstruct {
|
|||||||
type Output = VarInst;
|
type Output = VarInst;
|
||||||
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<VarInst> {
|
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<VarInst> {
|
||||||
let ty = self.name.lower(ctx.program, ctx.output);
|
let ty = self.name.lower(ctx.program, ctx.output);
|
||||||
let field_map = match ty {
|
|
||||||
Type::Struct { id, .. } => ctx.program.expect(id),
|
|
||||||
_ => {
|
|
||||||
ctx.err(format!(
|
|
||||||
"Type {} cannot be constructed",
|
|
||||||
ctx.program.type_name(&ty)
|
|
||||||
));
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.field_map
|
|
||||||
.clone();
|
|
||||||
let fields = match &self.fields {
|
let fields = match &self.fields {
|
||||||
PConstructFields::Named(nodes) => nodes
|
PConstructFields::Named(nodes) => nodes
|
||||||
.iter()
|
.iter()
|
||||||
@@ -31,15 +17,7 @@ impl FnLowerable for PConstruct {
|
|||||||
let def = n.as_ref()?;
|
let def = n.as_ref()?;
|
||||||
let name = def.name.as_ref()?.to_string();
|
let name = def.name.as_ref()?.to_string();
|
||||||
let expr = def.val.as_ref()?.lower(ctx)?;
|
let expr = def.val.as_ref()?.lower(ctx)?;
|
||||||
let Some(&field) = field_map.get(&name) else {
|
Some((name, expr))
|
||||||
ctx.err(format!(
|
|
||||||
"Struct {} has no field {}",
|
|
||||||
ctx.program.type_name(&ty),
|
|
||||||
name
|
|
||||||
));
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
Some((field, expr))
|
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
PConstructFields::Tuple(nodes) => nodes
|
PConstructFields::Tuple(nodes) => nodes
|
||||||
@@ -48,15 +26,7 @@ impl FnLowerable for PConstruct {
|
|||||||
.flat_map(|(i, n)| {
|
.flat_map(|(i, n)| {
|
||||||
let expr = n.as_ref()?.lower(ctx)?;
|
let expr = n.as_ref()?.lower(ctx)?;
|
||||||
let name = format!("{i}");
|
let name = format!("{i}");
|
||||||
let Some(&field) = field_map.get(&name) else {
|
Some((name, expr))
|
||||||
ctx.err(format!(
|
|
||||||
"Struct {} has no field {}",
|
|
||||||
ctx.program.type_name(&ty),
|
|
||||||
name
|
|
||||||
));
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
Some((field, expr))
|
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
PConstructFields::None => Default::default(),
|
PConstructFields::None => Default::default(),
|
||||||
@@ -75,7 +45,12 @@ impl PStruct {
|
|||||||
output: &mut CompilerOutput,
|
output: &mut CompilerOutput,
|
||||||
span: FileSpan,
|
span: FileSpan,
|
||||||
) -> Option<()> {
|
) -> Option<()> {
|
||||||
let mut field_map = HashMap::new();
|
p.push();
|
||||||
|
let generics = self
|
||||||
|
.generics
|
||||||
|
.iter()
|
||||||
|
.flat_map(|a| a.as_ref()?.lower(p))
|
||||||
|
.collect();
|
||||||
let fields = match &self.fields {
|
let fields = match &self.fields {
|
||||||
PStructFields::Named(nodes) => nodes
|
PStructFields::Named(nodes) => nodes
|
||||||
.iter()
|
.iter()
|
||||||
@@ -98,21 +73,17 @@ impl PStruct {
|
|||||||
PStructFields::None => vec![],
|
PStructFields::None => vec![],
|
||||||
}
|
}
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.enumerate()
|
.map(|(name, ty)| (name, StructField { ty }))
|
||||||
.map(|(i, (name, ty))| {
|
|
||||||
let id = FieldID::new(i);
|
|
||||||
field_map.insert(name.clone(), id);
|
|
||||||
StructField { name, ty }
|
|
||||||
})
|
|
||||||
.collect();
|
.collect();
|
||||||
p.write(
|
p.write(
|
||||||
id,
|
id,
|
||||||
UStruct {
|
UStruct {
|
||||||
origin: span,
|
origin: span,
|
||||||
field_map,
|
generics,
|
||||||
fields,
|
fields,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
p.pop();
|
||||||
Some(())
|
Some(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
53
src/parser/v3/lower/ty.rs
Normal file
53
src/parser/v3/lower/ty.rs
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
use crate::{
|
||||||
|
ir::{GenericID, Type, UGeneric, UProgram, UStruct},
|
||||||
|
parser::PGenericDef,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::{CompilerMsg, CompilerOutput, FileSpan, Node, PType};
|
||||||
|
|
||||||
|
impl Node<PType> {
|
||||||
|
pub fn lower(&self, namespace: &mut UProgram, output: &mut CompilerOutput) -> Type {
|
||||||
|
self.as_ref()
|
||||||
|
.map(|t| t.lower(namespace, output, self.span))
|
||||||
|
.unwrap_or(Type::Error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PType {
|
||||||
|
pub fn lower(&self, p: &mut UProgram, output: &mut CompilerOutput, span: FileSpan) -> Type {
|
||||||
|
let Some(name) = self.name.as_ref() else {
|
||||||
|
return Type::Error;
|
||||||
|
};
|
||||||
|
let ids = p.get_idents(name);
|
||||||
|
// TODO: should generics always take precedence?
|
||||||
|
if let Some(id) = ids.and_then(|ids| ids.get::<UGeneric>()) {
|
||||||
|
Type::Generic { id }
|
||||||
|
} else if let Some(id) = ids.and_then(|ids| ids.get::<UStruct>()) {
|
||||||
|
let args = self.args.iter().map(|n| n.lower(p, output)).collect();
|
||||||
|
Type::Struct { id, args }
|
||||||
|
} else if let Ok(num) = name.parse::<u32>() {
|
||||||
|
Type::Bits(num)
|
||||||
|
} else {
|
||||||
|
match name.as_str() {
|
||||||
|
"slice" => {
|
||||||
|
let inner = self.args[0].lower(p, output);
|
||||||
|
Type::Slice(Box::new(inner))
|
||||||
|
}
|
||||||
|
"_" => Type::Infer,
|
||||||
|
_ => {
|
||||||
|
output.err(CompilerMsg::from_span(span, "Type not found".to_string()));
|
||||||
|
Type::Error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PGenericDef {
|
||||||
|
pub fn lower(&self, p: &mut UProgram) -> Option<GenericID> {
|
||||||
|
let Some(name) = self.name.as_ref() else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
Some(p.def_searchable(name.to_string(), Some(UGeneric {})))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,13 +3,14 @@ use std::fmt::Debug;
|
|||||||
use crate::parser::ParsableWith;
|
use crate::parser::ParsableWith;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
util::parse_list, CompilerMsg, Keyword, Node, PExpr, PFieldDef, PIdent, PType, PVarDef,
|
util::parse_list, CompilerMsg, Keyword, Node, PExpr, PFieldDef, PIdent, PType, PGenericDef,
|
||||||
Parsable, ParseResult, ParserCtx, Symbol,
|
PVarDef, Parsable, ParseResult, ParserCtx, Symbol,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct PStruct {
|
pub struct PStruct {
|
||||||
pub name: Node<PIdent>,
|
pub name: Node<PIdent>,
|
||||||
|
pub generics: Vec<Node<PGenericDef>>,
|
||||||
pub fields: PStructFields,
|
pub fields: PStructFields,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,7 +38,15 @@ impl Parsable for PStruct {
|
|||||||
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||||
ctx.expect_kw(Keyword::Struct)?;
|
ctx.expect_kw(Keyword::Struct)?;
|
||||||
let name = ctx.parse()?;
|
let name = ctx.parse()?;
|
||||||
let next = ctx.expect_peek()?;
|
let mut next = ctx.expect_peek()?;
|
||||||
|
let args = if next.is_symbol(Symbol::OpenAngle) {
|
||||||
|
ctx.next();
|
||||||
|
let res = parse_list(ctx, Symbol::CloseAngle)?;
|
||||||
|
next = ctx.expect_peek()?;
|
||||||
|
res
|
||||||
|
} else {
|
||||||
|
Vec::new()
|
||||||
|
};
|
||||||
let fields = if next.is_symbol(Symbol::Semicolon) {
|
let fields = if next.is_symbol(Symbol::Semicolon) {
|
||||||
ctx.next();
|
ctx.next();
|
||||||
PStructFields::None
|
PStructFields::None
|
||||||
@@ -52,10 +61,11 @@ impl Parsable for PStruct {
|
|||||||
ctx.err(msg);
|
ctx.err(msg);
|
||||||
return ParseResult::Recover(PStruct {
|
return ParseResult::Recover(PStruct {
|
||||||
name,
|
name,
|
||||||
|
generics: args,
|
||||||
fields: PStructFields::None,
|
fields: PStructFields::None,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
ParseResult::Ok(PStruct { name, fields })
|
ParseResult::Ok(PStruct { name, generics: args, fields })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,16 @@
|
|||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
use super::{
|
use super::{util::parse_list, Node, PIdent, Parsable, ParseResult, ParserCtx, Symbol};
|
||||||
util::parse_list, CompilerMsg, Node, PIdent, Parsable, ParseResult, ParserCtx, Symbol, Token,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct PType {
|
pub struct PType {
|
||||||
pub name: Node<PIdent>,
|
pub name: Node<PIdent>,
|
||||||
pub args: Vec<Node<PType>>,
|
pub args: Vec<Node<PType>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct PGenericDef {
|
||||||
|
pub name: Node<PIdent>,
|
||||||
|
}
|
||||||
|
|
||||||
impl Parsable for PType {
|
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()?;
|
||||||
@@ -35,6 +37,12 @@ impl Parsable for PType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Parsable for PGenericDef {
|
||||||
|
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||||
|
ParseResult::Ok(Self { name: ctx.parse()? })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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)?;
|
||||||
@@ -46,3 +54,10 @@ impl Debug for PType {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Debug for PGenericDef {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{:?}", self.name)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user