prepare for modules
This commit is contained in:
@@ -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,
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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::*;
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 => {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
42
src/main.rs
42
src/main.rs
@@ -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);
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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> {
|
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -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,
|
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;
|
||||||
|
|||||||
@@ -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),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -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 => "#",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user