I can see the light
This commit is contained in:
@@ -3,8 +3,7 @@ use std::ops::{Deref, DerefMut};
|
||||
use crate::common::FileID;
|
||||
|
||||
use super::{
|
||||
CompilerMsg, CompilerOutput, MaybeParsable, Node, NodeParseResult, Parsable, ParsableWith,
|
||||
ParseResult, TokenCursor,
|
||||
CompilerMsg, CompilerOutput, Node, NodeParseResult, Parsable, ParsableWith, TokenCursor,
|
||||
};
|
||||
|
||||
pub struct ParserCtx<'a> {
|
||||
@@ -36,12 +35,15 @@ impl<'a> ParserCtx<'a> {
|
||||
pub fn parse<T: Parsable>(&mut self) -> NodeParseResult<T> {
|
||||
Node::parse(self)
|
||||
}
|
||||
pub fn maybe_parse<T>(&mut self) -> Option<NodeParseResult<T>>
|
||||
where
|
||||
Option<T>: Parsable,
|
||||
{
|
||||
Node::maybe_parse(self)
|
||||
}
|
||||
pub fn parse_with<T: ParsableWith>(&mut self, data: T::Data) -> NodeParseResult<T> {
|
||||
Node::parse_with(self, data)
|
||||
}
|
||||
pub fn maybe_parse<T: MaybeParsable>(&mut self) -> Option<Node<T>> {
|
||||
Node::maybe_parse(self)
|
||||
}
|
||||
pub fn new(file: FileID, string: &'a str, output: &'a mut CompilerOutput) -> Self {
|
||||
Self {
|
||||
cursor: TokenCursor::from_file_str(file, string),
|
||||
|
||||
@@ -27,15 +27,15 @@ impl FnLowerable for PBlock {
|
||||
},
|
||||
}
|
||||
}
|
||||
ctx.program.push();
|
||||
ctx.b.push();
|
||||
// then lower imports
|
||||
for i_n in &import_nodes {
|
||||
if let Some(i) = i_n.as_ref() {
|
||||
let name = &i.0;
|
||||
let path = ctx.program.path_for(name);
|
||||
let path = ctx.b.path_for(name);
|
||||
let import = Import(path.clone());
|
||||
if ctx.imports.insert(import) {
|
||||
ctx.program.def_searchable::<UVar>(
|
||||
ctx.b.def_searchable::<UVar>(
|
||||
name,
|
||||
Some(UVar {
|
||||
ty: Type::Module(path),
|
||||
@@ -48,27 +48,27 @@ impl FnLowerable for PBlock {
|
||||
// then lower const things
|
||||
let mut structs = Vec::new();
|
||||
for s in &struct_nodes {
|
||||
structs.push(s.lower_name(ctx.program));
|
||||
structs.push(s.lower_name(ctx.b));
|
||||
}
|
||||
for (s, id) in struct_nodes.iter().zip(structs) {
|
||||
if let Some(id) = id {
|
||||
s.lower(id, ctx.program, ctx.output);
|
||||
s.lower(id, ctx.b, ctx.output);
|
||||
}
|
||||
}
|
||||
let mut fns = Vec::new();
|
||||
for f in &fn_nodes {
|
||||
fns.push(f.lower_name(ctx.program));
|
||||
fns.push(f.lower_name(ctx.b));
|
||||
}
|
||||
for (f, id) in fn_nodes.iter().zip(fns) {
|
||||
if let Some(id) = id {
|
||||
f.lower(id, ctx.program, ctx.imports, ctx.output)
|
||||
f.lower(id, ctx.b, ctx.imports, ctx.output)
|
||||
}
|
||||
}
|
||||
// then lower statements
|
||||
for s in statements {
|
||||
last = s.lower(ctx);
|
||||
}
|
||||
ctx.program.pop();
|
||||
ctx.b.pop();
|
||||
last
|
||||
}
|
||||
}
|
||||
@@ -78,11 +78,11 @@ impl FnLowerable for PStatement {
|
||||
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<VarInst> {
|
||||
match self {
|
||||
PStatement::Let(def, e) => {
|
||||
let def = def.lower(ctx.program, ctx.output)?;
|
||||
let def = def.lower(ctx.b, ctx.output)?;
|
||||
let res = e.lower(ctx);
|
||||
if let Some(res) = res {
|
||||
ctx.push(UInstruction::Mv {
|
||||
dest: def,
|
||||
dst: def,
|
||||
src: res,
|
||||
});
|
||||
}
|
||||
@@ -91,10 +91,10 @@ impl FnLowerable for PStatement {
|
||||
PStatement::Return(e) => {
|
||||
if let Some(e) = e {
|
||||
let src = e.lower(ctx)?;
|
||||
ctx.push_at(UInstruction::Ret { src }, src.span);
|
||||
ctx.push_at(UInstruction::Ret { src }, src.origin);
|
||||
} else {
|
||||
let src = ctx.temp(Type::Unit);
|
||||
ctx.push_at(UInstruction::Ret { src }, src.span);
|
||||
ctx.push_at(UInstruction::Ret { src }, src.origin);
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
@@ -1,21 +1,18 @@
|
||||
use crate::ir::{Type, UProgram, UVar, VarInst};
|
||||
use crate::ir::{UProgram, UVar, VarInst};
|
||||
|
||||
use super::{CompilerOutput, Node, PVarDef};
|
||||
|
||||
impl Node<PVarDef> {
|
||||
pub fn lower(&self, program: &mut UProgram, output: &mut CompilerOutput) -> Option<VarInst> {
|
||||
let s = self.as_ref()?;
|
||||
let name = s
|
||||
.name
|
||||
.as_ref()
|
||||
.map_or("{error}", |v| v);
|
||||
let name = s.name.as_ref().map_or("{error}", |v| v);
|
||||
let ty = match &s.ty {
|
||||
Some(ty) => ty.lower(program, output),
|
||||
None => Type::Infer,
|
||||
None => program.infer(self.origin),
|
||||
};
|
||||
Some(VarInst {
|
||||
id: program.def_searchable(name, Some(UVar { ty }), self.origin),
|
||||
span: self.origin,
|
||||
origin: self.origin,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
+65
-77
@@ -1,60 +1,61 @@
|
||||
use super::{func::FnLowerCtx, FnLowerable, PExpr, PostfixOp};
|
||||
use crate::{
|
||||
ir::{FieldRef, Type, UData, UInstruction, VarInst},
|
||||
ir::{Type, UData, UInstruction, VarInst},
|
||||
parser::InfixOp,
|
||||
};
|
||||
|
||||
impl FnLowerable for PExpr {
|
||||
type Output = VarInst;
|
||||
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<VarInst> {
|
||||
Some(match self {
|
||||
PExpr::Lit(l) => match l.as_ref()? {
|
||||
let mut e = self;
|
||||
let mut path = Vec::new();
|
||||
while let PExpr::Member(node, ident) = e {
|
||||
e = if let Some(t) = node.as_ref() {
|
||||
path.push(ident);
|
||||
&**t
|
||||
} else {
|
||||
return None;
|
||||
};
|
||||
}
|
||||
Some(match e {
|
||||
PExpr::Lit(l) => match l {
|
||||
super::PLiteral::String(s) => {
|
||||
let dest = ctx.program.temp_var(l.origin, Type::Bits(8).slice());
|
||||
let dest = ctx.b.temp_var(ctx.origin, Type::Bits(8).slice());
|
||||
let data = s.as_bytes().to_vec();
|
||||
let src = ctx.program.def(
|
||||
&format!("string \"{}\"", s.replace("\n", "\\n")),
|
||||
Some(UData {
|
||||
ty: Type::Bits(8).arr(data.len() as u32),
|
||||
content: data,
|
||||
}),
|
||||
l.origin,
|
||||
);
|
||||
ctx.push(UInstruction::LoadSlice { dest, src });
|
||||
let src = ctx.b.def_data(UData {
|
||||
name: format!("string \"{}\"", s.replace("\n", "\\n")),
|
||||
ty: Type::Bits(8).arr(data.len() as u32),
|
||||
content: data,
|
||||
});
|
||||
ctx.push(UInstruction::LoadSlice { dst: dest, src });
|
||||
dest
|
||||
}
|
||||
super::PLiteral::Char(c) => {
|
||||
let ty = Type::Bits(8);
|
||||
let dest = ctx.program.temp_var(l.origin, ty.clone());
|
||||
let src = ctx.program.def(
|
||||
&format!("char '{c}'"),
|
||||
Some(UData {
|
||||
ty,
|
||||
content: c.to_string().as_bytes().to_vec(),
|
||||
}),
|
||||
l.origin,
|
||||
);
|
||||
ctx.push(UInstruction::LoadData { dest, src });
|
||||
let dest = ctx.b.temp_var(ctx.origin, ty.clone());
|
||||
let src = ctx.b.def_data(UData {
|
||||
name: format!("char '{c}'"),
|
||||
ty,
|
||||
content: c.to_string().as_bytes().to_vec(),
|
||||
});
|
||||
ctx.push(UInstruction::LoadData { dst: dest, src });
|
||||
dest
|
||||
}
|
||||
super::PLiteral::Number(n) => {
|
||||
// TODO: temp
|
||||
let ty = Type::Bits(64);
|
||||
let dest = ctx.program.temp_var(l.origin, ty.clone());
|
||||
let src = ctx.program.def(
|
||||
&format!("num {n:?}"),
|
||||
Some(UData {
|
||||
ty,
|
||||
content: n.whole.parse::<i64>().unwrap().to_le_bytes().to_vec(),
|
||||
}),
|
||||
l.origin,
|
||||
);
|
||||
ctx.push(UInstruction::LoadData { dest, src });
|
||||
let dest = ctx.b.temp_var(ctx.origin, ty.clone());
|
||||
let src = ctx.b.def_data(UData {
|
||||
name: format!("num {n:?}"),
|
||||
ty,
|
||||
content: n.whole.parse::<i64>().unwrap().to_le_bytes().to_vec(),
|
||||
});
|
||||
ctx.push(UInstruction::LoadData { dst: dest, src });
|
||||
dest
|
||||
}
|
||||
super::PLiteral::Unit => ctx.program.temp_var(l.origin, Type::Unit),
|
||||
super::PLiteral::Unit => ctx.b.temp_var(ctx.origin, Type::Unit),
|
||||
},
|
||||
PExpr::Ident(i) => ctx.get_var(i)?,
|
||||
PExpr::Ident(i) => ctx.get_var(i),
|
||||
PExpr::BinaryOp(op, e1, e2) => match op {
|
||||
InfixOp::Add => todo!(),
|
||||
InfixOp::Sub => todo!(),
|
||||
@@ -62,49 +63,30 @@ impl FnLowerable for PExpr {
|
||||
InfixOp::Div => todo!(),
|
||||
InfixOp::LessThan => todo!(),
|
||||
InfixOp::GreaterThan => todo!(),
|
||||
InfixOp::Member => {
|
||||
let res1 = e1.lower(ctx)?;
|
||||
let Some(box PExpr::Ident(ident)) = &e2.inner else {
|
||||
ctx.err("Field accessors must be identifiers".to_string());
|
||||
return None;
|
||||
};
|
||||
let fname = ident.as_ref()?.0.clone();
|
||||
ctx.temp(Type::Field(FieldRef {
|
||||
parent: res1.id,
|
||||
name: fname,
|
||||
}))
|
||||
}
|
||||
InfixOp::Assign => {
|
||||
let res1 = e1.lower(ctx)?;
|
||||
let res2 = e2.lower(ctx)?;
|
||||
ctx.push(UInstruction::Mv {
|
||||
dest: res1,
|
||||
dst: res1,
|
||||
src: res2,
|
||||
});
|
||||
res1
|
||||
}
|
||||
},
|
||||
PExpr::PostfixOp(op, e) => {
|
||||
PExpr::PostfixOp(e, op) => {
|
||||
let res = e.lower(ctx)?;
|
||||
match op {
|
||||
PostfixOp::Ref => {
|
||||
let temp = ctx.temp(ctx.program.expect(res.id).ty.clone().rf());
|
||||
ctx.push(UInstruction::Ref {
|
||||
dest: temp,
|
||||
src: res,
|
||||
});
|
||||
temp
|
||||
let ty = ctx.b.vars[res.id].ty.rf();
|
||||
let dest = ctx.temp(ty);
|
||||
ctx.push(UInstruction::Ref { dst: dest, src: res });
|
||||
dest
|
||||
}
|
||||
PostfixOp::Deref => {
|
||||
let t = &ctx.program.expect(res.id).ty;
|
||||
let Type::Ref(_) = t else {
|
||||
ctx.err(format!(
|
||||
"Cannot dereference type {:?}",
|
||||
ctx.program.type_name(t)
|
||||
));
|
||||
return None;
|
||||
};
|
||||
todo!();
|
||||
let ty = ctx.b.vars[res.id].ty.derf();
|
||||
let dest = ctx.temp(ty);
|
||||
ctx.push(UInstruction::Deref { dst: dest, src: res });
|
||||
dest
|
||||
}
|
||||
PostfixOp::Not => todo!(),
|
||||
}
|
||||
@@ -118,37 +100,36 @@ impl FnLowerable for PExpr {
|
||||
let arg = arg.lower(ctx)?;
|
||||
nargs.push(arg);
|
||||
}
|
||||
let ty = ctx
|
||||
.program
|
||||
.get_fn_var(fe.id)
|
||||
.map(|f| f.ret.clone())
|
||||
.unwrap_or(Type::Placeholder);
|
||||
let temp = ctx.temp(ty);
|
||||
let dest = ctx.temp(Type::Placeholder);
|
||||
ctx.push(UInstruction::Call {
|
||||
dest: temp,
|
||||
dst: dest,
|
||||
f: fe,
|
||||
args: nargs,
|
||||
});
|
||||
temp
|
||||
dest
|
||||
}
|
||||
PExpr::Group(e) => e.lower(ctx)?,
|
||||
PExpr::Construct(c) => c.lower(ctx)?,
|
||||
PExpr::Construct(e, map) => {
|
||||
let dest = ctx.temp(Type::Placeholder);
|
||||
ctx.push(UInstruction::Construct { dst: dest, fields: () });
|
||||
dest
|
||||
}
|
||||
PExpr::If(cond, body) => {
|
||||
let cond = cond.lower(ctx)?;
|
||||
ctx.program.push();
|
||||
ctx.b.push();
|
||||
let mut body_ctx = ctx.branch();
|
||||
body.lower(&mut body_ctx);
|
||||
let body = body_ctx.instructions;
|
||||
ctx.program.pop();
|
||||
ctx.b.pop();
|
||||
ctx.push(UInstruction::If { cond, body });
|
||||
return None;
|
||||
}
|
||||
PExpr::Loop(body) => {
|
||||
ctx.program.push();
|
||||
ctx.b.push();
|
||||
let mut body_ctx = ctx.branch();
|
||||
body.lower(&mut body_ctx);
|
||||
let body = body_ctx.instructions;
|
||||
ctx.program.pop();
|
||||
ctx.b.pop();
|
||||
ctx.push(UInstruction::Loop { body });
|
||||
return None;
|
||||
}
|
||||
@@ -160,6 +141,13 @@ impl FnLowerable for PExpr {
|
||||
ctx.push(UInstruction::Continue);
|
||||
return None;
|
||||
}
|
||||
PExpr::Member(e, name) => {
|
||||
ctx.err("Can't access a member here".to_string());
|
||||
return None;
|
||||
}
|
||||
PExpr::Field(e, name) => {
|
||||
todo!()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
+34
-13
@@ -1,6 +1,11 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use super::{CompilerMsg, CompilerOutput, FileSpan, FnLowerable, Imports, Node, PFunction};
|
||||
use crate::{
|
||||
ir::{FnID, Idents, Type, UFunc, UInstrInst, UInstruction, UProgram, UVar, VarInst},
|
||||
ir::{
|
||||
FnID, Idents, Typable, Type, UFunc, UInstrInst, UInstruction, UModuleBuilder, UProgram,
|
||||
UVar, VarID, VarInst,
|
||||
},
|
||||
parser,
|
||||
};
|
||||
|
||||
@@ -54,7 +59,7 @@ impl PFunction {
|
||||
};
|
||||
let mut ctx = FnLowerCtx {
|
||||
instructions: Vec::new(),
|
||||
program: p,
|
||||
b: p,
|
||||
output,
|
||||
origin: self.body.origin,
|
||||
imports,
|
||||
@@ -62,7 +67,7 @@ impl PFunction {
|
||||
if let Some(src) = self.body.lower(&mut ctx) {
|
||||
ctx.instructions.push(UInstrInst {
|
||||
i: UInstruction::Ret { src },
|
||||
span: src.span,
|
||||
origin: src.origin,
|
||||
});
|
||||
}
|
||||
let instructions = ctx.instructions;
|
||||
@@ -77,23 +82,24 @@ impl PFunction {
|
||||
}
|
||||
|
||||
pub struct FnLowerCtx<'a> {
|
||||
pub program: &'a mut UProgram,
|
||||
pub b: &'a mut UModuleBuilder<'a>,
|
||||
pub instructions: Vec<UInstrInst>,
|
||||
pub output: &'a mut CompilerOutput,
|
||||
pub origin: FileSpan,
|
||||
pub imports: &'a mut Imports,
|
||||
pub var_stack: Vec<HashMap<String, VarID>>,
|
||||
}
|
||||
|
||||
impl FnLowerCtx<'_> {
|
||||
pub fn get_idents(&mut self, node: &Node<parser::PIdent>) -> Option<Idents> {
|
||||
let name = node.inner.as_ref()?;
|
||||
let res = self.program.get_idents(name);
|
||||
let res = self.b.get_idents(name);
|
||||
if res.is_none() {
|
||||
self.err_at(node.origin, format!("Identifier '{}' not found", name));
|
||||
}
|
||||
res
|
||||
}
|
||||
pub fn get_var(&mut self, node: &Node<parser::PIdent>) -> Option<VarInst> {
|
||||
pub fn get_var(&mut self, node: &Node<parser::PIdent>) -> VarInst {
|
||||
let ids = self.get_idents(node)?;
|
||||
if ids.get::<UVar>().is_none() {
|
||||
self.err_at(
|
||||
@@ -103,27 +109,42 @@ impl FnLowerCtx<'_> {
|
||||
}
|
||||
ids.get::<UVar>().map(|id| VarInst {
|
||||
id,
|
||||
span: node.origin,
|
||||
origin: node.origin,
|
||||
})
|
||||
}
|
||||
pub fn err(&mut self, msg: String) {
|
||||
self.output.err(CompilerMsg::from_span(self.origin, msg))
|
||||
self.output.err(CompilerMsg::new(self.origin, msg))
|
||||
}
|
||||
pub fn err_at(&mut self, span: FileSpan, msg: String) {
|
||||
self.output.err(CompilerMsg::from_span(span, msg))
|
||||
self.output.err(CompilerMsg::new(span, msg))
|
||||
}
|
||||
pub fn temp(&mut self, ty: impl Into<Type>) -> VarInst {
|
||||
self.program.temp_var(self.origin, ty)
|
||||
pub fn temp<T: Typable>(&mut self, ty: Type) -> VarInst {
|
||||
self.b.temp_var(self.origin, ty)
|
||||
}
|
||||
pub fn push(&mut self, i: UInstruction) {
|
||||
self.push_at(i, self.origin);
|
||||
}
|
||||
pub fn push_at(&mut self, i: UInstruction, span: FileSpan) {
|
||||
self.instructions.push(UInstrInst { i, span });
|
||||
match i {
|
||||
UInstruction::Mv { dst: dest, src } => todo!(),
|
||||
UInstruction::Ref { dst: dest, src } => todo!(),
|
||||
UInstruction::LoadData { dst: dest, src } => todo!(),
|
||||
UInstruction::LoadSlice { dst: dest, src } => todo!(),
|
||||
UInstruction::LoadFn { dst: dest, src } => todo!(),
|
||||
UInstruction::Call { dst: dest, f, args } => todo!(),
|
||||
UInstruction::AsmBlock { instructions, args } => todo!(),
|
||||
UInstruction::Ret { src } => todo!(),
|
||||
UInstruction::Construct { dst: dest, fields } => todo!(),
|
||||
UInstruction::If { cond, body } => todo!(),
|
||||
UInstruction::Loop { body } => todo!(),
|
||||
UInstruction::Break => todo!(),
|
||||
UInstruction::Continue => todo!(),
|
||||
}
|
||||
self.instructions.push(UInstrInst { i, origin: span });
|
||||
}
|
||||
pub fn branch<'a>(&'a mut self) -> FnLowerCtx<'a> {
|
||||
FnLowerCtx {
|
||||
program: self.program,
|
||||
b: self.b,
|
||||
instructions: Vec::new(),
|
||||
output: self.output,
|
||||
origin: self.origin,
|
||||
|
||||
@@ -23,7 +23,7 @@ impl PModule {
|
||||
let fid = p.def_searchable(&name, None, self.block.origin);
|
||||
p.push_name(&name);
|
||||
let mut fctx = FnLowerCtx {
|
||||
program: p,
|
||||
b: p,
|
||||
instructions: Vec::new(),
|
||||
output,
|
||||
origin: self.block.origin,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
common::{CompilerOutput, FileSpan},
|
||||
ir::{StructField, StructID, UInstruction, UProgram, UStruct, VarInst},
|
||||
parser::{Node, PMap, PConstructFields, PStruct, PStructFields},
|
||||
ir::{StructField, StructID, UInstruction, UModuleBuilder, UProgram, UStruct, VarInst},
|
||||
parser::{Node, PMap, PStruct, PStructFields},
|
||||
};
|
||||
|
||||
use super::{FnLowerCtx, FnLowerable};
|
||||
@@ -9,7 +9,7 @@ use super::{FnLowerCtx, FnLowerable};
|
||||
impl FnLowerable for PMap {
|
||||
type Output = VarInst;
|
||||
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<VarInst> {
|
||||
let ty = self.name.lower(ctx.program, ctx.output);
|
||||
let ty = self.name.lower(ctx.b, ctx.output);
|
||||
let fields = match &self.fields {
|
||||
PConstructFields::Named(nodes) => nodes
|
||||
.iter()
|
||||
@@ -32,7 +32,7 @@ impl FnLowerable for PMap {
|
||||
PConstructFields::None => Default::default(),
|
||||
};
|
||||
let id = ctx.temp(ty);
|
||||
ctx.push(UInstruction::Construct { dest: id, fields });
|
||||
ctx.push(UInstruction::Construct { dst: id, fields });
|
||||
Some(id)
|
||||
}
|
||||
}
|
||||
@@ -41,7 +41,7 @@ impl PStruct {
|
||||
pub fn lower(
|
||||
&self,
|
||||
id: StructID,
|
||||
p: &mut UProgram,
|
||||
p: &mut UModuleBuilder,
|
||||
output: &mut CompilerOutput,
|
||||
span: FileSpan,
|
||||
) -> Option<()> {
|
||||
@@ -71,20 +71,23 @@ impl PStruct {
|
||||
.into_iter()
|
||||
.map(|(name, ty)| (name, StructField { ty }))
|
||||
.collect();
|
||||
p.write(id, UStruct { generics, fields });
|
||||
let name = self.name.as_ref()?.to_string();
|
||||
p.def_data(UStruct {
|
||||
name,
|
||||
generics,
|
||||
fields,
|
||||
origin: span,
|
||||
});
|
||||
p.pop();
|
||||
Some(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Node<PStruct> {
|
||||
pub fn lower_name(&self, p: &mut UProgram) -> Option<StructID> {
|
||||
pub fn lower(&self, id: StructID, p: &mut UProgram, output: &mut CompilerOutput) -> Option<()> {
|
||||
let s = self.as_ref()?;
|
||||
let name = s.name.as_ref()?;
|
||||
let id = p.def_searchable(name, None, s.name.origin);
|
||||
Some(id)
|
||||
}
|
||||
pub fn lower(&self, id: StructID, p: &mut UProgram, output: &mut CompilerOutput) {
|
||||
self.as_ref().map(|i| i.lower(id, p, output, self.origin));
|
||||
s.lower(id, p, output, self.origin);
|
||||
Some(())
|
||||
}
|
||||
}
|
||||
|
||||
+91
-33
@@ -1,52 +1,110 @@
|
||||
use crate::{
|
||||
ir::{StructInst, Type, TypeID, UGeneric, UProgram, UStruct},
|
||||
ir::{GenericID, MemberID, ModPath, Type, TypeID, UGeneric, UModuleBuilder, UProgram},
|
||||
parser::PGenericDef,
|
||||
};
|
||||
|
||||
use super::{CompilerMsg, CompilerOutput, FileSpan, Node, PType};
|
||||
use super::{CompilerOutput, FileSpan, Node, PType};
|
||||
|
||||
impl Node<PType> {
|
||||
pub fn lower(&self, namespace: &mut UProgram, output: &mut CompilerOutput) -> TypeID {
|
||||
impl Node<Box<PType>> {
|
||||
pub fn lower(&self, p: &mut UModuleBuilder, output: &mut CompilerOutput) -> TypeID {
|
||||
self.as_ref()
|
||||
.map(|t| t.lower(namespace, output, self.origin))
|
||||
.unwrap_or(Type::Error)
|
||||
.map(|t| t.lower(p, output, self.origin))
|
||||
.unwrap_or(p.error())
|
||||
}
|
||||
}
|
||||
impl Node<PType> {
|
||||
pub fn lower(&self, p: &mut UModuleBuilder, output: &mut CompilerOutput) -> TypeID {
|
||||
self.as_ref()
|
||||
.map(|t| t.lower(p, output, self.origin))
|
||||
.unwrap_or(p.error())
|
||||
}
|
||||
}
|
||||
|
||||
fn test() {}
|
||||
|
||||
impl PType {
|
||||
pub fn lower(&self, p: &mut UProgram, output: &mut CompilerOutput, span: FileSpan) -> TypeID {
|
||||
let Some(name) = self.name.as_ref() else {
|
||||
return p.error_type();
|
||||
};
|
||||
let ids = p.get_idents(name);
|
||||
// TODO: should generics always take precedence?
|
||||
if let Some(id) = ids.and_then(|ids| ids.get::<Type>()) {
|
||||
Type::Generic { id }
|
||||
} else if let Some(id) = ids.and_then(|ids| ids.get::<UStruct>()) {
|
||||
let args = self.args.iter().map(|n| n.lower(p, output)).collect();
|
||||
Type::Struct(StructInst { id, args })
|
||||
} else if let Ok(num) = name.parse::<u32>() {
|
||||
Type::Bits(num)
|
||||
} else {
|
||||
match name.as_str() {
|
||||
"slice" => {
|
||||
let inner = self.args[0].lower(p, output);
|
||||
Type::Slice(Box::new(inner))
|
||||
}
|
||||
"_" => Type::Infer,
|
||||
_ => {
|
||||
output.err(CompilerMsg::from_span(span, "Type not found".to_string()));
|
||||
Type::Error
|
||||
}
|
||||
}
|
||||
pub fn lower(
|
||||
&self,
|
||||
p: &mut UModuleBuilder,
|
||||
output: &mut CompilerOutput,
|
||||
mut origin: FileSpan,
|
||||
) -> TypeID {
|
||||
let mut ty = self;
|
||||
let mut path = Vec::new();
|
||||
while let PType::Member(node, ident) = ty {
|
||||
ty = if let Some(t) = node.as_ref() {
|
||||
let Some(name) = ident.as_ref() else {
|
||||
return p.error();
|
||||
};
|
||||
origin = node.origin;
|
||||
path.push(MemberID {
|
||||
name: name.0.clone(),
|
||||
origin: ident.origin,
|
||||
});
|
||||
&**t
|
||||
} else {
|
||||
return p.error();
|
||||
};
|
||||
}
|
||||
if !path.is_empty() {
|
||||
let PType::Ident(id) = ty else {
|
||||
return p.error();
|
||||
};
|
||||
path.push(MemberID {
|
||||
name: id.0.clone(),
|
||||
origin,
|
||||
});
|
||||
return p.def_ty(Type::Unres(ModPath { m: p.module, path }));
|
||||
}
|
||||
let ty = match ty {
|
||||
PType::Member(_, _) => unreachable!(),
|
||||
PType::Ident(node) => {
|
||||
path.push(MemberID {
|
||||
name: node.0.clone(),
|
||||
origin,
|
||||
});
|
||||
path.reverse();
|
||||
Type::Unres(ModPath { m: p.module, path })
|
||||
}
|
||||
PType::Ref(node) => node.lower(p, output).rf(),
|
||||
PType::Generic(node, nodes) => todo!(),
|
||||
};
|
||||
p.def_ty(ty)
|
||||
// let Some(name) = self.name.as_ref() else {
|
||||
// return p.error();
|
||||
// };
|
||||
// let ids = p.get_idents(name);
|
||||
// // TODO: should generics always take precedence?
|
||||
// if let Some(id) = ids.and_then(|ids| ids.get::<Type>()) {
|
||||
// Type::Generic { id }
|
||||
// } else if let Some(id) = ids.and_then(|ids| ids.get::<UStruct>()) {
|
||||
// let args = self.args.iter().map(|n| n.lower(p, output)).collect();
|
||||
// Type::Struct(StructInst { id, args })
|
||||
// } else if let Ok(num) = name.parse::<u32>() {
|
||||
// Type::Bits(num)
|
||||
// } else {
|
||||
// match name.as_str() {
|
||||
// "slice" => {
|
||||
// let inner = self.args[0].lower(p, output);
|
||||
// Type::Slice(Box::new(inner))
|
||||
// }
|
||||
// "_" => Type::Infer,
|
||||
// _ => {
|
||||
// output.err(CompilerMsg::from_span(span, "Type not found".to_string()));
|
||||
// Type::Error
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
impl Node<PGenericDef> {
|
||||
pub fn lower(&self, p: &mut UProgram) -> Option<GenericID> {
|
||||
let s = self.as_ref()?;
|
||||
let name = s.name.as_ref()?;
|
||||
Some(p.def_searchable(name, Some(UGeneric {}), self.origin))
|
||||
let name = s.name.as_ref()?.to_string();
|
||||
Some(p.def_generic(UGeneric {
|
||||
name,
|
||||
origin: self.origin,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ pub struct PInstruction {
|
||||
}
|
||||
|
||||
pub enum PAsmArg {
|
||||
Value(Node<PIdent>),
|
||||
Value(PIdent),
|
||||
Ref(Node<PIdent>),
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ impl Parsable for PInstruction {
|
||||
impl Parsable for PAsmArg {
|
||||
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||
if let Some(ident) = ctx.maybe_parse() {
|
||||
return ParseResult::Ok(Self::Value(ident));
|
||||
return ParseResult::Wrap(ident.map(Self::Value));
|
||||
}
|
||||
|
||||
let mut next = ctx.expect_peek()?;
|
||||
@@ -41,10 +41,10 @@ impl Parsable for PAsmArg {
|
||||
ctx.next();
|
||||
if let Some(mut ident) = ctx.maybe_parse::<PIdent>() {
|
||||
// TODO: this is so messed up
|
||||
if let Some(i) = ident.as_mut() {
|
||||
if let Some(i) = ident.node.as_mut() {
|
||||
i.0.insert(0, '-')
|
||||
}
|
||||
return ParseResult::Ok(Self::Value(ident));
|
||||
return ParseResult::Wrap(ident.map(Self::Value));
|
||||
}
|
||||
next = ctx.expect_peek()?;
|
||||
}
|
||||
|
||||
+23
-23
@@ -1,7 +1,7 @@
|
||||
use std::fmt::Debug;
|
||||
|
||||
use super::{
|
||||
CompilerMsg, MaybeParsable, Node, PExpr, PIdent, PType, Parsable, ParseResult, ParserCtx,
|
||||
CompilerMsg, Node, PExpr, PIdent, PType, Parsable, ParseResult, ParserCtx,
|
||||
Symbol, Token,
|
||||
};
|
||||
|
||||
@@ -55,28 +55,28 @@ pub enum SelfType {
|
||||
Take,
|
||||
}
|
||||
|
||||
impl MaybeParsable for SelfVar {
|
||||
fn maybe_parse(ctx: &mut ParserCtx) -> Result<Option<Self>, CompilerMsg> {
|
||||
if let Some(mut next) = ctx.peek() {
|
||||
let mut ty = SelfType::Take;
|
||||
if next.is_symbol(Symbol::Ampersand) {
|
||||
ctx.next();
|
||||
ty = SelfType::Ref;
|
||||
next = ctx.expect_peek()?;
|
||||
}
|
||||
if let Token::Word(name) = &next.token {
|
||||
if name == "self" {
|
||||
ctx.next();
|
||||
return Ok(Some(Self { ty }));
|
||||
}
|
||||
}
|
||||
if ty != SelfType::Take {
|
||||
return Err(CompilerMsg::unexpected_token(next, "self"));
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
// impl Parsable for Option<SelfVar> {
|
||||
// fn maybe_parse(ctx: &mut ParserCtx) -> Result<Option<Self>, CompilerMsg> {
|
||||
// if let Some(mut next) = ctx.peek() {
|
||||
// let mut ty = SelfType::Take;
|
||||
// if next.is_symbol(Symbol::Ampersand) {
|
||||
// ctx.next();
|
||||
// ty = SelfType::Ref;
|
||||
// next = ctx.expect_peek()?;
|
||||
// }
|
||||
// if let Token::Word(name) = &next.token {
|
||||
// if name == "self" {
|
||||
// ctx.next();
|
||||
// return Ok(Some(Self { ty }));
|
||||
// }
|
||||
// }
|
||||
// if ty != SelfType::Take {
|
||||
// return Err(CompilerMsg::unexpected_token(next, "self"));
|
||||
// }
|
||||
// }
|
||||
// Ok(None)
|
||||
// }
|
||||
// }
|
||||
|
||||
impl Debug for PVarDef {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
|
||||
+13
-10
@@ -12,14 +12,15 @@ use super::{
|
||||
type BoxNode = Node<Box<PExpr>>;
|
||||
|
||||
pub enum PExpr {
|
||||
Lit(Node<PLiteral>),
|
||||
Lit(PLiteral),
|
||||
Ident(Node<PIdent>),
|
||||
BinaryOp(InfixOp, BoxNode, BoxNode),
|
||||
PostfixOp(BoxNode, PostfixOp),
|
||||
Block(Node<PBlock>),
|
||||
Call(BoxNode, Vec<Node<PExpr>>),
|
||||
Group(BoxNode),
|
||||
Access(BoxNode, Node<PIdent>),
|
||||
Field(BoxNode, Node<PIdent>),
|
||||
Member(BoxNode, Node<PIdent>),
|
||||
AsmBlock(Node<PAsmBlock>),
|
||||
Construct(BoxNode, Node<PMap>),
|
||||
If(BoxNode, BoxNode),
|
||||
@@ -69,7 +70,11 @@ impl PExpr {
|
||||
continue;
|
||||
} else if next.is_symbol(Symbol::Dot) {
|
||||
let field = ctx.parse()?;
|
||||
e1 = Self::Access(Node::new(e1, span).bx(), field);
|
||||
e1 = Self::Field(Node::new(e1, span).bx(), field);
|
||||
continue;
|
||||
} else if next.is_symbol(Symbol::DoubleColon) {
|
||||
let field = ctx.parse()?;
|
||||
e1 = Self::Member(Node::new(e1, span).bx(), field);
|
||||
continue;
|
||||
} else if let Some(op) = PostfixOp::from_token(next) {
|
||||
ctx.next();
|
||||
@@ -86,10 +91,7 @@ impl PExpr {
|
||||
ctx.next();
|
||||
if ctx.expect_peek()?.is_symbol(Symbol::CloseParen) {
|
||||
ctx.next();
|
||||
return ParseResult::Ok(PExpr::Lit(Node::new(
|
||||
PLiteral::Unit,
|
||||
ctx.next_start().char_span(),
|
||||
)));
|
||||
return ParseResult::Ok(PExpr::Lit(PLiteral::Unit));
|
||||
}
|
||||
let res = ctx.parse();
|
||||
if res.recover {
|
||||
@@ -118,8 +120,8 @@ impl PExpr {
|
||||
} else if next.is_keyword(Keyword::Asm) {
|
||||
ctx.next();
|
||||
Self::AsmBlock(ctx.parse()?)
|
||||
} else if let Some(val) = ctx.maybe_parse() {
|
||||
Self::Lit(val)
|
||||
} else if let Some(res) = ctx.maybe_parse::<PLiteral>() {
|
||||
return ParseResult::Wrap(res.map(Self::Lit));
|
||||
} else {
|
||||
let res = ctx.parse();
|
||||
if res.node.is_some() {
|
||||
@@ -188,7 +190,8 @@ impl Debug for PExpr {
|
||||
PExpr::Loop(res) => write!(f, "loop -> {res:?}")?,
|
||||
PExpr::Break => write!(f, "break")?,
|
||||
PExpr::Continue => write!(f, "continue")?,
|
||||
PExpr::Access(e1, name) => write!(f, "{:?}.{:?}", e1, name)?,
|
||||
PExpr::Field(e1, name) => write!(f, "{:?}.{:?}", e1, name)?,
|
||||
PExpr::Member(e1, name) => write!(f, "{:?}::{:?}", e1, name)?,
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use super::{MaybeParsable, Parsable, ParseResult, ParserCtx, Token, CompilerMsg};
|
||||
use super::{CompilerMsg, Parsable, ParseResult, ParserCtx, Token};
|
||||
use std::{
|
||||
fmt::{Debug, Display},
|
||||
ops::Deref,
|
||||
@@ -19,15 +19,17 @@ impl Parsable for PIdent {
|
||||
}
|
||||
}
|
||||
|
||||
impl MaybeParsable for PIdent {
|
||||
fn maybe_parse(ctx: &mut ParserCtx) -> Result<Option<Self>, CompilerMsg> {
|
||||
let Some(next) = ctx.peek() else { return Ok(None) };
|
||||
impl Parsable for Option<PIdent> {
|
||||
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||
let Some(next) = ctx.peek() else {
|
||||
return ParseResult::Ok(None);
|
||||
};
|
||||
let Token::Word(name) = &next.token else {
|
||||
return Ok(None);
|
||||
return ParseResult::Ok(None);
|
||||
};
|
||||
let name = name.to_string();
|
||||
ctx.next();
|
||||
Ok(Some(Self(name)))
|
||||
ParseResult::Ok(Some(PIdent(name)))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+15
-36
@@ -1,4 +1,6 @@
|
||||
use super::{CharCursor, MaybeParsable, ParserCtx, CompilerMsg, Symbol, Token};
|
||||
use crate::parser::{Parsable, ParseResult};
|
||||
|
||||
use super::{PString, ParserCtx, Symbol, Token};
|
||||
use std::fmt::Debug;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
@@ -16,26 +18,29 @@ pub struct PNumber {
|
||||
pub ty: Option<String>,
|
||||
}
|
||||
|
||||
impl MaybeParsable for PLiteral {
|
||||
fn maybe_parse(ctx: &mut ParserCtx) -> Result<Option<Self>, CompilerMsg> {
|
||||
impl Parsable for Option<PLiteral> {
|
||||
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||
let inst = ctx.expect_peek()?;
|
||||
Ok(Some(match &inst.token {
|
||||
ParseResult::Ok(Some(match &inst.token {
|
||||
Token::Symbol(Symbol::SingleQuote) => {
|
||||
let chars = ctx.chars();
|
||||
let c = chars.expect_next()?;
|
||||
chars.expect('\'')?;
|
||||
ctx.next();
|
||||
Self::Char(c)
|
||||
PLiteral::Char(c)
|
||||
}
|
||||
Token::Symbol(Symbol::DoubleQuote) => {
|
||||
let res = Self::String(string_from(ctx.chars())?);
|
||||
ctx.next();
|
||||
res
|
||||
let s = ctx.parse::<PString>()?;
|
||||
return match s.inner {
|
||||
Some(s) => ParseResult::Ok(Some(PLiteral::String(s.0))),
|
||||
None => ParseResult::SubErr,
|
||||
};
|
||||
}
|
||||
Token::Word(text) => {
|
||||
let first = text.chars().next().unwrap();
|
||||
if !first.is_ascii_digit() {
|
||||
return Ok(None);
|
||||
return ParseResult::Ok(None);
|
||||
}
|
||||
let (whole, ty) = parse_whole_num(text);
|
||||
let mut num = PNumber {
|
||||
@@ -57,9 +62,9 @@ impl MaybeParsable for PLiteral {
|
||||
}
|
||||
}
|
||||
}
|
||||
Self::Number(num)
|
||||
PLiteral::Number(num)
|
||||
}
|
||||
_ => return Ok(None),
|
||||
_ => return ParseResult::Ok(None),
|
||||
}))
|
||||
}
|
||||
}
|
||||
@@ -81,32 +86,6 @@ pub fn parse_whole_num(text: &str) -> (String, Option<String>) {
|
||||
(whole, if ty.is_empty() { None } else { Some(ty) })
|
||||
}
|
||||
|
||||
pub fn string_from(cursor: &mut CharCursor) -> Result<String, CompilerMsg> {
|
||||
let mut str = String::new();
|
||||
loop {
|
||||
let c = cursor.expect_next()?;
|
||||
if c == '"' {
|
||||
return Ok(str);
|
||||
}
|
||||
str.push(match c {
|
||||
'\\' => {
|
||||
let next = cursor.expect_next()?;
|
||||
match next {
|
||||
'"' => '"',
|
||||
'\'' => '\'',
|
||||
't' => '\t',
|
||||
'n' => '\n',
|
||||
'0' => '\0',
|
||||
_ => {
|
||||
todo!();
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => c,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for PLiteral {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
|
||||
@@ -9,6 +9,7 @@ mod ident;
|
||||
mod lit;
|
||||
mod op;
|
||||
mod statement;
|
||||
mod string;
|
||||
mod struc;
|
||||
mod trai;
|
||||
mod ty;
|
||||
@@ -28,10 +29,9 @@ pub use statement::*;
|
||||
pub use struc::*;
|
||||
pub use trai::*;
|
||||
pub use ty::*;
|
||||
pub use string::*;
|
||||
|
||||
use crate::ir::UProgram;
|
||||
|
||||
use super::{lower::{FnLowerCtx, FnLowerable}, *};
|
||||
use super::*;
|
||||
|
||||
pub struct PModule {
|
||||
pub block: Node<PBlock>,
|
||||
|
||||
@@ -78,7 +78,7 @@ impl PostfixOp {
|
||||
match self {
|
||||
Self::Not => "!",
|
||||
Self::Ref => "@",
|
||||
Self::Deref => "*",
|
||||
Self::Deref => "^",
|
||||
}
|
||||
}
|
||||
pub fn from_token(token: &Token) -> Option<Self> {
|
||||
@@ -88,7 +88,7 @@ impl PostfixOp {
|
||||
Some(match symbol {
|
||||
Symbol::At => Self::Ref,
|
||||
Symbol::Bang => Self::Not,
|
||||
Symbol::Asterisk => Self::Deref,
|
||||
Symbol::Carrot => Self::Deref,
|
||||
_ => {
|
||||
return None;
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ impl Parsable for PStatementLike {
|
||||
let def = ctx.parse()?;
|
||||
ctx.expect_sym(Symbol::Equals)?;
|
||||
ctx.parse()
|
||||
.map(|expr| Self::Statement(PStatement::Let(def, expr)))
|
||||
.map_res(|expr| Self::Statement(PStatement::Let(def, expr)))
|
||||
}
|
||||
Token::Keyword(Keyword::Return) => {
|
||||
ctx.next();
|
||||
@@ -37,7 +37,7 @@ impl Parsable for PStatementLike {
|
||||
ParseResult::Ok(Self::Statement(PStatement::Return(None)))
|
||||
} else {
|
||||
ctx.parse()
|
||||
.map(|res| Self::Statement(PStatement::Return(Some(res))))
|
||||
.map_res(|res| Self::Statement(PStatement::Return(Some(res))))
|
||||
}
|
||||
}
|
||||
Token::Keyword(Keyword::Fn) => {
|
||||
@@ -52,7 +52,7 @@ impl Parsable for PStatementLike {
|
||||
ctx.next();
|
||||
ParseResult::Ok(Self::Const(PConstStatement::Import(ctx.parse()?)))
|
||||
}
|
||||
_ => ctx.parse().map(|n| Self::Statement(PStatement::Expr(n))),
|
||||
_ => ctx.parse().map_res(|n| Self::Statement(PStatement::Expr(n))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
use crate::{
|
||||
common::CompilerMsg,
|
||||
parser::{Parsable, ParseResult},
|
||||
};
|
||||
|
||||
pub struct PString(pub String);
|
||||
|
||||
impl Parsable for PString {
|
||||
fn parse(ctx: &mut crate::parser::ParserCtx) -> ParseResult<Self> {
|
||||
let cursor = ctx.cursor.chars();
|
||||
let mut str = String::new();
|
||||
loop {
|
||||
let c = cursor.expect_next()?;
|
||||
if c == '"' {
|
||||
return ParseResult::Ok(Self(str));
|
||||
}
|
||||
str.push(match c {
|
||||
'\\' => {
|
||||
let start = cursor.prev_pos();
|
||||
let next = cursor.expect_next()?;
|
||||
match next {
|
||||
'"' => '"',
|
||||
'\'' => '\'',
|
||||
't' => '\t',
|
||||
'n' => '\n',
|
||||
'0' => '\0',
|
||||
other => {
|
||||
let end = cursor.prev_pos();
|
||||
ctx.output.err(CompilerMsg {
|
||||
msg: format!("Unknown escape sequence '\\{}'", other),
|
||||
spans: vec![start.to(end)],
|
||||
});
|
||||
other
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => c,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
+35
-28
@@ -2,9 +2,13 @@ use std::fmt::Debug;
|
||||
|
||||
use super::{util::parse_list, Node, PIdent, Parsable, ParseResult, ParserCtx, Symbol};
|
||||
|
||||
pub struct PType {
|
||||
pub name: Node<PIdent>,
|
||||
pub args: Vec<Node<PType>>,
|
||||
type BoxNode = Node<Box<PType>>;
|
||||
|
||||
pub enum PType {
|
||||
Member(BoxNode, Node<PIdent>),
|
||||
Ref(BoxNode),
|
||||
Generic(BoxNode, Vec<Node<PType>>),
|
||||
Ident(PIdent),
|
||||
}
|
||||
|
||||
pub struct PGenericDef {
|
||||
@@ -13,27 +17,30 @@ pub struct PGenericDef {
|
||||
|
||||
impl Parsable for PType {
|
||||
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||
let next = ctx.expect_peek()?;
|
||||
let res = if next.is_symbol(Symbol::Ampersand) {
|
||||
let name = Node::new(PIdent("&".to_string()), next.span);
|
||||
ctx.next();
|
||||
let arg = ctx.parse()?;
|
||||
Self {
|
||||
name,
|
||||
args: vec![arg],
|
||||
let start = ctx.next_start();
|
||||
let mut cur = ctx.parse()?.map(PType::Ident);
|
||||
loop {
|
||||
let span = start.to(ctx.prev_end());
|
||||
let Some(next) = ctx.peek() else {
|
||||
break;
|
||||
};
|
||||
if next.is_symbol(Symbol::Ampersand) {
|
||||
ctx.next();
|
||||
cur = Node::new(PType::Ref(cur.bx()), span);
|
||||
continue;
|
||||
} else if next.is_symbol(Symbol::OpenAngle) {
|
||||
ctx.next();
|
||||
let args = parse_list(ctx, Symbol::CloseAngle)?;
|
||||
cur = Node::new(PType::Generic(cur.bx(), args), span);
|
||||
continue;
|
||||
} else if next.is_symbol(Symbol::DoubleColon) {
|
||||
ctx.next();
|
||||
let mem = ctx.parse()?;
|
||||
cur = Node::new(PType::Member(cur.bx(), mem), span);
|
||||
}
|
||||
} else {
|
||||
let n = ctx.parse()?;
|
||||
let mut args = Vec::new();
|
||||
if let Some(next) = ctx.peek() {
|
||||
if next.is_symbol(Symbol::OpenAngle) {
|
||||
ctx.next();
|
||||
args = parse_list(ctx, Symbol::CloseAngle)?;
|
||||
}
|
||||
}
|
||||
Self { name: n, args }
|
||||
};
|
||||
ParseResult::Ok(res)
|
||||
break;
|
||||
}
|
||||
ParseResult::Wrap(cur)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,11 +52,11 @@ impl Parsable for PGenericDef {
|
||||
|
||||
impl Debug for PType {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{:?}", self.name)?;
|
||||
if self.name.as_ref().is_some_and(|n| n.0 == "&") {
|
||||
write!(f, "{:?}", self.args[0])?;
|
||||
} else if !self.args.is_empty() {
|
||||
write!(f, "<{:?}>", self.args)?;
|
||||
match self {
|
||||
PType::Member(node, name) => write!(f, "{:?}.{:?}", node, name)?,
|
||||
PType::Ref(node) => write!(f, "{:?}&", node)?,
|
||||
PType::Generic(node, args) => write!(f, "{:?}<{:?}>", node, args)?,
|
||||
PType::Ident(node) => node.fmt(f)?,
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
+60
-20
@@ -7,6 +7,8 @@ use super::{CompilerMsg, FilePos, Node, ParserCtx};
|
||||
|
||||
pub enum ParseResult<T> {
|
||||
Ok(T),
|
||||
Wrap(NodeParseResult<T>),
|
||||
Node(Node<T>),
|
||||
Recover(T),
|
||||
Err(CompilerMsg),
|
||||
SubErr,
|
||||
@@ -33,6 +35,20 @@ impl<T> Try for ParseResult<T> {
|
||||
ParseResult::Ok(v) => ControlFlow::Continue(v),
|
||||
// TODO: this is messed up; need to break w a Result<Option<T>> or smth :woozy:
|
||||
ParseResult::Recover(v) => ControlFlow::Break(None),
|
||||
ParseResult::Wrap(n) => {
|
||||
if n.recover {
|
||||
ControlFlow::Break(None)
|
||||
} else {
|
||||
match n.node.inner {
|
||||
Some(v) => ControlFlow::Continue(v),
|
||||
None => ControlFlow::Break(None),
|
||||
}
|
||||
}
|
||||
}
|
||||
ParseResult::Node(n) => match n.inner {
|
||||
Some(v) => ControlFlow::Continue(v),
|
||||
None => ControlFlow::Break(None),
|
||||
},
|
||||
ParseResult::Err(e) => ControlFlow::Break(Some(e)),
|
||||
ParseResult::SubErr => ControlFlow::Break(None),
|
||||
}
|
||||
@@ -72,7 +88,7 @@ pub struct NodeParseResult<T> {
|
||||
}
|
||||
|
||||
impl<T> NodeParseResult<T> {
|
||||
pub fn map<F: FnOnce(Node<T>) -> U, U>(self, op: F) -> ParseResult<U> {
|
||||
pub fn map_res<F: FnOnce(Node<T>) -> U, U>(self, op: F) -> ParseResult<U> {
|
||||
let res = op(self.node);
|
||||
if self.recover {
|
||||
ParseResult::Recover(res)
|
||||
@@ -80,6 +96,15 @@ impl<T> NodeParseResult<T> {
|
||||
ParseResult::Ok(res)
|
||||
}
|
||||
}
|
||||
pub fn map<F: FnOnce(T) -> U, U>(self, op: F) -> NodeParseResult<U> {
|
||||
NodeParseResult {
|
||||
node: Node {
|
||||
inner: self.node.inner.map(op),
|
||||
origin: self.node.origin,
|
||||
},
|
||||
recover: self.recover,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Try for NodeParseResult<T> {
|
||||
@@ -119,10 +144,6 @@ pub trait ParsableWith: Sized {
|
||||
fn parse(ctx: &mut ParserCtx, data: Self::Data) -> ParseResult<Self>;
|
||||
}
|
||||
|
||||
pub trait MaybeParsable: Sized {
|
||||
fn maybe_parse(ctx: &mut ParserCtx) -> Result<Option<Self>, CompilerMsg>;
|
||||
}
|
||||
|
||||
impl<T: Parsable> ParsableWith for T {
|
||||
type Data = ();
|
||||
|
||||
@@ -140,6 +161,13 @@ impl<T: ParsableWith> Node<T> {
|
||||
let (inner, recover) = match T::parse(ctx, data) {
|
||||
ParseResult::Ok(v) => (Some(v), false),
|
||||
ParseResult::Recover(v) => (Some(v), true),
|
||||
ParseResult::Wrap(r) => return r,
|
||||
ParseResult::Node(node) => {
|
||||
return NodeParseResult {
|
||||
node,
|
||||
recover: false,
|
||||
}
|
||||
}
|
||||
ParseResult::Err(e) => {
|
||||
ctx.err(e);
|
||||
(None, true)
|
||||
@@ -163,21 +191,33 @@ impl<T: Parsable> Node<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: MaybeParsable> Node<T> {
|
||||
pub fn maybe_parse(ctx: &mut ParserCtx) -> Option<Self> {
|
||||
let start = ctx.next_start();
|
||||
let inner = match T::maybe_parse(ctx) {
|
||||
Ok(v) => Some(v?),
|
||||
Err(e) => {
|
||||
ctx.err(e);
|
||||
None
|
||||
}
|
||||
};
|
||||
let end = ctx.prev_end();
|
||||
Some(Self {
|
||||
inner,
|
||||
origin: start.to(end),
|
||||
})
|
||||
impl<T> Node<Option<T>>
|
||||
where
|
||||
Option<T>: Parsable,
|
||||
{
|
||||
pub fn maybe_parse(ctx: &mut ParserCtx) -> Option<NodeParseResult<T>> {
|
||||
let res = Node::<Option<T>>::parse_with(ctx, ());
|
||||
let origin = res.node.origin;
|
||||
let recover = res.recover;
|
||||
match res.node.inner {
|
||||
Some(val) => match val {
|
||||
Some(v) => Some(NodeParseResult {
|
||||
node: Node {
|
||||
inner: Some(v),
|
||||
origin,
|
||||
},
|
||||
recover,
|
||||
}),
|
||||
None => None,
|
||||
},
|
||||
None => Some(NodeParseResult {
|
||||
node: Node {
|
||||
inner: None,
|
||||
origin,
|
||||
},
|
||||
recover,
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ pub enum Symbol {
|
||||
Comma,
|
||||
Hash,
|
||||
At,
|
||||
Carrot,
|
||||
}
|
||||
|
||||
impl Symbol {
|
||||
@@ -72,6 +73,7 @@ impl Symbol {
|
||||
',' => Self::Comma,
|
||||
'#' => Self::Hash,
|
||||
'@' => Self::At,
|
||||
'^' => Self::Carrot,
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
@@ -147,6 +149,7 @@ impl Symbol {
|
||||
Self::DoublePipe => "||",
|
||||
Self::Hash => "#",
|
||||
Self::At => "@",
|
||||
Self::Carrot => "^",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user