moving to desktop
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::ir::{AsmBlockArgType, Size, StructTy, SymbolSpace, Type, UFunc, UInstrInst, VarOffset};
|
||||
use crate::ir::{
|
||||
AsmBlockArgType, FnID, Size, GenericTy, SymbolSpace, Type, UFunc, UInstrInst, VarOffset,
|
||||
};
|
||||
|
||||
use super::{
|
||||
IRLFunction, LInstruction, Len, Symbol, SymbolSpaceBuilder, UInstruction, UProgram, VarID,
|
||||
@@ -14,15 +16,11 @@ pub struct LProgram {
|
||||
// NOTE: there are THREE places here where I specify size (8)
|
||||
|
||||
impl LProgram {
|
||||
pub fn create(p: &UProgram) -> Result<Self, String> {
|
||||
let start = p
|
||||
.names
|
||||
.id::<UFunc>(&[], "crate")
|
||||
.ok_or("no start method found")?;
|
||||
pub fn create(p: &UProgram, start: FnID) -> Result<Self, String> {
|
||||
let mut ssbuilder = SymbolSpaceBuilder::with_entries(&[start]);
|
||||
let entry = ssbuilder.func(&start);
|
||||
while let Some((sym, i)) = ssbuilder.pop_fn() {
|
||||
let f = p.fns[i.0].as_ref().unwrap();
|
||||
let f = &p.fns[i];
|
||||
let mut fbuilder = LFunctionBuilder::new(p, &mut ssbuilder);
|
||||
for i in &f.instructions {
|
||||
fbuilder.insert_instr(i);
|
||||
@@ -31,7 +29,7 @@ impl LProgram {
|
||||
fbuilder.instrs.push(LInstruction::Ret { src: None });
|
||||
}
|
||||
let res = fbuilder.finish(f);
|
||||
ssbuilder.write_fn(sym, res, Some(p.names.path(i).to_string()));
|
||||
ssbuilder.write_fn(sym, res, Some(f.name.clone()));
|
||||
}
|
||||
let sym_space = ssbuilder.finish().expect("we failed the mission");
|
||||
Ok(Self { sym_space, entry })
|
||||
@@ -376,7 +374,7 @@ impl LFunctionBuilderData<'_> {
|
||||
pub fn addr_size(&self) -> Size {
|
||||
64
|
||||
}
|
||||
pub fn struct_inst(&mut self, p: &UProgram, ty: &StructTy) -> &StructInst {
|
||||
pub fn struct_inst(&mut self, p: &UProgram, ty: &GenericTy) -> &StructInst {
|
||||
// normally I'd let Some(..) here and return, but polonius does not exist :grief:
|
||||
if self.struct_insts.get(ty).is_none() {
|
||||
let StructInst { id, args } = ty;
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
use crate::common::{CompilerMsg, CompilerOutput, FileSpan};
|
||||
|
||||
use super::{UProgram, Type};
|
||||
|
||||
impl CompilerOutput {
|
||||
pub fn check_assign(&mut self, p: &UProgram, src: &Type, dest: &Type, span: FileSpan) {
|
||||
// TODO: spans
|
||||
if src != dest {
|
||||
if !src.is_resolved() || !dest.is_resolved() {
|
||||
return;
|
||||
}
|
||||
self.err(CompilerMsg {
|
||||
msg: format!(
|
||||
"Cannot assign type '{}' to '{}'",
|
||||
p.type_name(src),
|
||||
p.type_name(dest)
|
||||
),
|
||||
spans: vec![span],
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,26 +1,33 @@
|
||||
use crate::ir::VarID;
|
||||
use std::fmt::Debug;
|
||||
|
||||
use super::{Origin, UInstruction};
|
||||
use super::{MemberID, ModPath, Origin, UInstruction};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
#[derive(Clone)]
|
||||
pub struct VarInst {
|
||||
pub id: VarID,
|
||||
pub status: VarStatus,
|
||||
pub origin: Origin,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum VarStatus {
|
||||
Res(VarID),
|
||||
Unres { mid: ModPath, fields: Vec<MemberID> },
|
||||
Partial { v: VarID, fields: Vec<MemberID> },
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct VarParent {
|
||||
id: VarID,
|
||||
path: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct UInstrInst {
|
||||
pub i: UInstruction,
|
||||
pub origin: Origin,
|
||||
}
|
||||
|
||||
impl Debug for VarInst {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{:?}", self.id)
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for UInstrInst {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{:?}", self.i)
|
||||
|
||||
@@ -73,7 +73,8 @@ impl std::fmt::Debug for UInstruction {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Mv { dst: dest, src } => write!(f, "{dest:?} <- {src:?}")?,
|
||||
Self::Ref { dst: dest, src } => write!(f, "{dest:?} <- &{src:?}")?,
|
||||
Self::Ref { dst: dest, src } => write!(f, "{dest:?} <- {src:?}&")?,
|
||||
Self::Deref { dst: dest, src } => write!(f, "{dest:?} <- {src:?}^")?,
|
||||
Self::LoadData { dst: dest, src } => write!(f, "{dest:?} <- {src:?}")?,
|
||||
Self::LoadFn { dst: dest, src } => write!(f, "{dest:?} <- {src:?}")?,
|
||||
Self::LoadSlice { dst: dest, src } => write!(f, "{dest:?} <- &[{src:?}]")?,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use super::{Type, UInstrInst, UInstruction, UProgram};
|
||||
use super::{Type, UInstrInst, UInstruction};
|
||||
use crate::{
|
||||
common::FileSpan,
|
||||
ir::{Len, ID},
|
||||
@@ -12,7 +12,7 @@ pub struct UFunc {
|
||||
pub name: String,
|
||||
pub origin: Origin,
|
||||
pub args: Vec<VarID>,
|
||||
pub argtys: Vec<TypeID>,
|
||||
pub gargs: Vec<TypeID>,
|
||||
pub ret: TypeID,
|
||||
pub instructions: Vec<UInstrInst>,
|
||||
}
|
||||
@@ -41,13 +41,8 @@ pub struct UVar {
|
||||
pub name: String,
|
||||
pub origin: Origin,
|
||||
pub ty: TypeID,
|
||||
pub res: UVarTy,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct VarParent {
|
||||
id: VarID,
|
||||
path: Vec<String>,
|
||||
pub parent: Option<VarID>,
|
||||
pub children: Vec<VarID>,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||
@@ -62,25 +57,6 @@ pub struct ModPath {
|
||||
pub path: Vec<MemberID>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum UVarTy {
|
||||
Ptr(VarID),
|
||||
/// fully resolved & typed
|
||||
Res {
|
||||
parent: Option<VarParent>,
|
||||
},
|
||||
/// module doesn't exist yet
|
||||
Unres {
|
||||
path: ModPath,
|
||||
fields: Vec<MemberID>,
|
||||
},
|
||||
/// parent var exists but not typed enough for this field path
|
||||
Partial {
|
||||
v: VarID,
|
||||
fields: Vec<MemberID>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
|
||||
pub struct VarOffset {
|
||||
pub id: VarID,
|
||||
@@ -117,12 +93,6 @@ pub enum Member {
|
||||
pub type Origin = FileSpan;
|
||||
|
||||
impl UFunc {
|
||||
pub fn ty(&self, program: &UProgram) -> Type {
|
||||
Type::Fn {
|
||||
args: self.argtys.clone(),
|
||||
ret: Box::new(self.ret.clone()),
|
||||
}
|
||||
}
|
||||
pub fn flat_iter(&self) -> impl Iterator<Item = &UInstrInst> {
|
||||
InstrIter::new(self.instructions.iter())
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
mod assoc;
|
||||
mod error;
|
||||
mod inst;
|
||||
mod instr;
|
||||
mod kind;
|
||||
@@ -11,7 +10,6 @@ mod resolve;
|
||||
use super::*;
|
||||
use assoc::*;
|
||||
|
||||
pub use assoc::Idents;
|
||||
pub use inst::*;
|
||||
pub use instr::*;
|
||||
pub use kind::*;
|
||||
|
||||
@@ -12,6 +12,11 @@ pub struct UProgram {
|
||||
pub generics: Vec<UGeneric>,
|
||||
pub vars: Vec<UVar>,
|
||||
pub types: Vec<Type>,
|
||||
|
||||
pub unres_vars: Vec<VarID>,
|
||||
pub unres_tys: Vec<TypeID>,
|
||||
pub unit: TypeID,
|
||||
pub error: TypeID,
|
||||
}
|
||||
|
||||
pub struct UModuleBuilder<'a> {
|
||||
@@ -22,6 +27,9 @@ pub struct UModuleBuilder<'a> {
|
||||
|
||||
impl UProgram {
|
||||
pub fn new() -> Self {
|
||||
let mut types = Vec::new();
|
||||
let unit = Self::push_id(&mut types, Type::Unit);
|
||||
let error = Self::push_id(&mut types, Type::Error);
|
||||
Self {
|
||||
fns: Vec::new(),
|
||||
vars: Vec::new(),
|
||||
@@ -30,24 +38,36 @@ impl UProgram {
|
||||
generics: Vec::new(),
|
||||
data: Vec::new(),
|
||||
modules: Vec::new(),
|
||||
unres_vars: Vec::new(),
|
||||
unres_tys: Vec::new(),
|
||||
error,
|
||||
unit,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn instantiate_type(&mut self, ty: Type) {
|
||||
self.def_ty(match ty {
|
||||
Type::Ref(node) => Type::Ref(node.lower()),
|
||||
Type::Generic(node, nodes) => todo!(),
|
||||
Type::Ident(node) => todo!(),
|
||||
});
|
||||
pub fn inst_type(&mut self, ty: TypeID, gs: Vec<TypeID>) -> TypeID {
|
||||
let ty = match &self.types[ty] {
|
||||
Type::Ref(id) => Type::Ref(self.inst_type(*id, gs)),
|
||||
Type::Generic(id) => return gs[id.0],
|
||||
Type::Bits(b) => Type::Bits(*b),
|
||||
Type::Struct(struct_ty) => Type::Struct(struct_ty.clone()),
|
||||
Type::Fn() => todo!(),
|
||||
Type::Deref(id) => todo!(),
|
||||
Type::Slice(id) => todo!(),
|
||||
Type::Array(id, _) => todo!(),
|
||||
Type::Unit => todo!(),
|
||||
Type::Unres(mod_path) => todo!(),
|
||||
Type::Infer => todo!(),
|
||||
Type::Error => todo!(),
|
||||
};
|
||||
self.def_ty(ty)
|
||||
}
|
||||
|
||||
pub fn infer(&mut self) -> TypeID {
|
||||
self.def_ty(Type::Infer)
|
||||
}
|
||||
|
||||
pub fn error(&mut self) -> TypeID {
|
||||
self.def_ty(Type::Error)
|
||||
}
|
||||
pub fn set_type(id: TypeID, ty: Type) {}
|
||||
|
||||
pub fn def_var(&mut self, v: UVar) -> VarID {
|
||||
Self::push_id(&mut self.vars, v)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use super::{Origin, StructTy, Type, TypeID, TypeIDed, UInstruction, UProgram, UStruct, UVar};
|
||||
use super::{Origin, GenericTy, Type, TypeID, TypeIDed, UInstruction, UProgram, UStruct, UVar};
|
||||
use crate::common::{CompilerMsg, CompilerOutput};
|
||||
use std::{collections::HashMap, ops::BitOrAssign};
|
||||
|
||||
@@ -65,10 +65,6 @@ impl UProgram {
|
||||
format!("Type of {:?} cannot be inferred", var.name),
|
||||
var.origin,
|
||||
)),
|
||||
Type::Placeholder => output.err(CompilerMsg::new(
|
||||
format!("Var {:?} still placeholder!", var.name),
|
||||
var.origin,
|
||||
)),
|
||||
Type::Unres(_) => output.err(CompilerMsg::new(
|
||||
format!("Var {:?} type still unresolved!", var.name),
|
||||
var.origin,
|
||||
@@ -91,11 +87,12 @@ pub fn resolve_instr(data: &mut ResData, i: &UInstruction) -> InstrRes {
|
||||
let mut uf = InstrRes::Finished;
|
||||
match &i {
|
||||
UInstruction::Call { dst, f, args } => {
|
||||
let fty = data.vars[f.id].ty;
|
||||
let Type::Fn { args: fargs, ret } = &data.types[fty] else {
|
||||
let ftyid = data.vars[f.id].ty;
|
||||
let fty = &data.types[ftyid];
|
||||
let Type::Fn { args: fargs, ret } = fty else {
|
||||
data.errs.push(ResErr::NotCallable {
|
||||
origin: f.origin,
|
||||
ty: fty,
|
||||
ty: ftyid,
|
||||
});
|
||||
return InstrRes::Finished;
|
||||
};
|
||||
@@ -131,7 +128,7 @@ pub fn resolve_instr(data: &mut ResData, i: &UInstruction) -> InstrRes {
|
||||
let dest_ty = get(vars, dst.id)?;
|
||||
let Type::Struct(sty) = dest_ty else {};
|
||||
let id = sty.id;
|
||||
let Some(struc) = self.get(id) else {};
|
||||
let Some(struc) = get(id) else {};
|
||||
let mut new = HashMap::new();
|
||||
for (name, field) in &struc.fields {
|
||||
let Some(src) = fields.get(name) else {
|
||||
@@ -155,7 +152,7 @@ pub fn resolve_instr(data: &mut ResData, i: &UInstruction) -> InstrRes {
|
||||
args[i] = ty;
|
||||
}
|
||||
}
|
||||
set(vars, dst.id, Type::Struct(StructTy { id, args }));
|
||||
set(vars, dst.id, Type::Struct(GenericTy { id, args }));
|
||||
}
|
||||
UInstruction::If { cond, body } => {
|
||||
for i in body {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use super::{FnID, GenericID, Len, ModPath, StructID, TypeID, UVar, VarID, VarInst};
|
||||
use super::{GenericID, Len, ModPath, TypeID, UFunc, UProgram, UStruct, UVar, VarID, VarInst};
|
||||
use crate::ir::ID;
|
||||
|
||||
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
|
||||
pub struct FieldRef {
|
||||
@@ -7,16 +8,16 @@ pub struct FieldRef {
|
||||
}
|
||||
|
||||
#[derive(Clone, Eq, PartialEq, Hash)]
|
||||
pub struct StructTy {
|
||||
pub id: StructID,
|
||||
pub struct GenericTy<T> {
|
||||
pub id: ID<T>,
|
||||
pub args: Vec<TypeID>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum Type {
|
||||
Bits(u32),
|
||||
Struct(StructTy),
|
||||
Fn(FnID),
|
||||
Struct(GenericTy<UStruct>),
|
||||
Fn(GenericTy<UFunc>),
|
||||
Ref(TypeID),
|
||||
Deref(TypeID),
|
||||
Slice(TypeID),
|
||||
@@ -27,7 +28,21 @@ pub enum Type {
|
||||
Generic(GenericID),
|
||||
Infer,
|
||||
Error,
|
||||
Placeholder,
|
||||
}
|
||||
|
||||
impl Type {
|
||||
pub fn rf(self, p: &mut UProgram) -> Self {
|
||||
p.def_ty(self).rf()
|
||||
}
|
||||
pub fn derf(self, p: &mut UProgram) -> Self {
|
||||
p.def_ty(self).derf()
|
||||
}
|
||||
pub fn arr(self, p: &mut UProgram, len: Len) -> Self {
|
||||
p.def_ty(self).arr(len)
|
||||
}
|
||||
pub fn slice(self, p: &mut UProgram) -> Self {
|
||||
p.def_ty(self).slice()
|
||||
}
|
||||
}
|
||||
|
||||
impl TypeID {
|
||||
@@ -46,9 +61,6 @@ impl TypeID {
|
||||
}
|
||||
|
||||
impl Type {
|
||||
pub fn is_resolved(&self) -> bool {
|
||||
!matches!(self, Self::Error | Self::Placeholder | Self::Infer)
|
||||
}
|
||||
pub fn bx(self) -> Box<Self> {
|
||||
Box::new(self)
|
||||
}
|
||||
|
||||
@@ -174,7 +174,7 @@ pub fn arg_to_var(node: &Node<PAsmArg>, ctx: &mut FnLowerCtx) -> Option<VarInst>
|
||||
);
|
||||
return None;
|
||||
};
|
||||
ctx.get_var(node)
|
||||
ctx.var(node)
|
||||
}
|
||||
|
||||
impl RegRef {
|
||||
@@ -184,7 +184,7 @@ impl RegRef {
|
||||
let reg = Reg::from_ident(node, ctx)?;
|
||||
Self::Reg(reg)
|
||||
}
|
||||
PAsmArg::Ref(node) => Self::Var(ctx.get_var(node)?),
|
||||
PAsmArg::Ref(node) => Self::Var(ctx.var(node)?),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use crate::ir::{UProgram, UVar, VarInst};
|
||||
use crate::ir::{UProgram, UVar, VarID, VarInst};
|
||||
|
||||
use super::{CompilerOutput, 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<VarID> {
|
||||
let s = self.as_ref()?;
|
||||
let name = s.name.as_ref().map_or("{error}", |v| v);
|
||||
let ty = match &s.ty {
|
||||
|
||||
@@ -20,11 +20,11 @@ impl FnLowerable for PExpr {
|
||||
Some(match e {
|
||||
PExpr::Lit(l) => match l {
|
||||
super::PLiteral::String(s) => {
|
||||
let dest = ctx.b.temp_var(ctx.origin, Type::Bits(8).slice());
|
||||
let dest = ctx.b.temp_var(ctx.origin, Type::Bits(8).slice(ctx.b.p));
|
||||
let data = s.as_bytes().to_vec();
|
||||
let src = ctx.b.def_data(UData {
|
||||
name: format!("string \"{}\"", s.replace("\n", "\\n")),
|
||||
ty: Type::Bits(8).arr(data.len() as u32),
|
||||
ty: Type::Bits(8).arr(ctx.b.p, data.len() as u32),
|
||||
content: data,
|
||||
});
|
||||
ctx.push(UInstruction::LoadSlice { dst: dest, src });
|
||||
@@ -55,7 +55,7 @@ impl FnLowerable for PExpr {
|
||||
}
|
||||
super::PLiteral::Unit => ctx.b.temp_var(ctx.origin, Type::Unit),
|
||||
},
|
||||
PExpr::Ident(i) => ctx.get_var(i),
|
||||
PExpr::Ident(i) => ctx.var(i),
|
||||
PExpr::BinaryOp(op, e1, e2) => match op {
|
||||
InfixOp::Add => todo!(),
|
||||
InfixOp::Sub => todo!(),
|
||||
@@ -77,13 +77,13 @@ impl FnLowerable for PExpr {
|
||||
let res = e.lower(ctx)?;
|
||||
match op {
|
||||
PostfixOp::Ref => {
|
||||
let ty = ctx.b.vars[res.id].ty.rf();
|
||||
let ty = Type::Ref(ctx.b.infer());
|
||||
let dest = ctx.temp(ty);
|
||||
ctx.push(UInstruction::Ref { dst: dest, src: res });
|
||||
dest
|
||||
}
|
||||
PostfixOp::Deref => {
|
||||
let ty = ctx.b.vars[res.id].ty.derf();
|
||||
let ty = Type::Deref(ctx.b.infer());
|
||||
let dest = ctx.temp(ty);
|
||||
ctx.push(UInstruction::Deref { dst: dest, src: res });
|
||||
dest
|
||||
@@ -100,9 +100,9 @@ impl FnLowerable for PExpr {
|
||||
let arg = arg.lower(ctx)?;
|
||||
nargs.push(arg);
|
||||
}
|
||||
let dest = ctx.temp(Type::Placeholder);
|
||||
let dest = ctx.temp(Type::Infer);
|
||||
ctx.push(UInstruction::Call {
|
||||
dst: dest,
|
||||
dst: VarInst { status: , origin: () },
|
||||
f: fe,
|
||||
args: nargs,
|
||||
});
|
||||
|
||||
@@ -3,120 +3,111 @@ use std::collections::HashMap;
|
||||
use super::{CompilerMsg, CompilerOutput, FileSpan, FnLowerable, Imports, Node, PFunction};
|
||||
use crate::{
|
||||
ir::{
|
||||
FnID, Idents, Typable, Type, UFunc, UInstrInst, UInstruction, UModuleBuilder, UProgram,
|
||||
UVar, VarID, VarInst,
|
||||
FnID, Origin, Typable, Type, UFunc, UInstrInst, UInstruction, UModuleBuilder, UVar, VarID,
|
||||
VarInst, VarStatus,
|
||||
},
|
||||
parser,
|
||||
parser, util::NameStack,
|
||||
};
|
||||
|
||||
impl Node<PFunction> {
|
||||
pub fn lower_name(&self, p: &mut UProgram) -> Option<FnID> {
|
||||
self.as_ref()?.lower_name(p)
|
||||
}
|
||||
pub fn lower(
|
||||
&self,
|
||||
id: FnID,
|
||||
p: &mut UProgram,
|
||||
b: &mut UModuleBuilder,
|
||||
imports: &mut Imports,
|
||||
output: &mut CompilerOutput,
|
||||
) {
|
||||
if let Some(s) = self.as_ref() {
|
||||
s.lower(id, p, imports, output)
|
||||
}
|
||||
) -> Option<FnID> {
|
||||
self.as_ref()
|
||||
.map(|s| s.lower(b, imports, output, self.origin))
|
||||
.flatten()
|
||||
}
|
||||
}
|
||||
|
||||
impl PFunction {
|
||||
pub fn lower_name(&self, p: &mut UProgram) -> Option<FnID> {
|
||||
let header = self.header.as_ref()?;
|
||||
let name = header.name.as_ref()?;
|
||||
let id = p.def_searchable(name, None, self.header.origin);
|
||||
Some(id)
|
||||
}
|
||||
pub fn lower(
|
||||
&self,
|
||||
id: FnID,
|
||||
p: &mut UProgram,
|
||||
b: &mut UModuleBuilder,
|
||||
imports: &mut Imports,
|
||||
output: &mut CompilerOutput,
|
||||
) {
|
||||
let name = p.names.name(id).to_string();
|
||||
p.push_name(&name);
|
||||
let (args, ret) = if let Some(header) = self.header.as_ref() {
|
||||
origin: Origin,
|
||||
) -> Option<FnID> {
|
||||
let header = self.header.as_ref()?;
|
||||
let name = header.name.as_ref()?.0.clone();
|
||||
let (generic_args, args, ret) = if let Some(header) = self.header.as_ref() {
|
||||
(
|
||||
header
|
||||
.gargs
|
||||
.iter()
|
||||
.map(|a| Some(a.lower(b, output)))
|
||||
.collect(),
|
||||
header
|
||||
.args
|
||||
.iter()
|
||||
.flat_map(|a| Some(a.lower(p, output)?.id))
|
||||
.flat_map(|a| Some(a.lower(b, output)?))
|
||||
.collect(),
|
||||
match &header.ret {
|
||||
Some(ty) => ty.lower(p, output),
|
||||
None => Type::Unit,
|
||||
Some(ty) => ty.lower(b, output),
|
||||
None => b.def_ty(Type::Unit),
|
||||
},
|
||||
)
|
||||
} else {
|
||||
(Vec::new(), Type::Error)
|
||||
(Vec::new(), Vec::new(), b.error)
|
||||
};
|
||||
let mut ctx = FnLowerCtx {
|
||||
instructions: Vec::new(),
|
||||
b: p,
|
||||
output,
|
||||
origin: self.body.origin,
|
||||
imports,
|
||||
let instructions = {
|
||||
let mut var_stack = Vec::new();
|
||||
let mut ctx = FnLowerCtx {
|
||||
instructions: Vec::new(),
|
||||
var_stack: &mut var_stack,
|
||||
b,
|
||||
output,
|
||||
origin: self.body.origin,
|
||||
imports,
|
||||
};
|
||||
if let Some(src) = self.body.lower(&mut ctx) {
|
||||
ctx.instructions.push(UInstrInst {
|
||||
origin: src.origin,
|
||||
i: UInstruction::Ret { src },
|
||||
});
|
||||
}
|
||||
ctx.instructions
|
||||
};
|
||||
if let Some(src) = self.body.lower(&mut ctx) {
|
||||
ctx.instructions.push(UInstrInst {
|
||||
i: UInstruction::Ret { src },
|
||||
origin: src.origin,
|
||||
});
|
||||
}
|
||||
let instructions = ctx.instructions;
|
||||
let gargs = args.iter().map(|a| b.vars[a].ty).collect();
|
||||
let f = UFunc {
|
||||
origin,
|
||||
gargs,
|
||||
name,
|
||||
args,
|
||||
ret,
|
||||
instructions,
|
||||
};
|
||||
p.pop_name();
|
||||
p.write(id, f)
|
||||
Some(b.def_fn(f))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FnLowerCtx<'a> {
|
||||
pub b: &'a mut UModuleBuilder<'a>,
|
||||
pub struct FnLowerCtx<'a, 'b> {
|
||||
pub b: &'a mut UModuleBuilder<'b>,
|
||||
pub instructions: Vec<UInstrInst>,
|
||||
pub output: &'a mut CompilerOutput,
|
||||
pub origin: FileSpan,
|
||||
pub imports: &'a mut Imports,
|
||||
pub var_stack: Vec<HashMap<String, VarID>>,
|
||||
pub var_stack: &'a mut NameStack<VarID>,
|
||||
}
|
||||
|
||||
impl FnLowerCtx<'_> {
|
||||
pub fn get_idents(&mut self, node: &Node<parser::PIdent>) -> Option<Idents> {
|
||||
let name = node.inner.as_ref()?;
|
||||
let res = self.b.get_idents(name);
|
||||
if res.is_none() {
|
||||
self.err_at(node.origin, format!("Identifier '{}' not found", name));
|
||||
impl<'a, 'b> FnLowerCtx<'a, 'b> {
|
||||
pub fn var(&mut self, node: &Node<parser::PIdent>) -> VarInst {
|
||||
if let Some(n) = node.as_ref() {
|
||||
if let Some(&var) = self.var_stack.search(&n.0) {
|
||||
return VarInst {
|
||||
status: VarStatus::Res(var),
|
||||
origin: node.origin,
|
||||
}
|
||||
}
|
||||
}
|
||||
res
|
||||
}
|
||||
pub fn get_var(&mut self, node: &Node<parser::PIdent>) -> VarInst {
|
||||
let ids = self.get_idents(node)?;
|
||||
if ids.get::<UVar>().is_none() {
|
||||
self.err_at(
|
||||
node.origin,
|
||||
format!("Variable '{}' not found", node.inner.as_ref()?),
|
||||
);
|
||||
}
|
||||
ids.get::<UVar>().map(|id| VarInst {
|
||||
id,
|
||||
origin: node.origin,
|
||||
})
|
||||
}
|
||||
pub fn err(&mut self, msg: String) {
|
||||
self.output.err(CompilerMsg::new(self.origin, msg))
|
||||
self.output.err(CompilerMsg::new(msg, self.origin))
|
||||
}
|
||||
pub fn err_at(&mut self, span: FileSpan, msg: String) {
|
||||
self.output.err(CompilerMsg::new(span, msg))
|
||||
self.output.err(CompilerMsg::new(msg, span))
|
||||
}
|
||||
pub fn temp<T: Typable>(&mut self, ty: Type) -> VarInst {
|
||||
self.b.temp_var(self.origin, ty)
|
||||
@@ -125,27 +116,13 @@ impl FnLowerCtx<'_> {
|
||||
self.push_at(i, self.origin);
|
||||
}
|
||||
pub fn push_at(&mut self, i: UInstruction, span: FileSpan) {
|
||||
match i {
|
||||
UInstruction::Mv { dst: dest, src } => todo!(),
|
||||
UInstruction::Ref { dst: dest, src } => todo!(),
|
||||
UInstruction::LoadData { dst: dest, src } => todo!(),
|
||||
UInstruction::LoadSlice { dst: dest, src } => todo!(),
|
||||
UInstruction::LoadFn { dst: dest, src } => todo!(),
|
||||
UInstruction::Call { dst: dest, f, args } => todo!(),
|
||||
UInstruction::AsmBlock { instructions, args } => todo!(),
|
||||
UInstruction::Ret { src } => todo!(),
|
||||
UInstruction::Construct { dst: dest, fields } => todo!(),
|
||||
UInstruction::If { cond, body } => todo!(),
|
||||
UInstruction::Loop { body } => todo!(),
|
||||
UInstruction::Break => todo!(),
|
||||
UInstruction::Continue => todo!(),
|
||||
}
|
||||
self.instructions.push(UInstrInst { i, origin: span });
|
||||
}
|
||||
pub fn branch<'a>(&'a mut self) -> FnLowerCtx<'a> {
|
||||
pub fn branch(&'a mut self) -> FnLowerCtx<'a, 'b> {
|
||||
FnLowerCtx {
|
||||
b: self.b,
|
||||
instructions: Vec::new(),
|
||||
var_stack: self.var_stack,
|
||||
output: self.output,
|
||||
origin: self.origin,
|
||||
imports: self.imports,
|
||||
|
||||
@@ -8,13 +8,13 @@ mod struc;
|
||||
mod ty;
|
||||
|
||||
use super::*;
|
||||
use crate::ir::{Type, UFunc, UProgram};
|
||||
use crate::ir::{Type, UFunc, UModuleBuilder};
|
||||
|
||||
impl PModule {
|
||||
pub fn lower(
|
||||
&self,
|
||||
path: Vec<String>,
|
||||
p: &mut UProgram,
|
||||
p: &mut UModuleBuilder,
|
||||
imports: &mut Imports,
|
||||
output: &mut CompilerOutput,
|
||||
) {
|
||||
|
||||
@@ -9,14 +9,14 @@ impl Node<Box<PType>> {
|
||||
pub fn lower(&self, p: &mut UModuleBuilder, output: &mut CompilerOutput) -> TypeID {
|
||||
self.as_ref()
|
||||
.map(|t| t.lower(p, output, self.origin))
|
||||
.unwrap_or(p.error())
|
||||
.unwrap_or(p.error)
|
||||
}
|
||||
}
|
||||
impl Node<PType> {
|
||||
pub fn lower(&self, p: &mut UModuleBuilder, output: &mut CompilerOutput) -> TypeID {
|
||||
self.as_ref()
|
||||
.map(|t| t.lower(p, output, self.origin))
|
||||
.unwrap_or(p.error())
|
||||
.unwrap_or(p.error)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ impl PType {
|
||||
while let PType::Member(node, ident) = ty {
|
||||
ty = if let Some(t) = node.as_ref() {
|
||||
let Some(name) = ident.as_ref() else {
|
||||
return p.error();
|
||||
return p.error;
|
||||
};
|
||||
origin = node.origin;
|
||||
path.push(MemberID {
|
||||
@@ -43,18 +43,19 @@ impl PType {
|
||||
});
|
||||
&**t
|
||||
} else {
|
||||
return p.error();
|
||||
return p.error;
|
||||
};
|
||||
}
|
||||
if !path.is_empty() {
|
||||
let PType::Ident(id) = ty else {
|
||||
return p.error();
|
||||
return p.error;
|
||||
};
|
||||
path.push(MemberID {
|
||||
name: id.0.clone(),
|
||||
origin,
|
||||
});
|
||||
return p.def_ty(Type::Unres(ModPath { m: p.module, path }));
|
||||
let ty = Type::Unres(ModPath { m: p.module, path });
|
||||
return p.def_ty(ty);
|
||||
}
|
||||
let ty = match ty {
|
||||
PType::Member(_, _) => unreachable!(),
|
||||
@@ -70,31 +71,6 @@ impl PType {
|
||||
PType::Generic(node, nodes) => todo!(),
|
||||
};
|
||||
p.def_ty(ty)
|
||||
// let Some(name) = self.name.as_ref() else {
|
||||
// return p.error();
|
||||
// };
|
||||
// let ids = p.get_idents(name);
|
||||
// // TODO: should generics always take precedence?
|
||||
// if let Some(id) = ids.and_then(|ids| ids.get::<Type>()) {
|
||||
// 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(StructInst { 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
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
use super::{
|
||||
util::parse_list, PBlock, PIdent, Node, Parsable, ParseResult, ParserCtx,
|
||||
Symbol, PType, PVarDef,
|
||||
util::parse_list, Node, PBlock, PIdent, PType, PVarDef, Parsable, ParseResult, ParserCtx,
|
||||
Symbol,
|
||||
};
|
||||
use std::fmt::Debug;
|
||||
|
||||
pub struct PFunctionHeader {
|
||||
pub name: Node<PIdent>,
|
||||
pub args: Vec<Node<PVarDef>>,
|
||||
pub gargs: Vec<Node<PType>>,
|
||||
pub ret: Option<Node<PType>>,
|
||||
}
|
||||
|
||||
@@ -18,6 +19,12 @@ pub struct PFunction {
|
||||
impl Parsable for PFunctionHeader {
|
||||
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||
let name = ctx.parse()?;
|
||||
let generic_args = if ctx.expect_peek()?.is_symbol(Symbol::OpenAngle) {
|
||||
ctx.next();
|
||||
parse_list(ctx, Symbol::CloseAngle)?
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
ctx.expect_sym(Symbol::OpenParen)?;
|
||||
// let sel = ctx.maybe_parse();
|
||||
// if sel.is_some() {
|
||||
@@ -39,6 +46,7 @@ impl Parsable for PFunctionHeader {
|
||||
ParseResult::Ok(Self {
|
||||
name,
|
||||
args,
|
||||
gargs: generic_args,
|
||||
ret,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ impl Parsable for PType {
|
||||
}
|
||||
break;
|
||||
}
|
||||
ParseResult::Wrap(cur)
|
||||
ParseResult::Node(cur)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
mod padder;
|
||||
mod bits;
|
||||
mod label;
|
||||
mod name_stack;
|
||||
|
||||
pub use padder::*;
|
||||
pub use bits::*;
|
||||
pub use label::*;
|
||||
pub use name_stack::*;
|
||||
|
||||
17
src/util/name_stack.rs
Normal file
17
src/util/name_stack.rs
Normal file
@@ -0,0 +1,17 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub struct NameStack<T>(Vec<HashMap<String, T>>);
|
||||
|
||||
impl<T> NameStack<T> {
|
||||
pub fn new() -> Self {
|
||||
Self(Vec::new())
|
||||
}
|
||||
pub fn search(&self, name: &str) -> Option<&T> {
|
||||
for level in self.0.iter().rev() {
|
||||
if let Some(v) = level.get(name) {
|
||||
return Some(v);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user