I can see the light

This commit is contained in:
2025-05-02 18:18:13 -04:00
parent d7222cc7a4
commit 57c46b653e
35 changed files with 1247 additions and 1000 deletions

View File

@@ -11,7 +11,7 @@ fn println(msg: slice<8>) {
} }
fn print(msg: slice<8>) { fn print(msg: slice<8>) {
asm (a1 = &msg) { asm (a1 = msg@) {
ld a2, 8, a1 ld a2, 8, a1
ld a1, 0, a1 ld a1, 0, a1
li a0, 1 li a0, 1
@@ -29,7 +29,7 @@ fn print_hex(x: 64) {
c = add(c, 7); c = add(c, 7);
}; };
c = add(c, 48); c = add(c, 48);
asm (a1 = &c) { asm (a1 = c@) {
li a2, 1 li a2, 1
li a0, 1 li a0, 1
li a7, 64 li a7, 64
@@ -65,7 +65,7 @@ fn print_dec(x: 64) {
c = add(c, 7); c = add(c, 7);
}; };
c = add(c, 48); c = add(c, 48);
asm (a1 = &c) { asm (a1 = c@) {
li a2, 1 li a2, 1
li a0, 1 li a0, 1
li a7, 64 li a7, 64

View File

@@ -9,14 +9,14 @@ pub struct SrcFile {
pub text: String, pub text: String,
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct FilePos { pub struct FilePos {
pub file: FileID, pub file: FileID,
pub line: usize, pub line: usize,
pub col: usize, pub col: usize,
} }
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
pub struct FileSpan { pub struct FileSpan {
pub file: FileID, pub file: FileID,
pub start: FilePos, pub start: FilePos,

View File

@@ -19,7 +19,7 @@ impl CompilerMsg {
spans: Vec::new(), spans: Vec::new(),
} }
} }
pub fn from_span(span: FileSpan, msg: String) -> Self { pub fn new(msg: String, span: FileSpan) -> Self {
Self { Self {
msg, msg,
spans: vec![span], spans: vec![span],

View File

@@ -1,4 +1,8 @@
use std::{fmt::Debug, marker::PhantomData}; use std::{
fmt::Debug,
marker::PhantomData,
ops::{Index, IndexMut},
};
// I had an idea for why these were different... now I don't // I had an idea for why these were different... now I don't
pub type Size = u32; pub type Size = u32;
@@ -12,19 +16,15 @@ impl<T> ID<T> {
} }
} }
pub trait Named {
const NAME: &str;
}
impl<T> From<usize> for ID<T> { impl<T> From<usize> for ID<T> {
fn from(value: usize) -> Self { fn from(value: usize) -> Self {
Self(value, PhantomData) Self(value, PhantomData)
} }
} }
impl<K: Named> Debug for ID<K> { impl<T> Debug for ID<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}{}", K::NAME, self.0) write!(f, "{{{}}}", self.0)
} }
} }
@@ -49,3 +49,60 @@ impl<T> Clone for ID<T> {
} }
impl<T> Copy for ID<T> {} impl<T> Copy for ID<T> {}
// :fear:
impl<T> Index<ID<T>> for Vec<T> {
type Output = T;
fn index(&self, i: ID<T>) -> &Self::Output {
&self[i.0]
}
}
impl<T> IndexMut<ID<T>> for Vec<T> {
fn index_mut(&mut self, i: ID<T>) -> &mut Self::Output {
&mut self[i.0]
}
}
impl<T> Index<&ID<T>> for Vec<T> {
type Output = T;
fn index(&self, i: &ID<T>) -> &Self::Output {
&self[i.0]
}
}
impl<T> IndexMut<&ID<T>> for Vec<T> {
fn index_mut(&mut self, i: &ID<T>) -> &mut Self::Output {
&mut self[i.0]
}
}
impl<T> Index<ID<T>> for [T] {
type Output = T;
fn index(&self, i: ID<T>) -> &Self::Output {
&self[i.0]
}
}
impl<T> IndexMut<ID<T>> for [T] {
fn index_mut(&mut self, i: ID<T>) -> &mut Self::Output {
&mut self[i.0]
}
}
impl<T> Index<&ID<T>> for [T] {
type Output = T;
fn index(&self, i: &ID<T>) -> &Self::Output {
&self[i.0]
}
}
impl<T> IndexMut<&ID<T>> for [T] {
fn index_mut(&mut self, i: &ID<T>) -> &mut Self::Output {
&mut self[i.0]
}
}

View File

@@ -128,7 +128,7 @@ impl<'a> LFunctionBuilder<'a> {
} }
pub fn insert_instr(&mut self, i: &UInstrInst) -> Option<Option<String>> { pub fn insert_instr(&mut self, i: &UInstrInst) -> Option<Option<String>> {
match &i.i { match &i.i {
UInstruction::Mv { dest, src } => { UInstruction::Mv { dst: dest, src } => {
self.alloc_stack(dest.id)?; self.alloc_stack(dest.id)?;
self.map_subvar(src.id); self.map_subvar(src.id);
self.instrs.push(LInstruction::Mv { self.instrs.push(LInstruction::Mv {
@@ -138,7 +138,7 @@ impl<'a> LFunctionBuilder<'a> {
src_offset: 0, src_offset: 0,
}); });
} }
UInstruction::Ref { dest, src } => { UInstruction::Ref { dst: dest, src } => {
self.alloc_stack(dest.id)?; self.alloc_stack(dest.id)?;
self.map_subvar(src.id); self.map_subvar(src.id);
self.instrs.push(LInstruction::Ref { self.instrs.push(LInstruction::Ref {
@@ -146,7 +146,7 @@ impl<'a> LFunctionBuilder<'a> {
src: src.id, src: src.id,
}); });
} }
UInstruction::LoadData { dest, src } => { UInstruction::LoadData { dst: 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.data.builder.ro_data( let sym = self.data.builder.ro_data(
@@ -161,7 +161,7 @@ impl<'a> LFunctionBuilder<'a> {
src: sym, src: sym,
}); });
} }
UInstruction::LoadSlice { dest, src } => { UInstruction::LoadSlice { dst: 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 Type::Array(_, len) = &data.ty else { let Type::Array(_, len) = &data.ty else {
@@ -191,7 +191,7 @@ impl<'a> LFunctionBuilder<'a> {
src: sym, src: sym,
}); });
} }
UInstruction::LoadFn { dest, src } => { UInstruction::LoadFn { dst: dest, src } => {
self.alloc_stack(dest.id)?; self.alloc_stack(dest.id)?;
let sym = self.builder.func(src); let sym = self.builder.func(src);
self.instrs.push(LInstruction::LoadAddr { self.instrs.push(LInstruction::LoadAddr {
@@ -200,7 +200,7 @@ impl<'a> LFunctionBuilder<'a> {
src: sym, src: sym,
}); });
} }
UInstruction::Call { dest, f, args } => { UInstruction::Call { dst: dest, f, args } => {
self.alloc_stack(dest.id); self.alloc_stack(dest.id);
self.makes_call = true; self.makes_call = true;
let fid = &self.program.fn_var.fun(f.id).expect("a"); let fid = &self.program.fn_var.fun(f.id).expect("a");
@@ -267,7 +267,7 @@ impl<'a> LFunctionBuilder<'a> {
}; };
self.data.instrs.push(LInstruction::Ret { src }) self.data.instrs.push(LInstruction::Ret { src })
} }
UInstruction::Construct { dest, fields } => { UInstruction::Construct { dst: dest, fields } => {
let sty = &self.program.expect_type(dest.id); let sty = &self.program.expect_type(dest.id);
let Type::Struct(sty) = sty else { let Type::Struct(sty) = sty else {
panic!("bruh htis aint' a struct"); panic!("bruh htis aint' a struct");

View File

@@ -1,157 +1,31 @@
use super::{FnID, Kind, Origin, VarID, NAMED_KINDS};
use crate::ir::ID;
use std::collections::HashMap;
pub struct OriginMap { // #[derive(Debug, Clone, Copy)]
origins: [Vec<Origin>; NAMED_KINDS], // pub struct Ident {
} // id: usize,
// kind: usize,
impl OriginMap { // }
pub fn new() -> Self { //
Self { // // this isn't really a map... but also keeps track of "side data"
origins: core::array::from_fn(|_| Vec::new()), // #[derive(Debug, Clone, Copy)]
} // pub struct Idents {
} // pub latest: Ident,
pub fn get<K: Kind>(&self, id: ID<K>) -> Origin { // pub kinds: [Option<usize>; NAMED_KINDS],
self.origins[K::INDEX][id.0] // }
} //
pub fn push<K: Kind>(&mut self, origin: Origin) { // impl Idents {
self.origins[K::INDEX].push(origin); // pub fn new(latest: Ident) -> Self {
} // let mut s = Self {
} // latest,
// kinds: [None; NAMED_KINDS],
pub type NamePath = Vec<String>; // };
// s.insert(latest);
pub struct NameTree { // s
ids: [HashMap<String, usize>; NAMED_KINDS], // }
children: HashMap<String, NameTree>, // pub fn insert(&mut self, i: Ident) {
} // self.latest = i;
// self.kinds[i.kind] = Some(i.id);
impl NameTree { // }
pub fn new() -> Self { // pub fn get(&self) -> Option<ID<K>> {
Self { // self.kinds[K::INDEX].map(|i| i.into())
ids: core::array::from_fn(|_| HashMap::new()), // }
children: HashMap::new(), // }
}
}
pub fn get(&self, path: &[String]) -> Option<&NameTree> {
let first = path.first()?;
self.children.get(first)?.get(&path[1..])
}
pub fn id<K: Kind>(&self, path: &[String], name: &str) -> Option<ID<K>> {
self.get(&path)?.ids[K::INDEX]
.get(name)
.copied()
.map(ID::new)
}
pub fn insert<K: Kind>(&mut self, path: &[String], id: usize) {
if let [key] = &path[..] {
self.ids[K::INDEX].insert(key.to_string(), id);
return;
}
let Some(key) = path.first() else {
return;
};
self.children
.entry(key.to_string())
.or_insert_with(|| NameTree::new())
.insert::<K>(&path[1..], id);
}
}
pub struct NameMap {
names: [Vec<String>; NAMED_KINDS],
tree: NameTree,
}
impl NameMap {
pub fn new() -> Self {
Self {
names: core::array::from_fn(|_| Vec::new()),
tree: NameTree::new(),
}
}
pub fn path<K: Kind>(&self, id: ID<K>) -> &str {
&self.names[K::INDEX][id.0]
}
pub fn name<K: Kind>(&self, id: ID<K>) -> &str {
let mut path = self.path(id);
while let Some(i) = path.find("::") {
path = &path[i + 2..];
}
path
}
pub fn id<K: Kind>(&self, path: &[String], name: &str) -> Option<ID<K>> {
Some(self.tree.id(path, name)?)
}
pub fn push<K: Kind>(&mut self, path: &[String]) {
let id = self.names[K::INDEX].len();
self.tree.insert::<K>(path, id);
let name = path.join("::");
self.names[K::INDEX].push(name);
}
}
pub struct FnVarMap {
vtf: HashMap<VarID, FnID>,
ftv: Vec<VarID>,
}
impl FnVarMap {
pub fn new() -> Self {
Self {
vtf: HashMap::new(),
ftv: Vec::new(),
}
}
pub fn insert(&mut self, f: FnID, v: VarID) {
self.vtf.insert(v, f);
self.ftv.push(v);
}
pub fn var(&self, f: FnID) -> VarID {
self.ftv[f.0]
}
pub fn fun(&self, v: VarID) -> Option<FnID> {
self.vtf.get(&v).copied()
}
}
#[derive(Debug, Clone, Copy)]
pub struct Ident {
id: usize,
kind: usize,
}
impl<K: Kind> From<ID<K>> for Ident {
fn from(id: ID<K>) -> Self {
Self {
id: id.0,
kind: K::INDEX,
}
}
}
// this isn't really a map... but also keeps track of "side data"
#[derive(Debug, Clone, Copy)]
pub struct Idents {
pub latest: Ident,
pub kinds: [Option<usize>; NAMED_KINDS],
}
impl Idents {
pub fn new(latest: Ident) -> Self {
let mut s = Self {
latest,
kinds: [None; NAMED_KINDS],
};
s.insert(latest);
s
}
pub fn insert(&mut self, i: Ident) {
self.latest = i;
self.kinds[i.kind] = Some(i.id);
}
pub fn get<K: Kind>(&self) -> Option<ID<K>> {
self.kinds[K::INDEX].map(|i| i.into())
}
}

View File

@@ -1,18 +1,18 @@
use crate::{common::FileSpan, ir::VarID}; use crate::ir::VarID;
use std::fmt::Debug; use std::fmt::Debug;
use super::UInstruction; use super::{Origin, UInstruction};
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub struct VarInst { pub struct VarInst {
pub id: VarID, pub id: VarID,
pub span: FileSpan, pub origin: Origin,
} }
#[derive(Clone)] #[derive(Clone)]
pub struct UInstrInst { pub struct UInstrInst {
pub i: UInstruction, pub i: UInstruction,
pub span: FileSpan, pub origin: Origin,
} }
impl Debug for VarInst { impl Debug for VarInst {

View File

@@ -6,27 +6,31 @@ use crate::{compiler::arch::riscv::Reg, util::Padder};
#[derive(Clone)] #[derive(Clone)]
pub enum UInstruction { pub enum UInstruction {
Mv { Mv {
dest: VarInst, dst: VarInst,
src: VarInst, src: VarInst,
}, },
Ref { Ref {
dest: VarInst, dst: VarInst,
src: VarInst,
},
Deref {
dst: VarInst,
src: VarInst, src: VarInst,
}, },
LoadData { LoadData {
dest: VarInst, dst: VarInst,
src: DataID, src: DataID,
}, },
LoadSlice { LoadSlice {
dest: VarInst, dst: VarInst,
src: DataID, src: DataID,
}, },
LoadFn { LoadFn {
dest: VarInst, dst: VarInst,
src: FnID, src: FnID,
}, },
Call { Call {
dest: VarInst, dst: VarInst,
f: VarInst, f: VarInst,
args: Vec<VarInst>, args: Vec<VarInst>,
}, },
@@ -38,7 +42,7 @@ pub enum UInstruction {
src: VarInst, src: VarInst,
}, },
Construct { Construct {
dest: VarInst, dst: VarInst,
fields: HashMap<String, VarInst>, fields: HashMap<String, VarInst>,
}, },
If { If {
@@ -68,19 +72,19 @@ pub enum AsmBlockArgType {
impl std::fmt::Debug for UInstruction { impl std::fmt::Debug for UInstruction {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
Self::Mv { dest, src } => write!(f, "{dest:?} <- {src:?}")?, Self::Mv { dst: dest, src } => write!(f, "{dest:?} <- {src:?}")?,
Self::Ref { dest, src } => write!(f, "{dest:?} <- &{src:?}")?, Self::Ref { dst: dest, src } => write!(f, "{dest:?} <- &{src:?}")?,
Self::LoadData { dest, src } => write!(f, "{dest:?} <- {src:?}")?, Self::LoadData { dst: dest, src } => write!(f, "{dest:?} <- {src:?}")?,
Self::LoadFn { dest, src } => write!(f, "{dest:?} <- {src:?}")?, Self::LoadFn { dst: dest, src } => write!(f, "{dest:?} <- {src:?}")?,
Self::LoadSlice { dest, src } => write!(f, "{dest:?} <- &[{src:?}]")?, Self::LoadSlice { dst: dest, src } => write!(f, "{dest:?} <- &[{src:?}]")?,
Self::Call { Self::Call {
dest, dst: dest,
f: func, f: func,
args, args,
} => 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::Construct { dst: dest, fields } => write!(f, "{dest:?} <- {fields:?}")?,
Self::If { cond, body } => { Self::If { cond, body } => {
write!(f, "if {cond:?}:")?; write!(f, "if {cond:?}:")?;
if !body.is_empty() { if !body.is_empty() {

View File

@@ -1,14 +1,19 @@
use super::{Type, UInstrInst, UInstruction, UProgram}; use super::{Type, UInstrInst, UInstruction, UProgram};
use crate::{ use crate::{
common::FileSpan, common::FileSpan,
ir::{Len, Named, ID}, ir::{Len, ID},
}; };
use std::{collections::HashMap, fmt::Debug}; use std::{collections::HashMap, fmt::Debug};
pub type NamePath = Vec<String>;
#[derive(Clone)] #[derive(Clone)]
pub struct UFunc { pub struct UFunc {
pub name: String,
pub origin: Origin,
pub args: Vec<VarID>, pub args: Vec<VarID>,
pub ret: Type, pub argtys: Vec<TypeID>,
pub ret: TypeID,
pub instructions: Vec<UInstrInst>, pub instructions: Vec<UInstrInst>,
} }
@@ -19,16 +24,61 @@ pub struct StructField {
#[derive(Clone)] #[derive(Clone)]
pub struct UStruct { pub struct UStruct {
pub name: String,
pub origin: Origin,
pub fields: HashMap<String, StructField>, pub fields: HashMap<String, StructField>,
pub generics: Vec<GenericID>, pub generics: Vec<GenericID>,
} }
#[derive(Clone)] #[derive(Clone)]
pub struct UGeneric {} pub struct UGeneric {
pub name: String,
pub origin: Origin,
}
#[derive(Clone)] #[derive(Clone)]
pub struct UVar { pub struct UVar {
pub name: String,
pub origin: Origin,
pub ty: TypeID, pub ty: TypeID,
pub res: UVarTy,
}
#[derive(Clone)]
pub struct VarParent {
id: VarID,
path: Vec<String>,
}
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct MemberID {
pub name: String,
pub origin: Origin,
}
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct ModPath {
pub m: ModID,
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)] #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
@@ -39,17 +89,38 @@ pub struct VarOffset {
#[derive(Clone)] #[derive(Clone)]
pub struct UData { pub struct UData {
pub name: String,
pub ty: Type, pub ty: Type,
pub content: Vec<u8>, pub content: Vec<u8>,
} }
#[derive(Clone)]
pub struct UModule {
pub name: String,
pub members: HashMap<String, MemberID>,
pub children: HashMap<String, ModID>,
pub parent: Option<ModID>,
}
pub struct ModMissing {
pub import_all: Vec<ModID>,
pub vars: Vec<VarID>,
}
#[derive(Clone)]
pub enum Member {
Fn(FnID),
Struct(StructID),
Var(VarID),
}
pub type Origin = FileSpan; pub type Origin = FileSpan;
impl UFunc { impl UFunc {
pub fn ty(&self, program: &UProgram) -> Type { pub fn ty(&self, program: &UProgram) -> Type {
Type::Fn { Type::Fn {
args: self.args.iter().map(|a| program.expect(*a).ty).collect(), args: self.argtys.clone(),
ret: self.ret, ret: Box::new(self.ret.clone()),
} }
} }
pub fn flat_iter(&self) -> impl Iterator<Item = &UInstrInst> { pub fn flat_iter(&self) -> impl Iterator<Item = &UInstrInst> {
@@ -85,62 +156,12 @@ impl<'a> Iterator for InstrIter<'a> {
} }
} }
macro_rules! impl_kind {
// TRUST THIS IS SANE!!! KEEP THE CODE DRY AND SAFE!!!!!!
($struc:ty, $idx:expr, $field:ident, $name:expr) => {
impl_kind!($struc, $idx, $field, $name, nofin);
impl Finish for $struc {
fn finish(_: &mut UProgram, _: ID<Self>, _: &str) {}
}
};
($struc:ty, $idx:expr, $field:ident, $name:expr, nofin) => {
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", nofin);
impl_kind!(UVar, 1, vars, "var");
impl_kind!(UStruct, 2, structs, "struct");
impl_kind!(Type, 3, types, "type");
impl_kind!(UData, 4, data, "data");
pub const NAMED_KINDS: usize = 5; pub const NAMED_KINDS: usize = 5;
pub type FnID = ID<UFunc>; pub type FnID = ID<UFunc>;
pub type VarID = ID<UVar>; pub type VarID = ID<UVar>;
pub type TypeID = ID<Type>;
pub type GenericID = ID<UGeneric>;
pub type StructID = ID<UStruct>; pub type StructID = ID<UStruct>;
pub type DataID = ID<UData>; pub type DataID = ID<UData>;
pub type TypeID = ID<Type>; pub type ModID = ID<Option<UModule>>;
impl Finish for UFunc {
fn finish(p: &mut UProgram, id: ID<Self>, name: &str) {
let var = p.def_searchable(
name,
Some(UVar {
ty: Type::Placeholder,
}),
p.origins.get(id),
);
p.fn_var.insert(id, var);
}
}
pub trait Kind: Sized {
const INDEX: usize;
fn from_program_mut(program: &mut UProgram) -> &mut Vec<Option<Self>>;
fn from_program(program: &UProgram) -> &Vec<Option<Self>>;
}
pub trait Finish: Sized {
fn finish(program: &mut UProgram, id: ID<Self>, name: &str);
}

View File

@@ -6,6 +6,7 @@ mod kind;
mod program; mod program;
mod ty; mod ty;
mod validate; mod validate;
mod resolve;
use super::*; use super::*;
use assoc::*; use assoc::*;

View File

@@ -1,21 +1,22 @@
use super::*; use super::*;
use std::collections::HashMap; use std::{
collections::HashMap,
ops::{Deref, DerefMut},
};
pub struct UProgram { pub struct UProgram {
// kinds pub fns: Vec<UFunc>,
pub fns: Vec<Option<UFunc>>, pub structs: Vec<UStruct>,
pub vars: Vec<Option<UVar>>, pub modules: Vec<Option<UModule>>,
pub structs: Vec<Option<UStruct>>, pub data: Vec<UData>,
pub types: Vec<Option<Type>>, pub generics: Vec<UGeneric>,
pub data: Vec<Option<UData>>, pub vars: Vec<UVar>,
// associated data pub types: Vec<Type>,
pub names: NameMap, }
pub origins: OriginMap,
pub fn_var: FnVarMap, pub struct UModuleBuilder<'a> {
// utils for creation pub p: &'a mut UProgram,
error: Option<TypeID>, pub module: ModID,
pub path: Vec<String>,
pub name_stack: Vec<HashMap<String, Idents>>,
pub temp: usize, pub temp: usize,
} }
@@ -26,179 +27,64 @@ impl UProgram {
vars: Vec::new(), vars: Vec::new(),
structs: Vec::new(), structs: Vec::new(),
types: Vec::new(), types: Vec::new(),
generics: Vec::new(),
data: Vec::new(), data: Vec::new(),
names: NameMap::new(), modules: Vec::new(),
origins: OriginMap::new(),
fn_var: FnVarMap::new(),
error: None,
path: Vec::new(),
name_stack: Vec::new(),
temp: 0,
}
}
pub fn error_type(&mut self) -> TypeID {
self.error
.unwrap_or_else(|| self.def("error", Some(Type::Error), Origin::builtin()))
}
pub fn set_module(&mut self, path: Vec<String>) {
self.path = path;
self.name_stack = vec![HashMap::new()];
}
pub fn push(&mut self) {
self.name_stack.push(HashMap::new());
}
pub fn pop(&mut self) {
self.name_stack.pop();
}
pub fn push_name(&mut self, name: &str) {
self.path.push(name.to_string());
}
pub fn pop_name(&mut self) {
self.path.pop();
}
pub fn get_idents(&self, name: &str) -> Option<Idents> {
for map in self.name_stack.iter().rev() {
let res = map.get(name);
if res.is_some() {
return res.cloned();
}
}
None
}
pub fn get<K: Kind>(&self, id: ID<K>) -> Option<&K> {
K::from_program(self)[id.0].as_ref()
}
pub fn get_mut<K: Kind>(&mut self, id: ID<K>) -> Option<&mut K> {
K::from_program_mut(self)[id.0].as_mut()
}
pub fn expect<K: Kind + Named>(&self, id: ID<K>) -> &K {
self.get(id)
.unwrap_or_else(|| panic!("{id:?} not defined yet!"))
}
pub fn expect_type(&self, var: VarID) -> &Type {
self.expect(self.expect(var).ty)
}
pub fn expect_mut<K: Kind + Named>(&mut self, id: ID<K>) -> &mut K {
self.get_mut(id)
.unwrap_or_else(|| panic!("{id:?} not defined yet!"))
}
pub fn get_fn_var(&self, id: VarID) -> Option<&UFunc> {
self.fns[self.fn_var.fun(id)?.0].as_ref()
}
pub fn temp_var(&mut self, origin: Origin, ty: TypeID) -> VarInst {
self.temp_var_inner(origin, ty)
}
fn temp_var_inner(&mut self, origin: Origin, ty: TypeID) -> VarInst {
let v = self.def(&format!("temp{}", self.temp), Some(UVar { ty }), origin);
self.temp += 1;
VarInst {
id: v,
span: origin,
} }
} }
pub fn write<K: Kind>(&mut self, id: ID<K>, k: K) { pub fn instantiate_type(&mut self, ty: Type) {
K::from_program_mut(self)[id.0] = Some(k); self.def_ty(match ty {
Type::Ref(node) => Type::Ref(node.lower()),
Type::Generic(node, nodes) => todo!(),
Type::Ident(node) => todo!(),
});
} }
pub fn def<K: Kind + Finish>(&mut self, name: &str, k: Option<K>, origin: Origin) -> ID<K> { pub fn infer(&mut self) -> TypeID {
self.names.push::<K>(&self.path_for(name)); self.def_ty(Type::Infer)
self.origins.push::<K>(origin); }
let vec = K::from_program_mut(self);
let id = ID::new(vec.len()); pub fn error(&mut self) -> TypeID {
vec.push(k); self.def_ty(Type::Error)
K::finish(self, id, name); }
pub fn def_var(&mut self, v: UVar) -> VarID {
Self::push_id(&mut self.vars, v)
}
pub fn def_fn(&mut self, f: UFunc) -> FnID {
Self::push_id(&mut self.fns, f)
}
pub fn def_ty(&mut self, t: Type) -> TypeID {
Self::push_id(&mut self.types, t)
}
pub fn def_generic(&mut self, g: UGeneric) -> GenericID {
Self::push_id(&mut self.generics, g)
}
pub fn def_data(&mut self, d: UData) -> DataID {
Self::push_id(&mut self.data, d)
}
pub fn def_struct(&mut self, s: UStruct) -> StructID {
Self::push_id(&mut self.structs, s)
}
fn push_id<T>(v: &mut Vec<T>, t: T) -> ID<T> {
let id = ID::new(v.len());
v.push(t);
id id
} }
pub fn path_for(&self, name: &str) -> Vec<String> { pub fn type_name<T: Typer>(&self, ty: T) -> String {
if self.path.is_empty() {
return vec![name.to_string()];
}
let mut path = self.path.clone();
path.push(name.to_string());
path
}
pub fn def_searchable<K: Kind + Finish>(
&mut self,
name: &str,
k: Option<K>,
origin: Origin,
) -> ID<K> {
let id = self.def(&name, k, origin);
self.name_on_stack(id, name.to_string());
id
}
// hopefully these are not needed after redoing types
// pub fn field_type<'a>(&'a self, ty: &'a Type, field: &str) -> Option<&'a Type> {
// if let Type::Struct(sty) = ty {
// Some(&self.get(*sty.fields.get(field)?)?.ty)
// } else if let Type::Module(path) = ty {
// let id = self.names.id::<UVar>(path, field)?;
// Some(&self.get(id)?.ty)
// } else {
// None
// }
// }
//
// pub fn follow_ref(&self, m: &FieldRef) -> Option<&Type> {
// let parent = self.get(m.parent)?;
// self.field_type(self.follow_type(&parent.ty)?, &m.name)
// }
//
// pub fn get_type<'a>(&'a self, v: VarID) -> Option<&'a Type> {
// self.follow_type(&self.get(v)?.ty)
// }
//
// pub fn set_type(&mut self, mut var: VarID, set: Type) -> Option<()> {
// let mut path = Vec::new();
// while let Type::Field(parent) = &self.get(var)?.ty {
// var = parent.parent;
// path.push(parent.name.clone());
// }
// let mut ty = &mut self.vars[var.0].as_mut()?.ty;
// 'outer: while let Type::Struct(sty) = ty {
// let Some(name) = path.pop() else {
// break;
// };
// let struc = &self.structs[sty.id.0].as_ref()?;
// let field = struc.fields.get(&name)?;
// let Type::Generic { id } = field.ty else {
// return None;
// };
// for (i, g) in struc.generics.iter().enumerate() {
// if *g == id {
// ty = &mut sty.args[i];
// continue 'outer;
// }
// }
// return None;
// }
// *ty = set;
// Some(())
// }
//
// pub fn follow_type<'a>(&'a self, ty: &'a Type) -> Option<&'a Type> {
// match ty {
// Type::Field(m) => {
// let parent = self.get(m.parent)?;
// self.field_type(self.follow_type(&parent.ty)?, &m.name)
// }
// ty => Some(ty),
// }
// }
pub fn type_name(&self, ty: &Type) -> String {
let mut str = String::new(); let mut str = String::new();
match ty { match ty.ty(self) {
Type::Struct(ty) => { Type::Struct(ty) => {
let base = ty.id; str += &self.structs[ty.id].name;
let args = &ty.args; let args = &ty.args;
str += self.names.name(base);
if let Some(arg) = args.first() { if let Some(arg) = args.first() {
str = str + "<" + &self.type_name(arg); str = str + "<" + &self.type_name(arg);
} }
@@ -221,9 +107,16 @@ impl UProgram {
str += &self.type_name(ret); str += &self.type_name(ret);
} }
Type::Ref(t) => { Type::Ref(t) => {
str = str + "&" + &self.type_name(t); str += &self.type_name(t);
str += "&";
}
Type::Deref(t) => {
str += &self.type_name(t);
str += "^";
}
Type::Unres(_) => {
str += "{unresolved}";
} }
Type::Generic { id } => str += self.names.name(*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 += "()",
@@ -231,50 +124,111 @@ impl UProgram {
Type::Error => str += "{error}", Type::Error => str += "{error}",
Type::Infer => str += "{inferred}", Type::Infer => str += "{inferred}",
Type::Placeholder => str += "{placeholder}", Type::Placeholder => str += "{placeholder}",
Type::Module(path) => str += &path.join("::"),
Type::Field(m) => {
str += &self
.follow_ref(m)
.map(|t| self.type_name(t))
.unwrap_or("{error}".to_string())
}
} }
str str
} }
pub fn path_var(&self, path: &NamePath, name: &str) -> Option<VarID> {
self.names.id(path, name)
} }
pub fn path_ty(&self, path: &NamePath, name: &str) -> Option<&Type> {
Some(&self.get(self.path_var(path, name)?)?.ty) impl<'a> UModuleBuilder<'a> {
} pub fn new(program: &'a mut UProgram, id: ModID, error: TypeID) -> Self {
fn name_on_stack<K: Kind>(&mut self, id: ID<K>, name: String) { Self {
let idx = self.name_stack.len() - 1; p: program,
let last = &mut self.name_stack[idx]; module: id,
if let Some(l) = last.get_mut(&name) { error,
l.insert(id.into()); name_stack: Vec::new(),
} else { temp: 0,
last.insert(name, Idents::new(id.into()));
} }
} }
pub fn iter_vars(&self) -> impl Iterator<Item = (VarID, &UVar)> { pub fn push(&mut self) {
self.vars self.name_stack.push(HashMap::new());
.iter()
.flatten()
.enumerate()
.map(|(i, x)| (ID::new(i), x))
} }
pub fn iter_fns(&self) -> impl Iterator<Item = (FnID, &UFunc)> { pub fn pop(&mut self) {
self.fns self.name_stack.pop();
.iter()
.flatten()
.enumerate()
.map(|(i, x)| (ID::new(i), x))
} }
pub fn cloned_fns(&self) -> impl Iterator<Item = (FnID, UFunc)> + use<'_> { pub fn get_idents(&self, name: &str) -> Option<Idents> {
self.fns for map in self.name_stack.iter().rev() {
.iter() let res = map.get(name);
.flatten() if res.is_some() {
.enumerate() return res.cloned();
.map(|(i, x)| (ID::new(i), x.clone())) }
}
None
}
pub fn def_var(&mut self, name: &str, v: UVar, origin: Origin) -> VarID {
let id = self.p.def_var(name, v, origin);
self.name_on_stack(id, name.to_string());
id
}
pub fn temp_var<T: Typable>(&mut self, origin: Origin, ty: T) -> VarInst {
self.temp_var_inner(origin, ty)
}
fn temp_var_inner<T: Typable>(&mut self, origin: Origin, ty: T) -> VarInst {
let t = self.temp;
let v = self
.p
.def_var(&format!("temp{}", t), UVar { ty: ty.ty(self) }, origin);
self.temp += 1;
VarInst { id: v, origin }
}
}
// I'm done with names...
pub trait Typer {
fn ty<'a>(&'a self, p: &'a UProgram) -> &'a Type;
}
impl Typer for &Type {
fn ty(&self, _: &UProgram) -> &Type {
self
}
}
impl Typer for TypeID {
fn ty<'a>(&'a self, p: &'a UProgram) -> &'a Type {
&p.types[self]
}
}
impl Typer for &TypeID {
fn ty<'a>(&'a self, p: &'a UProgram) -> &'a Type {
&p.types[*self]
}
}
impl Typer for &Box<Type> {
fn ty<'a>(&'a self, _: &'a UProgram) -> &'a Type {
&**self
}
}
pub trait Typable {
fn ty(self, p: &mut UProgram) -> TypeID;
}
impl Typable for Type {
fn ty(self, p: &mut UProgram) -> TypeID {
p.def_ty(self)
}
}
impl Typable for TypeID {
fn ty(self, p: &mut UProgram) -> TypeID {
self
}
}
impl Deref for UModuleBuilder<'_> {
type Target = UProgram;
fn deref(&self) -> &Self::Target {
self.p
}
}
impl DerefMut for UModuleBuilder<'_> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.p
} }
} }

343
src/ir/upper/resolve.rs Normal file
View File

@@ -0,0 +1,343 @@
use super::{Origin, StructTy, Type, TypeID, TypeIDed, UInstruction, UProgram, UStruct, UVar};
use crate::common::{CompilerMsg, CompilerOutput};
use std::{collections::HashMap, ops::BitOrAssign};
impl UProgram {
pub fn resolve(&mut self, output: &mut CompilerOutput) {
let mut unfinished = Vec::new();
let mut unfinished_new = Vec::new();
let data = &mut ResData {
changed: false,
types: &mut self.types,
vars: &self.vars,
structs: &self.structs,
errs: Vec::new(),
};
for f in &self.fns {
for i in f.flat_iter() {
if resolve_instr(data, &i.i).unfinished() {
unfinished.push(i);
}
}
}
while !unfinished.is_empty() && data.changed {
data.changed = false;
for &i in &unfinished {
if resolve_instr(data, &i.i).unfinished() {
unfinished_new.push(i);
}
}
std::mem::swap(&mut unfinished, &mut unfinished_new);
unfinished_new.clear();
}
for err in &data.errs {
match err {
&ResErr::Type {
dst,
src,
ref errs,
origin,
} => {
let mut msg = type_assign_err(self, dst, src);
for inner in errs {
if inner.dst != dst && inner.src != src {
msg.push_str("\n ");
msg.push_str(&type_assign_err(self, inner.dst, inner.src));
}
}
output.err(CompilerMsg::new(msg, origin));
}
&ResErr::NotCallable { origin, ty } => {
output.err(CompilerMsg::new(
format!("Cannot call type {}", self.type_name(ty)),
origin,
));
}
}
}
for var in &self.vars {
match &self.types[var.ty] {
Type::Error => output.err(CompilerMsg::new(
format!("Var {:?} is error type!", var.name),
var.origin,
)),
Type::Infer => output.err(CompilerMsg::new(
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,
)),
_ => (),
}
}
}
}
pub fn type_assign_err(p: &mut UProgram, dst: TypeID, src: TypeID) -> String {
format!(
"Cannot assign type {} to {}",
p.type_name(src),
p.type_name(dst)
)
}
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 {
data.errs.push(ResErr::NotCallable {
origin: f.origin,
ty: fty,
});
return InstrRes::Finished;
};
uf |= data.match_types(dst, ret, dst.origin);
for (src, dest) in args.iter().zip(fargs) {
uf |= data.match_types(dest, src, src.origin);
}
}
UInstruction::Mv { dst, src } => {
uf |= data.match_types(dst, src, src.origin);
}
UInstruction::Ref { dst, src } => {
let Type::Ref(dest_ty) = data.types[data.vars[dst.id].ty] else {
// TODO: this is probably a compiler error / should never happen
panic!("how could this happen to me (you)");
};
uf |= data.match_types(dest_ty, src, src.origin);
}
UInstruction::LoadData { dst, src } => {
// TODO
}
UInstruction::LoadSlice { dst, src } => {
// TODO
}
UInstruction::LoadFn { dst, src } => {
// TODO
}
UInstruction::AsmBlock { instructions, args } => {
// TODO
}
UInstruction::Ret { .. } => {}
UInstruction::Construct { dst, fields } => {
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 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(vars, types, &field.ty, src_ty) {
if let Type::Generic { id } = field.ty {
new.insert(id, ty.clone());
}
set(vars, src.id, ty);
}
}
let mut args: Vec<_> = struc
.generics
.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;
}
}
set(vars, dst.id, Type::Struct(StructTy { id, args }));
}
UInstruction::If { cond, body } => {
for i in body {
uf |= resolve_instr(data, &i.i);
}
}
UInstruction::Loop { body } => {}
UInstruction::Break => {}
UInstruction::Continue => {}
}
uf
}
pub fn match_types<T1: TypeIDed, T2: TypeIDed>(
data: &mut TypeResData,
dst: T1,
src: T2,
) -> MatchRes {
let dst = dst.type_id(data.vars);
let src = src.type_id(data.vars);
if dst == src {
return MatchRes::Finished;
}
let error = || MatchRes::Error(vec![TypeMismatch { dst, src }]);
match (&data.types[dst], &data.types[src]) {
(Type::Error, _) | (_, Type::Error) => MatchRes::Finished,
(Type::Placeholder, _) | (_, Type::Placeholder) => MatchRes::Unfinished,
(Type::Infer, Type::Infer) => MatchRes::Unfinished,
(Type::Infer, x) => {
*data.changed = true;
data.types[dst] = x.clone();
MatchRes::Finished
}
(x, Type::Infer) => {
*data.changed = true;
data.types[src] = x.clone();
MatchRes::Finished
}
(Type::Struct(dest), Type::Struct(src)) => {
if dest.id != src.id {
return error();
}
let mut finished = true;
let mut errors = Vec::new();
let dargs = dest.args.clone();
let sargs = dest.args.clone();
for (darg, sarg) in dargs.iter().zip(&sargs) {
match match_types(data, darg, sarg) {
MatchRes::Unfinished => finished = false,
MatchRes::Error(errs) => errors.extend(errs),
MatchRes::Finished => (),
}
}
if finished {
if errors.is_empty() {
MatchRes::Finished
} else {
MatchRes::Error(errors)
}
} else {
MatchRes::Unfinished
}
}
(
Type::Fn {
args: dest_args,
ret: dest_ret,
},
Type::Fn {
args: src_args,
ret: src_ret,
},
) => {
// TODO
MatchRes::Finished
}
(&Type::Ref(dest), &Type::Ref(src)) => match_types(data, dest, src),
(&Type::Slice(dest), &Type::Slice(src)) => match_types(data, dest, src),
(&Type::Array(dest, dlen), &Type::Array(src, slen)) => {
if dlen == slen {
match_types(data, dest, src)
} else {
error()
}
}
_ => error(),
}
}
struct ResData<'a> {
changed: bool,
types: &'a mut [Type],
vars: &'a [UVar],
structs: &'a [UStruct],
errs: Vec<ResErr>,
}
struct TypeResData<'a> {
changed: &'a mut bool,
types: &'a mut [Type],
vars: &'a [UVar],
structs: &'a [UStruct],
}
enum ResErr {
NotCallable {
origin: Origin,
ty: TypeID,
},
Type {
dst: TypeID,
src: TypeID,
errs: Vec<TypeMismatch>,
origin: Origin,
},
}
impl<'a> ResData<'a> {
pub fn match_types<T1: TypeIDed, T2: TypeIDed>(
&'a mut self,
dst: T1,
src: T2,
origin: Origin,
) -> InstrRes {
let dst = dst.type_id(self.vars);
let src = src.type_id(self.vars);
let res = match_types(
&mut TypeResData {
changed: &mut self.changed,
types: self.types,
vars: self.vars,
structs: self.structs,
},
dst,
src,
);
match res {
MatchRes::Unfinished => InstrRes::Unfinished,
MatchRes::Finished => InstrRes::Finished,
MatchRes::Error(es) => {
self.errs.push(ResErr::Type {
errs: es,
origin,
dst,
src,
});
InstrRes::Finished
}
}
}
}
pub struct TypeMismatch {
dst: TypeID,
src: TypeID,
}
pub enum MatchRes {
Unfinished,
Finished,
Error(Vec<TypeMismatch>),
}
pub enum InstrRes {
Finished,
Unfinished,
}
impl BitOrAssign for InstrRes {
fn bitor_assign(&mut self, rhs: Self) {
match rhs {
InstrRes::Finished => (),
InstrRes::Unfinished => *self = InstrRes::Unfinished,
}
}
}
impl InstrRes {
pub fn unfinished(&self) -> bool {
match self {
Self::Finished => false,
Self::Unfinished => true,
}
}
}

View File

@@ -1,6 +1,4 @@
use std::collections::HashMap; use super::{FnID, GenericID, Len, ModPath, StructID, TypeID, UVar, VarID, VarInst};
use super::{assoc::NamePath, Len, StructID, TypeID, UInstruction, UProgram, VarID};
#[derive(Debug, Clone, Hash, Eq, PartialEq)] #[derive(Debug, Clone, Hash, Eq, PartialEq)]
pub struct FieldRef { pub struct FieldRef {
@@ -8,211 +6,84 @@ pub struct FieldRef {
pub name: String, pub name: String,
} }
#[derive(Clone, Eq, PartialEq)] #[derive(Clone, Eq, PartialEq, Hash)]
pub struct StructTy { pub struct StructTy {
pub id: StructID, pub id: StructID,
pub fields: HashMap<String, VarID>, pub args: Vec<TypeID>,
} }
#[derive(Clone, PartialEq, Eq)] #[derive(Clone)]
pub enum Type { pub enum Type {
Bits(u32), Bits(u32),
Struct(StructTy), Struct(StructTy),
Fn { args: Vec<TypeID>, ret: TypeID }, Fn(FnID),
Ref(TypeID), Ref(TypeID),
Deref(TypeID),
Slice(TypeID), Slice(TypeID),
Array(TypeID, Len), Array(TypeID, Len),
Unit, Unit,
// fake types // "fake" types
Field(FieldRef), Unres(ModPath),
Module(NamePath), Generic(GenericID),
Infer, Infer,
Error, Error,
Placeholder, Placeholder,
} }
impl TypeID {
pub fn rf(self) -> Type {
Type::Ref(self)
}
pub fn derf(self) -> Type {
Type::Deref(self)
}
pub fn arr(self, len: Len) -> Type {
Type::Array(self, len)
}
pub fn slice(self) -> Type {
Type::Slice(self)
}
}
impl Type { impl Type {
pub fn is_resolved(&self) -> bool { pub fn is_resolved(&self) -> bool {
!matches!(self, Self::Error | Self::Placeholder | Self::Infer) !matches!(self, Self::Error | Self::Placeholder | Self::Infer)
} }
} pub fn bx(self) -> Box<Self> {
Box::new(self)
impl UProgram {
pub fn resolve_types(&mut self) {
// PARTIAL BORROWING :SOB:
let fns: Vec<_> = self.cloned_fns().collect();
for (i, f) in &fns {
let vi = self.fn_var.var(*i);
self.expect_mut(vi).ty = f.ty(self);
}
for (i, f) in &fns {
let mut redo_iter = Vec::new();
let mut redo_new = Vec::new();
for i in f.flat_iter() {
if self.resolve_instr_types(&i.i).is_none() {
redo_iter.push(i);
}
}
while !redo_iter.is_empty() {
for &i in &redo_iter {
if self.resolve_instr_types(&i.i).is_none() {
redo_new.push(i);
}
}
std::mem::swap(&mut redo_iter, &mut redo_new);
redo_new.clear();
}
} }
} }
pub fn resolve_instr_types(&mut self, i: &UInstruction) -> Option<()> { pub trait TypeIDed {
'outer: { fn type_id(&self, vars: &[UVar]) -> TypeID;
match &i {
UInstruction::Call { dest, f, args } => {
let fun = self.get_fn_var(f.id).expect("bruh");
self.expect_mut(dest.id).ty = fun.ret.clone();
for (src, &dest) in args.iter().zip(&fun.args) {
let dest_ty = self.get_type(dest)?;
let src_ty = self.get_type(src.id)?;
if let Some(ty) = self.match_types(dest_ty, src_ty) {
self.expect_mut(dest).ty = ty.clone();
set(vars, dest, ty.clone());
set(vars, src.id, ty);
}
}
}
UInstruction::Mv { dest, src } => {
let dest_ty = get(vars, dest.id)?;
let src_ty = get(vars, src.id)?;
if let Some(ty) = self.match_types(dest_ty, src_ty) {
set(vars, dest.id, ty.clone());
set(vars, src.id, ty);
}
}
UInstruction::Ref { dest, src } => {
let dest_ty = get(vars, dest.id)?;
let src_ty = get(vars, src.id)?;
let Type::Ref(dest_ty) = dest_ty else {
break 'outer;
};
if let Some(ty) = self.match_types(dest_ty, src_ty) {
set(vars, dest.id, ty.clone().rf());
set(vars, src.id, ty);
}
}
UInstruction::LoadData { dest, src } => {
// TODO
}
UInstruction::LoadSlice { dest, src } => {
// TODO
}
UInstruction::LoadFn { dest, src } => {
// TODO
}
UInstruction::AsmBlock { instructions, args } => {
// TODO
}
UInstruction::Ret { .. } => {}
UInstruction::Construct { dest, fields } => {
let dest_ty = get(vars, dest.id)?;
let Type::Struct(sty) = dest_ty else {
break 'outer;
};
let id = sty.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) = self.match_types(&field.ty, src_ty) {
if let Type::Generic { id } = field.ty {
new.insert(id, ty.clone());
}
set(vars, src.id, ty);
}
}
let mut args: Vec<_> = struc
.generics
.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;
}
}
set(vars, dest.id, Type::Struct(StructTy { id, args }));
}
UInstruction::If { cond, body: _ } => {}
UInstruction::Loop { body: _ } => {}
UInstruction::Break => {}
UInstruction::Continue => {}
}
}
Some(())
} }
pub fn match_types<'a>(&'a self, mut dest: &'a Type, mut src: &'a Type) -> Option<Type> { impl TypeIDed for TypeID {
dest = self.follow_type(dest)?; fn type_id(&self, _: &[UVar]) -> TypeID {
src = self.follow_type(src)?; *self
if dest == src {
return None;
}
match (dest, src) {
(Type::Error, _) | (_, Type::Error) => None,
(Type::Placeholder, _) | (_, Type::Placeholder) => None,
(Type::Infer, Type::Infer) => None,
(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(dest), Type::Struct(src)) => {
if dest.id != src.id {
return None;
}
let mut args = Vec::new();
let mut changed = false;
for (darg, sarg) in dest.args.iter().zip(&src.args) {
if let Some(ty) = self.match_types(darg, sarg) {
args.push(ty);
changed = true;
} else if darg != sarg {
return None;
} else {
args.push(darg.clone());
} }
} }
if changed {
Some(Type::Struct(StructTy { id: dest.id, args })) impl TypeIDed for &TypeID {
} else { fn type_id(&self, _: &[UVar]) -> TypeID {
None **self
} }
} }
(
Type::Fn { impl TypeIDed for VarID {
args: dest_args, fn type_id(&self, vars: &[UVar]) -> TypeID {
ret: dest_ret, vars[self].ty
},
Type::Fn {
args: src_args,
ret: src_ret,
},
) => {
// TODO
None
}
(Type::Ref(dest), Type::Ref(src)) => Some(self.match_types(dest, src)?.rf()),
(Type::Slice(dest), Type::Slice(src)) => Some(self.match_types(dest, src)?.slice()),
(Type::Array(dest, dlen), Type::Array(src, slen)) => {
if dlen != slen {
return None;
}
Some(self.match_types(dest, src)?.arr(*dlen))
}
_ => None,
} }
} }
impl TypeIDed for VarInst {
fn type_id(&self, vars: &[UVar]) -> TypeID {
self.id.type_id(vars)
}
}
impl TypeIDed for &VarInst {
fn type_id(&self, vars: &[UVar]) -> TypeID {
self.id.type_id(vars)
}
} }

View File

@@ -13,26 +13,6 @@ impl UProgram {
false, false,
); );
} }
for (id, var) in self.iter_vars() {
if var.ty == Type::Error {
output.err(CompilerMsg {
msg: format!("Var {:?} is error type!", id),
spans: vec![self.origins.get(id)],
});
}
if var.ty == Type::Infer {
output.err(CompilerMsg {
msg: format!("Var {:?} cannot be inferred!", id),
spans: vec![self.origins.get(id)],
});
}
if var.ty == Type::Placeholder {
output.err(CompilerMsg {
msg: format!("Var {:?} still placeholder!", id),
spans: vec![self.origins.get(id)],
});
}
}
} }
pub fn validate_fn( pub fn validate_fn(
@@ -47,50 +27,50 @@ impl UProgram {
let mut no_ret = true; let mut no_ret = true;
for i in instructions { for i in instructions {
match &i.i { match &i.i {
UInstruction::Mv { dest, src } => { UInstruction::Mv { dst: dest, src } => {
let dest = self.expect(dest.id); let dest = self.expect(dest.id);
let src = self.expect(src.id); let src = self.expect(src.id);
output.check_assign(self, &src.ty, &dest.ty, i.span); output.check_assign(self, &src.ty, &dest.ty, i.origin);
} }
UInstruction::Ref { dest, src } => { UInstruction::Ref { dst: dest, src } => {
let dest = self.expect(dest.id); let dest = self.expect(dest.id);
let src = self.expect(src.id); let src = self.expect(src.id);
output.check_assign(self, &src.ty.clone().rf(), &dest.ty, i.span); output.check_assign(self, &src.ty.clone().rf(), &dest.ty, i.origin);
} }
UInstruction::LoadData { dest, src } => { UInstruction::LoadData { dst: dest, src } => {
let dest = self.expect(dest.id); let dest = self.expect(dest.id);
let src = self.expect(*src); let src = self.expect(*src);
output.check_assign(self, &src.ty, &dest.ty, i.span); output.check_assign(self, &src.ty, &dest.ty, i.origin);
} }
UInstruction::LoadSlice { dest, src } => { UInstruction::LoadSlice { dst: dest, src } => {
let dest = self.expect(dest.id); let dest = self.expect(dest.id);
let src = self.expect(*src); let src = self.expect(*src);
let Type::Array(srcty, ..) = &src.ty else { let Type::Array(srcty, ..) = &src.ty else {
todo!() todo!()
}; };
output.check_assign(self, &Type::Slice(srcty.clone()), &dest.ty, i.span); output.check_assign(self, &Type::Slice(srcty.clone()), &dest.ty, i.origin);
} }
UInstruction::LoadFn { dest, src } => todo!(), UInstruction::LoadFn { dst: dest, src } => todo!(),
UInstruction::Call { dest, f, args } => { UInstruction::Call { dst: dest, f, args } => {
let destty = &self.expect(dest.id).ty; let destty = &self.expect(dest.id).ty;
let f = self.expect(f.id); let f = self.expect(f.id);
let Type::Fn { args: argtys, ret } = &f.ty else { let Type::Fn { args: argtys, ret } = &f.ty else {
output.err(CompilerMsg { output.err(CompilerMsg {
msg: format!("Type {} is not callable", self.type_name(&f.ty)), msg: format!("Type {} is not callable", self.type_name(&f.ty)),
spans: vec![dest.span], spans: vec![dest.origin],
}); });
continue; continue;
}; };
output.check_assign(self, ret, destty, dest.span); output.check_assign(self, ret, destty, dest.origin);
if args.len() != argtys.len() { if args.len() != argtys.len() {
output.err(CompilerMsg { output.err(CompilerMsg {
msg: "Wrong number of arguments to function".to_string(), msg: "Wrong number of arguments to function".to_string(),
spans: vec![dest.span], spans: vec![dest.origin],
}); });
} }
for (dst_ty, src) in argtys.iter().zip(args) { for (dst_ty, src) in argtys.iter().zip(args) {
let src_var = self.expect(src.id); let src_var = self.expect(src.id);
output.check_assign(self, &src_var.ty, dst_ty, src.span); output.check_assign(self, &src_var.ty, dst_ty, src.origin);
} }
} }
UInstruction::AsmBlock { instructions, args } => { UInstruction::AsmBlock { instructions, args } => {
@@ -109,10 +89,10 @@ impl UProgram {
} }
UInstruction::Ret { src } => { UInstruction::Ret { src } => {
let srcty = &self.expect(src.id).ty; let srcty = &self.expect(src.id).ty;
output.check_assign(self, srcty, ret, src.span); output.check_assign(self, srcty, ret, src.origin);
no_ret = false; no_ret = false;
} }
UInstruction::Construct { dest, fields } => { UInstruction::Construct { dst: dest, fields } => {
let dest_def = self.expect(dest.id); let dest_def = self.expect(dest.id);
let sty = match &dest_def.ty { let sty = match &dest_def.ty {
Type::Struct(sty) => sty, Type::Struct(sty) => sty,
@@ -122,7 +102,7 @@ impl UProgram {
"Type {} cannot be constructed", "Type {} cannot be constructed",
self.type_name(&dest_def.ty) self.type_name(&dest_def.ty)
), ),
spans: vec![dest.span], spans: vec![dest.origin],
}); });
continue; continue;
} }
@@ -139,18 +119,18 @@ impl UProgram {
} }
} }
let ety = &self.expect(var.id).ty; let ety = &self.expect(var.id).ty;
output.check_assign(self, ety, fty, var.span); output.check_assign(self, ety, fty, var.origin);
} else { } else {
output.err(CompilerMsg { output.err(CompilerMsg {
msg: format!("field '{}' missing from struct", name), msg: format!("field '{}' missing from struct", name),
spans: vec![dest.span], spans: vec![dest.origin],
}); });
} }
} }
} }
UInstruction::If { cond, body } => { UInstruction::If { cond, body } => {
let cond = self.expect(cond.id); let cond = self.expect(cond.id);
output.check_assign(self, &cond.ty, &Type::Bits(64), i.span); output.check_assign(self, &cond.ty, &Type::Bits(64), i.origin);
self.validate_fn(body, origin, ret, output, false, breakable); self.validate_fn(body, origin, ret, output, false, breakable);
} }
UInstruction::Loop { body } => { UInstruction::Loop { body } => {
@@ -160,7 +140,7 @@ impl UProgram {
if !breakable { if !breakable {
output.err(CompilerMsg { output.err(CompilerMsg {
msg: "Can't break here (outside of loop)".to_string(), msg: "Can't break here (outside of loop)".to_string(),
spans: vec![i.span], spans: vec![i.origin],
}); });
} }
// TODO // TODO
@@ -169,7 +149,7 @@ impl UProgram {
if !breakable { if !breakable {
output.err(CompilerMsg { output.err(CompilerMsg {
msg: "Can't continue here (outside of loop)".to_string(), msg: "Can't continue here (outside of loop)".to_string(),
spans: vec![i.span], spans: vec![i.origin],
}); });
} }
// TODO // TODO

View File

@@ -9,12 +9,11 @@ pub const FILE_EXT: &str = "lang";
use common::{CompilerOutput, SrcFile}; use common::{CompilerOutput, SrcFile};
use ir::{LProgram, UProgram}; use ir::{LProgram, UProgram};
use parser::{Import, Imports, PModule, ParseResult, ParserCtx}; use parser::{Import, Imports, PModule, ParserCtx};
use std::{ use std::{
collections::{HashMap, HashSet}, collections::HashSet,
ffi::OsString,
fs::{create_dir_all, OpenOptions}, fs::{create_dir_all, OpenOptions},
io::{stdout, BufRead, BufReader}, io::stdout,
os::unix::fs::OpenOptionsExt, os::unix::fs::OpenOptionsExt,
path::{Path, PathBuf}, path::{Path, PathBuf},
process::Command, process::Command,
@@ -88,8 +87,7 @@ impl UProgram {
fn run_file(path: &Path, gdb: bool, asm: bool) { fn run_file(path: &Path, gdb: bool, asm: bool) {
let (mut program, mut output) = UProgram::from_path(path); let (mut program, mut output) = UProgram::from_path(path);
program.resolve_types(); program.resolve(&mut output);
program.validate(&mut output);
// println!("vars:"); // println!("vars:");
// for (id, def) in program.iter_vars() { // for (id, def) in program.iter_vars() {
// println!(" {id:?} = {}: {}", program.names.path(id), program.type_name(&def.ty)); // println!(" {id:?} = {}: {}", program.names.path(id), program.type_name(&def.ty));

View File

@@ -3,8 +3,7 @@ use std::ops::{Deref, DerefMut};
use crate::common::FileID; use crate::common::FileID;
use super::{ use super::{
CompilerMsg, CompilerOutput, MaybeParsable, Node, NodeParseResult, Parsable, ParsableWith, CompilerMsg, CompilerOutput, Node, NodeParseResult, Parsable, ParsableWith, TokenCursor,
ParseResult, TokenCursor,
}; };
pub struct ParserCtx<'a> { pub struct ParserCtx<'a> {
@@ -36,12 +35,15 @@ impl<'a> ParserCtx<'a> {
pub fn parse<T: Parsable>(&mut self) -> NodeParseResult<T> { pub fn parse<T: Parsable>(&mut self) -> NodeParseResult<T> {
Node::parse(self) Node::parse(self)
} }
pub fn maybe_parse<T>(&mut self) -> Option<NodeParseResult<T>>
where
Option<T>: Parsable,
{
Node::maybe_parse(self)
}
pub fn parse_with<T: ParsableWith>(&mut self, data: T::Data) -> NodeParseResult<T> { pub fn parse_with<T: ParsableWith>(&mut self, data: T::Data) -> NodeParseResult<T> {
Node::parse_with(self, data) Node::parse_with(self, data)
} }
pub fn maybe_parse<T: MaybeParsable>(&mut self) -> Option<Node<T>> {
Node::maybe_parse(self)
}
pub fn new(file: FileID, string: &'a str, output: &'a mut CompilerOutput) -> Self { pub fn new(file: FileID, string: &'a str, output: &'a mut CompilerOutput) -> Self {
Self { Self {
cursor: TokenCursor::from_file_str(file, string), cursor: TokenCursor::from_file_str(file, string),

View File

@@ -27,15 +27,15 @@ impl FnLowerable for PBlock {
}, },
} }
} }
ctx.program.push(); ctx.b.push();
// then lower imports // then lower imports
for i_n in &import_nodes { for i_n in &import_nodes {
if let Some(i) = i_n.as_ref() { if let Some(i) = i_n.as_ref() {
let name = &i.0; let name = &i.0;
let path = ctx.program.path_for(name); let path = ctx.b.path_for(name);
let import = Import(path.clone()); let import = Import(path.clone());
if ctx.imports.insert(import) { if ctx.imports.insert(import) {
ctx.program.def_searchable::<UVar>( ctx.b.def_searchable::<UVar>(
name, name,
Some(UVar { Some(UVar {
ty: Type::Module(path), ty: Type::Module(path),
@@ -48,27 +48,27 @@ impl FnLowerable for PBlock {
// then lower const things // then lower const things
let mut structs = Vec::new(); let mut structs = Vec::new();
for s in &struct_nodes { for s in &struct_nodes {
structs.push(s.lower_name(ctx.program)); structs.push(s.lower_name(ctx.b));
} }
for (s, id) in struct_nodes.iter().zip(structs) { for (s, id) in struct_nodes.iter().zip(structs) {
if let Some(id) = id { if let Some(id) = id {
s.lower(id, ctx.program, ctx.output); s.lower(id, ctx.b, ctx.output);
} }
} }
let mut fns = Vec::new(); let mut fns = Vec::new();
for f in &fn_nodes { for f in &fn_nodes {
fns.push(f.lower_name(ctx.program)); fns.push(f.lower_name(ctx.b));
} }
for (f, id) in fn_nodes.iter().zip(fns) { for (f, id) in fn_nodes.iter().zip(fns) {
if let Some(id) = id { if let Some(id) = id {
f.lower(id, ctx.program, ctx.imports, ctx.output) f.lower(id, ctx.b, ctx.imports, ctx.output)
} }
} }
// then lower statements // then lower statements
for s in statements { for s in statements {
last = s.lower(ctx); last = s.lower(ctx);
} }
ctx.program.pop(); ctx.b.pop();
last last
} }
} }
@@ -78,11 +78,11 @@ impl FnLowerable for PStatement {
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<VarInst> { fn lower(&self, ctx: &mut FnLowerCtx) -> Option<VarInst> {
match self { match self {
PStatement::Let(def, e) => { PStatement::Let(def, e) => {
let def = def.lower(ctx.program, ctx.output)?; let def = def.lower(ctx.b, ctx.output)?;
let res = e.lower(ctx); let res = e.lower(ctx);
if let Some(res) = res { if let Some(res) = res {
ctx.push(UInstruction::Mv { ctx.push(UInstruction::Mv {
dest: def, dst: def,
src: res, src: res,
}); });
} }
@@ -91,10 +91,10 @@ impl FnLowerable for PStatement {
PStatement::Return(e) => { PStatement::Return(e) => {
if let Some(e) = e { if let Some(e) = e {
let src = e.lower(ctx)?; let src = e.lower(ctx)?;
ctx.push_at(UInstruction::Ret { src }, src.span); ctx.push_at(UInstruction::Ret { src }, src.origin);
} else { } else {
let src = ctx.temp(Type::Unit); let src = ctx.temp(Type::Unit);
ctx.push_at(UInstruction::Ret { src }, src.span); ctx.push_at(UInstruction::Ret { src }, src.origin);
} }
None None
} }

View File

@@ -1,21 +1,18 @@
use crate::ir::{Type, UProgram, UVar, VarInst}; use crate::ir::{UProgram, UVar, VarInst};
use super::{CompilerOutput, Node, 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> {
let s = self.as_ref()?; let s = self.as_ref()?;
let name = s let name = s.name.as_ref().map_or("{error}", |v| v);
.name
.as_ref()
.map_or("{error}", |v| v);
let ty = match &s.ty { let ty = match &s.ty {
Some(ty) => ty.lower(program, output), Some(ty) => ty.lower(program, output),
None => Type::Infer, None => program.infer(self.origin),
}; };
Some(VarInst { Some(VarInst {
id: program.def_searchable(name, Some(UVar { ty }), self.origin), id: program.def_searchable(name, Some(UVar { ty }), self.origin),
span: self.origin, origin: self.origin,
}) })
} }
} }

View File

@@ -1,60 +1,61 @@
use super::{func::FnLowerCtx, FnLowerable, PExpr, PostfixOp}; use super::{func::FnLowerCtx, FnLowerable, PExpr, PostfixOp};
use crate::{ use crate::{
ir::{FieldRef, Type, UData, UInstruction, VarInst}, ir::{Type, UData, UInstruction, VarInst},
parser::InfixOp, parser::InfixOp,
}; };
impl FnLowerable for PExpr { impl FnLowerable for PExpr {
type Output = VarInst; type Output = VarInst;
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<VarInst> { fn lower(&self, ctx: &mut FnLowerCtx) -> Option<VarInst> {
Some(match self { let mut e = self;
PExpr::Lit(l) => match l.as_ref()? { let mut path = Vec::new();
while let PExpr::Member(node, ident) = e {
e = if let Some(t) = node.as_ref() {
path.push(ident);
&**t
} else {
return None;
};
}
Some(match e {
PExpr::Lit(l) => match l {
super::PLiteral::String(s) => { super::PLiteral::String(s) => {
let dest = ctx.program.temp_var(l.origin, Type::Bits(8).slice()); let dest = ctx.b.temp_var(ctx.origin, Type::Bits(8).slice());
let data = s.as_bytes().to_vec(); let data = s.as_bytes().to_vec();
let src = ctx.program.def( let src = ctx.b.def_data(UData {
&format!("string \"{}\"", s.replace("\n", "\\n")), name: format!("string \"{}\"", s.replace("\n", "\\n")),
Some(UData {
ty: Type::Bits(8).arr(data.len() as u32), ty: Type::Bits(8).arr(data.len() as u32),
content: data, content: data,
}), });
l.origin, ctx.push(UInstruction::LoadSlice { dst: dest, src });
);
ctx.push(UInstruction::LoadSlice { dest, src });
dest dest
} }
super::PLiteral::Char(c) => { super::PLiteral::Char(c) => {
let ty = Type::Bits(8); let ty = Type::Bits(8);
let dest = ctx.program.temp_var(l.origin, ty.clone()); let dest = ctx.b.temp_var(ctx.origin, ty.clone());
let src = ctx.program.def( let src = ctx.b.def_data(UData {
&format!("char '{c}'"), name: format!("char '{c}'"),
Some(UData {
ty, ty,
content: c.to_string().as_bytes().to_vec(), content: c.to_string().as_bytes().to_vec(),
}), });
l.origin, ctx.push(UInstruction::LoadData { dst: dest, src });
);
ctx.push(UInstruction::LoadData { dest, src });
dest dest
} }
super::PLiteral::Number(n) => { super::PLiteral::Number(n) => {
// TODO: temp // TODO: temp
let ty = Type::Bits(64); let ty = Type::Bits(64);
let dest = ctx.program.temp_var(l.origin, ty.clone()); let dest = ctx.b.temp_var(ctx.origin, ty.clone());
let src = ctx.program.def( let src = ctx.b.def_data(UData {
&format!("num {n:?}"), name: format!("num {n:?}"),
Some(UData {
ty, ty,
content: n.whole.parse::<i64>().unwrap().to_le_bytes().to_vec(), content: n.whole.parse::<i64>().unwrap().to_le_bytes().to_vec(),
}), });
l.origin, ctx.push(UInstruction::LoadData { dst: dest, src });
);
ctx.push(UInstruction::LoadData { dest, src });
dest dest
} }
super::PLiteral::Unit => ctx.program.temp_var(l.origin, Type::Unit), super::PLiteral::Unit => ctx.b.temp_var(ctx.origin, Type::Unit),
}, },
PExpr::Ident(i) => ctx.get_var(i)?, PExpr::Ident(i) => ctx.get_var(i),
PExpr::BinaryOp(op, e1, e2) => match op { PExpr::BinaryOp(op, e1, e2) => match op {
InfixOp::Add => todo!(), InfixOp::Add => todo!(),
InfixOp::Sub => todo!(), InfixOp::Sub => todo!(),
@@ -62,49 +63,30 @@ impl FnLowerable for PExpr {
InfixOp::Div => todo!(), InfixOp::Div => todo!(),
InfixOp::LessThan => todo!(), InfixOp::LessThan => todo!(),
InfixOp::GreaterThan => todo!(), InfixOp::GreaterThan => todo!(),
InfixOp::Member => {
let res1 = e1.lower(ctx)?;
let Some(box PExpr::Ident(ident)) = &e2.inner else {
ctx.err("Field accessors must be identifiers".to_string());
return None;
};
let fname = ident.as_ref()?.0.clone();
ctx.temp(Type::Field(FieldRef {
parent: res1.id,
name: fname,
}))
}
InfixOp::Assign => { InfixOp::Assign => {
let res1 = e1.lower(ctx)?; let res1 = e1.lower(ctx)?;
let res2 = e2.lower(ctx)?; let res2 = e2.lower(ctx)?;
ctx.push(UInstruction::Mv { ctx.push(UInstruction::Mv {
dest: res1, dst: res1,
src: res2, src: res2,
}); });
res1 res1
} }
}, },
PExpr::PostfixOp(op, e) => { PExpr::PostfixOp(e, op) => {
let res = e.lower(ctx)?; let res = e.lower(ctx)?;
match op { match op {
PostfixOp::Ref => { PostfixOp::Ref => {
let temp = ctx.temp(ctx.program.expect(res.id).ty.clone().rf()); let ty = ctx.b.vars[res.id].ty.rf();
ctx.push(UInstruction::Ref { let dest = ctx.temp(ty);
dest: temp, ctx.push(UInstruction::Ref { dst: dest, src: res });
src: res, dest
});
temp
} }
PostfixOp::Deref => { PostfixOp::Deref => {
let t = &ctx.program.expect(res.id).ty; let ty = ctx.b.vars[res.id].ty.derf();
let Type::Ref(_) = t else { let dest = ctx.temp(ty);
ctx.err(format!( ctx.push(UInstruction::Deref { dst: dest, src: res });
"Cannot dereference type {:?}", dest
ctx.program.type_name(t)
));
return None;
};
todo!();
} }
PostfixOp::Not => todo!(), PostfixOp::Not => todo!(),
} }
@@ -118,37 +100,36 @@ impl FnLowerable for PExpr {
let arg = arg.lower(ctx)?; let arg = arg.lower(ctx)?;
nargs.push(arg); nargs.push(arg);
} }
let ty = ctx let dest = ctx.temp(Type::Placeholder);
.program
.get_fn_var(fe.id)
.map(|f| f.ret.clone())
.unwrap_or(Type::Placeholder);
let temp = ctx.temp(ty);
ctx.push(UInstruction::Call { ctx.push(UInstruction::Call {
dest: temp, dst: dest,
f: fe, f: fe,
args: nargs, args: nargs,
}); });
temp dest
} }
PExpr::Group(e) => e.lower(ctx)?, PExpr::Group(e) => e.lower(ctx)?,
PExpr::Construct(c) => c.lower(ctx)?, PExpr::Construct(e, map) => {
let dest = ctx.temp(Type::Placeholder);
ctx.push(UInstruction::Construct { dst: dest, fields: () });
dest
}
PExpr::If(cond, body) => { PExpr::If(cond, body) => {
let cond = cond.lower(ctx)?; let cond = cond.lower(ctx)?;
ctx.program.push(); ctx.b.push();
let mut body_ctx = ctx.branch(); let mut body_ctx = ctx.branch();
body.lower(&mut body_ctx); body.lower(&mut body_ctx);
let body = body_ctx.instructions; let body = body_ctx.instructions;
ctx.program.pop(); ctx.b.pop();
ctx.push(UInstruction::If { cond, body }); ctx.push(UInstruction::If { cond, body });
return None; return None;
} }
PExpr::Loop(body) => { PExpr::Loop(body) => {
ctx.program.push(); ctx.b.push();
let mut body_ctx = ctx.branch(); let mut body_ctx = ctx.branch();
body.lower(&mut body_ctx); body.lower(&mut body_ctx);
let body = body_ctx.instructions; let body = body_ctx.instructions;
ctx.program.pop(); ctx.b.pop();
ctx.push(UInstruction::Loop { body }); ctx.push(UInstruction::Loop { body });
return None; return None;
} }
@@ -160,6 +141,13 @@ impl FnLowerable for PExpr {
ctx.push(UInstruction::Continue); ctx.push(UInstruction::Continue);
return None; return None;
} }
PExpr::Member(e, name) => {
ctx.err("Can't access a member here".to_string());
return None;
}
PExpr::Field(e, name) => {
todo!()
}
}) })
} }
} }

View File

@@ -1,6 +1,11 @@
use std::collections::HashMap;
use super::{CompilerMsg, CompilerOutput, FileSpan, FnLowerable, Imports, Node, PFunction}; use super::{CompilerMsg, CompilerOutput, FileSpan, FnLowerable, Imports, Node, PFunction};
use crate::{ use crate::{
ir::{FnID, Idents, Type, UFunc, UInstrInst, UInstruction, UProgram, UVar, VarInst}, ir::{
FnID, Idents, Typable, Type, UFunc, UInstrInst, UInstruction, UModuleBuilder, UProgram,
UVar, VarID, VarInst,
},
parser, parser,
}; };
@@ -54,7 +59,7 @@ impl PFunction {
}; };
let mut ctx = FnLowerCtx { let mut ctx = FnLowerCtx {
instructions: Vec::new(), instructions: Vec::new(),
program: p, b: p,
output, output,
origin: self.body.origin, origin: self.body.origin,
imports, imports,
@@ -62,7 +67,7 @@ impl PFunction {
if let Some(src) = self.body.lower(&mut ctx) { if let Some(src) = self.body.lower(&mut ctx) {
ctx.instructions.push(UInstrInst { ctx.instructions.push(UInstrInst {
i: UInstruction::Ret { src }, i: UInstruction::Ret { src },
span: src.span, origin: src.origin,
}); });
} }
let instructions = ctx.instructions; let instructions = ctx.instructions;
@@ -77,23 +82,24 @@ impl PFunction {
} }
pub struct FnLowerCtx<'a> { pub struct FnLowerCtx<'a> {
pub program: &'a mut UProgram, pub b: &'a mut UModuleBuilder<'a>,
pub instructions: Vec<UInstrInst>, pub instructions: Vec<UInstrInst>,
pub output: &'a mut CompilerOutput, pub output: &'a mut CompilerOutput,
pub origin: FileSpan, pub origin: FileSpan,
pub imports: &'a mut Imports, pub imports: &'a mut Imports,
pub var_stack: Vec<HashMap<String, VarID>>,
} }
impl FnLowerCtx<'_> { impl FnLowerCtx<'_> {
pub fn get_idents(&mut self, node: &Node<parser::PIdent>) -> Option<Idents> { pub fn get_idents(&mut self, node: &Node<parser::PIdent>) -> Option<Idents> {
let name = node.inner.as_ref()?; let name = node.inner.as_ref()?;
let res = self.program.get_idents(name); let res = self.b.get_idents(name);
if res.is_none() { if res.is_none() {
self.err_at(node.origin, format!("Identifier '{}' not found", name)); self.err_at(node.origin, format!("Identifier '{}' not found", name));
} }
res res
} }
pub fn get_var(&mut self, node: &Node<parser::PIdent>) -> Option<VarInst> { pub fn get_var(&mut self, node: &Node<parser::PIdent>) -> VarInst {
let ids = self.get_idents(node)?; let ids = self.get_idents(node)?;
if ids.get::<UVar>().is_none() { if ids.get::<UVar>().is_none() {
self.err_at( self.err_at(
@@ -103,27 +109,42 @@ impl FnLowerCtx<'_> {
} }
ids.get::<UVar>().map(|id| VarInst { ids.get::<UVar>().map(|id| VarInst {
id, id,
span: node.origin, origin: node.origin,
}) })
} }
pub fn err(&mut self, msg: String) { pub fn err(&mut self, msg: String) {
self.output.err(CompilerMsg::from_span(self.origin, msg)) self.output.err(CompilerMsg::new(self.origin, msg))
} }
pub fn err_at(&mut self, span: FileSpan, msg: String) { pub fn err_at(&mut self, span: FileSpan, msg: String) {
self.output.err(CompilerMsg::from_span(span, msg)) self.output.err(CompilerMsg::new(span, msg))
} }
pub fn temp(&mut self, ty: impl Into<Type>) -> VarInst { pub fn temp<T: Typable>(&mut self, ty: Type) -> VarInst {
self.program.temp_var(self.origin, ty) self.b.temp_var(self.origin, ty)
} }
pub fn push(&mut self, i: UInstruction) { pub fn push(&mut self, i: UInstruction) {
self.push_at(i, self.origin); self.push_at(i, self.origin);
} }
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 }); 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>(&'a mut self) -> FnLowerCtx<'a> {
FnLowerCtx { FnLowerCtx {
program: self.program, b: self.b,
instructions: Vec::new(), instructions: Vec::new(),
output: self.output, output: self.output,
origin: self.origin, origin: self.origin,

View File

@@ -23,7 +23,7 @@ impl PModule {
let fid = p.def_searchable(&name, None, self.block.origin); let fid = p.def_searchable(&name, None, self.block.origin);
p.push_name(&name); p.push_name(&name);
let mut fctx = FnLowerCtx { let mut fctx = FnLowerCtx {
program: p, b: p,
instructions: Vec::new(), instructions: Vec::new(),
output, output,
origin: self.block.origin, origin: self.block.origin,

View File

@@ -1,7 +1,7 @@
use crate::{ use crate::{
common::{CompilerOutput, FileSpan}, common::{CompilerOutput, FileSpan},
ir::{StructField, StructID, UInstruction, UProgram, UStruct, VarInst}, ir::{StructField, StructID, UInstruction, UModuleBuilder, UProgram, UStruct, VarInst},
parser::{Node, PMap, PConstructFields, PStruct, PStructFields}, parser::{Node, PMap, PStruct, PStructFields},
}; };
use super::{FnLowerCtx, FnLowerable}; use super::{FnLowerCtx, FnLowerable};
@@ -9,7 +9,7 @@ use super::{FnLowerCtx, FnLowerable};
impl FnLowerable for PMap { impl FnLowerable for PMap {
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.b, ctx.output);
let fields = match &self.fields { let fields = match &self.fields {
PConstructFields::Named(nodes) => nodes PConstructFields::Named(nodes) => nodes
.iter() .iter()
@@ -32,7 +32,7 @@ impl FnLowerable for PMap {
PConstructFields::None => Default::default(), PConstructFields::None => Default::default(),
}; };
let id = ctx.temp(ty); let id = ctx.temp(ty);
ctx.push(UInstruction::Construct { dest: id, fields }); ctx.push(UInstruction::Construct { dst: id, fields });
Some(id) Some(id)
} }
} }
@@ -41,7 +41,7 @@ impl PStruct {
pub fn lower( pub fn lower(
&self, &self,
id: StructID, id: StructID,
p: &mut UProgram, p: &mut UModuleBuilder,
output: &mut CompilerOutput, output: &mut CompilerOutput,
span: FileSpan, span: FileSpan,
) -> Option<()> { ) -> Option<()> {
@@ -71,20 +71,23 @@ impl PStruct {
.into_iter() .into_iter()
.map(|(name, ty)| (name, StructField { ty })) .map(|(name, ty)| (name, StructField { ty }))
.collect(); .collect();
p.write(id, UStruct { generics, fields }); let name = self.name.as_ref()?.to_string();
p.def_data(UStruct {
name,
generics,
fields,
origin: span,
});
p.pop(); p.pop();
Some(()) Some(())
} }
} }
impl Node<PStruct> { impl Node<PStruct> {
pub fn lower_name(&self, p: &mut UProgram) -> Option<StructID> { pub fn lower(&self, id: StructID, p: &mut UProgram, output: &mut CompilerOutput) -> Option<()> {
let s = self.as_ref()?; let s = self.as_ref()?;
let name = s.name.as_ref()?; let name = s.name.as_ref()?;
let id = p.def_searchable(name, None, s.name.origin); s.lower(id, p, output, self.origin);
Some(id) Some(())
}
pub fn lower(&self, id: StructID, p: &mut UProgram, output: &mut CompilerOutput) {
self.as_ref().map(|i| i.lower(id, p, output, self.origin));
} }
} }

View File

@@ -1,52 +1,110 @@
use crate::{ use crate::{
ir::{StructInst, Type, TypeID, UGeneric, UProgram, UStruct}, ir::{GenericID, MemberID, ModPath, Type, TypeID, UGeneric, UModuleBuilder, UProgram},
parser::PGenericDef, parser::PGenericDef,
}; };
use super::{CompilerMsg, CompilerOutput, FileSpan, Node, PType}; use super::{CompilerOutput, FileSpan, Node, PType};
impl Node<PType> { impl Node<Box<PType>> {
pub fn lower(&self, namespace: &mut UProgram, output: &mut CompilerOutput) -> TypeID { pub fn lower(&self, p: &mut UModuleBuilder, output: &mut CompilerOutput) -> TypeID {
self.as_ref() self.as_ref()
.map(|t| t.lower(namespace, output, self.origin)) .map(|t| t.lower(p, output, self.origin))
.unwrap_or(Type::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())
}
}
fn test() {}
impl PType { impl PType {
pub fn lower(&self, p: &mut UProgram, output: &mut CompilerOutput, span: FileSpan) -> TypeID { pub fn lower(
let Some(name) = self.name.as_ref() else { &self,
return p.error_type(); p: &mut UModuleBuilder,
output: &mut CompilerOutput,
mut origin: FileSpan,
) -> TypeID {
let mut ty = self;
let mut path = Vec::new();
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();
}; };
let ids = p.get_idents(name); origin = node.origin;
// TODO: should generics always take precedence? path.push(MemberID {
if let Some(id) = ids.and_then(|ids| ids.get::<Type>()) { name: name.0.clone(),
Type::Generic { id } origin: ident.origin,
} else if let Some(id) = ids.and_then(|ids| ids.get::<UStruct>()) { });
let args = self.args.iter().map(|n| n.lower(p, output)).collect(); &**t
Type::Struct(StructInst { id, args })
} else if let Ok(num) = name.parse::<u32>() {
Type::Bits(num)
} else { } else {
match name.as_str() { return p.error();
"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
} }
if !path.is_empty() {
let PType::Ident(id) = ty else {
return p.error();
};
path.push(MemberID {
name: id.0.clone(),
origin,
});
return p.def_ty(Type::Unres(ModPath { m: p.module, path }));
} }
let ty = match ty {
PType::Member(_, _) => unreachable!(),
PType::Ident(node) => {
path.push(MemberID {
name: node.0.clone(),
origin,
});
path.reverse();
Type::Unres(ModPath { m: p.module, path })
} }
PType::Ref(node) => node.lower(p, output).rf(),
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
// }
// }
// }
} }
} }
impl Node<PGenericDef> { impl Node<PGenericDef> {
pub fn lower(&self, p: &mut UProgram) -> Option<GenericID> { pub fn lower(&self, p: &mut UProgram) -> Option<GenericID> {
let s = self.as_ref()?; let s = self.as_ref()?;
let name = s.name.as_ref()?; let name = s.name.as_ref()?.to_string();
Some(p.def_searchable(name, Some(UGeneric {}), self.origin)) Some(p.def_generic(UGeneric {
name,
origin: self.origin,
}))
} }
} }

View File

@@ -6,7 +6,7 @@ pub struct PInstruction {
} }
pub enum PAsmArg { pub enum PAsmArg {
Value(Node<PIdent>), Value(PIdent),
Ref(Node<PIdent>), Ref(Node<PIdent>),
} }
@@ -33,7 +33,7 @@ impl Parsable for PInstruction {
impl Parsable for PAsmArg { impl Parsable for PAsmArg {
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> { fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
if let Some(ident) = ctx.maybe_parse() { if let Some(ident) = ctx.maybe_parse() {
return ParseResult::Ok(Self::Value(ident)); return ParseResult::Wrap(ident.map(Self::Value));
} }
let mut next = ctx.expect_peek()?; let mut next = ctx.expect_peek()?;
@@ -41,10 +41,10 @@ impl Parsable for PAsmArg {
ctx.next(); ctx.next();
if let Some(mut ident) = ctx.maybe_parse::<PIdent>() { if let Some(mut ident) = ctx.maybe_parse::<PIdent>() {
// TODO: this is so messed up // TODO: this is so messed up
if let Some(i) = ident.as_mut() { if let Some(i) = ident.node.as_mut() {
i.0.insert(0, '-') i.0.insert(0, '-')
} }
return ParseResult::Ok(Self::Value(ident)); return ParseResult::Wrap(ident.map(Self::Value));
} }
next = ctx.expect_peek()?; next = ctx.expect_peek()?;
} }

View File

@@ -1,7 +1,7 @@
use std::fmt::Debug; use std::fmt::Debug;
use super::{ use super::{
CompilerMsg, MaybeParsable, Node, PExpr, PIdent, PType, Parsable, ParseResult, ParserCtx, CompilerMsg, Node, PExpr, PIdent, PType, Parsable, ParseResult, ParserCtx,
Symbol, Token, Symbol, Token,
}; };
@@ -55,28 +55,28 @@ pub enum SelfType {
Take, Take,
} }
impl MaybeParsable for SelfVar { // impl Parsable for Option<SelfVar> {
fn maybe_parse(ctx: &mut ParserCtx) -> Result<Option<Self>, CompilerMsg> { // fn maybe_parse(ctx: &mut ParserCtx) -> Result<Option<Self>, CompilerMsg> {
if let Some(mut next) = ctx.peek() { // if let Some(mut next) = ctx.peek() {
let mut ty = SelfType::Take; // let mut ty = SelfType::Take;
if next.is_symbol(Symbol::Ampersand) { // if next.is_symbol(Symbol::Ampersand) {
ctx.next(); // ctx.next();
ty = SelfType::Ref; // ty = SelfType::Ref;
next = ctx.expect_peek()?; // next = ctx.expect_peek()?;
} // }
if let Token::Word(name) = &next.token { // if let Token::Word(name) = &next.token {
if name == "self" { // if name == "self" {
ctx.next(); // ctx.next();
return Ok(Some(Self { ty })); // return Ok(Some(Self { ty }));
} // }
} // }
if ty != SelfType::Take { // if ty != SelfType::Take {
return Err(CompilerMsg::unexpected_token(next, "self")); // return Err(CompilerMsg::unexpected_token(next, "self"));
} // }
} // }
Ok(None) // Ok(None)
} // }
} // }
impl Debug for PVarDef { impl Debug for PVarDef {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {

View File

@@ -12,14 +12,15 @@ use super::{
type BoxNode = Node<Box<PExpr>>; type BoxNode = Node<Box<PExpr>>;
pub enum PExpr { pub enum PExpr {
Lit(Node<PLiteral>), Lit(PLiteral),
Ident(Node<PIdent>), Ident(Node<PIdent>),
BinaryOp(InfixOp, BoxNode, BoxNode), BinaryOp(InfixOp, BoxNode, BoxNode),
PostfixOp(BoxNode, PostfixOp), PostfixOp(BoxNode, PostfixOp),
Block(Node<PBlock>), Block(Node<PBlock>),
Call(BoxNode, Vec<Node<PExpr>>), Call(BoxNode, Vec<Node<PExpr>>),
Group(BoxNode), Group(BoxNode),
Access(BoxNode, Node<PIdent>), Field(BoxNode, Node<PIdent>),
Member(BoxNode, Node<PIdent>),
AsmBlock(Node<PAsmBlock>), AsmBlock(Node<PAsmBlock>),
Construct(BoxNode, Node<PMap>), Construct(BoxNode, Node<PMap>),
If(BoxNode, BoxNode), If(BoxNode, BoxNode),
@@ -69,7 +70,11 @@ impl PExpr {
continue; continue;
} else if next.is_symbol(Symbol::Dot) { } else if next.is_symbol(Symbol::Dot) {
let field = ctx.parse()?; let field = ctx.parse()?;
e1 = Self::Access(Node::new(e1, span).bx(), field); e1 = Self::Field(Node::new(e1, span).bx(), field);
continue;
} else if next.is_symbol(Symbol::DoubleColon) {
let field = ctx.parse()?;
e1 = Self::Member(Node::new(e1, span).bx(), field);
continue; continue;
} else if let Some(op) = PostfixOp::from_token(next) { } else if let Some(op) = PostfixOp::from_token(next) {
ctx.next(); ctx.next();
@@ -86,10 +91,7 @@ impl PExpr {
ctx.next(); ctx.next();
if ctx.expect_peek()?.is_symbol(Symbol::CloseParen) { if ctx.expect_peek()?.is_symbol(Symbol::CloseParen) {
ctx.next(); ctx.next();
return ParseResult::Ok(PExpr::Lit(Node::new( return ParseResult::Ok(PExpr::Lit(PLiteral::Unit));
PLiteral::Unit,
ctx.next_start().char_span(),
)));
} }
let res = ctx.parse(); let res = ctx.parse();
if res.recover { if res.recover {
@@ -118,8 +120,8 @@ impl PExpr {
} else if next.is_keyword(Keyword::Asm) { } else if next.is_keyword(Keyword::Asm) {
ctx.next(); ctx.next();
Self::AsmBlock(ctx.parse()?) Self::AsmBlock(ctx.parse()?)
} else if let Some(val) = ctx.maybe_parse() { } else if let Some(res) = ctx.maybe_parse::<PLiteral>() {
Self::Lit(val) return ParseResult::Wrap(res.map(Self::Lit));
} else { } else {
let res = ctx.parse(); let res = ctx.parse();
if res.node.is_some() { if res.node.is_some() {
@@ -188,7 +190,8 @@ impl Debug for PExpr {
PExpr::Loop(res) => write!(f, "loop -> {res:?}")?, PExpr::Loop(res) => write!(f, "loop -> {res:?}")?,
PExpr::Break => write!(f, "break")?, PExpr::Break => write!(f, "break")?,
PExpr::Continue => write!(f, "continue")?, PExpr::Continue => write!(f, "continue")?,
PExpr::Access(e1, name) => write!(f, "{:?}.{:?}", e1, name)?, PExpr::Field(e1, name) => write!(f, "{:?}.{:?}", e1, name)?,
PExpr::Member(e1, name) => write!(f, "{:?}::{:?}", e1, name)?,
} }
Ok(()) Ok(())
} }

View File

@@ -1,4 +1,4 @@
use super::{MaybeParsable, Parsable, ParseResult, ParserCtx, Token, CompilerMsg}; use super::{CompilerMsg, Parsable, ParseResult, ParserCtx, Token};
use std::{ use std::{
fmt::{Debug, Display}, fmt::{Debug, Display},
ops::Deref, ops::Deref,
@@ -19,15 +19,17 @@ impl Parsable for PIdent {
} }
} }
impl MaybeParsable for PIdent { impl Parsable for Option<PIdent> {
fn maybe_parse(ctx: &mut ParserCtx) -> Result<Option<Self>, CompilerMsg> { fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
let Some(next) = ctx.peek() else { return Ok(None) }; let Some(next) = ctx.peek() else {
return ParseResult::Ok(None);
};
let Token::Word(name) = &next.token else { let Token::Word(name) = &next.token else {
return Ok(None); return ParseResult::Ok(None);
}; };
let name = name.to_string(); let name = name.to_string();
ctx.next(); ctx.next();
Ok(Some(Self(name))) ParseResult::Ok(Some(PIdent(name)))
} }
} }

View File

@@ -1,4 +1,6 @@
use super::{CharCursor, MaybeParsable, ParserCtx, CompilerMsg, Symbol, Token}; use crate::parser::{Parsable, ParseResult};
use super::{PString, ParserCtx, Symbol, Token};
use std::fmt::Debug; use std::fmt::Debug;
#[derive(Clone, PartialEq, Eq)] #[derive(Clone, PartialEq, Eq)]
@@ -16,26 +18,29 @@ pub struct PNumber {
pub ty: Option<String>, pub ty: Option<String>,
} }
impl MaybeParsable for PLiteral { impl Parsable for Option<PLiteral> {
fn maybe_parse(ctx: &mut ParserCtx) -> Result<Option<Self>, CompilerMsg> { fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
let inst = ctx.expect_peek()?; let inst = ctx.expect_peek()?;
Ok(Some(match &inst.token { ParseResult::Ok(Some(match &inst.token {
Token::Symbol(Symbol::SingleQuote) => { Token::Symbol(Symbol::SingleQuote) => {
let chars = ctx.chars(); let chars = ctx.chars();
let c = chars.expect_next()?; let c = chars.expect_next()?;
chars.expect('\'')?; chars.expect('\'')?;
ctx.next(); ctx.next();
Self::Char(c) PLiteral::Char(c)
} }
Token::Symbol(Symbol::DoubleQuote) => { Token::Symbol(Symbol::DoubleQuote) => {
let res = Self::String(string_from(ctx.chars())?);
ctx.next(); ctx.next();
res let s = ctx.parse::<PString>()?;
return match s.inner {
Some(s) => ParseResult::Ok(Some(PLiteral::String(s.0))),
None => ParseResult::SubErr,
};
} }
Token::Word(text) => { Token::Word(text) => {
let first = text.chars().next().unwrap(); let first = text.chars().next().unwrap();
if !first.is_ascii_digit() { if !first.is_ascii_digit() {
return Ok(None); return ParseResult::Ok(None);
} }
let (whole, ty) = parse_whole_num(text); let (whole, ty) = parse_whole_num(text);
let mut num = PNumber { let mut num = PNumber {
@@ -57,9 +62,9 @@ impl MaybeParsable for PLiteral {
} }
} }
} }
Self::Number(num) PLiteral::Number(num)
} }
_ => return Ok(None), _ => return ParseResult::Ok(None),
})) }))
} }
} }
@@ -81,32 +86,6 @@ pub fn parse_whole_num(text: &str) -> (String, Option<String>) {
(whole, if ty.is_empty() { None } else { Some(ty) }) (whole, if ty.is_empty() { None } else { Some(ty) })
} }
pub fn string_from(cursor: &mut CharCursor) -> Result<String, CompilerMsg> {
let mut str = String::new();
loop {
let c = cursor.expect_next()?;
if c == '"' {
return Ok(str);
}
str.push(match c {
'\\' => {
let next = cursor.expect_next()?;
match next {
'"' => '"',
'\'' => '\'',
't' => '\t',
'n' => '\n',
'0' => '\0',
_ => {
todo!();
}
}
}
_ => c,
})
}
}
impl Debug for PLiteral { impl Debug for PLiteral {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {

View File

@@ -9,6 +9,7 @@ mod ident;
mod lit; mod lit;
mod op; mod op;
mod statement; mod statement;
mod string;
mod struc; mod struc;
mod trai; mod trai;
mod ty; mod ty;
@@ -28,10 +29,9 @@ pub use statement::*;
pub use struc::*; pub use struc::*;
pub use trai::*; pub use trai::*;
pub use ty::*; pub use ty::*;
pub use string::*;
use crate::ir::UProgram; use super::*;
use super::{lower::{FnLowerCtx, FnLowerable}, *};
pub struct PModule { pub struct PModule {
pub block: Node<PBlock>, pub block: Node<PBlock>,

View File

@@ -78,7 +78,7 @@ impl PostfixOp {
match self { match self {
Self::Not => "!", Self::Not => "!",
Self::Ref => "@", Self::Ref => "@",
Self::Deref => "*", Self::Deref => "^",
} }
} }
pub fn from_token(token: &Token) -> Option<Self> { pub fn from_token(token: &Token) -> Option<Self> {
@@ -88,7 +88,7 @@ impl PostfixOp {
Some(match symbol { Some(match symbol {
Symbol::At => Self::Ref, Symbol::At => Self::Ref,
Symbol::Bang => Self::Not, Symbol::Bang => Self::Not,
Symbol::Asterisk => Self::Deref, Symbol::Carrot => Self::Deref,
_ => { _ => {
return None; return None;
} }

View File

@@ -29,7 +29,7 @@ impl Parsable for PStatementLike {
let def = ctx.parse()?; let def = ctx.parse()?;
ctx.expect_sym(Symbol::Equals)?; ctx.expect_sym(Symbol::Equals)?;
ctx.parse() ctx.parse()
.map(|expr| Self::Statement(PStatement::Let(def, expr))) .map_res(|expr| Self::Statement(PStatement::Let(def, expr)))
} }
Token::Keyword(Keyword::Return) => { Token::Keyword(Keyword::Return) => {
ctx.next(); ctx.next();
@@ -37,7 +37,7 @@ impl Parsable for PStatementLike {
ParseResult::Ok(Self::Statement(PStatement::Return(None))) ParseResult::Ok(Self::Statement(PStatement::Return(None)))
} else { } else {
ctx.parse() ctx.parse()
.map(|res| Self::Statement(PStatement::Return(Some(res)))) .map_res(|res| Self::Statement(PStatement::Return(Some(res))))
} }
} }
Token::Keyword(Keyword::Fn) => { Token::Keyword(Keyword::Fn) => {
@@ -52,7 +52,7 @@ impl Parsable for PStatementLike {
ctx.next(); ctx.next();
ParseResult::Ok(Self::Const(PConstStatement::Import(ctx.parse()?))) ParseResult::Ok(Self::Const(PConstStatement::Import(ctx.parse()?)))
} }
_ => ctx.parse().map(|n| Self::Statement(PStatement::Expr(n))), _ => ctx.parse().map_res(|n| Self::Statement(PStatement::Expr(n))),
} }
} }
} }

View File

@@ -0,0 +1,41 @@
use crate::{
common::CompilerMsg,
parser::{Parsable, ParseResult},
};
pub struct PString(pub String);
impl Parsable for PString {
fn parse(ctx: &mut crate::parser::ParserCtx) -> ParseResult<Self> {
let cursor = ctx.cursor.chars();
let mut str = String::new();
loop {
let c = cursor.expect_next()?;
if c == '"' {
return ParseResult::Ok(Self(str));
}
str.push(match c {
'\\' => {
let start = cursor.prev_pos();
let next = cursor.expect_next()?;
match next {
'"' => '"',
'\'' => '\'',
't' => '\t',
'n' => '\n',
'0' => '\0',
other => {
let end = cursor.prev_pos();
ctx.output.err(CompilerMsg {
msg: format!("Unknown escape sequence '\\{}'", other),
spans: vec![start.to(end)],
});
other
}
}
}
_ => c,
})
}
}
}

View File

@@ -2,9 +2,13 @@ use std::fmt::Debug;
use super::{util::parse_list, Node, PIdent, Parsable, ParseResult, ParserCtx, Symbol}; use super::{util::parse_list, Node, PIdent, Parsable, ParseResult, ParserCtx, Symbol};
pub struct PType { type BoxNode = Node<Box<PType>>;
pub name: Node<PIdent>,
pub args: Vec<Node<PType>>, pub enum PType {
Member(BoxNode, Node<PIdent>),
Ref(BoxNode),
Generic(BoxNode, Vec<Node<PType>>),
Ident(PIdent),
} }
pub struct PGenericDef { pub struct PGenericDef {
@@ -13,27 +17,30 @@ pub struct PGenericDef {
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 start = ctx.next_start();
let res = if next.is_symbol(Symbol::Ampersand) { let mut cur = ctx.parse()?.map(PType::Ident);
let name = Node::new(PIdent("&".to_string()), next.span); loop {
ctx.next(); let span = start.to(ctx.prev_end());
let arg = ctx.parse()?; let Some(next) = ctx.peek() else {
Self { break;
name,
args: vec![arg],
}
} else {
let n = ctx.parse()?;
let mut args = Vec::new();
if let Some(next) = ctx.peek() {
if next.is_symbol(Symbol::OpenAngle) {
ctx.next();
args = parse_list(ctx, Symbol::CloseAngle)?;
}
}
Self { name: n, args }
}; };
ParseResult::Ok(res) if next.is_symbol(Symbol::Ampersand) {
ctx.next();
cur = Node::new(PType::Ref(cur.bx()), span);
continue;
} else if next.is_symbol(Symbol::OpenAngle) {
ctx.next();
let args = parse_list(ctx, Symbol::CloseAngle)?;
cur = Node::new(PType::Generic(cur.bx(), args), span);
continue;
} else if next.is_symbol(Symbol::DoubleColon) {
ctx.next();
let mem = ctx.parse()?;
cur = Node::new(PType::Member(cur.bx(), mem), span);
}
break;
}
ParseResult::Wrap(cur)
} }
} }
@@ -45,11 +52,11 @@ impl Parsable for PGenericDef {
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)?; match self {
if self.name.as_ref().is_some_and(|n| n.0 == "&") { PType::Member(node, name) => write!(f, "{:?}.{:?}", node, name)?,
write!(f, "{:?}", self.args[0])?; PType::Ref(node) => write!(f, "{:?}&", node)?,
} else if !self.args.is_empty() { PType::Generic(node, args) => write!(f, "{:?}<{:?}>", node, args)?,
write!(f, "<{:?}>", self.args)?; PType::Ident(node) => node.fmt(f)?,
} }
Ok(()) Ok(())
} }

View File

@@ -7,6 +7,8 @@ use super::{CompilerMsg, FilePos, Node, ParserCtx};
pub enum ParseResult<T> { pub enum ParseResult<T> {
Ok(T), Ok(T),
Wrap(NodeParseResult<T>),
Node(Node<T>),
Recover(T), Recover(T),
Err(CompilerMsg), Err(CompilerMsg),
SubErr, SubErr,
@@ -33,6 +35,20 @@ impl<T> Try for ParseResult<T> {
ParseResult::Ok(v) => ControlFlow::Continue(v), ParseResult::Ok(v) => ControlFlow::Continue(v),
// TODO: this is messed up; need to break w a Result<Option<T>> or smth :woozy: // TODO: this is messed up; need to break w a Result<Option<T>> or smth :woozy:
ParseResult::Recover(v) => ControlFlow::Break(None), ParseResult::Recover(v) => ControlFlow::Break(None),
ParseResult::Wrap(n) => {
if n.recover {
ControlFlow::Break(None)
} else {
match n.node.inner {
Some(v) => ControlFlow::Continue(v),
None => ControlFlow::Break(None),
}
}
}
ParseResult::Node(n) => match n.inner {
Some(v) => ControlFlow::Continue(v),
None => ControlFlow::Break(None),
},
ParseResult::Err(e) => ControlFlow::Break(Some(e)), ParseResult::Err(e) => ControlFlow::Break(Some(e)),
ParseResult::SubErr => ControlFlow::Break(None), ParseResult::SubErr => ControlFlow::Break(None),
} }
@@ -72,7 +88,7 @@ pub struct NodeParseResult<T> {
} }
impl<T> NodeParseResult<T> { impl<T> NodeParseResult<T> {
pub fn map<F: FnOnce(Node<T>) -> U, U>(self, op: F) -> ParseResult<U> { pub fn map_res<F: FnOnce(Node<T>) -> U, U>(self, op: F) -> ParseResult<U> {
let res = op(self.node); let res = op(self.node);
if self.recover { if self.recover {
ParseResult::Recover(res) ParseResult::Recover(res)
@@ -80,6 +96,15 @@ impl<T> NodeParseResult<T> {
ParseResult::Ok(res) ParseResult::Ok(res)
} }
} }
pub fn map<F: FnOnce(T) -> U, U>(self, op: F) -> NodeParseResult<U> {
NodeParseResult {
node: Node {
inner: self.node.inner.map(op),
origin: self.node.origin,
},
recover: self.recover,
}
}
} }
impl<T> Try for NodeParseResult<T> { impl<T> Try for NodeParseResult<T> {
@@ -119,10 +144,6 @@ pub trait ParsableWith: Sized {
fn parse(ctx: &mut ParserCtx, data: Self::Data) -> ParseResult<Self>; fn parse(ctx: &mut ParserCtx, data: Self::Data) -> ParseResult<Self>;
} }
pub trait MaybeParsable: Sized {
fn maybe_parse(ctx: &mut ParserCtx) -> Result<Option<Self>, CompilerMsg>;
}
impl<T: Parsable> ParsableWith for T { impl<T: Parsable> ParsableWith for T {
type Data = (); type Data = ();
@@ -140,6 +161,13 @@ impl<T: ParsableWith> Node<T> {
let (inner, recover) = match T::parse(ctx, data) { let (inner, recover) = match T::parse(ctx, data) {
ParseResult::Ok(v) => (Some(v), false), ParseResult::Ok(v) => (Some(v), false),
ParseResult::Recover(v) => (Some(v), true), ParseResult::Recover(v) => (Some(v), true),
ParseResult::Wrap(r) => return r,
ParseResult::Node(node) => {
return NodeParseResult {
node,
recover: false,
}
}
ParseResult::Err(e) => { ParseResult::Err(e) => {
ctx.err(e); ctx.err(e);
(None, true) (None, true)
@@ -163,21 +191,33 @@ impl<T: Parsable> Node<T> {
} }
} }
impl<T: MaybeParsable> Node<T> { impl<T> Node<Option<T>>
pub fn maybe_parse(ctx: &mut ParserCtx) -> Option<Self> { where
let start = ctx.next_start(); Option<T>: Parsable,
let inner = match T::maybe_parse(ctx) { {
Ok(v) => Some(v?), pub fn maybe_parse(ctx: &mut ParserCtx) -> Option<NodeParseResult<T>> {
Err(e) => { let res = Node::<Option<T>>::parse_with(ctx, ());
ctx.err(e); let origin = res.node.origin;
None let recover = res.recover;
match res.node.inner {
Some(val) => match val {
Some(v) => Some(NodeParseResult {
node: Node {
inner: Some(v),
origin,
},
recover,
}),
None => None,
},
None => Some(NodeParseResult {
node: Node {
inner: None,
origin,
},
recover,
}),
} }
};
let end = ctx.prev_end();
Some(Self {
inner,
origin: start.to(end),
})
} }
} }

View File

@@ -36,6 +36,7 @@ pub enum Symbol {
Comma, Comma,
Hash, Hash,
At, At,
Carrot,
} }
impl Symbol { impl Symbol {
@@ -72,6 +73,7 @@ impl Symbol {
',' => Self::Comma, ',' => Self::Comma,
'#' => Self::Hash, '#' => Self::Hash,
'@' => Self::At, '@' => Self::At,
'^' => Self::Carrot,
_ => return None, _ => return None,
}) })
} }
@@ -147,6 +149,7 @@ impl Symbol {
Self::DoublePipe => "||", Self::DoublePipe => "||",
Self::Hash => "#", Self::Hash => "#",
Self::At => "@", Self::At => "@",
Self::Carrot => "^",
} }
} }
} }