going insane (not working yet)
This commit is contained in:
@@ -1,24 +1,45 @@
|
||||
use std::{collections::HashMap, path::PathBuf};
|
||||
|
||||
pub type FileID = usize;
|
||||
pub type FileMap = HashMap<FileID, SrcFile>;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct SrcFile {
|
||||
pub path: PathBuf,
|
||||
pub text: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct FilePos {
|
||||
pub file: FileID,
|
||||
pub line: usize,
|
||||
pub col: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct FileSpan {
|
||||
pub file: FileID,
|
||||
pub start: FilePos,
|
||||
pub end: FilePos,
|
||||
}
|
||||
|
||||
impl FilePos {
|
||||
pub fn start() -> Self {
|
||||
Self { line: 0, col: 0 }
|
||||
pub fn start(file: FileID) -> Self {
|
||||
Self {
|
||||
line: 0,
|
||||
col: 0,
|
||||
file,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FilePos {
|
||||
pub fn to(self, end: FilePos) -> FileSpan {
|
||||
FileSpan { start: self, end }
|
||||
FileSpan {
|
||||
start: self,
|
||||
end,
|
||||
file: self.file,
|
||||
}
|
||||
}
|
||||
pub fn char_span(self) -> FileSpan {
|
||||
FileSpan::at(self)
|
||||
@@ -33,6 +54,7 @@ impl FileSpan {
|
||||
Self {
|
||||
start: pos,
|
||||
end: pos,
|
||||
file: pos.file,
|
||||
}
|
||||
}
|
||||
pub fn write_for(&self, writer: &mut impl std::io::Write, file: &str) -> std::io::Result<()> {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use super::{FilePos, FileSpan};
|
||||
use super::{FileMap, FilePos, FileSpan};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CompilerMsg {
|
||||
@@ -7,6 +7,7 @@ pub struct CompilerMsg {
|
||||
}
|
||||
|
||||
pub struct CompilerOutput {
|
||||
pub file_map: FileMap,
|
||||
pub errs: Vec<CompilerMsg>,
|
||||
pub hints: Vec<CompilerMsg>,
|
||||
}
|
||||
@@ -30,11 +31,18 @@ impl CompilerMsg {
|
||||
spans: vec![FileSpan::at(pos)],
|
||||
}
|
||||
}
|
||||
pub fn write_for(&self, ty: &str, writer: &mut impl std::io::Write, file: &str) -> std::io::Result<()> {
|
||||
pub fn write_to(
|
||||
&self,
|
||||
ty: &str,
|
||||
writer: &mut impl std::io::Write,
|
||||
map: &FileMap,
|
||||
) -> std::io::Result<()> {
|
||||
let after = if self.spans.is_empty() { "" } else { ":" };
|
||||
writeln!(writer, "{}: {}{}", ty, self.msg, after)?;
|
||||
for span in &self.spans {
|
||||
span.write_for(writer, file)?;
|
||||
let file = map.get(&span.file).expect("unknown file id");
|
||||
writeln!(writer, "{:?}", &file.path)?;
|
||||
span.write_for(writer, &file.text)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -45,6 +53,7 @@ impl CompilerOutput {
|
||||
Self {
|
||||
errs: Vec::new(),
|
||||
hints: Vec::new(),
|
||||
file_map: FileMap::new(),
|
||||
}
|
||||
}
|
||||
pub fn err(&mut self, msg: CompilerMsg) {
|
||||
@@ -53,12 +62,12 @@ impl CompilerOutput {
|
||||
pub fn hint(&mut self, msg: CompilerMsg) {
|
||||
self.hints.push(msg);
|
||||
}
|
||||
pub fn write_for(&self, out: &mut impl std::io::Write, file: &str) {
|
||||
pub fn write_to(&self, out: &mut impl std::io::Write) {
|
||||
for err in &self.errs {
|
||||
err.write_for("error", out, file).unwrap();
|
||||
err.write_to("error", out, &self.file_map).unwrap();
|
||||
}
|
||||
for hint in &self.hints {
|
||||
hint.write_for("hint", out, file).unwrap();
|
||||
hint.write_to("hint", out, &self.file_map).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::ir::{AsmBlockArgType, Size, SymbolSpace, UFunc, UInstrInst, VarOffset};
|
||||
use crate::ir::{AsmBlockArgType, Size, StructTy, SymbolSpace, UFunc, UInstrInst, VarOffset};
|
||||
|
||||
use super::{
|
||||
IRLFunction, LInstruction, Len, Symbol, SymbolSpaceBuilder, Type, UInstruction, UProgram, VarID,
|
||||
@@ -17,7 +17,7 @@ impl LProgram {
|
||||
pub fn create(p: &UProgram) -> Result<Self, String> {
|
||||
let start = p
|
||||
.names
|
||||
.id::<UFunc>("crate")
|
||||
.id::<UFunc>(&["crate".to_string()])
|
||||
.ok_or("no start method found")?;
|
||||
let mut ssbuilder = SymbolSpaceBuilder::with_entries(&[start]);
|
||||
let entry = ssbuilder.func(&start);
|
||||
@@ -44,10 +44,20 @@ impl LProgram {
|
||||
|
||||
pub struct StructInst {
|
||||
offsets: Vec<Len>,
|
||||
types: Vec<Type>,
|
||||
order: HashMap<String, usize>,
|
||||
size: Size,
|
||||
}
|
||||
|
||||
impl StructInst {
|
||||
pub fn offset(&self, name: &str) -> Option<Len> {
|
||||
Some(self.offsets[*self.order.get(name)?])
|
||||
}
|
||||
pub fn ty(&self, name: &str) -> Option<&Type> {
|
||||
Some(&self.types[*self.order.get(name)?])
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LFunctionBuilder<'a> {
|
||||
data: LFunctionBuilderData<'a>,
|
||||
program: &'a UProgram,
|
||||
@@ -72,7 +82,7 @@ pub struct LFunctionBuilderData<'a> {
|
||||
instrs: Vec<LInstruction>,
|
||||
stack: HashMap<VarID, Size>,
|
||||
subvar_map: HashMap<VarID, VarOffset>,
|
||||
struct_insts: HashMap<Type, StructInst>,
|
||||
struct_insts: HashMap<StructTy, StructInst>,
|
||||
makes_call: bool,
|
||||
loopp: Option<LoopCtx>,
|
||||
}
|
||||
@@ -258,6 +268,10 @@ impl<'a> LFunctionBuilder<'a> {
|
||||
self.data.instrs.push(LInstruction::Ret { src })
|
||||
}
|
||||
UInstruction::Construct { dest, fields } => {
|
||||
let sty = &self.program.expect(dest.id).ty;
|
||||
let Type::Struct(sty) = sty else {
|
||||
panic!("bruh htis aint' a struct");
|
||||
};
|
||||
self.alloc_stack(dest.id)?;
|
||||
for (field, var) in fields {
|
||||
self.map_subvar(var.id);
|
||||
@@ -266,7 +280,7 @@ impl<'a> LFunctionBuilder<'a> {
|
||||
src: var.id,
|
||||
dest_offset: self
|
||||
.data
|
||||
.field_offset(self.program, dest.id, field)
|
||||
.field_offset(self.program, sty, field)
|
||||
.expect("field offset"),
|
||||
src_offset: 0,
|
||||
};
|
||||
@@ -344,22 +358,25 @@ impl<'a> LFunctionBuilder<'a> {
|
||||
impl LFunctionBuilderData<'_> {
|
||||
pub fn var_offset(&mut self, p: &UProgram, var: VarID) -> Option<VarOffset> {
|
||||
let mut current = VarOffset { id: var, offset: 0 };
|
||||
while let Some(parent) = &p.get(current.id)?.parent {
|
||||
current.id = parent.var;
|
||||
current.offset += self.field_offset(p, parent.var, &parent.field)?;
|
||||
while let Type::Member(parent) = &p.get(current.id)?.ty {
|
||||
current.id = parent.parent;
|
||||
// ... should it be set to 0 if not? what does that even mean??
|
||||
// "the field of this struct is a reference to another variable" ????
|
||||
if let Type::Struct(sty) = &p.get(parent.parent)?.ty {
|
||||
current.offset += self.field_offset(p, sty, &parent.name)?;
|
||||
}
|
||||
}
|
||||
Some(current)
|
||||
}
|
||||
pub fn addr_size(&self) -> Size {
|
||||
64
|
||||
}
|
||||
pub fn struct_inst(&mut self, p: &UProgram, ty: &Type) -> Option<&StructInst> {
|
||||
pub fn struct_inst(&mut self, p: &UProgram, ty: &StructTy) -> &StructInst {
|
||||
// normally I'd let Some(..) here and return, but polonius does not exist :grief:
|
||||
if self.struct_insts.get(ty).is_none() {
|
||||
let Type::Struct { id, args } = ty else {
|
||||
return None;
|
||||
};
|
||||
let struc = p.get(*id)?;
|
||||
let StructTy { id, args } = ty;
|
||||
let struc = p.expect(*id);
|
||||
let mut types = Vec::new();
|
||||
let mut sizes = struc
|
||||
.fields
|
||||
.iter()
|
||||
@@ -374,6 +391,7 @@ impl LFunctionBuilderData<'_> {
|
||||
} else {
|
||||
&f.ty
|
||||
};
|
||||
types.push(ty.clone());
|
||||
(n, self.size_of_type(p, ty).expect("unsized type"))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
@@ -392,25 +410,24 @@ impl LFunctionBuilderData<'_> {
|
||||
StructInst {
|
||||
offsets,
|
||||
order,
|
||||
types,
|
||||
size: offset,
|
||||
},
|
||||
);
|
||||
}
|
||||
self.struct_insts.get(ty)
|
||||
self.struct_insts.get(ty).unwrap()
|
||||
}
|
||||
|
||||
pub fn field_offset(&mut self, p: &UProgram, var: VarID, field: &str) -> Option<Len> {
|
||||
let ty = &p.get(var)?.ty;
|
||||
let inst = self.struct_inst(p, ty)?;
|
||||
let i = *inst.order.get(field)?;
|
||||
Some(*inst.offsets.get(i)?)
|
||||
pub fn field_offset(&mut self, p: &UProgram, sty: &StructTy, field: &str) -> Option<Len> {
|
||||
let inst = self.struct_inst(p, sty);
|
||||
Some(inst.offset(field)?)
|
||||
}
|
||||
|
||||
pub fn size_of_type(&mut self, p: &UProgram, ty: &Type) -> Option<Size> {
|
||||
// TODO: target matters
|
||||
Some(match ty {
|
||||
Type::Bits(b) => *b,
|
||||
Type::Struct { id, args } => self.struct_inst(p, ty)?.size,
|
||||
Type::Struct(ty) => self.struct_inst(p, ty).size,
|
||||
Type::Generic { id } => return None,
|
||||
Type::Fn { args, ret } => todo!(),
|
||||
Type::Ref(_) => self.addr_size(),
|
||||
@@ -420,6 +437,18 @@ impl LFunctionBuilderData<'_> {
|
||||
Type::Error => return None,
|
||||
Type::Unit => 0,
|
||||
Type::Placeholder => return None,
|
||||
Type::Module(_) => return None,
|
||||
Type::Member(m) => {
|
||||
let pty = &p.expect(m.parent).ty;
|
||||
let ty = match pty {
|
||||
Type::Struct(ty) => self.struct_inst(p, ty).ty(&m.name)?,
|
||||
Type::Module(path) => p.path_ty(path)?,
|
||||
Type::Member(_) => return self.size_of_type(p, pty),
|
||||
_ => return None,
|
||||
}
|
||||
.clone();
|
||||
self.size_of_type(p, &ty)?
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -20,16 +20,56 @@ impl OriginMap {
|
||||
}
|
||||
}
|
||||
|
||||
pub type NamePath = Vec<String>;
|
||||
|
||||
pub struct NameTree {
|
||||
ids: [HashMap<String, usize>; NAMED_KINDS],
|
||||
children: HashMap<String, NameTree>,
|
||||
}
|
||||
|
||||
impl NameTree {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
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]) -> Option<ID<K>> {
|
||||
let last = path.last()?;
|
||||
self.get(&path[..path.len() - 1])?.ids[K::INDEX]
|
||||
.get(last)
|
||||
.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],
|
||||
inv_names: [HashMap<String, usize>; NAMED_KINDS],
|
||||
tree: NameTree,
|
||||
}
|
||||
|
||||
impl NameMap {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
names: core::array::from_fn(|_| Vec::new()),
|
||||
inv_names: core::array::from_fn(|_| HashMap::new()),
|
||||
tree: NameTree::new(),
|
||||
}
|
||||
}
|
||||
pub fn path<K: Kind>(&self, id: ID<K>) -> &str {
|
||||
@@ -42,11 +82,13 @@ impl NameMap {
|
||||
}
|
||||
path
|
||||
}
|
||||
pub fn id<K: Kind>(&self, name: &str) -> Option<ID<K>> {
|
||||
Some(ID::new(*self.inv_names[K::INDEX].get(name)?))
|
||||
pub fn id<K: Kind>(&self, path: &[String]) -> Option<ID<K>> {
|
||||
Some(self.tree.id(path)?)
|
||||
}
|
||||
pub fn push<K: Kind>(&mut self, name: String) {
|
||||
self.inv_names[K::INDEX].insert(name.clone(), self.names[K::INDEX].len());
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@ pub struct UGeneric {}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct UVar {
|
||||
pub parent: Option<FieldRef>,
|
||||
pub ty: Type,
|
||||
}
|
||||
|
||||
@@ -37,12 +36,6 @@ pub struct VarOffset {
|
||||
pub offset: Len,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
|
||||
pub struct FieldRef {
|
||||
pub var: VarID,
|
||||
pub field: String,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct UData {
|
||||
pub ty: Type,
|
||||
@@ -124,7 +117,7 @@ impl_kind!(UVar, 1, vars, "var");
|
||||
impl_kind!(UStruct, 2, structs, "struct");
|
||||
impl_kind!(UGeneric, 3, types, "type");
|
||||
impl_kind!(UData, 4, data, "data");
|
||||
pub const NAMED_KINDS: usize = 5;
|
||||
pub const NAMED_KINDS: usize = 6;
|
||||
|
||||
pub type FnID = ID<UFunc>;
|
||||
pub type VarID = ID<UVar>;
|
||||
@@ -137,7 +130,6 @@ impl Finish for UFunc {
|
||||
let var = p.def_searchable(
|
||||
name.to_string(),
|
||||
Some(UVar {
|
||||
parent: None,
|
||||
ty: Type::Placeholder,
|
||||
}),
|
||||
p.origins.get(id),
|
||||
|
||||
@@ -71,19 +71,13 @@ impl UProgram {
|
||||
pub fn get_fn_var(&self, id: VarID) -> Option<&UFunc> {
|
||||
self.fns[self.fn_var.fun(id)?.0].as_ref()
|
||||
}
|
||||
pub fn temp_subvar(&mut self, origin: Origin, ty: Type, parent: FieldRef) -> VarInst {
|
||||
self.temp_var_inner(origin, ty, Some(parent))
|
||||
}
|
||||
|
||||
pub fn temp_var(&mut self, origin: Origin, ty: Type) -> VarInst {
|
||||
self.temp_var_inner(origin, ty, None)
|
||||
self.temp_var_inner(origin, ty)
|
||||
}
|
||||
|
||||
fn temp_var_inner(&mut self, origin: Origin, ty: Type, parent: Option<FieldRef>) -> VarInst {
|
||||
let v = self.def(
|
||||
&format!("temp{}", self.temp),
|
||||
Some(UVar { parent, ty }),
|
||||
origin,
|
||||
);
|
||||
fn temp_var_inner(&mut self, origin: Origin, ty: Type) -> VarInst {
|
||||
let v = self.def(&format!("temp{}", self.temp), Some(UVar { ty }), origin);
|
||||
self.temp += 1;
|
||||
VarInst {
|
||||
id: v,
|
||||
@@ -96,7 +90,7 @@ impl UProgram {
|
||||
}
|
||||
|
||||
pub fn def<K: Kind + Finish>(&mut self, name: &str, k: Option<K>, origin: Origin) -> ID<K> {
|
||||
self.names.push::<K>(self.path_for(name));
|
||||
self.names.push::<K>(&self.path_for(name));
|
||||
self.origins.push::<K>(origin);
|
||||
let vec = K::from_program_mut(self);
|
||||
let id = ID::new(vec.len());
|
||||
@@ -105,12 +99,12 @@ impl UProgram {
|
||||
id
|
||||
}
|
||||
|
||||
pub fn path_for(&self, name: &str) -> String {
|
||||
pub fn path_for(&self, name: &str) -> Vec<String> {
|
||||
if self.path.is_empty() {
|
||||
return name.to_string();
|
||||
return vec![name.to_string()];
|
||||
}
|
||||
let mut path = self.path.join("::");
|
||||
path = path + "::" + name;
|
||||
let mut path = self.path.clone();
|
||||
path.push(name.to_string());
|
||||
path
|
||||
}
|
||||
|
||||
@@ -125,27 +119,46 @@ impl UProgram {
|
||||
id
|
||||
}
|
||||
|
||||
pub fn ref_ty<'a>(&'a self, mem: &MemberRef) -> Option<&'a Type> {
|
||||
self.follow_ref(mem).and_then(|r| Some(&self.get(r)?.ty))
|
||||
}
|
||||
|
||||
pub fn follow_ref<'a>(&'a self, mem: &MemberRef) -> Option<VarID> {
|
||||
let parent = self.get(mem.parent)?;
|
||||
if let Type::Member(mem) = &parent.ty {
|
||||
self.follow_ref(mem)
|
||||
} else {
|
||||
Some(mem.parent)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn field_type<'a>(&'a self, sty: &'a Type, field: &str) -> Option<&'a Type> {
|
||||
let Type::Struct { id, args } = sty else {
|
||||
return None;
|
||||
};
|
||||
let struc = self.get(*id)?;
|
||||
if let Type::Struct(st) = sty {
|
||||
let struc = self.get(st.id)?;
|
||||
let field = struc.fields.get(field)?;
|
||||
if let Type::Generic { id } = field.ty {
|
||||
for (i, g) in struc.generics.iter().enumerate() {
|
||||
if *g == id {
|
||||
return Some(&args[i]);
|
||||
return Some(&st.args[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(&field.ty)
|
||||
} else if let Type::Module(path) = sty {
|
||||
let id = self.names.id::<UVar>(path)?;
|
||||
Some(&self.get(id)?.ty)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn type_name(&self, ty: &Type) -> String {
|
||||
let mut str = String::new();
|
||||
match ty {
|
||||
Type::Struct { id: base, args } => {
|
||||
str += self.names.name(*base);
|
||||
Type::Struct(ty) => {
|
||||
let base = ty.id;
|
||||
let args = &ty.args;
|
||||
str += self.names.name(base);
|
||||
if let Some(arg) = args.first() {
|
||||
str = str + "<" + &self.type_name(arg);
|
||||
}
|
||||
@@ -178,9 +191,22 @@ impl UProgram {
|
||||
Type::Unit => str += "()",
|
||||
Type::Slice(t) => str += &format!("&[{}]", self.type_name(t)),
|
||||
Type::Placeholder => str += "{placeholder}",
|
||||
Type::Module(path) => str += &path.join("::"),
|
||||
Type::Member(m) => {
|
||||
str += &self
|
||||
.ref_ty(m)
|
||||
.map(|t| self.type_name(t))
|
||||
.unwrap_or("{error}".to_string())
|
||||
}
|
||||
}
|
||||
str
|
||||
}
|
||||
pub fn path_var(&self, path: &NamePath) -> Option<VarID> {
|
||||
self.names.id(path)
|
||||
}
|
||||
pub fn path_ty(&self, path: &NamePath) -> Option<&Type> {
|
||||
Some(&self.get(self.path_var(path)?)?.ty)
|
||||
}
|
||||
fn name_on_stack<K: Kind>(&mut self, id: ID<K>, name: String) {
|
||||
let idx = self.name_stack.len() - 1;
|
||||
let last = &mut self.name_stack[idx];
|
||||
|
||||
@@ -1,16 +1,30 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use super::{GenericID, Len, StructID, UInstruction, UProgram, UVar, VarID};
|
||||
use super::{assoc::NamePath, GenericID, Len, StructID, UInstruction, UProgram, UVar, VarID};
|
||||
|
||||
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
|
||||
pub struct MemberRef {
|
||||
pub parent: VarID,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Hash, Eq, PartialEq)]
|
||||
pub struct StructTy {
|
||||
pub id: StructID,
|
||||
pub args: Vec<Type>,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||
pub enum Type {
|
||||
Bits(u32),
|
||||
Struct { id: StructID, args: Vec<Type> },
|
||||
Struct(StructTy),
|
||||
Generic { id: GenericID },
|
||||
Fn { args: Vec<Type>, ret: Box<Type> },
|
||||
Ref(Box<Type>),
|
||||
Slice(Box<Type>),
|
||||
Array(Box<Type>, Len),
|
||||
Member(MemberRef),
|
||||
Module(NamePath),
|
||||
Infer,
|
||||
Error,
|
||||
Placeholder,
|
||||
@@ -43,37 +57,16 @@ impl UProgram {
|
||||
}
|
||||
for (i, f) in self.iter_fns() {
|
||||
let mut redo_iter = Vec::new();
|
||||
let mut ph_vars = Vec::new();
|
||||
let mut redo_new = Vec::new();
|
||||
for i in f.flat_iter() {
|
||||
if let Err(id) = self.resolve_instr_types(&mut vars, &i.i) {
|
||||
if self.resolve_instr_types(&mut vars, &i.i).is_none() {
|
||||
redo_iter.push(i);
|
||||
ph_vars.push(id);
|
||||
}
|
||||
}
|
||||
while !redo_iter.is_empty() {
|
||||
let mut new_ph = Vec::new();
|
||||
for id in &ph_vars {
|
||||
let i = id.0;
|
||||
let Some(var) = &vars[i] else {
|
||||
continue;
|
||||
};
|
||||
if var.ty == Type::Placeholder
|
||||
&& let Some(parent) = var.parent.as_ref()
|
||||
{
|
||||
let pty = &vars[parent.var.0].as_ref().unwrap().ty;
|
||||
if let Some(ft) = self.field_type(pty, &parent.field) {
|
||||
vars[i].as_mut().unwrap().ty = ft.clone();
|
||||
} else {
|
||||
new_ph.push(parent.var);
|
||||
}
|
||||
}
|
||||
}
|
||||
ph_vars = new_ph;
|
||||
for &i in &redo_iter {
|
||||
if let Err(id) = self.resolve_instr_types(&mut vars, &i.i) {
|
||||
if self.resolve_instr_types(&mut vars, &i.i).is_none() {
|
||||
redo_new.push(i);
|
||||
ph_vars.push(id);
|
||||
}
|
||||
}
|
||||
std::mem::swap(&mut redo_iter, &mut redo_new);
|
||||
@@ -83,11 +76,7 @@ impl UProgram {
|
||||
self.vars = vars;
|
||||
}
|
||||
|
||||
pub fn resolve_instr_types(
|
||||
&self,
|
||||
vars: &mut [Option<UVar>],
|
||||
i: &UInstruction,
|
||||
) -> Result<(), VarID> {
|
||||
pub fn resolve_instr_types(&self, vars: &mut [Option<UVar>], i: &UInstruction) -> Option<()> {
|
||||
'outer: {
|
||||
match &i {
|
||||
UInstruction::Call { dest, f, args } => {
|
||||
@@ -96,7 +85,7 @@ impl UProgram {
|
||||
for (src, &dest) in args.iter().zip(&fun.args) {
|
||||
let dest_ty = get(vars, dest)?;
|
||||
let src_ty = get(vars, src.id)?;
|
||||
if let Some(ty) = match_types(dest_ty, src_ty) {
|
||||
if let Some(ty) = self.match_types(dest_ty, src_ty) {
|
||||
set(vars, dest, ty.clone());
|
||||
set(vars, src.id, ty);
|
||||
}
|
||||
@@ -105,7 +94,7 @@ impl UProgram {
|
||||
UInstruction::Mv { dest, src } => {
|
||||
let dest_ty = get(vars, dest.id)?;
|
||||
let src_ty = get(vars, src.id)?;
|
||||
if let Some(ty) = match_types(dest_ty, src_ty) {
|
||||
if let Some(ty) = self.match_types(dest_ty, src_ty) {
|
||||
set(vars, dest.id, ty.clone());
|
||||
set(vars, src.id, ty);
|
||||
}
|
||||
@@ -116,7 +105,7 @@ impl UProgram {
|
||||
let Type::Ref(dest_ty) = dest_ty else {
|
||||
break 'outer;
|
||||
};
|
||||
if let Some(ty) = match_types(dest_ty, src_ty) {
|
||||
if let Some(ty) = self.match_types(dest_ty, src_ty) {
|
||||
set(vars, dest.id, ty.clone().rf());
|
||||
set(vars, src.id, ty);
|
||||
}
|
||||
@@ -136,10 +125,10 @@ impl UProgram {
|
||||
UInstruction::Ret { .. } => {}
|
||||
UInstruction::Construct { dest, fields } => {
|
||||
let dest_ty = get(vars, dest.id)?;
|
||||
let Type::Struct { id, args } = dest_ty else {
|
||||
let Type::Struct(sty) = dest_ty else {
|
||||
break 'outer;
|
||||
};
|
||||
let id = *id;
|
||||
let id = sty.id;
|
||||
let Some(struc) = self.get(id) else {
|
||||
break 'outer;
|
||||
};
|
||||
@@ -149,7 +138,7 @@ impl UProgram {
|
||||
continue;
|
||||
};
|
||||
let src_ty = get(vars, src.id)?;
|
||||
if let Some(ty) = match_types(&field.ty, src_ty) {
|
||||
if let Some(ty) = self.match_types(&field.ty, src_ty) {
|
||||
if let Type::Generic { id } = field.ty {
|
||||
new.insert(id, ty.clone());
|
||||
}
|
||||
@@ -166,7 +155,7 @@ impl UProgram {
|
||||
args[i] = ty;
|
||||
}
|
||||
}
|
||||
set(vars, dest.id, Type::Struct { id, args });
|
||||
set(vars, dest.id, Type::Struct(StructTy { id, args }));
|
||||
}
|
||||
UInstruction::If { cond, body: _ } => {}
|
||||
UInstruction::Loop { body: _ } => {}
|
||||
@@ -174,28 +163,10 @@ impl UProgram {
|
||||
UInstruction::Continue => {}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Some(())
|
||||
}
|
||||
|
||||
pub fn get(vars: &[Option<UVar>], id: VarID) -> Result<&Type, VarID> {
|
||||
let var = vars[id.0]
|
||||
.as_ref()
|
||||
.expect("PARTIAL BORROWING WOULD BE REALLY COOL");
|
||||
if var.ty == Type::Placeholder {
|
||||
return Err(id);
|
||||
}
|
||||
Ok(&var.ty)
|
||||
}
|
||||
|
||||
pub fn set(vars: &mut [Option<UVar>], id: VarID, ty: Type) {
|
||||
vars[id.0]
|
||||
.as_mut()
|
||||
.expect("PARTIAL BORROWING WOULD BE REALLY COOL")
|
||||
.ty = ty;
|
||||
}
|
||||
|
||||
pub fn match_types(dest: &Type, src: &Type) -> Option<Type> {
|
||||
pub fn match_types(&self, dest: &Type, src: &Type) -> Option<Type> {
|
||||
if dest == src {
|
||||
return None;
|
||||
}
|
||||
@@ -205,23 +176,14 @@ pub fn match_types(dest: &Type, src: &Type) -> Option<Type> {
|
||||
(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 {
|
||||
id: dest_id,
|
||||
args: dest_args,
|
||||
},
|
||||
Type::Struct {
|
||||
id: src_id,
|
||||
args: src_args,
|
||||
},
|
||||
) => {
|
||||
if dest_id != src_id {
|
||||
(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) = match_types(darg, sarg) {
|
||||
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 {
|
||||
@@ -231,7 +193,7 @@ pub fn match_types(dest: &Type, src: &Type) -> Option<Type> {
|
||||
}
|
||||
}
|
||||
if changed {
|
||||
Some(Type::Struct { id: *dest_id, args })
|
||||
Some(Type::Struct(StructTy { id: dest.id, args }))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@@ -249,14 +211,45 @@ pub fn match_types(dest: &Type, src: &Type) -> Option<Type> {
|
||||
// TODO
|
||||
None
|
||||
}
|
||||
(Type::Ref(dest), Type::Ref(src)) => Some(match_types(dest, src)?.rf()),
|
||||
(Type::Slice(dest), Type::Slice(src)) => Some(match_types(dest, src)?.slice()),
|
||||
(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(match_types(dest, src)?.arr(*dlen))
|
||||
Some(self.match_types(dest, src)?.arr(*dlen))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get(vars: &[Option<UVar>], id: VarID) -> Option<&Type> {
|
||||
let mut var = vars[id.0]
|
||||
.as_ref()
|
||||
.expect("PARTIAL BORROWING WOULD BE REALLY COOL");
|
||||
if var.ty == Type::Placeholder {
|
||||
return None;
|
||||
}
|
||||
while let Type::Member(m) = &var.ty {
|
||||
var = vars[m.parent.0].as_ref().expect("xd");
|
||||
}
|
||||
// x.y().z == a.b.c()
|
||||
// 0 ------- member(1, z)
|
||||
// 1 ----- call(2)
|
||||
// 2 --- member(3, y)
|
||||
// 3 - x
|
||||
//
|
||||
// 0 ------- call(1)
|
||||
// 1 ----- member(c, 2)
|
||||
// 2 --- member(b, 3)
|
||||
// 3 - a
|
||||
Some(&var.ty)
|
||||
}
|
||||
|
||||
pub fn set(vars: &mut [Option<UVar>], id: VarID, ty: Type) {
|
||||
vars[id.0]
|
||||
.as_mut()
|
||||
.expect("PARTIAL BORROWING WOULD BE REALLY COOL")
|
||||
.ty = ty;
|
||||
}
|
||||
|
||||
@@ -3,14 +3,13 @@ use super::{Type, UInstrInst, UInstruction, UProgram};
|
||||
use crate::common::{CompilerMsg, CompilerOutput, FileSpan};
|
||||
|
||||
impl UProgram {
|
||||
pub fn validate(&self) -> CompilerOutput {
|
||||
let mut output = CompilerOutput::new();
|
||||
pub fn validate(&self, output: &mut CompilerOutput) {
|
||||
for (id, f) in self.iter_fns() {
|
||||
self.validate_fn(
|
||||
&f.instructions,
|
||||
self.origins.get(id),
|
||||
&f.ret,
|
||||
&mut output,
|
||||
output,
|
||||
true,
|
||||
false,
|
||||
);
|
||||
@@ -46,7 +45,6 @@ impl UProgram {
|
||||
}
|
||||
}
|
||||
}
|
||||
output
|
||||
}
|
||||
|
||||
pub fn validate_fn(
|
||||
|
||||
75
src/main.rs
75
src/main.rs
@@ -7,13 +7,16 @@
|
||||
|
||||
pub const FILE_EXT: &str = "lang";
|
||||
|
||||
use common::{CompilerOutput, SrcFile};
|
||||
use ir::{LProgram, UProgram};
|
||||
use parser::{PModule, ParseResult, ParserCtx};
|
||||
use parser::{Import, Imports, PModule, ParseResult, ParserCtx};
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
ffi::OsString,
|
||||
fs::{create_dir_all, OpenOptions},
|
||||
io::{stdout, BufRead, BufReader},
|
||||
os::unix::fs::OpenOptionsExt,
|
||||
path::Path,
|
||||
path::{Path, PathBuf},
|
||||
process::Command,
|
||||
};
|
||||
|
||||
@@ -29,29 +32,63 @@ fn main() {
|
||||
let gdb = std::env::args().nth(2).is_some_and(|a| a == "--debug");
|
||||
let asm = std::env::args().nth(2).is_some_and(|a| a == "--asm");
|
||||
if let Some(path) = file {
|
||||
let file = std::fs::read_to_string(path).expect("failed to read file");
|
||||
run_file(&file, gdb, asm);
|
||||
let path = PathBuf::from(path);
|
||||
run_file(&path, gdb, asm);
|
||||
} else {
|
||||
run_stdin();
|
||||
}
|
||||
}
|
||||
|
||||
fn run_file(file: &str, gdb: bool, asm: bool) {
|
||||
let mut ctx = ParserCtx::from(file);
|
||||
let res = PModule::parse(&mut ctx);
|
||||
let mut output = ctx.output;
|
||||
'outer: {
|
||||
if !output.errs.is_empty() {
|
||||
break 'outer;
|
||||
impl UProgram {
|
||||
pub fn from_path(path: &Path) -> (Self, CompilerOutput) {
|
||||
let parent = path.parent().expect("bruh");
|
||||
let mut program = Self::new();
|
||||
let mut output = CompilerOutput::new();
|
||||
|
||||
let mut imports = Imports::new();
|
||||
imports.insert(Import(
|
||||
path.file_name()
|
||||
.expect("bruh")
|
||||
.to_str()
|
||||
.expect("bruh")
|
||||
.to_string(),
|
||||
));
|
||||
let mut imported = HashSet::new();
|
||||
let mut fid = 0;
|
||||
|
||||
while !imports.is_empty() {
|
||||
let iter = std::mem::take(&mut imports);
|
||||
for i in iter {
|
||||
let name = &i.0;
|
||||
if imported.contains(&i) {
|
||||
continue;
|
||||
}
|
||||
let path = parent.join(name).with_extension(FILE_EXT);
|
||||
let text = std::fs::read_to_string(&path).expect("failed to read file");
|
||||
output.file_map.insert(
|
||||
fid,
|
||||
SrcFile {
|
||||
path,
|
||||
text: text.clone(),
|
||||
},
|
||||
);
|
||||
let mut ctx = ParserCtx::new(fid, text.as_str(), &mut output);
|
||||
fid += 1;
|
||||
let res = PModule::parse(&mut ctx);
|
||||
// println!("Parsed:");
|
||||
// println!("{:#?}", res.node);
|
||||
let mut program = UProgram::new();
|
||||
res.lower("crate".to_string(), &mut program, &mut output);
|
||||
if !output.errs.is_empty() {
|
||||
break 'outer;
|
||||
res.lower(name.clone(), &mut program, &mut imports, &mut output);
|
||||
imported.insert(i);
|
||||
}
|
||||
}
|
||||
(program, output)
|
||||
}
|
||||
}
|
||||
|
||||
fn run_file(path: &Path, gdb: bool, asm: bool) {
|
||||
let (mut program, mut output) = UProgram::from_path(path);
|
||||
program.resolve_types();
|
||||
program.validate(&mut output);
|
||||
// println!("vars:");
|
||||
// for (id, def) in program.iter_vars() {
|
||||
// println!(" {id:?} = {}: {}", program.names.path(id), program.type_name(&def.ty));
|
||||
@@ -59,11 +96,10 @@ fn run_file(file: &str, gdb: bool, asm: bool) {
|
||||
// for (id, f) in program.iter_fns() {
|
||||
// println!("{}:{id:?} = {:#?}", program.names.path(id), f);
|
||||
// }
|
||||
output = program.validate();
|
||||
if !output.errs.is_empty() {
|
||||
break 'outer;
|
||||
output.write_to(&mut stdout());
|
||||
return;
|
||||
}
|
||||
output.write_for(&mut stdout(), file);
|
||||
let program = LProgram::create(&program).expect("morir");
|
||||
let unlinked = compiler::compile(&program);
|
||||
if asm {
|
||||
@@ -73,8 +109,7 @@ fn run_file(file: &str, gdb: bool, asm: bool) {
|
||||
println!("compiled");
|
||||
save_run(&bin, gdb);
|
||||
}
|
||||
}
|
||||
output.write_for(&mut stdout(), file);
|
||||
output.write_to(&mut stdout());
|
||||
}
|
||||
|
||||
fn save_run(binary: &[u8], run_gdb: bool) {
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
use crate::common::FileID;
|
||||
|
||||
use super::{
|
||||
MaybeParsable, Node, NodeParseResult, Parsable, ParsableWith, CompilerMsg, CompilerOutput,
|
||||
CompilerMsg, CompilerOutput, MaybeParsable, Node, NodeParseResult, Parsable, ParsableWith,
|
||||
TokenCursor,
|
||||
};
|
||||
|
||||
pub struct ParserCtx<'a> {
|
||||
pub cursor: TokenCursor<'a>,
|
||||
pub output: CompilerOutput,
|
||||
pub output: &'a mut CompilerOutput,
|
||||
}
|
||||
|
||||
impl<'a> Deref for ParserCtx<'a> {
|
||||
@@ -40,22 +42,10 @@ impl<'a> ParserCtx<'a> {
|
||||
pub fn maybe_parse<T: MaybeParsable>(&mut self) -> Option<Node<T>> {
|
||||
Node::maybe_parse(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<TokenCursor<'a>> for ParserCtx<'a> {
|
||||
fn from(cursor: TokenCursor<'a>) -> Self {
|
||||
pub fn new(file: FileID, string: &'a str, output: &'a mut CompilerOutput) -> Self {
|
||||
Self {
|
||||
cursor,
|
||||
output: CompilerOutput::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a str> for ParserCtx<'a> {
|
||||
fn from(string: &'a str) -> Self {
|
||||
Self {
|
||||
cursor: TokenCursor::from(string),
|
||||
output: CompilerOutput::new(),
|
||||
cursor: TokenCursor::from_file_str(file, string),
|
||||
output,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
use crate::common::FileID;
|
||||
|
||||
use super::{
|
||||
token::{CharCursor, Keyword, Symbol, Token, TokenInstance},
|
||||
CompilerMsg, FilePos,
|
||||
@@ -17,7 +19,7 @@ impl<'a> TokenCursor<'a> {
|
||||
self.next_start = next
|
||||
.as_ref()
|
||||
.map(|i| i.span.end)
|
||||
.unwrap_or(FilePos::start());
|
||||
.unwrap_or(FilePos::start(self.file()));
|
||||
std::mem::replace(&mut self.next, next)
|
||||
}
|
||||
pub fn expect_next(&mut self) -> Result<TokenInstance, CompilerMsg> {
|
||||
@@ -78,11 +80,11 @@ impl<'a> TokenCursor<'a> {
|
||||
pub fn next_start(&self) -> FilePos {
|
||||
self.next_start
|
||||
}
|
||||
pub fn from_file_str(id: FileID, string: &'a str) -> Self {
|
||||
Self::from(CharCursor::from_file_str(id, string))
|
||||
}
|
||||
|
||||
impl<'a> From<&'a str> for TokenCursor<'a> {
|
||||
fn from(string: &'a str) -> Self {
|
||||
Self::from(CharCursor::from(string))
|
||||
pub fn file(&self) -> FileID {
|
||||
self.cursor.file()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,10 +92,10 @@ impl<'a> From<CharCursor<'a>> for TokenCursor<'a> {
|
||||
fn from(mut cursor: CharCursor<'a>) -> Self {
|
||||
let cur = TokenInstance::parse(&mut cursor);
|
||||
Self {
|
||||
next_start: FilePos::start(cursor.file()),
|
||||
prev_end: FilePos::start(cursor.file()),
|
||||
cursor,
|
||||
next: cur,
|
||||
next_start: FilePos::start(),
|
||||
prev_end: FilePos::start(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
5
src/parser/v3/import.rs
Normal file
5
src/parser/v3/import.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
use std::collections::HashSet;
|
||||
|
||||
#[derive(Clone, Eq, PartialEq, Hash)]
|
||||
pub struct Import(pub Vec<String>);
|
||||
pub type Imports = HashSet<Import>;
|
||||
@@ -1,14 +1,13 @@
|
||||
use crate::{
|
||||
ir::{Type, UInstruction, VarInst},
|
||||
ir::{Type, UInstruction, UVar, VarInst},
|
||||
parser::{PConstStatement, PStatementLike},
|
||||
};
|
||||
|
||||
use super::{import::Import, FnLowerCtx, FnLowerable, PBlock, PStatement};
|
||||
use super::{FnLowerCtx, FnLowerable, Import, PBlock, PStatement};
|
||||
|
||||
impl FnLowerable for PBlock {
|
||||
type Output = VarInst;
|
||||
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<VarInst> {
|
||||
ctx.program.push();
|
||||
let mut last = None;
|
||||
let mut statements = Vec::new();
|
||||
let mut fn_nodes = Vec::new();
|
||||
@@ -29,12 +28,26 @@ impl FnLowerable for PBlock {
|
||||
}
|
||||
}
|
||||
// then lower imports
|
||||
for i in &import_nodes {
|
||||
if let Some(i) = i.as_ref() {
|
||||
let import = Import(i.0.clone());
|
||||
ctx.imports.push(import);
|
||||
for i_n in &import_nodes {
|
||||
if let Some(i) = i_n.as_ref() {
|
||||
let name = &i.0;
|
||||
let import = Import(ctx.program.path_for(name));
|
||||
ctx
|
||||
.imports
|
||||
.entry(import)
|
||||
.or_insert(ctx.program.def(name, None, i_n.origin));
|
||||
// I could prevent this if someone imports something twice,
|
||||
// but that doesn't seem worth it at all
|
||||
ctx.program.def_searchable::<UVar>(
|
||||
name.clone(),
|
||||
Some(UVar {
|
||||
ty: Type::Module,
|
||||
}),
|
||||
i_n.origin,
|
||||
);
|
||||
}
|
||||
}
|
||||
ctx.program.push();
|
||||
// then lower const things
|
||||
let mut structs = Vec::new();
|
||||
for s in &struct_nodes {
|
||||
|
||||
@@ -15,7 +15,7 @@ impl Node<PVarDef> {
|
||||
None => Type::Infer,
|
||||
};
|
||||
Some(VarInst {
|
||||
id: program.def_searchable(name, Some(UVar { ty, parent: None }), self.origin),
|
||||
id: program.def_searchable(name, Some(UVar { ty }), self.origin),
|
||||
span: self.origin,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use super::{func::FnLowerCtx, FnLowerable, PExpr, UnaryOp};
|
||||
use crate::{
|
||||
ir::{FieldRef, Type, UData, UInstruction, VarInst},
|
||||
ir::{MemberRef, Type, UData, UInstruction, VarInst},
|
||||
parser::PInfixOp,
|
||||
};
|
||||
|
||||
@@ -69,13 +69,10 @@ impl FnLowerable for PExpr {
|
||||
return None;
|
||||
};
|
||||
let fname = ident.as_ref()?.0.clone();
|
||||
ctx.temp_subvar(
|
||||
Type::Placeholder,
|
||||
FieldRef {
|
||||
var: res1.id,
|
||||
field: fname,
|
||||
},
|
||||
)
|
||||
ctx.temp(Type::Member(MemberRef {
|
||||
parent: res1.id,
|
||||
name: fname,
|
||||
}))
|
||||
}
|
||||
PInfixOp::Assign => {
|
||||
let res1 = e1.lower(ctx)?;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use super::{import::Import, CompilerMsg, CompilerOutput, FileSpan, FnLowerable, Node, PFunction};
|
||||
use super::{Imports, CompilerMsg, CompilerOutput, FileSpan, FnLowerable, Node, PFunction};
|
||||
use crate::{
|
||||
ir::{FieldRef, FnID, Idents, Type, UFunc, UInstrInst, UInstruction, UProgram, UVar, VarInst},
|
||||
ir::{MemberRef, FnID, Idents, Type, UFunc, UInstrInst, UInstruction, UProgram, UVar, VarInst},
|
||||
parser,
|
||||
};
|
||||
|
||||
@@ -8,7 +8,13 @@ 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, imports: &mut Vec<Import>, output: &mut CompilerOutput) {
|
||||
pub fn lower(
|
||||
&self,
|
||||
id: FnID,
|
||||
p: &mut UProgram,
|
||||
imports: &mut Imports,
|
||||
output: &mut CompilerOutput,
|
||||
) {
|
||||
if let Some(s) = self.as_ref() {
|
||||
s.lower(id, p, imports, output)
|
||||
}
|
||||
@@ -22,7 +28,13 @@ impl PFunction {
|
||||
let id = p.def_searchable(name.to_string(), None, self.header.origin);
|
||||
Some(id)
|
||||
}
|
||||
pub fn lower(&self, id: FnID, p: &mut UProgram, imports: &mut Vec<Import>, output: &mut CompilerOutput) {
|
||||
pub fn lower(
|
||||
&self,
|
||||
id: FnID,
|
||||
p: &mut UProgram,
|
||||
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() {
|
||||
@@ -69,7 +81,7 @@ pub struct FnLowerCtx<'a> {
|
||||
pub instructions: Vec<UInstrInst>,
|
||||
pub output: &'a mut CompilerOutput,
|
||||
pub origin: FileSpan,
|
||||
pub imports: &'a mut Vec<Import>
|
||||
pub imports: &'a mut Imports,
|
||||
}
|
||||
|
||||
impl FnLowerCtx<'_> {
|
||||
@@ -103,9 +115,6 @@ impl FnLowerCtx<'_> {
|
||||
pub fn temp(&mut self, ty: Type) -> VarInst {
|
||||
self.program.temp_var(self.origin, ty)
|
||||
}
|
||||
pub fn temp_subvar(&mut self, ty: Type, parent: FieldRef) -> VarInst {
|
||||
self.program.temp_subvar(self.origin, ty, parent)
|
||||
}
|
||||
pub fn push(&mut self, i: UInstruction) {
|
||||
self.push_at(i, self.origin);
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
pub struct Import(pub String);
|
||||
@@ -6,21 +6,26 @@ mod expr;
|
||||
mod func;
|
||||
mod struc;
|
||||
mod ty;
|
||||
mod import;
|
||||
|
||||
use super::*;
|
||||
use crate::ir::{Type, UFunc, UProgram};
|
||||
|
||||
impl PModule {
|
||||
pub fn lower(&self, name: String, p: &mut UProgram, output: &mut CompilerOutput) {
|
||||
let id = p.def_searchable(name.clone(), None, self.block.origin);
|
||||
pub fn lower(
|
||||
&self,
|
||||
name: String,
|
||||
p: &mut UProgram,
|
||||
imports: &mut Imports,
|
||||
output: &mut CompilerOutput,
|
||||
) {
|
||||
let fid = p.def_searchable(name.clone(), None, self.block.origin);
|
||||
p.push_name(&name);
|
||||
let mut fctx = FnLowerCtx {
|
||||
program: p,
|
||||
instructions: Vec::new(),
|
||||
output,
|
||||
origin: self.block.origin,
|
||||
imports: Vec::new(),
|
||||
imports,
|
||||
};
|
||||
self.block.lower(&mut fctx);
|
||||
let f = UFunc {
|
||||
@@ -28,12 +33,13 @@ impl PModule {
|
||||
instructions: fctx.instructions,
|
||||
ret: Type::Unit,
|
||||
};
|
||||
p.write(id, f);
|
||||
p.write(fid, f);
|
||||
p.pop_name();
|
||||
}
|
||||
}
|
||||
|
||||
pub use func::FnLowerCtx;
|
||||
use import::Imports;
|
||||
|
||||
pub trait FnLowerable {
|
||||
type Output;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
ir::{GenericID, Type, UGeneric, UProgram, UStruct},
|
||||
ir::{GenericID, StructTy, Type, UGeneric, UProgram, UStruct},
|
||||
parser::PGenericDef,
|
||||
};
|
||||
|
||||
@@ -24,7 +24,7 @@ impl PType {
|
||||
Type::Generic { id }
|
||||
} else if let Some(id) = ids.and_then(|ids| ids.get::<UStruct>()) {
|
||||
let args = self.args.iter().map(|n| n.lower(p, output)).collect();
|
||||
Type::Struct { id, args }
|
||||
Type::Struct(StructTy { id, args })
|
||||
} else if let Ok(num) = name.parse::<u32>() {
|
||||
Type::Bits(num)
|
||||
} else {
|
||||
|
||||
@@ -6,6 +6,7 @@ mod node;
|
||||
mod nodes;
|
||||
mod parse;
|
||||
mod token;
|
||||
mod import;
|
||||
|
||||
use crate::common::{CompilerMsg, CompilerOutput, FileSpan, FilePos};
|
||||
pub use ctx::*;
|
||||
@@ -14,6 +15,7 @@ pub use node::*;
|
||||
pub use nodes::*;
|
||||
pub use parse::*;
|
||||
pub use token::*;
|
||||
pub use import::*;
|
||||
|
||||
// idea: create generic "map" and "tuple" types which are used for function calls, tuples, struct
|
||||
// creation, etc. instead of specializing at the parsing level
|
||||
|
||||
@@ -133,7 +133,7 @@ impl<T: Parsable> ParsableWith for T {
|
||||
|
||||
impl<T: ParsableWith> Node<T> {
|
||||
pub fn parse_with(ctx: &mut ParserCtx, data: T::Data) -> NodeParseResult<T> {
|
||||
let start = ctx.peek().map(|t| t.span.start).unwrap_or(FilePos::start());
|
||||
let start = ctx.peek().map(|t| t.span.start).unwrap_or(FilePos::start(ctx.cursor.file()));
|
||||
let (inner, recover) = match T::parse(ctx, data) {
|
||||
ParseResult::Ok(v) => (Some(v), false),
|
||||
ParseResult::Recover(v) => (Some(v), true),
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
use std::{iter::Peekable, str::Chars};
|
||||
|
||||
use crate::common::FileID;
|
||||
|
||||
use super::super::{CompilerMsg, FilePos};
|
||||
|
||||
pub struct CharCursor<'a> {
|
||||
file: FileID,
|
||||
chars: Peekable<Chars<'a>>,
|
||||
next_pos: FilePos,
|
||||
prev_pos: FilePos,
|
||||
}
|
||||
|
||||
impl CharCursor<'_> {
|
||||
impl<'a> CharCursor<'a> {
|
||||
pub fn next(&mut self) -> Option<char> {
|
||||
let res = self.peek()?;
|
||||
self.advance();
|
||||
@@ -54,14 +57,15 @@ impl CharCursor<'_> {
|
||||
pub fn prev_pos(&self) -> FilePos {
|
||||
self.prev_pos
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a str> for CharCursor<'a> {
|
||||
fn from(value: &'a str) -> Self {
|
||||
pub fn from_file_str(file: FileID, value: &'a str) -> Self {
|
||||
Self {
|
||||
chars: value.chars().peekable(),
|
||||
next_pos: FilePos::start(),
|
||||
prev_pos: FilePos::start(),
|
||||
next_pos: FilePos::start(file),
|
||||
prev_pos: FilePos::start(file),
|
||||
file,
|
||||
}
|
||||
}
|
||||
pub fn file(&self) -> FileID {
|
||||
self.file
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,10 +4,10 @@ mod symbol;
|
||||
|
||||
use std::ops::Deref;
|
||||
|
||||
use super::FileSpan;
|
||||
pub use cursor::*;
|
||||
pub use keyword::*;
|
||||
pub use symbol::*;
|
||||
use super::FileSpan;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
pub enum Token {
|
||||
@@ -35,7 +35,11 @@ impl TokenInstance {
|
||||
let end = cursor.prev_pos();
|
||||
return Some(Self {
|
||||
token: Token::Symbol(s),
|
||||
span: FileSpan { start, end },
|
||||
span: FileSpan {
|
||||
start,
|
||||
end,
|
||||
file: cursor.file(),
|
||||
},
|
||||
});
|
||||
}
|
||||
let mut word = String::new();
|
||||
@@ -54,7 +58,11 @@ impl TokenInstance {
|
||||
};
|
||||
Some(Self {
|
||||
token,
|
||||
span: FileSpan { start, end },
|
||||
span: FileSpan {
|
||||
start,
|
||||
end,
|
||||
file: cursor.file(),
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user