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