prepare for modules
This commit is contained in:
@@ -1,3 +1,8 @@
|
||||
println("testy");
|
||||
let x = 3;
|
||||
print_dec(x);
|
||||
start();
|
||||
|
||||
struct Test {
|
||||
a: 64,
|
||||
b: 64,
|
||||
|
||||
@@ -17,7 +17,7 @@ impl LProgram {
|
||||
pub fn create(p: &UProgram) -> Result<Self, String> {
|
||||
let start = p
|
||||
.names
|
||||
.id::<UFunc>("start")
|
||||
.id::<UFunc>("crate")
|
||||
.ok_or("no start method found")?;
|
||||
let mut ssbuilder = SymbolSpaceBuilder::with_entries(&[start]);
|
||||
let entry = ssbuilder.func(&start);
|
||||
|
||||
@@ -100,7 +100,7 @@ macro_rules! impl_kind {
|
||||
($struc:ty, $idx:expr, $field:ident, $name:expr) => {
|
||||
impl_kind!($struc, $idx, $field, $name, nofin);
|
||||
impl Finish for $struc {
|
||||
fn finish(_: &mut UProgram, _: ID<Self>) {}
|
||||
fn finish(_: &mut UProgram, _: ID<Self>, _: &str) {}
|
||||
}
|
||||
};
|
||||
($struc:ty, $idx:expr, $field:ident, $name:expr, nofin) => {
|
||||
@@ -133,9 +133,9 @@ pub type DataID = ID<UData>;
|
||||
pub type GenericID = ID<UGeneric>;
|
||||
|
||||
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(
|
||||
p.names.name(id).to_string(),
|
||||
name.to_string(),
|
||||
Some(UVar {
|
||||
parent: None,
|
||||
ty: Type::Placeholder,
|
||||
@@ -153,5 +153,5 @@ pub trait Kind: Sized {
|
||||
}
|
||||
|
||||
pub trait Finish: Sized {
|
||||
fn finish(program: &mut UProgram, id: ID<Self>);
|
||||
fn finish(program: &mut UProgram, id: ID<Self>, name: &str);
|
||||
}
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
mod kind;
|
||||
mod instr;
|
||||
mod ty;
|
||||
mod program;
|
||||
mod validate;
|
||||
mod assoc;
|
||||
mod error;
|
||||
mod inst;
|
||||
mod maps;
|
||||
mod instr;
|
||||
mod kind;
|
||||
mod program;
|
||||
mod ty;
|
||||
mod validate;
|
||||
|
||||
use super::*;
|
||||
use maps::*;
|
||||
pub use maps::Idents;
|
||||
pub use kind::*;
|
||||
pub use instr::*;
|
||||
pub use ty::*;
|
||||
pub use program::*;
|
||||
use assoc::*;
|
||||
|
||||
pub use assoc::Idents;
|
||||
pub use inst::*;
|
||||
pub use instr::*;
|
||||
pub use kind::*;
|
||||
pub use program::*;
|
||||
pub use ty::*;
|
||||
|
||||
@@ -2,16 +2,19 @@ use super::*;
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub struct UProgram {
|
||||
// kinds
|
||||
pub fns: Vec<Option<UFunc>>,
|
||||
pub vars: Vec<Option<UVar>>,
|
||||
pub structs: Vec<Option<UStruct>>,
|
||||
pub types: Vec<Option<UGeneric>>,
|
||||
pub data: Vec<Option<UData>>,
|
||||
// associated data
|
||||
pub names: NameMap,
|
||||
pub origins: OriginMap,
|
||||
pub fn_var: FnVarMap,
|
||||
pub temp: usize,
|
||||
pub path: Vec<String>,
|
||||
pub name_stack: Vec<HashMap<String, Idents>>,
|
||||
pub temp: usize,
|
||||
}
|
||||
|
||||
impl UProgram {
|
||||
@@ -25,8 +28,9 @@ impl UProgram {
|
||||
names: NameMap::new(),
|
||||
origins: OriginMap::new(),
|
||||
fn_var: FnVarMap::new(),
|
||||
temp: 0,
|
||||
path: Vec::new(),
|
||||
name_stack: vec![HashMap::new()],
|
||||
temp: 0,
|
||||
}
|
||||
}
|
||||
pub fn push(&mut self) {
|
||||
@@ -35,6 +39,12 @@ impl UProgram {
|
||||
pub fn pop(&mut self) {
|
||||
self.name_stack.pop();
|
||||
}
|
||||
pub fn push_name(&mut self, name: &str) {
|
||||
self.path.push(name.to_string());
|
||||
}
|
||||
pub fn pop_name(&mut self) {
|
||||
self.path.pop();
|
||||
}
|
||||
pub fn get_idents(&self, name: &str) -> Option<Idents> {
|
||||
for map in self.name_stack.iter().rev() {
|
||||
let res = map.get(name);
|
||||
@@ -70,7 +80,7 @@ impl UProgram {
|
||||
|
||||
fn temp_var_inner(&mut self, origin: Origin, ty: Type, parent: Option<FieldRef>) -> VarInst {
|
||||
let v = self.def(
|
||||
format!("temp{}", self.temp),
|
||||
&format!("temp{}", self.temp),
|
||||
Some(UVar { parent, ty }),
|
||||
origin,
|
||||
);
|
||||
@@ -85,23 +95,32 @@ impl UProgram {
|
||||
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> {
|
||||
self.names.push::<K>(name);
|
||||
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.origins.push::<K>(origin);
|
||||
let vec = K::from_program_mut(self);
|
||||
let id = ID::new(vec.len());
|
||||
vec.push(k);
|
||||
K::finish(self, id);
|
||||
K::finish(self, id, name);
|
||||
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>(
|
||||
&mut self,
|
||||
name: String,
|
||||
k: Option<K>,
|
||||
origin: Origin,
|
||||
) -> ID<K> {
|
||||
let id = self.def(name.clone(), k, origin);
|
||||
let id = self.def(&name, k, origin);
|
||||
self.name_on_stack(id, name);
|
||||
id
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::collections::HashMap;
|
||||
|
||||
use super::{GenericID, Len, StructID, UInstruction, UProgram, UVar, VarID};
|
||||
|
||||
@@ -80,7 +80,7 @@ impl UProgram {
|
||||
|
||||
pub fn resolve_instr_types(
|
||||
&self,
|
||||
vars: &mut Vec<Option<UVar>>,
|
||||
vars: &mut [Option<UVar>],
|
||||
i: &UInstruction,
|
||||
) -> Result<(), VarID> {
|
||||
'outer: {
|
||||
@@ -161,13 +161,10 @@ impl UProgram {
|
||||
args[i] = ty;
|
||||
}
|
||||
}
|
||||
// for arg in &args {
|
||||
// println!("{:?}", self.type_name(arg));
|
||||
// }
|
||||
set(vars, dest.id, Type::Struct { id, args });
|
||||
}
|
||||
UInstruction::If { cond, body } => {}
|
||||
UInstruction::Loop { body } => {}
|
||||
UInstruction::If { cond, body: _ } => {}
|
||||
UInstruction::Loop { body: _ } => {}
|
||||
UInstruction::Break => {}
|
||||
UInstruction::Continue => {}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ impl UProgram {
|
||||
}
|
||||
if var.ty == Type::Infer {
|
||||
output.err(CompilerMsg {
|
||||
msg: format!("Var {:?} cannot be inferred", id),
|
||||
msg: format!("Var {:?} cannot be inferred!", id),
|
||||
spans: vec![self.origins.get(id)],
|
||||
});
|
||||
}
|
||||
@@ -40,7 +40,7 @@ impl UProgram {
|
||||
output.check_assign(self, &var.ty, ft, self.origins.get(id));
|
||||
} else {
|
||||
output.err(CompilerMsg {
|
||||
msg: format!("invalid parent!"),
|
||||
msg: "invalid parent!".to_string(),
|
||||
spans: vec![self.origins.get(id)],
|
||||
});
|
||||
}
|
||||
|
||||
42
src/main.rs
42
src/main.rs
@@ -6,7 +6,7 @@
|
||||
#![feature(str_as_str)]
|
||||
|
||||
use ir::{LProgram, UProgram};
|
||||
use parser::{NodeParsable, PModule, PStatement, ParserCtx};
|
||||
use parser::{PModule, ParseResult, ParserCtx};
|
||||
use std::{
|
||||
fs::{create_dir_all, OpenOptions},
|
||||
io::{stdout, BufRead, BufReader},
|
||||
@@ -36,7 +36,7 @@ fn main() {
|
||||
|
||||
fn run_file(file: &str, gdb: bool, asm: bool) {
|
||||
let mut ctx = ParserCtx::from(file);
|
||||
let res = PModule::parse_node(&mut ctx);
|
||||
let res = PModule::parse(&mut ctx);
|
||||
let mut output = ctx.output;
|
||||
'outer: {
|
||||
if !output.errs.is_empty() {
|
||||
@@ -44,22 +44,19 @@ fn run_file(file: &str, gdb: bool, asm: bool) {
|
||||
}
|
||||
// println!("Parsed:");
|
||||
// println!("{:#?}", res.node);
|
||||
let Some(module) = res.node.as_ref() else {
|
||||
break 'outer;
|
||||
};
|
||||
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() {
|
||||
break 'outer;
|
||||
}
|
||||
program.resolve_types();
|
||||
// println!("vars:");
|
||||
// for (id, def) in program.iter_vars() {
|
||||
// println!(" {id:?} = {}: {}", program.names.get(id), program.type_name(&def.ty));
|
||||
// }
|
||||
// for (id, f) in program.iter_fns() {
|
||||
// println!("{}:{id:?} = {:#?}", program.names.get(id), f);
|
||||
// println!(" {id:?} = {}: {}", program.names.name(id), program.type_name(&def.ty));
|
||||
// }
|
||||
for (id, f) in program.iter_fns() {
|
||||
println!("{}:{id:?} = {:#?}", program.names.name(id), f);
|
||||
}
|
||||
output = program.validate();
|
||||
if !output.errs.is_empty() {
|
||||
break 'outer;
|
||||
@@ -128,16 +125,17 @@ fn save_run(binary: &[u8], run_gdb: bool) {
|
||||
}
|
||||
|
||||
pub fn run_stdin() {
|
||||
for line in BufReader::new(std::io::stdin()).lines() {
|
||||
let str = &line.expect("failed to read line");
|
||||
let mut ctx = ParserCtx::from(&str[..]);
|
||||
if let Some(expr) = PStatement::parse_node(&mut ctx).node.as_ref() {
|
||||
if ctx.next().is_none() {
|
||||
println!("{:?}", expr);
|
||||
} else {
|
||||
println!("uhhhh ehehe");
|
||||
}
|
||||
}
|
||||
ctx.output.write_for(&mut stdout(), str);
|
||||
}
|
||||
println!("todo");
|
||||
// for line in BufReader::new(std::io::stdin()).lines() {
|
||||
// let str = &line.expect("failed to read line");
|
||||
// let mut ctx = ParserCtx::from(&str[..]);
|
||||
// if let Some(expr) = PStatement::parse_node(&mut ctx).node.as_ref() {
|
||||
// if ctx.next().is_none() {
|
||||
// println!("{:?}", expr);
|
||||
// } else {
|
||||
// println!("uhhhh ehehe");
|
||||
// }
|
||||
// }
|
||||
// ctx.output.write_for(&mut stdout(), str);
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ impl CompilerMsg {
|
||||
pub fn identifier_not_found(id: &Node<PIdent>) -> Self {
|
||||
Self {
|
||||
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 {
|
||||
|
||||
@@ -159,7 +159,7 @@ impl RV64Instruction {
|
||||
"remu" => op(ctx, op32m::REMU, op32m::FUNCT7)?,
|
||||
|
||||
w => {
|
||||
ctx.err_at(inst.op.span, format!("Unknown instruction '{}'", w));
|
||||
ctx.err_at(inst.op.origin, format!("Unknown instruction '{}'", w));
|
||||
return None;
|
||||
}
|
||||
})
|
||||
@@ -169,7 +169,7 @@ impl RV64Instruction {
|
||||
pub fn arg_to_var(node: &Node<PAsmArg>, ctx: &mut FnLowerCtx) -> Option<VarInst> {
|
||||
let PAsmArg::Ref(node) = node.inner.as_ref()? else {
|
||||
ctx.err_at(
|
||||
node.span,
|
||||
node.origin,
|
||||
"Expected variable / function reference".to_string(),
|
||||
);
|
||||
return None;
|
||||
@@ -194,7 +194,7 @@ impl Reg {
|
||||
let s = &**node.inner.as_ref()?;
|
||||
let res = Reg::from_str(s);
|
||||
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
|
||||
}
|
||||
@@ -202,14 +202,14 @@ impl Reg {
|
||||
|
||||
fn i32_from_arg(node: &Node<PAsmArg>, ctx: &mut FnLowerCtx) -> Option<i32> {
|
||||
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;
|
||||
};
|
||||
let word = node.inner.as_ref()?;
|
||||
match word.parse::<i32>() {
|
||||
Ok(x) => Some(x),
|
||||
Err(_) => {
|
||||
ctx.err_at(node.span, format!("Expected an i64, found {}", word));
|
||||
ctx.err_at(node.origin, format!("Expected an i64, found {}", word));
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -6,12 +9,48 @@ impl FnLowerable for PBlock {
|
||||
type Output = VarInst;
|
||||
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<VarInst> {
|
||||
ctx.program.push();
|
||||
for statement in &self.statements {
|
||||
statement.lower(ctx);
|
||||
let mut last = None;
|
||||
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();
|
||||
res
|
||||
last
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +58,7 @@ impl FnLowerable for PStatement {
|
||||
type Output = VarInst;
|
||||
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<VarInst> {
|
||||
match self {
|
||||
super::PStatement::Let(def, e) => {
|
||||
PStatement::Let(def, e) => {
|
||||
let def = def.lower(ctx.program, ctx.output)?;
|
||||
let res = e.lower(ctx);
|
||||
if let Some(res) = res {
|
||||
@@ -30,7 +69,7 @@ impl FnLowerable for PStatement {
|
||||
}
|
||||
None
|
||||
}
|
||||
super::PStatement::Return(e) => {
|
||||
PStatement::Return(e) => {
|
||||
if let Some(e) = e {
|
||||
let src = e.lower(ctx)?;
|
||||
ctx.push_at(UInstruction::Ret { src }, src.span);
|
||||
@@ -40,7 +79,7 @@ impl FnLowerable for PStatement {
|
||||
}
|
||||
None
|
||||
}
|
||||
super::PStatement::Expr(e) => e.lower(ctx),
|
||||
PStatement::Expr(e) => e.lower(ctx),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,8 +15,8 @@ impl Node<PVarDef> {
|
||||
None => Type::Infer,
|
||||
};
|
||||
Some(VarInst {
|
||||
id: program.def_searchable(name, Some(UVar { ty, parent: None }), self.span),
|
||||
span: self.span,
|
||||
id: program.def_searchable(name, Some(UVar { ty, parent: None }), self.origin),
|
||||
span: self.origin,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,29 +10,29 @@ impl FnLowerable for PExpr {
|
||||
Some(match self {
|
||||
PExpr::Lit(l) => match l.as_ref()? {
|
||||
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 src = ctx.program.def(
|
||||
format!("string \"{}\"", s.replace("\n", "\\n")),
|
||||
&format!("string \"{}\"", s.replace("\n", "\\n")),
|
||||
Some(UData {
|
||||
ty: Type::Bits(8).arr(data.len() as u32),
|
||||
content: data,
|
||||
}),
|
||||
l.span,
|
||||
l.origin,
|
||||
);
|
||||
ctx.push(UInstruction::LoadSlice { dest, src });
|
||||
dest
|
||||
}
|
||||
super::PLiteral::Char(c) => {
|
||||
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(
|
||||
format!("char '{c}'"),
|
||||
&format!("char '{c}'"),
|
||||
Some(UData {
|
||||
ty,
|
||||
content: c.to_string().as_bytes().to_vec(),
|
||||
}),
|
||||
l.span,
|
||||
l.origin,
|
||||
);
|
||||
ctx.push(UInstruction::LoadData { dest, src });
|
||||
dest
|
||||
@@ -40,24 +40,30 @@ impl FnLowerable for PExpr {
|
||||
super::PLiteral::Number(n) => {
|
||||
// TODO: temp
|
||||
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(
|
||||
format!("num {n:?}"),
|
||||
&format!("num {n:?}"),
|
||||
Some(UData {
|
||||
ty,
|
||||
content: n.whole.parse::<i64>().unwrap().to_le_bytes().to_vec(),
|
||||
}),
|
||||
l.span
|
||||
l.origin,
|
||||
);
|
||||
ctx.push(UInstruction::LoadData { dest, src });
|
||||
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::BinaryOp(op, e1, e2) => {
|
||||
let res1 = e1.lower(ctx)?;
|
||||
if *op == PInfixOp::Access {
|
||||
PExpr::BinaryOp(op, e1, e2) => match op {
|
||||
PInfixOp::Add => todo!(),
|
||||
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 {
|
||||
ctx.err("Field accessors must be identifiers".to_string());
|
||||
return None;
|
||||
@@ -70,26 +76,17 @@ impl FnLowerable for PExpr {
|
||||
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) => {
|
||||
let res = e.lower(ctx)?;
|
||||
match op {
|
||||
|
||||
@@ -19,7 +19,7 @@ impl PFunction {
|
||||
pub fn lower_name(&self, p: &mut UProgram) -> Option<FnID> {
|
||||
let header = self.header.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)
|
||||
}
|
||||
pub fn lower(&self, id: FnID, p: &mut UProgram, output: &mut CompilerOutput) {
|
||||
@@ -42,7 +42,7 @@ impl PFunction {
|
||||
instructions: Vec::new(),
|
||||
program: p,
|
||||
output,
|
||||
span: self.body.span,
|
||||
origin: self.body.origin,
|
||||
};
|
||||
if let Some(src) = self.body.lower(&mut ctx) {
|
||||
ctx.instructions.push(UInstrInst {
|
||||
@@ -65,7 +65,7 @@ pub struct FnLowerCtx<'a> {
|
||||
pub program: &'a mut UProgram,
|
||||
pub instructions: Vec<UInstrInst>,
|
||||
pub output: &'a mut CompilerOutput,
|
||||
pub span: FileSpan,
|
||||
pub origin: FileSpan,
|
||||
}
|
||||
|
||||
impl FnLowerCtx<'_> {
|
||||
@@ -73,7 +73,7 @@ impl FnLowerCtx<'_> {
|
||||
let name = node.inner.as_ref()?;
|
||||
let res = self.program.get_idents(name);
|
||||
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
|
||||
}
|
||||
@@ -81,29 +81,29 @@ impl FnLowerCtx<'_> {
|
||||
let ids = self.get_idents(node)?;
|
||||
if ids.get::<UVar>().is_none() {
|
||||
self.err_at(
|
||||
node.span,
|
||||
node.origin,
|
||||
format!("Variable '{}' not found", node.inner.as_ref()?),
|
||||
);
|
||||
}
|
||||
ids.get::<UVar>().map(|id| VarInst {
|
||||
id,
|
||||
span: node.span,
|
||||
span: node.origin,
|
||||
})
|
||||
}
|
||||
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) {
|
||||
self.output.err(CompilerMsg::from_span(span, msg))
|
||||
}
|
||||
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 {
|
||||
self.program.temp_subvar(self.span, ty, parent)
|
||||
self.program.temp_subvar(self.origin, ty, parent)
|
||||
}
|
||||
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) {
|
||||
self.instructions.push(UInstrInst { i, span });
|
||||
@@ -113,7 +113,7 @@ impl FnLowerCtx<'_> {
|
||||
program: self.program,
|
||||
instructions: Vec::new(),
|
||||
output: self.output,
|
||||
span: self.span,
|
||||
origin: self.origin,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,11 +4,34 @@ mod block;
|
||||
mod def;
|
||||
mod expr;
|
||||
mod func;
|
||||
mod module;
|
||||
mod struc;
|
||||
mod ty;
|
||||
|
||||
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;
|
||||
|
||||
@@ -20,10 +43,10 @@ pub trait FnLowerable {
|
||||
impl<T: FnLowerable> FnLowerable for Node<T> {
|
||||
type Output = T::Output;
|
||||
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<T::Output> {
|
||||
let old_span = ctx.span;
|
||||
ctx.span = self.span;
|
||||
let old_span = ctx.origin;
|
||||
ctx.origin = self.origin;
|
||||
let res = self.as_ref()?.lower(ctx);
|
||||
ctx.span = old_span;
|
||||
ctx.origin = old_span;
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -85,10 +85,10 @@ impl Node<PStruct> {
|
||||
pub fn lower_name(&self, p: &mut UProgram) -> Option<StructID> {
|
||||
let s = self.as_ref()?;
|
||||
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)
|
||||
}
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ use super::{CompilerMsg, CompilerOutput, FileSpan, Node, PType};
|
||||
impl Node<PType> {
|
||||
pub fn lower(&self, namespace: &mut UProgram, output: &mut CompilerOutput) -> Type {
|
||||
self.as_ref()
|
||||
.map(|t| t.lower(namespace, output, self.span))
|
||||
.map(|t| t.lower(namespace, output, self.origin))
|
||||
.unwrap_or(Type::Error)
|
||||
}
|
||||
}
|
||||
@@ -47,6 +47,6 @@ 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.to_string(), Some(UGeneric {}), self.span))
|
||||
Some(p.def_searchable(name.to_string(), Some(UGeneric {}), self.origin))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,30 +3,30 @@ use std::{
|
||||
ops::{Deref, DerefMut},
|
||||
};
|
||||
|
||||
use super::FileSpan;
|
||||
use crate::ir::Origin;
|
||||
|
||||
pub struct Node<T> {
|
||||
pub inner: Option<T>,
|
||||
pub span: FileSpan,
|
||||
pub origin: Origin,
|
||||
}
|
||||
|
||||
impl<T> Node<T> {
|
||||
pub fn new(inner: T, span: FileSpan) -> Self {
|
||||
pub fn new(inner: T, span: Origin) -> Self {
|
||||
Self {
|
||||
inner: Some(inner),
|
||||
span,
|
||||
origin: span,
|
||||
}
|
||||
}
|
||||
pub fn bx(self) -> Node<Box<T>> {
|
||||
Node {
|
||||
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> {
|
||||
Node {
|
||||
inner: self.inner.map(f),
|
||||
span: self.span,
|
||||
origin: self.origin,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,33 +1,41 @@
|
||||
use std::fmt::{Debug, Write};
|
||||
|
||||
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 statements: Vec<Node<PStatement>>,
|
||||
pub result: Option<Node<Box<PStatement>>>,
|
||||
pub statements: Vec<Node<PStatementLike>>,
|
||||
pub ret_last: bool,
|
||||
}
|
||||
|
||||
impl Parsable for PBlock {
|
||||
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||
impl ParsableWith for PBlock {
|
||||
type Data = Option<Symbol>;
|
||||
fn parse(ctx: &mut ParserCtx, end: Option<Symbol>) -> ParseResult<Self> {
|
||||
let mut statements = Vec::new();
|
||||
let mut result = None;
|
||||
ctx.expect_sym(Symbol::OpenCurly)?;
|
||||
if ctx.expect_peek()?.is_symbol(Symbol::CloseCurly) {
|
||||
let is_end = |t: &TokenInstance| -> bool { end.map(|e| t.is_symbol(e)).unwrap_or(false) };
|
||||
if ctx.peek().is_none_or(is_end) {
|
||||
ctx.next();
|
||||
return ParseResult::Ok(Self { statements, result });
|
||||
return ParseResult::Ok(Self {
|
||||
statements,
|
||||
ret_last: false,
|
||||
});
|
||||
}
|
||||
let mut expect_semi = false;
|
||||
let mut recover = false;
|
||||
loop {
|
||||
let Some(next) = ctx.peek() else {
|
||||
recover = true;
|
||||
ctx.err(CompilerMsg::unexpected_end());
|
||||
if end.is_some() {
|
||||
recover = true;
|
||||
ctx.err(CompilerMsg::unexpected_end());
|
||||
}
|
||||
break;
|
||||
};
|
||||
if next.is_symbol(Symbol::CloseCurly) {
|
||||
if is_end(next) {
|
||||
ctx.next();
|
||||
break;
|
||||
}
|
||||
@@ -41,9 +49,12 @@ impl Parsable for PBlock {
|
||||
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);
|
||||
expect_semi = true;
|
||||
if res.recover {
|
||||
ctx.seek_syms(&[Symbol::Semicolon, Symbol::CloseCurly]);
|
||||
if ctx.peek().is_none() {
|
||||
@@ -52,26 +63,34 @@ impl Parsable for PBlock {
|
||||
}
|
||||
}
|
||||
}
|
||||
if expect_semi {
|
||||
if let Some(s) = statements.pop() {
|
||||
result = Some(s.bx());
|
||||
}
|
||||
}
|
||||
ParseResult::from_recover(Self { statements, result }, recover)
|
||||
ParseResult::from_recover(
|
||||
Self {
|
||||
statements,
|
||||
ret_last: expect_semi,
|
||||
},
|
||||
recover,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for PBlock {
|
||||
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 ")?;
|
||||
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:
|
||||
padder.write_str(&format!("{s:?};\n"))?;
|
||||
}
|
||||
if let Some(res) = &self.result {
|
||||
padder.write_str(&format!("{res:?}\n"))?;
|
||||
if self.ret_last
|
||||
&& let Some(s) = self.statements.last()
|
||||
{
|
||||
padder.write_str(&format!("{s:?}\n"))?;
|
||||
}
|
||||
f.write_char('}')?;
|
||||
} else {
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
use std::fmt::{Debug, Write};
|
||||
|
||||
use crate::common::FilePos;
|
||||
use crate::{common::FilePos, parser::NodeParsableWith};
|
||||
|
||||
use super::{
|
||||
op::{PInfixOp, UnaryOp},
|
||||
util::parse_list,
|
||||
CompilerMsg, Keyword, Node, NodeParsable, PAsmBlock, PBlock, PConstruct, PIdent, PLiteral,
|
||||
CompilerMsg, Keyword, Node, PAsmBlock, PBlock, PConstruct, PIdent, PLiteral,
|
||||
Parsable, ParseResult, ParserCtx, Symbol,
|
||||
};
|
||||
|
||||
@@ -47,7 +47,8 @@ impl Parsable for PExpr {
|
||||
ctx.expect_sym(Symbol::CloseParen)?;
|
||||
Self::Group(res.node.bx())
|
||||
} 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) {
|
||||
ctx.next();
|
||||
let cond = ctx.parse()?.bx();
|
||||
@@ -71,7 +72,7 @@ impl Parsable for PExpr {
|
||||
return ctx.parse().map(|n| {
|
||||
let n = n.bx();
|
||||
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)
|
||||
} else {
|
||||
Self::UnaryOp(op, n)
|
||||
@@ -138,7 +139,7 @@ pub fn fix_precedence(
|
||||
let Some(box PExpr::BinaryOp(op2, n21, n22)) = n2.inner else {
|
||||
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);
|
||||
n1 = Node::new(PExpr::BinaryOp(op1, n11, n12), span).bx();
|
||||
op = op2;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use super::{
|
||||
util::parse_list, PBlock, PIdent, Keyword, Node, Parsable, ParseResult, ParserCtx,
|
||||
util::parse_list, PBlock, PIdent, Node, Parsable, ParseResult, ParserCtx,
|
||||
Symbol, PType, PVarDef,
|
||||
};
|
||||
use std::fmt::Debug;
|
||||
@@ -17,7 +17,6 @@ pub struct PFunction {
|
||||
|
||||
impl Parsable for PFunctionHeader {
|
||||
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||
ctx.expect_kw(Keyword::Fn)?;
|
||||
let name = ctx.parse()?;
|
||||
ctx.expect_sym(Symbol::OpenParen)?;
|
||||
// let sel = ctx.maybe_parse();
|
||||
@@ -48,7 +47,8 @@ impl Parsable for PFunctionHeader {
|
||||
impl Parsable for PFunction {
|
||||
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||
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 })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,35 +1,46 @@
|
||||
mod asm_block;
|
||||
mod asm_fn;
|
||||
mod asm_instr;
|
||||
mod block;
|
||||
mod def;
|
||||
mod expr;
|
||||
mod func;
|
||||
mod module;
|
||||
mod ident;
|
||||
mod lit;
|
||||
mod op;
|
||||
mod statement;
|
||||
mod lit;
|
||||
mod ident;
|
||||
mod ty;
|
||||
mod def;
|
||||
mod struc;
|
||||
mod util;
|
||||
mod trai;
|
||||
mod asm_fn;
|
||||
mod asm_block;
|
||||
mod asm_instr;
|
||||
mod ty;
|
||||
mod util;
|
||||
|
||||
pub use asm_block::*;
|
||||
pub use asm_fn::*;
|
||||
pub use asm_instr::*;
|
||||
pub use block::*;
|
||||
pub use def::*;
|
||||
pub use expr::*;
|
||||
pub use func::*;
|
||||
pub use module::*;
|
||||
pub use statement::*;
|
||||
pub use lit::*;
|
||||
pub use ident::*;
|
||||
pub use ty::*;
|
||||
pub use def::*;
|
||||
pub use lit::*;
|
||||
pub use op::*;
|
||||
pub use statement::*;
|
||||
pub use struc::*;
|
||||
pub use trai::*;
|
||||
pub use op::*;
|
||||
pub use asm_fn::*;
|
||||
pub use asm_block::*;
|
||||
pub use asm_instr::*;
|
||||
pub use ty::*;
|
||||
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ pub enum PInfixOp {
|
||||
Div,
|
||||
LessThan,
|
||||
GreaterThan,
|
||||
Access,
|
||||
Member,
|
||||
Assign,
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ impl PInfixOp {
|
||||
Self::Sub => 3,
|
||||
Self::Mul => 4,
|
||||
Self::Div => 5,
|
||||
Self::Access => 6,
|
||||
Self::Member => 6,
|
||||
}
|
||||
}
|
||||
pub fn str(&self) -> &str {
|
||||
@@ -33,7 +33,7 @@ impl PInfixOp {
|
||||
Self::Div => "/",
|
||||
Self::LessThan => "<",
|
||||
Self::GreaterThan => ">",
|
||||
Self::Access => ".",
|
||||
Self::Member => ".",
|
||||
Self::Assign => "=",
|
||||
}
|
||||
}
|
||||
@@ -45,22 +45,10 @@ impl PInfixOp {
|
||||
Self::Div => true,
|
||||
Self::LessThan => true,
|
||||
Self::GreaterThan => true,
|
||||
Self::Access => false,
|
||||
Self::Member => false,
|
||||
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 {
|
||||
@@ -81,7 +69,7 @@ impl PInfixOp {
|
||||
Symbol::Minus => Self::Sub,
|
||||
Symbol::Asterisk => Self::Mul,
|
||||
Symbol::Slash => Self::Div,
|
||||
Symbol::Dot => Self::Access,
|
||||
Symbol::Dot => Self::Member,
|
||||
Symbol::Equals => Self::Assign,
|
||||
_ => {
|
||||
return None;
|
||||
|
||||
@@ -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 {
|
||||
Let(Node<PVarDef>, Node<PExpr>),
|
||||
@@ -6,7 +9,17 @@ pub enum PStatement {
|
||||
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> {
|
||||
let next = ctx.expect_peek()?;
|
||||
match next.token {
|
||||
@@ -14,17 +27,27 @@ impl Parsable for PStatement {
|
||||
ctx.next();
|
||||
let def = ctx.parse()?;
|
||||
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) => {
|
||||
ctx.next();
|
||||
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 {
|
||||
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(())
|
||||
}
|
||||
}
|
||||
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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,6 @@ pub enum PConstructFields {
|
||||
|
||||
impl Parsable for PStruct {
|
||||
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||
ctx.expect_kw(Keyword::Struct)?;
|
||||
let name = ctx.parse()?;
|
||||
let mut next = ctx.expect_peek()?;
|
||||
let args = if next.is_symbol(Symbol::OpenAngle) {
|
||||
@@ -75,7 +74,7 @@ impl ParsableWith for PConstruct {
|
||||
let next = ctx.expect_peek()?;
|
||||
// TODO: this is not correct span; type should also span generics, which aren't even in
|
||||
// here yet
|
||||
let span = name_node.span;
|
||||
let span = name_node.origin;
|
||||
let name = Node::new(
|
||||
PType {
|
||||
name: name_node,
|
||||
|
||||
@@ -147,7 +147,7 @@ impl<T: ParsableWith> Node<T> {
|
||||
NodeParseResult {
|
||||
node: Self {
|
||||
inner,
|
||||
span: start.to(end),
|
||||
origin: start.to(end),
|
||||
},
|
||||
recover,
|
||||
}
|
||||
@@ -173,7 +173,7 @@ impl<T: MaybeParsable> Node<T> {
|
||||
let end = ctx.prev_end();
|
||||
Some(Self {
|
||||
inner,
|
||||
span: start.to(end),
|
||||
origin: start.to(end),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -191,3 +191,19 @@ impl<T: Parsable> NodeParsable for T {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ pub enum Symbol {
|
||||
Pipe,
|
||||
DoublePipe,
|
||||
Comma,
|
||||
Hash,
|
||||
}
|
||||
|
||||
impl Symbol {
|
||||
@@ -68,6 +69,7 @@ impl Symbol {
|
||||
'&' => Self::Ampersand,
|
||||
'|' => Self::Pipe,
|
||||
',' => Self::Comma,
|
||||
'#' => Self::Hash,
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
@@ -104,7 +106,7 @@ impl Symbol {
|
||||
Self::Dot => match next {
|
||||
'.' => Self::DoubleDot,
|
||||
_ => return,
|
||||
}
|
||||
},
|
||||
_ => return,
|
||||
};
|
||||
cursor.advance();
|
||||
@@ -141,6 +143,7 @@ impl Symbol {
|
||||
Self::DoubleAmpersand => "&&",
|
||||
Self::Pipe => "|",
|
||||
Self::DoublePipe => "||",
|
||||
Self::Hash => "#",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user