prepare for modules

This commit is contained in:
2025-04-25 04:16:54 -04:00
parent 0ceb82445e
commit 4e7c201690
30 changed files with 369 additions and 333 deletions

View File

@@ -1,3 +1,8 @@
println("testy");
let x = 3;
print_dec(x);
start();
struct Test { struct Test {
a: 64, a: 64,
b: 64, b: 64,

View File

@@ -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>("start") .id::<UFunc>("crate")
.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);

View File

@@ -100,7 +100,7 @@ macro_rules! impl_kind {
($struc:ty, $idx:expr, $field:ident, $name:expr) => { ($struc:ty, $idx:expr, $field:ident, $name:expr) => {
impl_kind!($struc, $idx, $field, $name, nofin); impl_kind!($struc, $idx, $field, $name, nofin);
impl Finish for $struc { impl Finish for $struc {
fn finish(_: &mut UProgram, _: ID<Self>) {} fn finish(_: &mut UProgram, _: ID<Self>, _: &str) {}
} }
}; };
($struc:ty, $idx:expr, $field:ident, $name:expr, nofin) => { ($struc:ty, $idx:expr, $field:ident, $name:expr, nofin) => {
@@ -133,9 +133,9 @@ pub type DataID = ID<UData>;
pub type GenericID = ID<UGeneric>; pub type GenericID = ID<UGeneric>;
impl Finish for UFunc { impl Finish for UFunc {
fn finish(p: &mut UProgram, id: ID<Self>) { fn finish(p: &mut UProgram, id: ID<Self>, name: &str) {
let var = p.def_searchable( let var = p.def_searchable(
p.names.name(id).to_string(), name.to_string(),
Some(UVar { Some(UVar {
parent: None, parent: None,
ty: Type::Placeholder, ty: Type::Placeholder,
@@ -153,5 +153,5 @@ pub trait Kind: Sized {
} }
pub trait Finish: Sized { pub trait Finish: Sized {
fn finish(program: &mut UProgram, id: ID<Self>); fn finish(program: &mut UProgram, id: ID<Self>, name: &str);
} }

View File

@@ -1,17 +1,18 @@
mod kind; mod assoc;
mod instr;
mod ty;
mod program;
mod validate;
mod error; mod error;
mod inst; mod inst;
mod maps; mod instr;
mod kind;
mod program;
mod ty;
mod validate;
use super::*; use super::*;
use maps::*; use assoc::*;
pub use maps::Idents;
pub use kind::*; pub use assoc::Idents;
pub use instr::*;
pub use ty::*;
pub use program::*;
pub use inst::*; pub use inst::*;
pub use instr::*;
pub use kind::*;
pub use program::*;
pub use ty::*;

View File

@@ -2,16 +2,19 @@ use super::*;
use std::collections::HashMap; use std::collections::HashMap;
pub struct UProgram { pub struct UProgram {
// kinds
pub fns: Vec<Option<UFunc>>, pub fns: Vec<Option<UFunc>>,
pub vars: Vec<Option<UVar>>, pub vars: Vec<Option<UVar>>,
pub structs: Vec<Option<UStruct>>, pub structs: Vec<Option<UStruct>>,
pub types: Vec<Option<UGeneric>>, pub types: Vec<Option<UGeneric>>,
pub data: Vec<Option<UData>>, pub data: Vec<Option<UData>>,
// associated data
pub names: NameMap, pub names: NameMap,
pub origins: OriginMap, pub origins: OriginMap,
pub fn_var: FnVarMap, pub fn_var: FnVarMap,
pub temp: usize, pub path: Vec<String>,
pub name_stack: Vec<HashMap<String, Idents>>, pub name_stack: Vec<HashMap<String, Idents>>,
pub temp: usize,
} }
impl UProgram { impl UProgram {
@@ -25,8 +28,9 @@ impl UProgram {
names: NameMap::new(), names: NameMap::new(),
origins: OriginMap::new(), origins: OriginMap::new(),
fn_var: FnVarMap::new(), fn_var: FnVarMap::new(),
temp: 0, path: Vec::new(),
name_stack: vec![HashMap::new()], name_stack: vec![HashMap::new()],
temp: 0,
} }
} }
pub fn push(&mut self) { pub fn push(&mut self) {
@@ -35,6 +39,12 @@ impl UProgram {
pub fn pop(&mut self) { pub fn pop(&mut self) {
self.name_stack.pop(); self.name_stack.pop();
} }
pub fn push_name(&mut self, name: &str) {
self.path.push(name.to_string());
}
pub fn pop_name(&mut self) {
self.path.pop();
}
pub fn get_idents(&self, name: &str) -> Option<Idents> { pub fn get_idents(&self, name: &str) -> Option<Idents> {
for map in self.name_stack.iter().rev() { for map in self.name_stack.iter().rev() {
let res = map.get(name); let res = map.get(name);
@@ -70,7 +80,7 @@ impl UProgram {
fn temp_var_inner(&mut self, origin: Origin, ty: Type, parent: Option<FieldRef>) -> VarInst { fn temp_var_inner(&mut self, origin: Origin, ty: Type, parent: Option<FieldRef>) -> VarInst {
let v = self.def( let v = self.def(
format!("temp{}", self.temp), &format!("temp{}", self.temp),
Some(UVar { parent, ty }), Some(UVar { parent, ty }),
origin, origin,
); );
@@ -85,23 +95,32 @@ impl UProgram {
K::from_program_mut(self)[id.0] = Some(k); K::from_program_mut(self)[id.0] = Some(k);
} }
pub fn def<K: Kind + Finish>(&mut self, name: String, 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>(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());
vec.push(k); vec.push(k);
K::finish(self, id); K::finish(self, id, name);
id id
} }
pub fn path_for(&self, name: &str) -> String {
if self.path.is_empty() {
return name.to_string();
}
let mut path = self.path.join("::");
path = path + "::" + name;
path
}
pub fn def_searchable<K: Kind + Finish>( pub fn def_searchable<K: Kind + Finish>(
&mut self, &mut self,
name: String, name: String,
k: Option<K>, k: Option<K>,
origin: Origin, origin: Origin,
) -> ID<K> { ) -> ID<K> {
let id = self.def(name.clone(), k, origin); let id = self.def(&name, k, origin);
self.name_on_stack(id, name); self.name_on_stack(id, name);
id id
} }

View File

@@ -1,4 +1,4 @@
use std::collections::{HashMap, HashSet}; use std::collections::HashMap;
use super::{GenericID, Len, StructID, UInstruction, UProgram, UVar, VarID}; use super::{GenericID, Len, StructID, UInstruction, UProgram, UVar, VarID};
@@ -80,7 +80,7 @@ impl UProgram {
pub fn resolve_instr_types( pub fn resolve_instr_types(
&self, &self,
vars: &mut Vec<Option<UVar>>, vars: &mut [Option<UVar>],
i: &UInstruction, i: &UInstruction,
) -> Result<(), VarID> { ) -> Result<(), VarID> {
'outer: { 'outer: {
@@ -161,13 +161,10 @@ impl UProgram {
args[i] = ty; args[i] = ty;
} }
} }
// for arg in &args {
// println!("{:?}", self.type_name(arg));
// }
set(vars, dest.id, Type::Struct { id, args }); set(vars, dest.id, Type::Struct { id, args });
} }
UInstruction::If { cond, body } => {} UInstruction::If { cond, body: _ } => {}
UInstruction::Loop { body } => {} UInstruction::Loop { body: _ } => {}
UInstruction::Break => {} UInstruction::Break => {}
UInstruction::Continue => {} UInstruction::Continue => {}
} }

View File

@@ -24,7 +24,7 @@ impl UProgram {
} }
if var.ty == Type::Infer { if var.ty == Type::Infer {
output.err(CompilerMsg { output.err(CompilerMsg {
msg: format!("Var {:?} cannot be inferred", id), msg: format!("Var {:?} cannot be inferred!", id),
spans: vec![self.origins.get(id)], spans: vec![self.origins.get(id)],
}); });
} }
@@ -40,7 +40,7 @@ impl UProgram {
output.check_assign(self, &var.ty, ft, self.origins.get(id)); output.check_assign(self, &var.ty, ft, self.origins.get(id));
} else { } else {
output.err(CompilerMsg { output.err(CompilerMsg {
msg: format!("invalid parent!"), msg: "invalid parent!".to_string(),
spans: vec![self.origins.get(id)], spans: vec![self.origins.get(id)],
}); });
} }

View File

@@ -6,7 +6,7 @@
#![feature(str_as_str)] #![feature(str_as_str)]
use ir::{LProgram, UProgram}; use ir::{LProgram, UProgram};
use parser::{NodeParsable, PModule, PStatement, ParserCtx}; use parser::{PModule, ParseResult, ParserCtx};
use std::{ use std::{
fs::{create_dir_all, OpenOptions}, fs::{create_dir_all, OpenOptions},
io::{stdout, BufRead, BufReader}, io::{stdout, BufRead, BufReader},
@@ -36,7 +36,7 @@ fn main() {
fn run_file(file: &str, gdb: bool, asm: bool) { fn run_file(file: &str, gdb: bool, asm: bool) {
let mut ctx = ParserCtx::from(file); let mut ctx = ParserCtx::from(file);
let res = PModule::parse_node(&mut ctx); let res = PModule::parse(&mut ctx);
let mut output = ctx.output; let mut output = ctx.output;
'outer: { 'outer: {
if !output.errs.is_empty() { if !output.errs.is_empty() {
@@ -44,22 +44,19 @@ fn run_file(file: &str, gdb: bool, asm: bool) {
} }
// println!("Parsed:"); // println!("Parsed:");
// println!("{:#?}", res.node); // println!("{:#?}", res.node);
let Some(module) = res.node.as_ref() else {
break 'outer;
};
let mut program = UProgram::new(); let mut program = UProgram::new();
module.lower(&mut program, &mut output); res.lower("crate".to_string(), &mut program, &mut output);
if !output.errs.is_empty() { if !output.errs.is_empty() {
break 'outer; break 'outer;
} }
program.resolve_types(); program.resolve_types();
// println!("vars:"); // println!("vars:");
// for (id, def) in program.iter_vars() { // for (id, def) in program.iter_vars() {
// println!(" {id:?} = {}: {}", program.names.get(id), program.type_name(&def.ty)); // println!(" {id:?} = {}: {}", program.names.name(id), program.type_name(&def.ty));
// }
// for (id, f) in program.iter_fns() {
// println!("{}:{id:?} = {:#?}", program.names.get(id), f);
// } // }
for (id, f) in program.iter_fns() {
println!("{}:{id:?} = {:#?}", program.names.name(id), f);
}
output = program.validate(); output = program.validate();
if !output.errs.is_empty() { if !output.errs.is_empty() {
break 'outer; break 'outer;
@@ -128,16 +125,17 @@ fn save_run(binary: &[u8], run_gdb: bool) {
} }
pub fn run_stdin() { pub fn run_stdin() {
for line in BufReader::new(std::io::stdin()).lines() { println!("todo");
let str = &line.expect("failed to read line"); // for line in BufReader::new(std::io::stdin()).lines() {
let mut ctx = ParserCtx::from(&str[..]); // let str = &line.expect("failed to read line");
if let Some(expr) = PStatement::parse_node(&mut ctx).node.as_ref() { // let mut ctx = ParserCtx::from(&str[..]);
if ctx.next().is_none() { // if let Some(expr) = PStatement::parse_node(&mut ctx).node.as_ref() {
println!("{:?}", expr); // if ctx.next().is_none() {
} else { // println!("{:?}", expr);
println!("uhhhh ehehe"); // } else {
} // println!("uhhhh ehehe");
} // }
ctx.output.write_for(&mut stdout(), str); // }
} // ctx.output.write_for(&mut stdout(), str);
// }
} }

View File

@@ -16,7 +16,7 @@ impl CompilerMsg {
pub fn identifier_not_found(id: &Node<PIdent>) -> Self { pub fn identifier_not_found(id: &Node<PIdent>) -> Self {
Self { Self {
msg: format!("Identifier '{}' not found", id.as_ref().unwrap()), msg: format!("Identifier '{}' not found", id.as_ref().unwrap()),
spans: vec![id.span], spans: vec![id.origin],
} }
} }
pub fn unexpected_token(inst: &TokenInstance, expected: &str) -> Self { pub fn unexpected_token(inst: &TokenInstance, expected: &str) -> Self {

View File

@@ -159,7 +159,7 @@ impl RV64Instruction {
"remu" => op(ctx, op32m::REMU, op32m::FUNCT7)?, "remu" => op(ctx, op32m::REMU, op32m::FUNCT7)?,
w => { w => {
ctx.err_at(inst.op.span, format!("Unknown instruction '{}'", w)); ctx.err_at(inst.op.origin, format!("Unknown instruction '{}'", w));
return None; return None;
} }
}) })
@@ -169,7 +169,7 @@ impl RV64Instruction {
pub fn arg_to_var(node: &Node<PAsmArg>, ctx: &mut FnLowerCtx) -> Option<VarInst> { pub fn arg_to_var(node: &Node<PAsmArg>, ctx: &mut FnLowerCtx) -> Option<VarInst> {
let PAsmArg::Ref(node) = node.inner.as_ref()? else { let PAsmArg::Ref(node) = node.inner.as_ref()? else {
ctx.err_at( ctx.err_at(
node.span, node.origin,
"Expected variable / function reference".to_string(), "Expected variable / function reference".to_string(),
); );
return None; return None;
@@ -194,7 +194,7 @@ impl Reg {
let s = &**node.inner.as_ref()?; let s = &**node.inner.as_ref()?;
let res = Reg::from_str(s); let res = Reg::from_str(s);
if res.is_none() { if res.is_none() {
ctx.err_at(node.span, format!("Unknown reg name '{}'", s)); ctx.err_at(node.origin, format!("Unknown reg name '{}'", s));
} }
res res
} }
@@ -202,14 +202,14 @@ impl Reg {
fn i32_from_arg(node: &Node<PAsmArg>, ctx: &mut FnLowerCtx) -> Option<i32> { fn i32_from_arg(node: &Node<PAsmArg>, ctx: &mut FnLowerCtx) -> Option<i32> {
let PAsmArg::Value(node) = node.inner.as_ref()? else { let PAsmArg::Value(node) = node.inner.as_ref()? else {
ctx.err_at(node.span, "Expected an i32, found reference".to_string()); ctx.err_at(node.origin, "Expected an i32, found reference".to_string());
return None; return None;
}; };
let word = node.inner.as_ref()?; let word = node.inner.as_ref()?;
match word.parse::<i32>() { match word.parse::<i32>() {
Ok(x) => Some(x), Ok(x) => Some(x),
Err(_) => { Err(_) => {
ctx.err_at(node.span, format!("Expected an i64, found {}", word)); ctx.err_at(node.origin, format!("Expected an i64, found {}", word));
None None
} }
} }

View File

@@ -1,4 +1,7 @@
use crate::ir::{Type, UInstruction, VarInst}; use crate::{
ir::{Type, UInstruction, VarInst},
parser::{PConstStatement, PStatementLike},
};
use super::{FnLowerCtx, FnLowerable, PBlock, PStatement}; use super::{FnLowerCtx, FnLowerable, PBlock, PStatement};
@@ -6,12 +9,48 @@ 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(); ctx.program.push();
for statement in &self.statements { let mut last = None;
statement.lower(ctx); let mut statements = Vec::new();
let mut fn_nodes = Vec::new();
let mut struct_nodes = Vec::new();
// first sort statements
for s in &self.statements {
let Some(s) = s.as_ref() else {
continue;
};
match s {
PStatementLike::Statement(s) => statements.push(s),
PStatementLike::Const(pconst_statement) => match pconst_statement {
PConstStatement::Fn(f) => fn_nodes.push(f),
PConstStatement::Struct(s) => struct_nodes.push(s),
},
}
}
// then lower const things
let mut structs = Vec::new();
for s in &struct_nodes {
structs.push(s.lower_name(ctx.program));
}
for (s, id) in struct_nodes.iter().zip(structs) {
if let Some(id) = id {
s.lower(id, ctx.program, ctx.output);
}
}
let mut fns = Vec::new();
for f in &fn_nodes {
fns.push(f.lower_name(ctx.program));
}
for (f, id) in fn_nodes.iter().zip(fns) {
if let Some(id) = id {
f.lower(id, ctx.program, ctx.output)
}
}
// then lower statements
for s in statements {
last = s.lower(ctx);
} }
let res = self.result.as_ref().and_then(|r| r.lower(ctx));
ctx.program.pop(); ctx.program.pop();
res last
} }
} }
@@ -19,7 +58,7 @@ impl FnLowerable for PStatement {
type Output = VarInst; type Output = VarInst;
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<VarInst> { fn lower(&self, ctx: &mut FnLowerCtx) -> Option<VarInst> {
match self { match self {
super::PStatement::Let(def, e) => { PStatement::Let(def, e) => {
let def = def.lower(ctx.program, ctx.output)?; let def = def.lower(ctx.program, ctx.output)?;
let res = e.lower(ctx); let res = e.lower(ctx);
if let Some(res) = res { if let Some(res) = res {
@@ -30,7 +69,7 @@ impl FnLowerable for PStatement {
} }
None None
} }
super::PStatement::Return(e) => { PStatement::Return(e) => {
if let Some(e) = e { if let Some(e) = e {
let src = e.lower(ctx)?; let src = e.lower(ctx)?;
ctx.push_at(UInstruction::Ret { src }, src.span); ctx.push_at(UInstruction::Ret { src }, src.span);
@@ -40,7 +79,7 @@ impl FnLowerable for PStatement {
} }
None None
} }
super::PStatement::Expr(e) => e.lower(ctx), PStatement::Expr(e) => e.lower(ctx),
} }
} }
} }

View File

@@ -15,8 +15,8 @@ impl Node<PVarDef> {
None => Type::Infer, None => Type::Infer,
}; };
Some(VarInst { Some(VarInst {
id: program.def_searchable(name, Some(UVar { ty, parent: None }), self.span), id: program.def_searchable(name, Some(UVar { ty, parent: None }), self.origin),
span: self.span, span: self.origin,
}) })
} }
} }

View File

@@ -10,29 +10,29 @@ impl FnLowerable for PExpr {
Some(match self { Some(match self {
PExpr::Lit(l) => match l.as_ref()? { PExpr::Lit(l) => match l.as_ref()? {
super::PLiteral::String(s) => { super::PLiteral::String(s) => {
let dest = ctx.program.temp_var(l.span, Type::Bits(8).slice()); let dest = ctx.program.temp_var(l.origin, Type::Bits(8).slice());
let data = s.as_bytes().to_vec(); let data = s.as_bytes().to_vec();
let src = ctx.program.def( let src = ctx.program.def(
format!("string \"{}\"", s.replace("\n", "\\n")), &format!("string \"{}\"", s.replace("\n", "\\n")),
Some(UData { Some(UData {
ty: Type::Bits(8).arr(data.len() as u32), ty: Type::Bits(8).arr(data.len() as u32),
content: data, content: data,
}), }),
l.span, l.origin,
); );
ctx.push(UInstruction::LoadSlice { dest, src }); ctx.push(UInstruction::LoadSlice { dest, src });
dest dest
} }
super::PLiteral::Char(c) => { super::PLiteral::Char(c) => {
let ty = Type::Bits(8); let ty = Type::Bits(8);
let dest = ctx.program.temp_var(l.span, ty.clone()); let dest = ctx.program.temp_var(l.origin, ty.clone());
let src = ctx.program.def( let src = ctx.program.def(
format!("char '{c}'"), &format!("char '{c}'"),
Some(UData { Some(UData {
ty, ty,
content: c.to_string().as_bytes().to_vec(), content: c.to_string().as_bytes().to_vec(),
}), }),
l.span, l.origin,
); );
ctx.push(UInstruction::LoadData { dest, src }); ctx.push(UInstruction::LoadData { dest, src });
dest dest
@@ -40,24 +40,30 @@ impl FnLowerable for PExpr {
super::PLiteral::Number(n) => { super::PLiteral::Number(n) => {
// TODO: temp // TODO: temp
let ty = Type::Bits(64); let ty = Type::Bits(64);
let dest = ctx.program.temp_var(l.span, Type::Bits(64)); let dest = ctx.program.temp_var(l.origin, Type::Bits(64));
let src = ctx.program.def( let src = ctx.program.def(
format!("num {n:?}"), &format!("num {n:?}"),
Some(UData { Some(UData {
ty, ty,
content: n.whole.parse::<i64>().unwrap().to_le_bytes().to_vec(), content: n.whole.parse::<i64>().unwrap().to_le_bytes().to_vec(),
}), }),
l.span l.origin,
); );
ctx.push(UInstruction::LoadData { dest, src }); ctx.push(UInstruction::LoadData { dest, src });
dest dest
} }
super::PLiteral::Unit => ctx.program.temp_var(l.span, Type::Unit), super::PLiteral::Unit => ctx.program.temp_var(l.origin, Type::Unit),
}, },
PExpr::Ident(i) => ctx.get_var(i)?, PExpr::Ident(i) => ctx.get_var(i)?,
PExpr::BinaryOp(op, e1, e2) => { PExpr::BinaryOp(op, e1, e2) => match op {
let res1 = e1.lower(ctx)?; PInfixOp::Add => todo!(),
if *op == PInfixOp::Access { PInfixOp::Sub => todo!(),
PInfixOp::Mul => todo!(),
PInfixOp::Div => todo!(),
PInfixOp::LessThan => todo!(),
PInfixOp::GreaterThan => todo!(),
PInfixOp::Member => {
let res1 = e1.lower(ctx)?;
let Some(box PExpr::Ident(ident)) = &e2.inner else { let Some(box PExpr::Ident(ident)) = &e2.inner else {
ctx.err("Field accessors must be identifiers".to_string()); ctx.err("Field accessors must be identifiers".to_string());
return None; return None;
@@ -70,26 +76,17 @@ impl FnLowerable for PExpr {
field: fname, field: fname,
}, },
) )
} else {
let res2 = e2.lower(ctx)?;
match op {
PInfixOp::Add => todo!(),
PInfixOp::Sub => todo!(),
PInfixOp::Mul => todo!(),
PInfixOp::Div => todo!(),
PInfixOp::LessThan => todo!(),
PInfixOp::GreaterThan => todo!(),
PInfixOp::Access => todo!(),
PInfixOp::Assign => {
ctx.push(UInstruction::Mv {
dest: res1,
src: res2,
});
res1
}
}
} }
} PInfixOp::Assign => {
let res1 = e1.lower(ctx)?;
let res2 = e2.lower(ctx)?;
ctx.push(UInstruction::Mv {
dest: res1,
src: res2,
});
res1
}
},
PExpr::UnaryOp(op, e) => { PExpr::UnaryOp(op, e) => {
let res = e.lower(ctx)?; let res = e.lower(ctx)?;
match op { match op {

View File

@@ -19,7 +19,7 @@ impl PFunction {
pub fn lower_name(&self, p: &mut UProgram) -> Option<FnID> { pub fn lower_name(&self, p: &mut UProgram) -> Option<FnID> {
let header = self.header.as_ref()?; let header = self.header.as_ref()?;
let name = header.name.as_ref()?; let name = header.name.as_ref()?;
let id = p.def_searchable(name.to_string(), None, self.header.span); 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, output: &mut CompilerOutput) { pub fn lower(&self, id: FnID, p: &mut UProgram, output: &mut CompilerOutput) {
@@ -42,7 +42,7 @@ impl PFunction {
instructions: Vec::new(), instructions: Vec::new(),
program: p, program: p,
output, output,
span: self.body.span, origin: self.body.origin,
}; };
if let Some(src) = self.body.lower(&mut ctx) { if let Some(src) = self.body.lower(&mut ctx) {
ctx.instructions.push(UInstrInst { ctx.instructions.push(UInstrInst {
@@ -65,7 +65,7 @@ pub struct FnLowerCtx<'a> {
pub program: &'a mut UProgram, pub program: &'a mut UProgram,
pub instructions: Vec<UInstrInst>, pub instructions: Vec<UInstrInst>,
pub output: &'a mut CompilerOutput, pub output: &'a mut CompilerOutput,
pub span: FileSpan, pub origin: FileSpan,
} }
impl FnLowerCtx<'_> { impl FnLowerCtx<'_> {
@@ -73,7 +73,7 @@ impl FnLowerCtx<'_> {
let name = node.inner.as_ref()?; let name = node.inner.as_ref()?;
let res = self.program.get_idents(name); let res = self.program.get_idents(name);
if res.is_none() { if res.is_none() {
self.err_at(node.span, format!("Identifier '{}' not found", name)); self.err_at(node.origin, format!("Identifier '{}' not found", name));
} }
res res
} }
@@ -81,29 +81,29 @@ impl FnLowerCtx<'_> {
let ids = self.get_idents(node)?; let ids = self.get_idents(node)?;
if ids.get::<UVar>().is_none() { if ids.get::<UVar>().is_none() {
self.err_at( self.err_at(
node.span, node.origin,
format!("Variable '{}' not found", node.inner.as_ref()?), format!("Variable '{}' not found", node.inner.as_ref()?),
); );
} }
ids.get::<UVar>().map(|id| VarInst { ids.get::<UVar>().map(|id| VarInst {
id, id,
span: node.span, span: node.origin,
}) })
} }
pub fn err(&mut self, msg: String) { pub fn err(&mut self, msg: String) {
self.output.err(CompilerMsg::from_span(self.span, msg)) self.output.err(CompilerMsg::from_span(self.origin, msg))
} }
pub fn err_at(&mut self, span: FileSpan, msg: String) { pub fn err_at(&mut self, span: FileSpan, msg: String) {
self.output.err(CompilerMsg::from_span(span, msg)) self.output.err(CompilerMsg::from_span(span, msg))
} }
pub fn temp(&mut self, ty: Type) -> VarInst { pub fn temp(&mut self, ty: Type) -> VarInst {
self.program.temp_var(self.span, ty) self.program.temp_var(self.origin, ty)
} }
pub fn temp_subvar(&mut self, ty: Type, parent: FieldRef) -> VarInst { pub fn temp_subvar(&mut self, ty: Type, parent: FieldRef) -> VarInst {
self.program.temp_subvar(self.span, ty, parent) 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.span); self.push_at(i, self.origin);
} }
pub fn push_at(&mut self, i: UInstruction, span: FileSpan) { pub fn push_at(&mut self, i: UInstruction, span: FileSpan) {
self.instructions.push(UInstrInst { i, span }); self.instructions.push(UInstrInst { i, span });
@@ -113,7 +113,7 @@ impl FnLowerCtx<'_> {
program: self.program, program: self.program,
instructions: Vec::new(), instructions: Vec::new(),
output: self.output, output: self.output,
span: self.span, origin: self.origin,
} }
} }
} }

View File

@@ -4,11 +4,34 @@ mod block;
mod def; mod def;
mod expr; mod expr;
mod func; mod func;
mod module;
mod struc; mod struc;
mod ty; mod ty;
use super::*; use super::*;
use crate::ir::{Type, UFunc, UProgram};
impl PModule {
pub fn lower(&self, name: String, p: &mut UProgram, output: &mut CompilerOutput) {
let id = p.def_searchable(name.clone(), None, self.block.origin);
p.push_name(&name);
let mut fctx = FnLowerCtx {
program: p,
instructions: Vec::new(),
output,
origin: self.block.origin,
};
self.block.lower(&mut fctx);
let f = UFunc {
args: Vec::new(),
instructions: fctx.instructions,
ret: Type::Unit,
};
let ty = f.ty(p);
p.write(id, f);
p.pop_name();
p.expect_mut(p.fn_var.var(id)).ty = ty;
}
}
pub use func::FnLowerCtx; pub use func::FnLowerCtx;
@@ -20,10 +43,10 @@ pub trait FnLowerable {
impl<T: FnLowerable> FnLowerable for Node<T> { impl<T: FnLowerable> FnLowerable for Node<T> {
type Output = T::Output; type Output = T::Output;
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<T::Output> { fn lower(&self, ctx: &mut FnLowerCtx) -> Option<T::Output> {
let old_span = ctx.span; let old_span = ctx.origin;
ctx.span = self.span; ctx.origin = self.origin;
let res = self.as_ref()?.lower(ctx); let res = self.as_ref()?.lower(ctx);
ctx.span = old_span; ctx.origin = old_span;
res res
} }
} }

View File

@@ -1,26 +0,0 @@
use crate::ir::UProgram;
use super::{CompilerOutput, PModule};
impl PModule {
pub fn lower(&self, p: &mut UProgram, output: &mut CompilerOutput) {
let mut structs = Vec::new();
for s in &self.structs {
structs.push(s.lower_name(p));
}
for (s, id) in self.structs.iter().zip(structs) {
if let Some(id) = id {
s.lower(id, p, output);
}
}
let mut fns = Vec::new();
for f in &self.functions {
fns.push(f.lower_name(p));
}
for (f, id) in self.functions.iter().zip(fns) {
if let Some(id) = id {
f.lower(id, p, output)
}
}
}
}

View File

@@ -85,10 +85,10 @@ impl Node<PStruct> {
pub fn lower_name(&self, p: &mut UProgram) -> Option<StructID> { pub fn lower_name(&self, p: &mut UProgram) -> Option<StructID> {
let s = self.as_ref()?; let s = self.as_ref()?;
let name = s.name.as_ref()?.to_string(); let name = s.name.as_ref()?.to_string();
let id = p.def_searchable(name.to_string(), None, s.name.span); let id = p.def_searchable(name.to_string(), None, s.name.origin);
Some(id) Some(id)
} }
pub fn lower(&self, id: StructID, p: &mut UProgram, output: &mut CompilerOutput) { pub fn lower(&self, id: StructID, p: &mut UProgram, output: &mut CompilerOutput) {
self.as_ref().map(|i| i.lower(id, p, output, self.span)); self.as_ref().map(|i| i.lower(id, p, output, self.origin));
} }
} }

View File

@@ -8,7 +8,7 @@ use super::{CompilerMsg, CompilerOutput, FileSpan, Node, PType};
impl Node<PType> { impl Node<PType> {
pub fn lower(&self, namespace: &mut UProgram, output: &mut CompilerOutput) -> Type { pub fn lower(&self, namespace: &mut UProgram, output: &mut CompilerOutput) -> Type {
self.as_ref() self.as_ref()
.map(|t| t.lower(namespace, output, self.span)) .map(|t| t.lower(namespace, output, self.origin))
.unwrap_or(Type::Error) .unwrap_or(Type::Error)
} }
} }
@@ -47,6 +47,6 @@ impl Node<PGenericDef> {
pub fn lower(&self, p: &mut UProgram) -> Option<GenericID> { pub fn lower(&self, p: &mut UProgram) -> Option<GenericID> {
let s = self.as_ref()?; let s = self.as_ref()?;
let name = s.name.as_ref()?; let name = s.name.as_ref()?;
Some(p.def_searchable(name.to_string(), Some(UGeneric {}), self.span)) Some(p.def_searchable(name.to_string(), Some(UGeneric {}), self.origin))
} }
} }

View File

@@ -3,30 +3,30 @@ use std::{
ops::{Deref, DerefMut}, ops::{Deref, DerefMut},
}; };
use super::FileSpan; use crate::ir::Origin;
pub struct Node<T> { pub struct Node<T> {
pub inner: Option<T>, pub inner: Option<T>,
pub span: FileSpan, pub origin: Origin,
} }
impl<T> Node<T> { impl<T> Node<T> {
pub fn new(inner: T, span: FileSpan) -> Self { pub fn new(inner: T, span: Origin) -> Self {
Self { Self {
inner: Some(inner), inner: Some(inner),
span, origin: span,
} }
} }
pub fn bx(self) -> Node<Box<T>> { pub fn bx(self) -> Node<Box<T>> {
Node { Node {
inner: self.inner.map(|v| Box::new(v)), inner: self.inner.map(|v| Box::new(v)),
span: self.span, origin: self.origin,
} }
} }
pub fn map<T2, F: Fn(T) -> T2>(self, f: F) -> Node<T2> { pub fn map<T2, F: Fn(T) -> T2>(self, f: F) -> Node<T2> {
Node { Node {
inner: self.inner.map(f), inner: self.inner.map(f),
span: self.span, origin: self.origin,
} }
} }
} }

View File

@@ -1,33 +1,41 @@
use std::fmt::{Debug, Write}; use std::fmt::{Debug, Write};
use super::{ use super::{
token::Symbol, Node, NodeParsable, PStatement, Parsable, ParseResult, ParserCtx, CompilerMsg, token::Symbol, CompilerMsg, Node, NodeParsable, PStatementLike, ParseResult, ParserCtx,
};
use crate::{
parser::{ParsableWith, TokenInstance},
util::Padder,
}; };
use crate::util::Padder;
pub struct PBlock { pub struct PBlock {
pub statements: Vec<Node<PStatement>>, pub statements: Vec<Node<PStatementLike>>,
pub result: Option<Node<Box<PStatement>>>, pub ret_last: bool,
} }
impl Parsable for PBlock { impl ParsableWith for PBlock {
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> { type Data = Option<Symbol>;
fn parse(ctx: &mut ParserCtx, end: Option<Symbol>) -> ParseResult<Self> {
let mut statements = Vec::new(); let mut statements = Vec::new();
let mut result = None; let is_end = |t: &TokenInstance| -> bool { end.map(|e| t.is_symbol(e)).unwrap_or(false) };
ctx.expect_sym(Symbol::OpenCurly)?; if ctx.peek().is_none_or(is_end) {
if ctx.expect_peek()?.is_symbol(Symbol::CloseCurly) {
ctx.next(); ctx.next();
return ParseResult::Ok(Self { statements, result }); return ParseResult::Ok(Self {
statements,
ret_last: false,
});
} }
let mut expect_semi = false; let mut expect_semi = false;
let mut recover = false; let mut recover = false;
loop { loop {
let Some(next) = ctx.peek() else { let Some(next) = ctx.peek() else {
recover = true; if end.is_some() {
ctx.err(CompilerMsg::unexpected_end()); recover = true;
ctx.err(CompilerMsg::unexpected_end());
}
break; break;
}; };
if next.is_symbol(Symbol::CloseCurly) { if is_end(next) {
ctx.next(); ctx.next();
break; break;
} }
@@ -41,9 +49,12 @@ impl Parsable for PBlock {
spans: vec![ctx.next_start().char_span()], spans: vec![ctx.next_start().char_span()],
}); });
} }
let res = PStatement::parse_node(ctx); let res = PStatementLike::parse_node(ctx);
expect_semi = res
.node
.as_ref()
.is_some_and(|s| matches!(s, PStatementLike::Statement(..)));
statements.push(res.node); statements.push(res.node);
expect_semi = true;
if res.recover { if res.recover {
ctx.seek_syms(&[Symbol::Semicolon, Symbol::CloseCurly]); ctx.seek_syms(&[Symbol::Semicolon, Symbol::CloseCurly]);
if ctx.peek().is_none() { if ctx.peek().is_none() {
@@ -52,26 +63,34 @@ impl Parsable for PBlock {
} }
} }
} }
if expect_semi { ParseResult::from_recover(
if let Some(s) = statements.pop() { Self {
result = Some(s.bx()); statements,
} ret_last: expect_semi,
} },
ParseResult::from_recover(Self { statements, result }, recover) recover,
)
} }
} }
impl Debug for PBlock { impl Debug for PBlock {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if !self.statements.is_empty() || self.result.is_some() { if !self.statements.is_empty() {
f.write_str("{\n ")?; f.write_str("{\n ")?;
let mut padder = Padder::new(f); let mut padder = Padder::new(f);
for s in &self.statements { let mut end = self.statements.len();
if self.ret_last {
end -= 1;
}
for i in 0..end {
let s = &self.statements[i];
// they don't expose wrap_buf :grief: // they don't expose wrap_buf :grief:
padder.write_str(&format!("{s:?};\n"))?; padder.write_str(&format!("{s:?};\n"))?;
} }
if let Some(res) = &self.result { if self.ret_last
padder.write_str(&format!("{res:?}\n"))?; && let Some(s) = self.statements.last()
{
padder.write_str(&format!("{s:?}\n"))?;
} }
f.write_char('}')?; f.write_char('}')?;
} else { } else {

View File

@@ -1,11 +1,11 @@
use std::fmt::{Debug, Write}; use std::fmt::{Debug, Write};
use crate::common::FilePos; use crate::{common::FilePos, parser::NodeParsableWith};
use super::{ use super::{
op::{PInfixOp, UnaryOp}, op::{PInfixOp, UnaryOp},
util::parse_list, util::parse_list,
CompilerMsg, Keyword, Node, NodeParsable, PAsmBlock, PBlock, PConstruct, PIdent, PLiteral, CompilerMsg, Keyword, Node, PAsmBlock, PBlock, PConstruct, PIdent, PLiteral,
Parsable, ParseResult, ParserCtx, Symbol, Parsable, ParseResult, ParserCtx, Symbol,
}; };
@@ -47,7 +47,8 @@ impl Parsable for PExpr {
ctx.expect_sym(Symbol::CloseParen)?; ctx.expect_sym(Symbol::CloseParen)?;
Self::Group(res.node.bx()) Self::Group(res.node.bx())
} else if next.is_symbol(Symbol::OpenCurly) { } else if next.is_symbol(Symbol::OpenCurly) {
Self::Block(PBlock::parse_node(ctx)?) ctx.next();
Self::Block(PBlock::parse_node(ctx, Some(Symbol::CloseCurly))?)
} else if next.is_keyword(Keyword::If) { } else if next.is_keyword(Keyword::If) {
ctx.next(); ctx.next();
let cond = ctx.parse()?.bx(); let cond = ctx.parse()?.bx();
@@ -71,7 +72,7 @@ impl Parsable for PExpr {
return ctx.parse().map(|n| { return ctx.parse().map(|n| {
let n = n.bx(); let n = n.bx();
if let Some(box Self::BinaryOp(op2, n1, n2)) = n.inner { if let Some(box Self::BinaryOp(op2, n1, n2)) = n.inner {
let span = start.to(n1.span.end); let span = start.to(n1.origin.end);
Self::BinaryOp(op2, Node::new(Self::UnaryOp(op, n1), span).bx(), n2) Self::BinaryOp(op2, Node::new(Self::UnaryOp(op, n1), span).bx(), n2)
} else { } else {
Self::UnaryOp(op, n) Self::UnaryOp(op, n)
@@ -138,7 +139,7 @@ pub fn fix_precedence(
let Some(box PExpr::BinaryOp(op2, n21, n22)) = n2.inner else { let Some(box PExpr::BinaryOp(op2, n21, n22)) = n2.inner else {
unreachable!(); unreachable!();
}; };
let span = start.to(n21.span.end); let span = start.to(n21.origin.end);
let (n11, op1, n12) = fix_precedence(n1, op, n21, start); let (n11, op1, n12) = fix_precedence(n1, op, n21, start);
n1 = Node::new(PExpr::BinaryOp(op1, n11, n12), span).bx(); n1 = Node::new(PExpr::BinaryOp(op1, n11, n12), span).bx();
op = op2; op = op2;

View File

@@ -1,5 +1,5 @@
use super::{ use super::{
util::parse_list, PBlock, PIdent, Keyword, Node, Parsable, ParseResult, ParserCtx, util::parse_list, PBlock, PIdent, Node, Parsable, ParseResult, ParserCtx,
Symbol, PType, PVarDef, Symbol, PType, PVarDef,
}; };
use std::fmt::Debug; use std::fmt::Debug;
@@ -17,7 +17,6 @@ pub struct PFunction {
impl Parsable for PFunctionHeader { impl Parsable for PFunctionHeader {
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> { fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
ctx.expect_kw(Keyword::Fn)?;
let name = ctx.parse()?; let name = ctx.parse()?;
ctx.expect_sym(Symbol::OpenParen)?; ctx.expect_sym(Symbol::OpenParen)?;
// let sel = ctx.maybe_parse(); // let sel = ctx.maybe_parse();
@@ -48,7 +47,8 @@ impl Parsable for PFunctionHeader {
impl Parsable for PFunction { impl Parsable for PFunction {
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> { fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
let header = ctx.parse()?; let header = ctx.parse()?;
let body = ctx.parse()?; ctx.expect_sym(Symbol::OpenCurly)?;
let body = ctx.parse_with(Some(Symbol::CloseCurly))?;
ParseResult::Ok(Self { header, body }) ParseResult::Ok(Self { header, body })
} }
} }

View File

@@ -1,35 +1,46 @@
mod asm_block;
mod asm_fn;
mod asm_instr;
mod block; mod block;
mod def;
mod expr; mod expr;
mod func; mod func;
mod module; mod ident;
mod lit;
mod op; mod op;
mod statement; mod statement;
mod lit;
mod ident;
mod ty;
mod def;
mod struc; mod struc;
mod util;
mod trai; mod trai;
mod asm_fn; mod ty;
mod asm_block; mod util;
mod asm_instr;
pub use asm_block::*;
pub use asm_fn::*;
pub use asm_instr::*;
pub use block::*; pub use block::*;
pub use def::*;
pub use expr::*; pub use expr::*;
pub use func::*; pub use func::*;
pub use module::*;
pub use statement::*;
pub use lit::*;
pub use ident::*; pub use ident::*;
pub use ty::*; pub use lit::*;
pub use def::*; pub use op::*;
pub use statement::*;
pub use struc::*; pub use struc::*;
pub use trai::*; pub use trai::*;
pub use op::*; pub use ty::*;
pub use asm_fn::*;
pub use asm_block::*;
pub use asm_instr::*;
use crate::ir::UProgram;
use super::*; use super::{lower::{FnLowerCtx, FnLowerable}, *};
pub struct PModule {
pub block: Node<PBlock>,
}
impl PModule {
pub fn parse(ctx: &mut ParserCtx) -> Self {
Self {
block: PBlock::parse_node(ctx, None).node,
}
}
}

View File

@@ -1,99 +0,0 @@
use super::{
PFunction, PImpl, Keyword, Node, Parsable, ParseResult, ParserCtx, CompilerMsg,
PStruct, Symbol, Token, PTrait,
};
use std::fmt::Debug;
pub struct PModule {
pub traits: Vec<Node<PTrait>>,
pub structs: Vec<Node<PStruct>>,
pub functions: Vec<Node<PFunction>>,
pub impls: Vec<Node<PImpl>>,
}
impl Parsable for PModule {
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
let mut functions = Vec::new();
let mut structs = Vec::new();
let mut traits = Vec::new();
let mut impls = Vec::new();
loop {
let Some(next) = ctx.peek() else {
break;
};
if let Token::Keyword(kw) = next.token {
match kw {
Keyword::Fn => {
let res = ctx.parse();
functions.push(res.node);
if res.recover {
break;
}
}
Keyword::Struct => {
let res = ctx.parse();
structs.push(res.node);
if res.recover {
break;
}
}
Keyword::Trait => {
let res = ctx.parse();
traits.push(res.node);
if res.recover {
break;
}
}
Keyword::Impl => {
let res = ctx.parse();
impls.push(res.node);
if res.recover {
break;
}
}
_ => {
ctx.err(CompilerMsg::unexpected_token(next, "a definition"));
ctx.next();
}
}
} else if next.is_symbol(Symbol::Semicolon) {
ctx.hint(CompilerMsg::from_instances(
&[next],
"unneeded semicolon".to_string(),
));
ctx.next();
} else {
ctx.err(CompilerMsg::unexpected_token(next, "a definition"));
ctx.next();
}
}
ParseResult::Ok(Self {
functions,
structs,
traits,
impls,
})
}
}
impl Debug for PModule {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
for st in &self.structs {
st.fmt(f)?;
writeln!(f)?;
}
for t in &self.traits {
t.fmt(f)?;
writeln!(f)?;
}
for t in &self.impls {
t.fmt(f)?;
writeln!(f)?;
}
for func in &self.functions {
func.fmt(f)?;
writeln!(f)?;
}
Ok(())
}
}

View File

@@ -8,7 +8,7 @@ pub enum PInfixOp {
Div, Div,
LessThan, LessThan,
GreaterThan, GreaterThan,
Access, Member,
Assign, Assign,
} }
@@ -22,7 +22,7 @@ impl PInfixOp {
Self::Sub => 3, Self::Sub => 3,
Self::Mul => 4, Self::Mul => 4,
Self::Div => 5, Self::Div => 5,
Self::Access => 6, Self::Member => 6,
} }
} }
pub fn str(&self) -> &str { pub fn str(&self) -> &str {
@@ -33,7 +33,7 @@ impl PInfixOp {
Self::Div => "/", Self::Div => "/",
Self::LessThan => "<", Self::LessThan => "<",
Self::GreaterThan => ">", Self::GreaterThan => ">",
Self::Access => ".", Self::Member => ".",
Self::Assign => "=", Self::Assign => "=",
} }
} }
@@ -45,22 +45,10 @@ impl PInfixOp {
Self::Div => true, Self::Div => true,
Self::LessThan => true, Self::LessThan => true,
Self::GreaterThan => true, Self::GreaterThan => true,
Self::Access => false, Self::Member => false,
Self::Assign => true, Self::Assign => true,
} }
} }
pub fn traitt(&self) -> &str {
match self {
Self::Add => "Add",
Self::Sub => "Sub",
Self::Mul => "Mul",
Self::Div => "Div",
Self::LessThan => "LessThan",
Self::GreaterThan => "GreaterThan",
Self::Access => "Access",
Self::Assign => "Assign",
}
}
} }
pub enum UnaryOp { pub enum UnaryOp {
@@ -81,7 +69,7 @@ impl PInfixOp {
Symbol::Minus => Self::Sub, Symbol::Minus => Self::Sub,
Symbol::Asterisk => Self::Mul, Symbol::Asterisk => Self::Mul,
Symbol::Slash => Self::Div, Symbol::Slash => Self::Div,
Symbol::Dot => Self::Access, Symbol::Dot => Self::Member,
Symbol::Equals => Self::Assign, Symbol::Equals => Self::Assign,
_ => { _ => {
return None; return None;

View File

@@ -1,4 +1,7 @@
use super::{Keyword, Node, PExpr, PVarDef, Parsable, ParseResult, ParserCtx, Symbol, Token}; use super::{
Keyword, Node, PExpr, PFunction, PStruct, PVarDef, Parsable, ParseResult, ParserCtx, Symbol,
Token,
};
pub enum PStatement { pub enum PStatement {
Let(Node<PVarDef>, Node<PExpr>), Let(Node<PVarDef>, Node<PExpr>),
@@ -6,7 +9,17 @@ pub enum PStatement {
Expr(Node<PExpr>), Expr(Node<PExpr>),
} }
impl Parsable for PStatement { pub enum PConstStatement {
Fn(Node<PFunction>),
Struct(Node<PStruct>),
}
pub enum PStatementLike {
Statement(PStatement),
Const(PConstStatement),
}
impl Parsable for PStatementLike {
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> { fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
let next = ctx.expect_peek()?; let next = ctx.expect_peek()?;
match next.token { match next.token {
@@ -14,17 +27,27 @@ impl Parsable for PStatement {
ctx.next(); ctx.next();
let def = ctx.parse()?; let def = ctx.parse()?;
ctx.expect_sym(Symbol::Equals)?; ctx.expect_sym(Symbol::Equals)?;
ctx.parse().map(|expr| Self::Let(def, expr)) ctx.parse()
.map(|expr| Self::Statement(PStatement::Let(def, expr)))
} }
Token::Keyword(Keyword::Return) => { Token::Keyword(Keyword::Return) => {
ctx.next(); ctx.next();
if ctx.peek().is_some_and(|t| t.is_symbol(Symbol::Semicolon)) { if ctx.peek().is_some_and(|t| t.is_symbol(Symbol::Semicolon)) {
ParseResult::Ok(Self::Return(None)) ParseResult::Ok(Self::Statement(PStatement::Return(None)))
} else { } else {
ctx.parse().map(|res| Self::Return(Some(res))) ctx.parse()
.map(|res| Self::Statement(PStatement::Return(Some(res))))
} }
} }
_ => ctx.parse().map(Self::Expr), Token::Keyword(Keyword::Fn) => {
ctx.next();
ParseResult::Ok(Self::Const(PConstStatement::Fn(ctx.parse()?)))
}
Token::Keyword(Keyword::Struct) => {
ctx.next();
ParseResult::Ok(Self::Const(PConstStatement::Struct(ctx.parse()?)))
}
_ => ctx.parse().map(|n| Self::Statement(PStatement::Expr(n))),
} }
} }
} }
@@ -49,3 +72,25 @@ impl std::fmt::Debug for PStatement {
Ok(()) Ok(())
} }
} }
impl std::fmt::Debug for PConstStatement {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Fn(fun) => {
fun.fmt(f)?;
}
Self::Struct(s) => {
s.fmt(f)?;
}
}
Ok(())
}
}
impl std::fmt::Debug for PStatementLike {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Statement(s) => s.fmt(f),
Self::Const(c) => c.fmt(f),
}
}
}

View File

@@ -36,7 +36,6 @@ pub enum PConstructFields {
impl Parsable for PStruct { impl Parsable for PStruct {
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> { fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
ctx.expect_kw(Keyword::Struct)?;
let name = ctx.parse()?; let name = ctx.parse()?;
let mut next = ctx.expect_peek()?; let mut next = ctx.expect_peek()?;
let args = if next.is_symbol(Symbol::OpenAngle) { let args = if next.is_symbol(Symbol::OpenAngle) {
@@ -75,7 +74,7 @@ impl ParsableWith for PConstruct {
let next = ctx.expect_peek()?; let next = ctx.expect_peek()?;
// TODO: this is not correct span; type should also span generics, which aren't even in // TODO: this is not correct span; type should also span generics, which aren't even in
// here yet // here yet
let span = name_node.span; let span = name_node.origin;
let name = Node::new( let name = Node::new(
PType { PType {
name: name_node, name: name_node,

View File

@@ -147,7 +147,7 @@ impl<T: ParsableWith> Node<T> {
NodeParseResult { NodeParseResult {
node: Self { node: Self {
inner, inner,
span: start.to(end), origin: start.to(end),
}, },
recover, recover,
} }
@@ -173,7 +173,7 @@ impl<T: MaybeParsable> Node<T> {
let end = ctx.prev_end(); let end = ctx.prev_end();
Some(Self { Some(Self {
inner, inner,
span: start.to(end), origin: start.to(end),
}) })
} }
} }
@@ -191,3 +191,19 @@ impl<T: Parsable> NodeParsable for T {
Node::<Self>::parse(ctx) Node::<Self>::parse(ctx)
} }
} }
pub trait NodeParsableWith {
type Data;
fn parse_node(ctx: &mut ParserCtx, data: Self::Data) -> NodeParseResult<Self>
where
Self: Sized;
}
impl<T: ParsableWith<Data = D>, D> NodeParsableWith for T {
type Data = D;
fn parse_node(ctx: &mut ParserCtx, data: Self::Data) -> NodeParseResult<Self>
where
Self: Sized,
{
Node::<Self>::parse_with(ctx, data)
}
}

View File

@@ -34,6 +34,7 @@ pub enum Symbol {
Pipe, Pipe,
DoublePipe, DoublePipe,
Comma, Comma,
Hash,
} }
impl Symbol { impl Symbol {
@@ -68,6 +69,7 @@ impl Symbol {
'&' => Self::Ampersand, '&' => Self::Ampersand,
'|' => Self::Pipe, '|' => Self::Pipe,
',' => Self::Comma, ',' => Self::Comma,
'#' => Self::Hash,
_ => return None, _ => return None,
}) })
} }
@@ -104,7 +106,7 @@ impl Symbol {
Self::Dot => match next { Self::Dot => match next {
'.' => Self::DoubleDot, '.' => Self::DoubleDot,
_ => return, _ => return,
} },
_ => return, _ => return,
}; };
cursor.advance(); cursor.advance();
@@ -141,6 +143,7 @@ impl Symbol {
Self::DoubleAmpersand => "&&", Self::DoubleAmpersand => "&&",
Self::Pipe => "|", Self::Pipe => "|",
Self::DoublePipe => "||", Self::DoublePipe => "||",
Self::Hash => "#",
} }
} }
} }