a ton of stuff idk more ir work
This commit is contained in:
@@ -1,4 +1,8 @@
|
|||||||
fn main() {
|
fn main() {
|
||||||
let x = 3;
|
asm {
|
||||||
exit(x);
|
li a0, 3
|
||||||
|
li a7, 93
|
||||||
|
ecall
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use std::{
|
|||||||
|
|
||||||
mod elf;
|
mod elf;
|
||||||
mod program;
|
mod program;
|
||||||
mod riscv64;
|
pub mod riscv64;
|
||||||
mod target;
|
mod target;
|
||||||
|
|
||||||
pub use program::*;
|
pub use program::*;
|
||||||
|
|||||||
@@ -2,34 +2,41 @@ use crate::compiler::program::{Addr, Instr, SymTable, Symbol};
|
|||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
pub enum AsmInstruction {
|
pub enum AsmInstruction {
|
||||||
Add(Reg, Reg, Reg),
|
Add { dest: Reg, src1: Reg, src2: Reg },
|
||||||
Addi(Reg, Reg, i32),
|
Addi { dest: Reg, src: Reg, imm: i32 },
|
||||||
Andi(Reg, Reg, i32),
|
Andi { dest: Reg, src: Reg, imm: i32 },
|
||||||
Slli(Reg, Reg, i32),
|
Slli { dest: Reg, src: Reg, imm: i32 },
|
||||||
Srli(Reg, Reg, i32),
|
Srli { dest: Reg, src: Reg, imm: i32 },
|
||||||
Sd(Reg, i32, Reg),
|
Sd { src: Reg, offset: i32, base: Reg },
|
||||||
Mv(Reg, Reg),
|
Mv { dest: Reg, src: Reg },
|
||||||
La(Reg, Symbol),
|
La { dest: Reg, sym: Symbol },
|
||||||
Jal(Reg, i32),
|
Jal { dest: Reg, offset: i32 },
|
||||||
Call(Symbol),
|
Call(Symbol),
|
||||||
J(Symbol),
|
J(Symbol),
|
||||||
Ret,
|
Ret,
|
||||||
Ecall,
|
Ecall,
|
||||||
Li(Reg, i32),
|
Li { dest: Reg, imm: i64 },
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Instr for AsmInstruction {
|
impl Instr for AsmInstruction {
|
||||||
fn push(&self, data: &mut Vec<u8>, sym_map: &SymTable, pos: Addr, missing: bool) -> Option<Symbol> {
|
fn push(
|
||||||
|
&self,
|
||||||
|
data: &mut Vec<u8>,
|
||||||
|
sym_map: &SymTable,
|
||||||
|
pos: Addr,
|
||||||
|
missing: bool,
|
||||||
|
) -> Option<Symbol> {
|
||||||
let last = match self {
|
let last = match self {
|
||||||
Self::Add(dest, src1, src2) => add(*dest, *src1, *src2),
|
Self::Add { dest, src1, src2 } => add(*dest, *src1, *src2),
|
||||||
Self::Addi(dest, src, imm) => addi(*dest, *src, BitsI32::new(*imm)),
|
Self::Addi { dest, src, imm } => addi(*dest, *src, BitsI32::new(*imm)),
|
||||||
Self::Andi(dest, src, imm) => andi(*dest, *src, BitsI32::new(*imm)),
|
Self::Andi { dest, src, imm } => andi(*dest, *src, BitsI32::new(*imm)),
|
||||||
Self::Slli(dest, src, imm) => slli(*dest, *src, BitsI32::new(*imm)),
|
Self::Slli { dest, src, imm } => slli(*dest, *src, BitsI32::new(*imm)),
|
||||||
Self::Srli(dest, src, imm) => srli(*dest, *src, BitsI32::new(*imm)),
|
Self::Srli { dest, src, imm } => srli(*dest, *src, BitsI32::new(*imm)),
|
||||||
Self::Sd(src, offset, base) => sd(*src, BitsI32::new(*offset), *base),
|
Self::Sd { src, offset, base } => sd(*src, BitsI32::new(*offset), *base),
|
||||||
Self::Mv(dest, src) => addi(*dest, *src, BitsI32::new(0)),
|
Self::Mv { dest, src } => addi(*dest, *src, BitsI32::new(0)),
|
||||||
Self::La(dest, sym) => {
|
Self::La { dest, sym } => {
|
||||||
if let Some(addr) = sym_map.get(*sym) {
|
if let Some(addr) = sym_map.get(*sym) {
|
||||||
let offset = addr.val() as i32 - pos.val() as i32;
|
let offset = addr.val() as i32 - pos.val() as i32;
|
||||||
data.extend(auipc(*dest, BitsI32::new(0)).to_le_bytes());
|
data.extend(auipc(*dest, BitsI32::new(0)).to_le_bytes());
|
||||||
@@ -39,7 +46,7 @@ impl Instr for AsmInstruction {
|
|||||||
return Some(*sym);
|
return Some(*sym);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Self::Jal(dest, offset) => jal(*dest, BitsI32::new(*offset)),
|
Self::Jal { dest, offset } => jal(*dest, BitsI32::new(*offset)),
|
||||||
Self::J(sym) => {
|
Self::J(sym) => {
|
||||||
if let Some(addr) = sym_map.get(*sym) {
|
if let Some(addr) = sym_map.get(*sym) {
|
||||||
let offset = addr.val() as i32 - pos.val() as i32;
|
let offset = addr.val() as i32 - pos.val() as i32;
|
||||||
@@ -60,7 +67,7 @@ impl Instr for AsmInstruction {
|
|||||||
}
|
}
|
||||||
Self::Ret => ret(),
|
Self::Ret => ret(),
|
||||||
Self::Ecall => ecall(),
|
Self::Ecall => ecall(),
|
||||||
Self::Li(reg, val) => addi(*reg, zero, BitsI32::new(*val)),
|
Self::Li { dest, imm } => addi(*dest, zero, BitsI32::new(*imm as i32)),
|
||||||
};
|
};
|
||||||
data.extend(last.to_le_bytes());
|
data.extend(last.to_le_bytes());
|
||||||
None
|
None
|
||||||
|
|||||||
@@ -2,14 +2,17 @@ mod asm;
|
|||||||
mod base;
|
mod base;
|
||||||
mod funct;
|
mod funct;
|
||||||
mod opcode;
|
mod opcode;
|
||||||
|
mod parse;
|
||||||
mod reg;
|
mod reg;
|
||||||
mod single;
|
mod single;
|
||||||
|
|
||||||
use super::{create_program, elf, SymMap};
|
use super::{create_program, elf, SymMap};
|
||||||
use crate::util::BitsI32;
|
use crate::util::BitsI32;
|
||||||
|
pub use asm::*;
|
||||||
use base::*;
|
use base::*;
|
||||||
use funct::{op::*, width};
|
use funct::{op::*, width};
|
||||||
use opcode::*;
|
use opcode::*;
|
||||||
|
pub use parse::*;
|
||||||
pub use reg::*;
|
pub use reg::*;
|
||||||
|
|
||||||
use single::*;
|
use single::*;
|
||||||
@@ -22,23 +25,35 @@ pub fn gen() -> Vec<u8> {
|
|||||||
let print_stuff = table.reserve();
|
let print_stuff = table.reserve();
|
||||||
let start = table.push_fn(vec![
|
let start = table.push_fn(vec![
|
||||||
I::Call(*print_stuff),
|
I::Call(*print_stuff),
|
||||||
I::Li(a0, 0),
|
I::Li { dest: a0, imm: 0 },
|
||||||
I::Li(a7, 93),
|
I::Li { dest: a7, imm: 93 },
|
||||||
I::Ecall,
|
I::Ecall,
|
||||||
I::Jal(zero, 0),
|
I::Jal {
|
||||||
|
dest: zero,
|
||||||
|
offset: 0,
|
||||||
|
},
|
||||||
]);
|
]);
|
||||||
table.write_fn(
|
table.write_fn(
|
||||||
print_stuff,
|
print_stuff,
|
||||||
vec![
|
vec![
|
||||||
I::Li(a0, 1),
|
I::Li { dest: a0, imm: 1 },
|
||||||
I::La(a1, msg),
|
I::La { dest: a1, sym: msg },
|
||||||
I::Li(a2, len as i32),
|
I::Li {
|
||||||
I::Li(a7, 64),
|
dest: a2,
|
||||||
|
imm: len as i64,
|
||||||
|
},
|
||||||
|
I::Li { dest: a7, imm: 64 },
|
||||||
I::Ecall,
|
I::Ecall,
|
||||||
I::Li(a0, 1),
|
I::Li { dest: a0, imm: 1 },
|
||||||
I::La(a1, msg2),
|
I::La {
|
||||||
I::Li(a2, len2 as i32),
|
dest: a1,
|
||||||
I::Li(a7, 64),
|
sym: msg2,
|
||||||
|
},
|
||||||
|
I::Li {
|
||||||
|
dest: a2,
|
||||||
|
imm: len2 as i64,
|
||||||
|
},
|
||||||
|
I::Li { dest: a7, imm: 64 },
|
||||||
I::Ecall,
|
I::Ecall,
|
||||||
I::Ret,
|
I::Ret,
|
||||||
],
|
],
|
||||||
|
|||||||
104
src/compiler/riscv64/parse.rs
Normal file
104
src/compiler/riscv64/parse.rs
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
use super::{reg::*, AsmInstruction, Reg};
|
||||||
|
use crate::parser::{Parsable, ParseResult, ParserMsg, ParserOutput, Symbol, Token};
|
||||||
|
|
||||||
|
impl Parsable for AsmInstruction {
|
||||||
|
fn parse(
|
||||||
|
cursor: &mut crate::parser::TokenCursor,
|
||||||
|
output: &mut ParserOutput,
|
||||||
|
) -> ParseResult<Self> {
|
||||||
|
let t = cursor.expect_next()?;
|
||||||
|
let span = t.span;
|
||||||
|
match &t.token {
|
||||||
|
Token::Word(w) => ParseResult::Ok(match w.as_str() {
|
||||||
|
"ecall" => Self::Ecall,
|
||||||
|
"li" => {
|
||||||
|
let dest = Reg::parse(cursor, output)?;
|
||||||
|
cursor.expect_sym(Symbol::Comma)?;
|
||||||
|
let imm = i64::parse(cursor, output)?;
|
||||||
|
Self::Li { dest, imm }
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return ParseResult::Err(ParserMsg::from_span(
|
||||||
|
span,
|
||||||
|
format!("Unknown instruction {}", w),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
_ => return ParseResult::Err(ParserMsg::unexpected_token(&t, "assembly or }")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parsable for Reg {
|
||||||
|
fn parse(
|
||||||
|
cursor: &mut crate::parser::TokenCursor,
|
||||||
|
output: &mut ParserOutput,
|
||||||
|
) -> ParseResult<Self> {
|
||||||
|
let next = cursor.expect_next()?;
|
||||||
|
let Token::Word(word) = next.token else {
|
||||||
|
return ParseResult::Err(ParserMsg::unexpected_token(&next, "a riscv register"));
|
||||||
|
};
|
||||||
|
ParseResult::Ok(match word.as_str() {
|
||||||
|
"zero" => zero,
|
||||||
|
"ra" => ra,
|
||||||
|
"sp" => sp,
|
||||||
|
"gp" => gp,
|
||||||
|
"tp" => tp,
|
||||||
|
"t0" => t0,
|
||||||
|
"t1" => t1,
|
||||||
|
"t2" => t2,
|
||||||
|
"fp" => fp,
|
||||||
|
"s0" => s0,
|
||||||
|
"s1" => s1,
|
||||||
|
"a0" => a0,
|
||||||
|
"a1" => a1,
|
||||||
|
"a2" => a2,
|
||||||
|
"a3" => a3,
|
||||||
|
"a4" => a4,
|
||||||
|
"a5" => a5,
|
||||||
|
"a6" => a6,
|
||||||
|
"a7" => a7,
|
||||||
|
"s2" => s2,
|
||||||
|
"s3" => s3,
|
||||||
|
"s4" => s4,
|
||||||
|
"s5" => s5,
|
||||||
|
"s6" => s6,
|
||||||
|
"s7" => s7,
|
||||||
|
"s8" => s8,
|
||||||
|
"s9" => s9,
|
||||||
|
"s10" => s10,
|
||||||
|
"s11" => s11,
|
||||||
|
"t3" => t3,
|
||||||
|
"t4" => t4,
|
||||||
|
"t5" => t5,
|
||||||
|
"t6" => t6,
|
||||||
|
other => {
|
||||||
|
return ParseResult::Err(ParserMsg::from_span(
|
||||||
|
next.span,
|
||||||
|
format!("Unknown reg name {}", other),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parsable for i64 {
|
||||||
|
fn parse(
|
||||||
|
cursor: &mut crate::parser::TokenCursor,
|
||||||
|
_output: &mut ParserOutput,
|
||||||
|
) -> ParseResult<Self> {
|
||||||
|
let next = cursor.expect_next()?;
|
||||||
|
let span = next.span;
|
||||||
|
let Token::Word(word) = next.token else {
|
||||||
|
return ParseResult::Err(ParserMsg::unexpected_token(&next, "an i32"));
|
||||||
|
};
|
||||||
|
let res = word.parse::<Self>();
|
||||||
|
match res {
|
||||||
|
Ok(int) => ParseResult::Ok(int),
|
||||||
|
Err(_) => ParseResult::Err(ParserMsg::from_span(
|
||||||
|
span,
|
||||||
|
format!("Expected an i32, found {}", word),
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
282
src/ir/mod.rs
282
src/ir/mod.rs
@@ -1,278 +1,8 @@
|
|||||||
use std::{
|
mod namespace;
|
||||||
collections::HashMap,
|
mod structure;
|
||||||
ops::{Deref, DerefMut},
|
mod file;
|
||||||
};
|
|
||||||
|
|
||||||
use crate::parser::{
|
pub use namespace::*;
|
||||||
Body, Expr, FileSpan, Function, Ident, Literal, Module, ParserError, ParserErrors, Statement,
|
pub use structure::*;
|
||||||
};
|
pub use file::*;
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum IRInstruction {
|
|
||||||
Li(Var, Literal),
|
|
||||||
Mv(Var, Var),
|
|
||||||
Not(Var, Var),
|
|
||||||
Noti(Var, Literal),
|
|
||||||
La(Var, IRIdent),
|
|
||||||
Call(FnIdent, Vec<Var>),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct IRFunction {
|
|
||||||
instructions: Vec<IRInstruction>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Module {
|
|
||||||
pub fn lower(&self, map: &mut Namespace, errors: &mut ParserErrors) {
|
|
||||||
for f in &self.functions {
|
|
||||||
if let Some(f) = f.as_ref() {
|
|
||||||
f.lower(map, errors);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Function {
|
|
||||||
pub fn lower(&self, map: &mut Namespace, errors: &mut ParserErrors) {
|
|
||||||
let Some(name) = self.name.as_ref() else {
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
if map.get(name).is_some() {
|
|
||||||
errors.add(ParserError {
|
|
||||||
msg: format!("Already something named '{:?}'", self.name),
|
|
||||||
spans: vec![self.name.span],
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
let f = map.reserve_fn(self.name.span);
|
|
||||||
let mut instructions = Vec::new();
|
|
||||||
if let Some(b) = self.body.as_ref() {
|
|
||||||
b.lower(map, &mut instructions, errors)
|
|
||||||
}
|
|
||||||
map.write_fn(name, f, IRFunction { instructions });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Body {
|
|
||||||
pub fn lower(
|
|
||||||
&self,
|
|
||||||
map: &mut Namespace,
|
|
||||||
instructions: &mut Vec<IRInstruction>,
|
|
||||||
errors: &mut ParserErrors,
|
|
||||||
) {
|
|
||||||
let mut map = map.push();
|
|
||||||
for statement in &self.statements {
|
|
||||||
let Some(statement) = statement.as_ref() else {
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
match statement {
|
|
||||||
Statement::Let(name_node, expr) => {
|
|
||||||
let Some(name) = name_node.as_ref() else {
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
let Some(expr) = expr.as_ref() else {
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
let res = expr.lower(&mut map, instructions, errors);
|
|
||||||
let name = map.add_var(name, name_node.span);
|
|
||||||
if let Some(res) = res {
|
|
||||||
instructions.push(match res {
|
|
||||||
ExprResult::Lit(l) => IRInstruction::Li(name, l),
|
|
||||||
ExprResult::Var(i) => IRInstruction::Mv(name, i),
|
|
||||||
ExprResult::Fn(f) => todo!(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Statement::Return(e) => todo!(),
|
|
||||||
Statement::Expr(expr) => {
|
|
||||||
expr.as_ref().map(|e| e.lower(&mut map, instructions, errors));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Expr {
|
|
||||||
pub fn lower(
|
|
||||||
&self,
|
|
||||||
map: &mut Namespace,
|
|
||||||
instructions: &mut Vec<IRInstruction>,
|
|
||||||
errors: &mut ParserErrors,
|
|
||||||
) -> Option<ExprResult> {
|
|
||||||
match self {
|
|
||||||
Expr::Lit(l) => Some(ExprResult::Lit(l.as_ref()?.clone())),
|
|
||||||
Expr::Ident(i) => {
|
|
||||||
let Some(id) = map.get(i.as_ref()?) else {
|
|
||||||
errors.add(ParserError::identifier_not_found(i));
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
match id.ty() {
|
|
||||||
IdentTypeMatch::Var(var) => Some(ExprResult::Var(var)),
|
|
||||||
IdentTypeMatch::Fn(f) => Some(ExprResult::Fn(f)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Expr::BinaryOp(_, _, _) => todo!(),
|
|
||||||
Expr::UnaryOp(op, e) => {
|
|
||||||
let res = e.as_ref()?.lower(&mut map, instructions, errors)?;
|
|
||||||
let res = match op {
|
|
||||||
crate::parser::UnaryOperator::Not => {
|
|
||||||
let temp = map.reserve_var(e.span);
|
|
||||||
match res {
|
|
||||||
ExprResult::Lit(l) => instructions.push(IRInstruction::Noti(temp, l)),
|
|
||||||
ExprResult::Var(i) => instructions.push(IRInstruction::Not(temp, i)),
|
|
||||||
ExprResult::Fn(_) => {
|
|
||||||
errors.add(ParserError::from_span(
|
|
||||||
e.span,
|
|
||||||
"Cannot call not on a function".to_string(),
|
|
||||||
));
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
temp
|
|
||||||
}
|
|
||||||
crate::parser::UnaryOperator::Ref => todo!(),
|
|
||||||
};
|
|
||||||
Some(ExprResult::Var(res))
|
|
||||||
}
|
|
||||||
Expr::Block(_) => todo!(),
|
|
||||||
Expr::Call(e, args) => {
|
|
||||||
let e = e.as_ref()?.lower(&mut map, instructions, errors);
|
|
||||||
let args = args.iter().map(|a| a.as_ref()?.lower(map, instructions, errors)).collect();
|
|
||||||
if let Some(r) = e {
|
|
||||||
let fun = match r {
|
|
||||||
ExprResult::Lit(literal) => todo!(),
|
|
||||||
ExprResult::Var(var) => todo!(),
|
|
||||||
ExprResult::Fn(f) => {
|
|
||||||
instructions.push(IRInstruction::Call(f, args));
|
|
||||||
},
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
todo!();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Expr::Group(e) => e.as_ref()?.lower(&mut map, instructions, errors),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum ExprResult {
|
|
||||||
Lit(Literal),
|
|
||||||
Var(Var),
|
|
||||||
Fn(FnIdent),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Namespace {
|
|
||||||
pub fns: Vec<Option<IRFunction>>,
|
|
||||||
pub vars: usize,
|
|
||||||
pub stack: Vec<HashMap<String, IRIdent>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Namespace {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
fns: Vec::new(),
|
|
||||||
vars: 0,
|
|
||||||
stack: vec![HashMap::new()],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn push(&mut self) -> NamespaceGuard {
|
|
||||||
self.stack.push(HashMap::new());
|
|
||||||
NamespaceGuard(self)
|
|
||||||
}
|
|
||||||
pub fn get(&self, name: &Ident) -> Option<IRIdent> {
|
|
||||||
for map in self.stack.iter().rev() {
|
|
||||||
let res = map.get(name.val());
|
|
||||||
if res.is_some() {
|
|
||||||
return res.copied();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
pub fn reserve_var(&mut self, origin: FileSpan) -> Var {
|
|
||||||
let i = self.vars;
|
|
||||||
self.vars += 1;
|
|
||||||
Var(IRIdent {
|
|
||||||
origin,
|
|
||||||
ty: IdentType::Var,
|
|
||||||
i,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
pub fn reserve_fn(&mut self, origin: FileSpan) -> FnIdent {
|
|
||||||
let i = self.fns.len();
|
|
||||||
self.fns.push(None);
|
|
||||||
FnIdent(IRIdent {
|
|
||||||
origin,
|
|
||||||
ty: IdentType::Fn,
|
|
||||||
i,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
pub fn write_fn(&mut self, name: &Ident, id: FnIdent, f: IRFunction) -> IRIdent {
|
|
||||||
self.insert(name, id.0);
|
|
||||||
self.fns[id.0.i] = Some(f);
|
|
||||||
id.0
|
|
||||||
}
|
|
||||||
pub fn add_var(&mut self, name: &Ident, origin: FileSpan) -> Var {
|
|
||||||
let id = self.reserve_var(origin);
|
|
||||||
self.insert(name, id.0);
|
|
||||||
id
|
|
||||||
}
|
|
||||||
fn insert(&mut self, name: &Ident, id: IRIdent) {
|
|
||||||
let last = self.stack.len() - 1;
|
|
||||||
self.stack[last].insert(name.val().to_string(), id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct NamespaceGuard<'a>(&'a mut Namespace);
|
|
||||||
|
|
||||||
impl Drop for NamespaceGuard<'_> {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
self.0.stack.pop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Deref for NamespaceGuard<'_> {
|
|
||||||
type Target = Namespace;
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DerefMut for NamespaceGuard<'_> {
|
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
||||||
&mut self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub struct IRIdent {
|
|
||||||
origin: FileSpan,
|
|
||||||
ty: IdentType,
|
|
||||||
i: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub struct FnIdent(IRIdent);
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub struct Var(IRIdent);
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub enum IdentType {
|
|
||||||
Var,
|
|
||||||
Fn,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub enum IdentTypeMatch {
|
|
||||||
Var(Var),
|
|
||||||
Fn(FnIdent),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IRIdent {
|
|
||||||
pub fn ty(self) -> IdentTypeMatch {
|
|
||||||
match self.ty {
|
|
||||||
IdentType::Var => IdentTypeMatch::Var(Var(self)),
|
|
||||||
IdentType::Fn => IdentTypeMatch::Fn(FnIdent(self)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
241
src/ir/namespace.rs
Normal file
241
src/ir/namespace.rs
Normal file
@@ -0,0 +1,241 @@
|
|||||||
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
|
fmt::Debug,
|
||||||
|
ops::{Deref, DerefMut},
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::{BuiltinType, FileSpan, FnDef, Function, Type, TypeDef, VarDef};
|
||||||
|
|
||||||
|
pub struct Namespace {
|
||||||
|
pub fn_defs: Vec<FnDef>,
|
||||||
|
pub var_defs: Vec<VarDef>,
|
||||||
|
pub type_defs: Vec<TypeDef>,
|
||||||
|
pub fns: Vec<Option<Function>>,
|
||||||
|
pub temp: usize,
|
||||||
|
pub stack: Vec<HashMap<String, Idents>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Namespace {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let mut s = Self {
|
||||||
|
fn_defs: Vec::new(),
|
||||||
|
var_defs: Vec::new(),
|
||||||
|
type_defs: Vec::new(),
|
||||||
|
fns: Vec::new(),
|
||||||
|
temp: 0,
|
||||||
|
stack: vec![HashMap::new()],
|
||||||
|
};
|
||||||
|
for b in BuiltinType::enumerate() {
|
||||||
|
s.def_type(b.def());
|
||||||
|
}
|
||||||
|
s
|
||||||
|
}
|
||||||
|
pub fn push(&mut self) -> NamespaceGuard {
|
||||||
|
self.stack.push(HashMap::new());
|
||||||
|
NamespaceGuard(self)
|
||||||
|
}
|
||||||
|
pub fn get(&self, name: &str) -> Option<Idents> {
|
||||||
|
for map in self.stack.iter().rev() {
|
||||||
|
let res = map.get(name);
|
||||||
|
if res.is_some() {
|
||||||
|
return res.cloned();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
pub fn get_var(&self, id: VarIdent) -> &VarDef {
|
||||||
|
&self.var_defs[id.0]
|
||||||
|
}
|
||||||
|
pub fn get_fn(&self, id: FnIdent) -> &FnDef {
|
||||||
|
&self.fn_defs[id.0]
|
||||||
|
}
|
||||||
|
pub fn get_type(&self, id: TypeIdent) -> &TypeDef {
|
||||||
|
&self.type_defs[id.0]
|
||||||
|
}
|
||||||
|
pub fn alias_fn(&mut self, name: &str, id: FnIdent) {
|
||||||
|
self.insert(name, Ident::Fn(id));
|
||||||
|
}
|
||||||
|
pub fn name_var(&mut self, def: &VarDef, var: VarIdent) {
|
||||||
|
self.insert(&def.name, Ident::Var(var));
|
||||||
|
}
|
||||||
|
pub fn def_var(&mut self, var: VarDef) -> VarIdent {
|
||||||
|
let i = self.var_defs.len();
|
||||||
|
self.var_defs.push(var);
|
||||||
|
VarIdent(i)
|
||||||
|
}
|
||||||
|
pub fn temp_var(&mut self, origin: FileSpan, ty: Type) -> VarIdent {
|
||||||
|
let v = self.def_var(VarDef {
|
||||||
|
name: format!("temp{}", self.temp),
|
||||||
|
origin: super::Origin::File(origin),
|
||||||
|
ty,
|
||||||
|
});
|
||||||
|
self.temp += 1;
|
||||||
|
v
|
||||||
|
}
|
||||||
|
pub fn def_fn(&mut self, def: FnDef) -> FnIdent {
|
||||||
|
let i = self.fn_defs.len();
|
||||||
|
let id = FnIdent(i);
|
||||||
|
self.insert(&def.name, Ident::Fn(id));
|
||||||
|
self.fn_defs.push(def);
|
||||||
|
self.fns.push(None);
|
||||||
|
id
|
||||||
|
}
|
||||||
|
pub fn def_type(&mut self, def: TypeDef) -> TypeIdent {
|
||||||
|
let i = self.type_defs.len();
|
||||||
|
let id = TypeIdent(i);
|
||||||
|
self.insert(&def.name, Ident::Type(id));
|
||||||
|
self.type_defs.push(def);
|
||||||
|
id
|
||||||
|
}
|
||||||
|
pub fn type_name(&self, ty: &Type) -> String {
|
||||||
|
let mut str = String::new();
|
||||||
|
match ty {
|
||||||
|
Type::Concrete(t) => {
|
||||||
|
str += &self.get_type(*t).name;
|
||||||
|
}
|
||||||
|
Type::Generic { base, args } => {
|
||||||
|
str += &self.get_type(*base).name;
|
||||||
|
if let Some(arg) = args.first() {
|
||||||
|
str = str + "<" + &self.type_name(arg);
|
||||||
|
}
|
||||||
|
for arg in args.iter().skip(1) {
|
||||||
|
str = str + ", " + &self.type_name(arg);
|
||||||
|
}
|
||||||
|
if !args.is_empty() {
|
||||||
|
str += ">";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Type::Fn { args, ret } => {
|
||||||
|
str += "fn(";
|
||||||
|
if let Some(arg) = args.first() {
|
||||||
|
str += &self.type_name(arg);
|
||||||
|
}
|
||||||
|
for arg in args.iter().skip(1) {
|
||||||
|
str = str + ", " + &self.type_name(arg);
|
||||||
|
}
|
||||||
|
str += ") -> ";
|
||||||
|
str += &self.type_name(ret);
|
||||||
|
}
|
||||||
|
Type::Ref(t) => {
|
||||||
|
str = str + "&" + &self.type_name(t);
|
||||||
|
}
|
||||||
|
Type::Error => str += "{error}",
|
||||||
|
Type::Infer => str += "{inferred}",
|
||||||
|
}
|
||||||
|
str
|
||||||
|
}
|
||||||
|
fn insert(&mut self, name: &str, id: Ident) {
|
||||||
|
let idx = self.stack.len() - 1;
|
||||||
|
let last = &mut self.stack[idx];
|
||||||
|
if let Some(l) = last.get_mut(name) {
|
||||||
|
l.insert(id);
|
||||||
|
} else {
|
||||||
|
last.insert(name.to_string(), Idents::new(id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn write_fn(&mut self, id: FnIdent, f: Function) {
|
||||||
|
self.fns[id.0] = Some(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct NamespaceGuard<'a>(&'a mut Namespace);
|
||||||
|
|
||||||
|
impl Drop for NamespaceGuard<'_> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.0.stack.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for NamespaceGuard<'_> {
|
||||||
|
type Target = Namespace;
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DerefMut for NamespaceGuard<'_> {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum Ident {
|
||||||
|
Var(VarIdent),
|
||||||
|
Fn(FnIdent),
|
||||||
|
Type(TypeIdent),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct Idents {
|
||||||
|
pub latest: Ident,
|
||||||
|
pub var: Option<VarIdent>,
|
||||||
|
pub func: Option<FnIdent>,
|
||||||
|
pub var_func: Option<VarOrFnIdent>,
|
||||||
|
pub ty: Option<TypeIdent>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Idents {
|
||||||
|
fn new(latest: Ident) -> Self {
|
||||||
|
let mut s = Self {
|
||||||
|
latest,
|
||||||
|
var: None,
|
||||||
|
func: None,
|
||||||
|
var_func: None,
|
||||||
|
ty: None,
|
||||||
|
};
|
||||||
|
s.insert(latest);
|
||||||
|
s
|
||||||
|
}
|
||||||
|
fn insert(&mut self, i: Ident) {
|
||||||
|
self.latest = i;
|
||||||
|
match i {
|
||||||
|
Ident::Var(v) => {
|
||||||
|
self.var = Some(v);
|
||||||
|
self.var_func = Some(VarOrFnIdent::Var(v));
|
||||||
|
}
|
||||||
|
Ident::Fn(f) => {
|
||||||
|
self.func = Some(f);
|
||||||
|
self.var_func = Some(VarOrFnIdent::Fn(f));
|
||||||
|
}
|
||||||
|
Ident::Type(t) => self.ty = Some(t),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct TypeIdent(usize);
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct VarIdent(usize);
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct FnIdent(usize);
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum VarOrFnIdent {
|
||||||
|
Var(VarIdent),
|
||||||
|
Fn(FnIdent),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TypeIdent {
|
||||||
|
pub fn builtin(ty: &BuiltinType) -> Self {
|
||||||
|
Self(*ty as usize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for VarIdent {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "v{}", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for TypeIdent {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "t{}", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for FnIdent {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "f{}", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
226
src/ir/old.rs
Normal file
226
src/ir/old.rs
Normal file
@@ -0,0 +1,226 @@
|
|||||||
|
#[derive(Debug)]
|
||||||
|
pub enum IRInstruction {
|
||||||
|
Li(Var, Literal),
|
||||||
|
Mv(Var, Var),
|
||||||
|
Not(Var, Var),
|
||||||
|
Add(Var, Var, Var),
|
||||||
|
La(Var, IRIdent),
|
||||||
|
Call(Var, FnIdent, Vec<ExprResult>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct IRFunction {
|
||||||
|
args: Vec<Var>,
|
||||||
|
instructions: Vec<IRInstruction>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Module {
|
||||||
|
pub fn lower(&self, map: &mut Namespace, errors: &mut ParserErrors) {
|
||||||
|
let mut fns = Vec::new();
|
||||||
|
for f in &self.functions {
|
||||||
|
if let Some(f) = f.as_ref() {
|
||||||
|
if let Some(id) = f.reserve(map, errors) {
|
||||||
|
fns.push((id, f));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (id, f) in fns {
|
||||||
|
f.lower(id, map, errors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Function {
|
||||||
|
pub fn reserve(&self, map: &mut Namespace, errors: &mut ParserErrors) -> Option<FnIdent> {
|
||||||
|
let name = self.name.as_ref()?;
|
||||||
|
if let Some(other) = map.get(name) {
|
||||||
|
errors.add(ParserError {
|
||||||
|
msg: format!("Already {:?} named '{:?}'", other.ty, self.name),
|
||||||
|
spans: vec![self.name.span, other.origin],
|
||||||
|
});
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(map.reserve_fn(name, self.name.span))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn lower(
|
||||||
|
&self,
|
||||||
|
ident: FnIdent,
|
||||||
|
map: &mut Namespace,
|
||||||
|
errors: &mut ParserErrors,
|
||||||
|
) -> Option<()> {
|
||||||
|
let mut instructions = Vec::new();
|
||||||
|
let mut map = map.push();
|
||||||
|
let mut args = Vec::new();
|
||||||
|
for arg in &self.args {
|
||||||
|
args.push(map.def_var(arg.as_ref()?, arg.span)?);
|
||||||
|
}
|
||||||
|
if let Some(b) = self.body.as_ref() {
|
||||||
|
b.lower(&mut map, &mut instructions, errors)
|
||||||
|
}
|
||||||
|
map.write_fn(ident, IRFunction { instructions, args });
|
||||||
|
Some(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Body {
|
||||||
|
pub fn lower(
|
||||||
|
&self,
|
||||||
|
map: &mut Namespace,
|
||||||
|
instructions: &mut Vec<IRInstruction>,
|
||||||
|
errors: &mut ParserErrors,
|
||||||
|
) {
|
||||||
|
let mut map = map.push();
|
||||||
|
for statement in &self.statements {
|
||||||
|
let Some(statement) = statement.as_ref() else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
match statement {
|
||||||
|
Statement::Let(name_node, expr) => {
|
||||||
|
let Some(name) = name_node.as_ref() else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
let res = expr.lower(&mut map, instructions, errors);
|
||||||
|
if let Some(res) = res {
|
||||||
|
match res {
|
||||||
|
ExprResult::Var(v) => map.name_var(name, v),
|
||||||
|
ExprResult::Fn(f) => todo!(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Statement::Return(e) => todo!(),
|
||||||
|
Statement::Expr(expr) => {
|
||||||
|
expr.lower(&mut map, instructions, errors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Node<Box<Expr>> {
|
||||||
|
pub fn lower(
|
||||||
|
&self,
|
||||||
|
map: &mut Namespace,
|
||||||
|
instructions: &mut Vec<IRInstruction>,
|
||||||
|
errors: &mut ParserErrors,
|
||||||
|
) -> Option<ExprResult> {
|
||||||
|
self.as_ref()?.lower(self.span, map, instructions, errors)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Node<Expr> {
|
||||||
|
pub fn lower(
|
||||||
|
&self,
|
||||||
|
map: &mut Namespace,
|
||||||
|
instructions: &mut Vec<IRInstruction>,
|
||||||
|
errors: &mut ParserErrors,
|
||||||
|
) -> Option<ExprResult> {
|
||||||
|
self.as_ref()?.lowerr(self.span, map, instructions, errors)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Expr {
|
||||||
|
pub fn lowerr(
|
||||||
|
&self,
|
||||||
|
span: FileSpan,
|
||||||
|
map: &mut Namespace,
|
||||||
|
instructions: &mut Vec<IRInstruction>,
|
||||||
|
errors: &mut ParserErrors,
|
||||||
|
) -> Option<ExprResult> {
|
||||||
|
match self {
|
||||||
|
Expr::Lit(l) => {
|
||||||
|
let temp = map.temp_var(span);
|
||||||
|
instructions.push(IRInstruction::Li(temp, l.as_ref()?.clone()));
|
||||||
|
Some(ExprResult::Var(temp))
|
||||||
|
},
|
||||||
|
Expr::Ident(i) => {
|
||||||
|
let Some(id) = map.get(i.as_ref()?) else {
|
||||||
|
errors.add(ParserError::identifier_not_found(i));
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
match id.ty() {
|
||||||
|
IdentTypeMatch::Var(var) => Some(ExprResult::Var(var)),
|
||||||
|
IdentTypeMatch::Fn(f) => Some(ExprResult::Fn(f)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Expr::BinaryOp(op, e1, e2) => {
|
||||||
|
let res1 = e1.lower(map, instructions, errors)?;
|
||||||
|
let res2 = e2.lower(map, instructions, errors)?;
|
||||||
|
let (ExprResult::Var(v1), ExprResult::Var(v2)) = (res1, res2) else {
|
||||||
|
errors.add(ParserError::from_span(span, "Cannot operate on functions".to_string()));
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
let temp = map.temp_var(span);
|
||||||
|
match op {
|
||||||
|
crate::parser::BinaryOperator::Add => {
|
||||||
|
instructions.push(IRInstruction::Add(temp, v1, v2))
|
||||||
|
}
|
||||||
|
crate::parser::BinaryOperator::Sub => todo!(),
|
||||||
|
crate::parser::BinaryOperator::Mul => todo!(),
|
||||||
|
crate::parser::BinaryOperator::Div => todo!(),
|
||||||
|
crate::parser::BinaryOperator::LessThan => todo!(),
|
||||||
|
crate::parser::BinaryOperator::GreaterThan => todo!(),
|
||||||
|
crate::parser::BinaryOperator::Access => todo!(),
|
||||||
|
crate::parser::BinaryOperator::Assign => todo!(),
|
||||||
|
}
|
||||||
|
Some(ExprResult::Var(temp))
|
||||||
|
}
|
||||||
|
Expr::UnaryOp(op, e) => {
|
||||||
|
let res = e.lower(map, instructions, errors)?;
|
||||||
|
let res = match op {
|
||||||
|
crate::parser::UnaryOperator::Not => {
|
||||||
|
let temp = map.temp_var(span);
|
||||||
|
match res {
|
||||||
|
ExprResult::Var(i) => instructions.push(IRInstruction::Not(temp, i)),
|
||||||
|
ExprResult::Fn(_) => {
|
||||||
|
errors.add(ParserError::from_span(
|
||||||
|
span,
|
||||||
|
"Cannot call not on a function".to_string(),
|
||||||
|
));
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
temp
|
||||||
|
}
|
||||||
|
crate::parser::UnaryOperator::Ref => todo!(),
|
||||||
|
};
|
||||||
|
Some(ExprResult::Var(res))
|
||||||
|
}
|
||||||
|
Expr::Block(_) => todo!(),
|
||||||
|
Expr::Call(e, args) => {
|
||||||
|
let fe = e.lower(map, instructions, errors);
|
||||||
|
let mut nargs = Vec::new();
|
||||||
|
for arg in args.iter() {
|
||||||
|
let arg = arg.lower(map, instructions, errors)?;
|
||||||
|
nargs.push(arg);
|
||||||
|
}
|
||||||
|
if let Some(r) = fe {
|
||||||
|
match r {
|
||||||
|
ExprResult::Fn(f) => {
|
||||||
|
let temp = map.temp_var(span);
|
||||||
|
instructions.push(IRInstruction::Call(temp, f, nargs));
|
||||||
|
Some(ExprResult::Var(temp))
|
||||||
|
}
|
||||||
|
o => {
|
||||||
|
errors.add(ParserError::from_span(
|
||||||
|
span,
|
||||||
|
"Expected function".to_string(),
|
||||||
|
));
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Expr::Group(e) => e.lower(map, instructions, errors),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum ExprResult {
|
||||||
|
Var(Var),
|
||||||
|
Fn(FnIdent),
|
||||||
|
}
|
||||||
|
|
||||||
37
src/ir/structure/def.rs
Normal file
37
src/ir/structure/def.rs
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
use super::{FileSpan, Type};
|
||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
pub struct FnDef {
|
||||||
|
pub name: String,
|
||||||
|
pub args: Vec<VarDef>,
|
||||||
|
pub ret: Type,
|
||||||
|
pub origin: Origin,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TypeDef {
|
||||||
|
pub name: String,
|
||||||
|
pub args: usize,
|
||||||
|
pub origin: Origin,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct VarDef {
|
||||||
|
pub name: String,
|
||||||
|
pub ty: Type,
|
||||||
|
pub origin: Origin,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum Origin {
|
||||||
|
Builtin,
|
||||||
|
File(FileSpan),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FnDef {
|
||||||
|
pub fn ty(&self) -> Type {
|
||||||
|
Type::Fn {
|
||||||
|
args: self.args.iter().map(|a| a.ty.clone()).collect(),
|
||||||
|
ret: Box::new(self.ret.clone()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
56
src/ir/structure/func.rs
Normal file
56
src/ir/structure/func.rs
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
use crate::compiler::riscv64::AsmInstruction;
|
||||||
|
|
||||||
|
use super::{FnIdent, VarIdent};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Function {
|
||||||
|
instructions: Vec<Instruction>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Instruction {
|
||||||
|
Mv {
|
||||||
|
dest: VarIdent,
|
||||||
|
src: VarIdent,
|
||||||
|
},
|
||||||
|
Ref {
|
||||||
|
dest: VarIdent,
|
||||||
|
src: VarIdent,
|
||||||
|
},
|
||||||
|
Lf {
|
||||||
|
dest: VarIdent,
|
||||||
|
src: FnIdent,
|
||||||
|
},
|
||||||
|
Call {
|
||||||
|
dest: VarIdent,
|
||||||
|
f: FnIdent,
|
||||||
|
args: Vec<VarIdent>,
|
||||||
|
},
|
||||||
|
AsmBlock {
|
||||||
|
instructions: Vec<AsmInstruction>,
|
||||||
|
},
|
||||||
|
Ret {
|
||||||
|
src: VarIdent,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Instructions {
|
||||||
|
vec: Vec<Instruction>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Function {
|
||||||
|
pub fn new(instructions: Instructions) -> Self {
|
||||||
|
Self {
|
||||||
|
instructions: instructions.vec,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Instructions {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self { vec: Vec::new() }
|
||||||
|
}
|
||||||
|
pub fn push(&mut self, i: Instruction) {
|
||||||
|
self.vec.push(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
9
src/ir/structure/mod.rs
Normal file
9
src/ir/structure/mod.rs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
mod def;
|
||||||
|
mod func;
|
||||||
|
mod ty;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
pub use def::*;
|
||||||
|
pub use func::*;
|
||||||
|
pub use ty::*;
|
||||||
|
|
||||||
35
src/ir/structure/ty.rs
Normal file
35
src/ir/structure/ty.rs
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
use super::{Origin, TypeDef, TypeIdent};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum Type {
|
||||||
|
Concrete(TypeIdent),
|
||||||
|
Generic { base: TypeIdent, args: Vec<Type> },
|
||||||
|
Fn { args: Vec<Type>, ret: Box<Type> },
|
||||||
|
Ref(Box<Type>),
|
||||||
|
Infer,
|
||||||
|
Error,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(usize)]
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum BuiltinType {
|
||||||
|
Unit,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BuiltinType {
|
||||||
|
pub fn enumerate() -> &'static [Self; 1] {
|
||||||
|
&[Self::Unit]
|
||||||
|
}
|
||||||
|
pub fn def(&self) -> TypeDef {
|
||||||
|
match self {
|
||||||
|
BuiltinType::Unit => TypeDef {
|
||||||
|
name: "()".to_string(),
|
||||||
|
args: 0,
|
||||||
|
origin: Origin::Builtin,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn id(&self) -> TypeIdent {
|
||||||
|
TypeIdent::builtin(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
43
src/main.rs
43
src/main.rs
@@ -1,19 +1,54 @@
|
|||||||
#![feature(box_patterns)]
|
#![feature(box_patterns)]
|
||||||
#![feature(try_trait_v2)]
|
#![feature(try_trait_v2)]
|
||||||
|
|
||||||
mod util;
|
use std::io::{stdout, BufRead, BufReader};
|
||||||
|
|
||||||
|
use ir::Namespace;
|
||||||
|
use parser::{Module, NodeParsable, ParserOutput, Statement, TokenCursor};
|
||||||
|
|
||||||
mod compiler;
|
mod compiler;
|
||||||
mod ir;
|
mod ir;
|
||||||
mod parser;
|
mod parser;
|
||||||
|
mod util;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let arg = std::env::args_os().nth(1);
|
let arg = std::env::args_os().nth(1);
|
||||||
if let Some(path) = arg {
|
if let Some(path) = arg {
|
||||||
let file = std::fs::read_to_string(path).expect("failed to read file");
|
let file = std::fs::read_to_string(path).expect("failed to read file");
|
||||||
println!("{file}");
|
run_file(&file);
|
||||||
parser::parse_file(&file);
|
|
||||||
} else {
|
} else {
|
||||||
parser::run_stdin();
|
run_stdin();
|
||||||
}
|
}
|
||||||
// compiler::main();
|
// compiler::main();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn run_file(file: &str) {
|
||||||
|
let mut output = ParserOutput::new();
|
||||||
|
let res = Module::parse_node(&mut TokenCursor::from(file), &mut output);
|
||||||
|
println!("{:?}", res.node);
|
||||||
|
if let Some(module) = res.node.as_ref() {
|
||||||
|
let mut namespace = Namespace::new();
|
||||||
|
module.lower(&mut namespace.push(), &mut output);
|
||||||
|
println!("{:?}", namespace.fns);
|
||||||
|
}
|
||||||
|
output.write_for(&mut stdout(), file);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run_stdin() {
|
||||||
|
for line in BufReader::new(std::io::stdin()).lines() {
|
||||||
|
let mut output = ParserOutput::new();
|
||||||
|
let str = &line.expect("failed to read line");
|
||||||
|
let mut cursor = TokenCursor::from(&str[..]);
|
||||||
|
if let Some(expr) = Statement::parse_node(&mut cursor, &mut output)
|
||||||
|
.node
|
||||||
|
.as_ref()
|
||||||
|
{
|
||||||
|
if cursor.next().is_none() {
|
||||||
|
println!("{:?}", expr);
|
||||||
|
} else {
|
||||||
|
println!("uhhhh ehehe");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
output.write_for(&mut stdout(), str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
mod v1;
|
// mod v1;
|
||||||
mod v2;
|
// mod v2;
|
||||||
mod v3;
|
mod v3;
|
||||||
|
|
||||||
pub use v3::*;
|
pub use v3::*;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use super::error::ParserError;
|
use crate::ir::FilePos;
|
||||||
|
|
||||||
|
use super::error::ParserMsg;
|
||||||
use super::token::{CharCursor, Keyword, Symbol, Token, TokenInstance};
|
use super::token::{CharCursor, Keyword, Symbol, Token, TokenInstance};
|
||||||
use super::FilePos;
|
|
||||||
|
|
||||||
pub struct TokenCursor<'a> {
|
pub struct TokenCursor<'a> {
|
||||||
cursor: CharCursor<'a>,
|
cursor: CharCursor<'a>,
|
||||||
@@ -15,19 +16,19 @@ impl<'a> TokenCursor<'a> {
|
|||||||
self.next_pos = self.cursor.next_pos();
|
self.next_pos = self.cursor.next_pos();
|
||||||
std::mem::replace(&mut self.next, TokenInstance::parse(&mut self.cursor))
|
std::mem::replace(&mut self.next, TokenInstance::parse(&mut self.cursor))
|
||||||
}
|
}
|
||||||
pub fn expect_next(&mut self) -> Result<TokenInstance, ParserError> {
|
pub fn expect_next(&mut self) -> Result<TokenInstance, ParserMsg> {
|
||||||
self.peek().ok_or(ParserError::unexpected_end())?;
|
self.peek().ok_or(ParserMsg::unexpected_end())?;
|
||||||
Ok(self.next().unwrap())
|
Ok(self.next().unwrap())
|
||||||
}
|
}
|
||||||
pub fn expect_token(&mut self, t: Token) -> Result<(), ParserError> {
|
pub fn expect_token(&mut self, t: Token) -> Result<(), ParserMsg> {
|
||||||
let next = self.expect_next()?;
|
let next = self.expect_next()?;
|
||||||
if t == next.token {
|
if t == next.token {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(ParserError::unexpected_token(&next, &format!("{t:?}")))
|
Err(ParserMsg::unexpected_token(&next, &format!("{t:?}")))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn expect_sym(&mut self, symbol: Symbol) -> Result<(), ParserError> {
|
pub fn expect_sym(&mut self, symbol: Symbol) -> Result<(), ParserMsg> {
|
||||||
self.expect_token(Token::Symbol(symbol))
|
self.expect_token(Token::Symbol(symbol))
|
||||||
}
|
}
|
||||||
pub fn seek_sym(&mut self, symbol: Symbol) {
|
pub fn seek_sym(&mut self, symbol: Symbol) {
|
||||||
@@ -52,14 +53,14 @@ impl<'a> TokenCursor<'a> {
|
|||||||
self.next();
|
self.next();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn expect_kw(&mut self, kw: Keyword) -> Result<(), ParserError> {
|
pub fn expect_kw(&mut self, kw: Keyword) -> Result<(), ParserMsg> {
|
||||||
self.expect_token(Token::Keyword(kw))
|
self.expect_token(Token::Keyword(kw))
|
||||||
}
|
}
|
||||||
pub fn peek(&self) -> Option<&TokenInstance> {
|
pub fn peek(&self) -> Option<&TokenInstance> {
|
||||||
self.next.as_ref()
|
self.next.as_ref()
|
||||||
}
|
}
|
||||||
pub fn expect_peek(&mut self) -> Result<&TokenInstance, ParserError> {
|
pub fn expect_peek(&mut self) -> Result<&TokenInstance, ParserMsg> {
|
||||||
self.peek().ok_or(ParserError::unexpected_end())
|
self.peek().ok_or(ParserMsg::unexpected_end())
|
||||||
}
|
}
|
||||||
pub fn chars(&mut self) -> &mut CharCursor<'a> {
|
pub fn chars(&mut self) -> &mut CharCursor<'a> {
|
||||||
&mut self.cursor
|
&mut self.cursor
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
use super::{
|
use crate::ir::{FilePos, FileSpan};
|
||||||
token::{FileSpan, TokenInstance},
|
|
||||||
FilePos, Ident, Node,
|
use super::{token::TokenInstance, Ident, Node};
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ParserError {
|
pub struct ParserMsg {
|
||||||
pub msg: String,
|
pub msg: String,
|
||||||
pub spans: Vec<FileSpan>,
|
pub spans: Vec<FileSpan>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ParserErrors {
|
pub struct ParserOutput {
|
||||||
pub errs: Vec<ParserError>,
|
pub errs: Vec<ParserMsg>,
|
||||||
|
pub hints: Vec<ParserMsg>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ParserError {
|
impl ParserMsg {
|
||||||
pub fn from_instances(instances: &[&TokenInstance], msg: String) -> Self {
|
pub fn from_instances(instances: &[&TokenInstance], msg: String) -> Self {
|
||||||
ParserError {
|
ParserMsg {
|
||||||
msg,
|
msg,
|
||||||
spans: instances.iter().map(|i| i.span).collect(),
|
spans: instances.iter().map(|i| i.span).collect(),
|
||||||
}
|
}
|
||||||
@@ -49,14 +49,14 @@ impl ParserError {
|
|||||||
}
|
}
|
||||||
pub fn unexpected_token(inst: &TokenInstance, expected: &str) -> Self {
|
pub fn unexpected_token(inst: &TokenInstance, expected: &str) -> Self {
|
||||||
let t = &inst.token;
|
let t = &inst.token;
|
||||||
ParserError::from_instances(
|
ParserMsg::from_instances(
|
||||||
&[inst],
|
&[inst],
|
||||||
format!("unexpected token {t:?}; expected {expected}"),
|
format!("unexpected token {t:?}; expected {expected}"),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
pub fn write_for(&self, writer: &mut impl std::io::Write, file: &str) -> std::io::Result<()> {
|
pub fn write_for(&self, ty: &str, writer: &mut impl std::io::Write, file: &str) -> std::io::Result<()> {
|
||||||
let after = if self.spans.is_empty() { "" } else { ":" };
|
let after = if self.spans.is_empty() { "" } else { ":" };
|
||||||
writeln!(writer, "error: {}{}", self.msg, after)?;
|
writeln!(writer, "{}: {}{}", ty, self.msg, after)?;
|
||||||
for span in &self.spans {
|
for span in &self.spans {
|
||||||
span.write_for(writer, file)?;
|
span.write_for(writer, file)?;
|
||||||
}
|
}
|
||||||
@@ -64,11 +64,25 @@ impl ParserError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ParserErrors {
|
impl ParserOutput {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self { errs: Vec::new() }
|
Self {
|
||||||
|
errs: Vec::new(),
|
||||||
|
hints: Vec::new(),
|
||||||
}
|
}
|
||||||
pub fn add(&mut self, err: ParserError) {
|
}
|
||||||
|
pub fn err(&mut self, err: ParserMsg) {
|
||||||
self.errs.push(err);
|
self.errs.push(err);
|
||||||
}
|
}
|
||||||
|
pub fn hint(&mut self, err: ParserMsg) {
|
||||||
|
self.hints.push(err);
|
||||||
|
}
|
||||||
|
pub fn write_for(&self, out: &mut impl std::io::Write, file: &str) {
|
||||||
|
for err in &self.errs {
|
||||||
|
err.write_for("error", out, file).unwrap();
|
||||||
|
}
|
||||||
|
for hint in &self.hints {
|
||||||
|
hint.write_for("hint", out, file).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
58
src/parser/v3/lower/block.rs
Normal file
58
src/parser/v3/lower/block.rs
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
use crate::ir::Instruction;
|
||||||
|
|
||||||
|
use super::{Block, ExprResult, FnLowerCtx, Node, Statement};
|
||||||
|
|
||||||
|
impl Node<Block> {
|
||||||
|
pub fn lower(&self, ctx: &mut FnLowerCtx) -> Option<ExprResult> {
|
||||||
|
self.as_ref()?.lower(ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Block {
|
||||||
|
pub fn lower(&self, ctx: &mut FnLowerCtx) -> Option<ExprResult> {
|
||||||
|
let ctx = &mut ctx.sub();
|
||||||
|
for statement in &self.statements {
|
||||||
|
statement.lower(ctx);
|
||||||
|
}
|
||||||
|
self.result.as_ref()?.lower(ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Node<Box<Statement>> {
|
||||||
|
pub fn lower(&self, ctx: &mut FnLowerCtx) -> Option<ExprResult> {
|
||||||
|
self.as_ref()?.lower(ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Node<Statement> {
|
||||||
|
pub fn lower(&self, ctx: &mut FnLowerCtx) -> Option<ExprResult> {
|
||||||
|
self.as_ref()?.lower(ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Statement {
|
||||||
|
pub fn lower(&self, ctx: &mut FnLowerCtx) -> Option<ExprResult> {
|
||||||
|
match self {
|
||||||
|
super::Statement::Let(def, e) => {
|
||||||
|
let def = def.lower(ctx.map, ctx.output)?;
|
||||||
|
let res = e.lower(ctx);
|
||||||
|
if let Some(res) = res {
|
||||||
|
match res {
|
||||||
|
ExprResult::Var(v) => ctx.map.name_var(&def, v),
|
||||||
|
ExprResult::Fn(_) => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
super::Statement::Return(e) => {
|
||||||
|
let res = e.lower(ctx)?;
|
||||||
|
match res {
|
||||||
|
ExprResult::Var(v) => ctx.push(Instruction::Ret { src: v }),
|
||||||
|
_ => todo!(),
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
super::Statement::Expr(e) => e.lower(ctx),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
59
src/parser/v3/lower/def.rs
Normal file
59
src/parser/v3/lower/def.rs
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
use crate::ir::{FileSpan, NamespaceGuard, Origin, Type, VarDef};
|
||||||
|
|
||||||
|
use super::{Node, ParserMsg, ParserOutput, Type as PType, VarDef as PVarDef};
|
||||||
|
|
||||||
|
impl Node<PVarDef> {
|
||||||
|
pub fn lower(
|
||||||
|
&self,
|
||||||
|
namespace: &mut NamespaceGuard,
|
||||||
|
output: &mut ParserOutput,
|
||||||
|
) -> Option<VarDef> {
|
||||||
|
let s = self.as_ref()?;
|
||||||
|
let name = s.name.as_ref()?.val().clone();
|
||||||
|
let ty = match &s.ty {
|
||||||
|
Some(ty) => ty.lower(namespace, output),
|
||||||
|
None => Type::Infer,
|
||||||
|
};
|
||||||
|
Some(VarDef {
|
||||||
|
name,
|
||||||
|
ty,
|
||||||
|
origin: Origin::File(self.span),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Node<PType> {
|
||||||
|
pub fn lower(&self, namespace: &mut NamespaceGuard, output: &mut ParserOutput) -> Type {
|
||||||
|
self.as_ref()
|
||||||
|
.map(|t| t.lower(namespace, output, self.span))
|
||||||
|
.unwrap_or(Type::Error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PType {
|
||||||
|
pub fn lower(
|
||||||
|
&self,
|
||||||
|
namespace: &mut NamespaceGuard,
|
||||||
|
output: &mut ParserOutput,
|
||||||
|
span: FileSpan,
|
||||||
|
) -> Type {
|
||||||
|
match namespace.get(&self.name).map(|ids| ids.ty).flatten() {
|
||||||
|
Some(id) => {
|
||||||
|
if self.args.is_empty() {
|
||||||
|
Type::Concrete(id)
|
||||||
|
} else {
|
||||||
|
let args = self
|
||||||
|
.args
|
||||||
|
.iter()
|
||||||
|
.map(|n| n.lower(namespace, output))
|
||||||
|
.collect();
|
||||||
|
Type::Generic { base: id, args }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
output.err(ParserMsg::from_span(span, "Type not found".to_string()));
|
||||||
|
Type::Error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
136
src/parser/v3/lower/expr.rs
Normal file
136
src/parser/v3/lower/expr.rs
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
use super::{func::FnLowerCtx, Expr as PExpr, Node, UnaryOp};
|
||||||
|
use crate::ir::{FnIdent, Instruction, Type, VarIdent, VarOrFnIdent};
|
||||||
|
|
||||||
|
impl PExpr {
|
||||||
|
pub fn lower(&self, ctx: &mut FnLowerCtx) -> Option<ExprResult> {
|
||||||
|
Some(match self {
|
||||||
|
PExpr::Lit(l) => match l.as_ref()? {
|
||||||
|
super::Literal::String(s) => todo!(),
|
||||||
|
super::Literal::Char(c) => todo!(),
|
||||||
|
super::Literal::Number(n) => todo!(),
|
||||||
|
super::Literal::Unit => {
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
PExpr::Ident(i) => {
|
||||||
|
let name = i.as_ref()?.val();
|
||||||
|
let Some(id) = ctx.get(name) else {
|
||||||
|
ctx.err(format!("Identifier '{}' not found.", name));
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
let Some(vf) = id.var_func else {
|
||||||
|
ctx.err(format!("Variable or function '{}' not found; Found type, but types cannot be used here.", name));
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
match vf {
|
||||||
|
VarOrFnIdent::Var(var) => ExprResult::Var(var),
|
||||||
|
VarOrFnIdent::Fn(f) => ExprResult::Fn(f),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PExpr::BinaryOp(op, e1, e2) => {
|
||||||
|
let res1 = e1.lower(ctx)?;
|
||||||
|
let res2 = e2.lower(ctx)?;
|
||||||
|
op.traitt();
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
PExpr::UnaryOp(op, e) => {
|
||||||
|
let res = e.lower(ctx)?;
|
||||||
|
match op {
|
||||||
|
UnaryOp::Ref => ExprResult::Var(match res {
|
||||||
|
ExprResult::Var(v) => {
|
||||||
|
let temp = ctx.temp(ctx.map.get_var(v).ty.clone());
|
||||||
|
ctx.push(Instruction::Ref { dest: temp, src: v });
|
||||||
|
temp
|
||||||
|
}
|
||||||
|
ExprResult::Fn(f) => {
|
||||||
|
let temp = ctx.temp(Type::Ref(Box::new(ctx.map.get_fn(f).ty())));
|
||||||
|
ctx.push(Instruction::Lf { dest: temp, src: f });
|
||||||
|
temp
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
UnaryOp::Deref => match res {
|
||||||
|
ExprResult::Var(v) => match &ctx.map.get_var(v).ty {
|
||||||
|
Type::Ref(inner) => {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
t => {
|
||||||
|
ctx.err(format!(
|
||||||
|
"Cannot dereference type {:?}",
|
||||||
|
ctx.map.type_name(t)
|
||||||
|
));
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ExprResult::Fn(f) => {
|
||||||
|
ctx.err("Cannot dereference functions".to_string());
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
UnaryOp::Not => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PExpr::Block(b) => b.lower(ctx)?,
|
||||||
|
PExpr::AsmBlock(b) => {
|
||||||
|
ctx.push(Instruction::AsmBlock {
|
||||||
|
instructions: b.as_ref()?.instructions.clone(),
|
||||||
|
});
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
PExpr::Call(e, args) => {
|
||||||
|
let fe = e.lower(ctx)?;
|
||||||
|
let mut nargs = Vec::new();
|
||||||
|
for arg in args.iter() {
|
||||||
|
let arg = arg.lower(ctx)?;
|
||||||
|
nargs.push(match arg {
|
||||||
|
ExprResult::Var(v) => v,
|
||||||
|
ExprResult::Fn(_) => todo!(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
match fe {
|
||||||
|
ExprResult::Fn(f) => {
|
||||||
|
let temp = ctx.temp(ctx.map.get_fn(f).ret.clone());
|
||||||
|
ctx.push(Instruction::Call {
|
||||||
|
dest: temp,
|
||||||
|
f,
|
||||||
|
args: nargs,
|
||||||
|
});
|
||||||
|
ExprResult::Var(temp)
|
||||||
|
}
|
||||||
|
o => {
|
||||||
|
ctx.err(format!("Expected function, found {:?}", o));
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PExpr::Group(e) => e.lower(ctx)?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Node<PExpr> {
|
||||||
|
pub fn lower(&self, ctx: &mut FnLowerCtx) -> Option<ExprResult> {
|
||||||
|
self.inner.as_ref()?.lower(&mut FnLowerCtx {
|
||||||
|
map: ctx.map,
|
||||||
|
instructions: ctx.instructions,
|
||||||
|
output: ctx.output,
|
||||||
|
span: self.span,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Node<Box<PExpr>> {
|
||||||
|
pub fn lower(&self, ctx: &mut FnLowerCtx) -> Option<ExprResult> {
|
||||||
|
self.inner.as_ref()?.lower(&mut FnLowerCtx {
|
||||||
|
map: ctx.map,
|
||||||
|
instructions: ctx.instructions,
|
||||||
|
output: ctx.output,
|
||||||
|
span: self.span,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum ExprResult {
|
||||||
|
Var(VarIdent),
|
||||||
|
Fn(FnIdent),
|
||||||
|
}
|
||||||
101
src/parser/v3/lower/func.rs
Normal file
101
src/parser/v3/lower/func.rs
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
use super::{Function as PFunction, Node, ParserMsg, ParserOutput};
|
||||||
|
use crate::ir::{
|
||||||
|
BuiltinType, FileSpan, FnDef, FnIdent, Function, Idents, Instruction, Instructions,
|
||||||
|
NamespaceGuard, Origin, Type, VarDef, VarIdent,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl Node<PFunction> {
|
||||||
|
pub fn lower_header(
|
||||||
|
&self,
|
||||||
|
map: &mut NamespaceGuard,
|
||||||
|
output: &mut ParserOutput,
|
||||||
|
) -> Option<FnIdent> {
|
||||||
|
self.as_ref()?.lower_header(map, output)
|
||||||
|
}
|
||||||
|
pub fn lower_body(&self, map: &mut NamespaceGuard, output: &mut ParserOutput) -> Option<Function> {
|
||||||
|
if let Some(f) = self.as_ref() {
|
||||||
|
Some(f.lower_body(map, output))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PFunction {
|
||||||
|
pub fn lower_header(
|
||||||
|
&self,
|
||||||
|
map: &mut NamespaceGuard,
|
||||||
|
output: &mut ParserOutput,
|
||||||
|
) -> Option<FnIdent> {
|
||||||
|
let header = self.header.as_ref()?;
|
||||||
|
let name = header.name.as_ref()?;
|
||||||
|
let args = header
|
||||||
|
.args
|
||||||
|
.iter()
|
||||||
|
.map(|a| {
|
||||||
|
a.lower(map, output).unwrap_or(VarDef {
|
||||||
|
name: "{error}".to_string(),
|
||||||
|
origin: Origin::File(a.span),
|
||||||
|
ty: Type::Error,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
let ret = match &header.ret {
|
||||||
|
Some(ty) => ty.lower(map, output),
|
||||||
|
None => Type::Concrete(BuiltinType::Unit.id()),
|
||||||
|
};
|
||||||
|
// ignoring self var for now
|
||||||
|
Some(map.def_fn(FnDef {
|
||||||
|
name: name.val().clone(),
|
||||||
|
origin: Origin::File(self.header.span),
|
||||||
|
args,
|
||||||
|
ret,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
pub fn lower_body(&self, map: &mut NamespaceGuard, output: &mut ParserOutput) -> Function {
|
||||||
|
let mut instructions = Instructions::new();
|
||||||
|
let mut ctx = FnLowerCtx {
|
||||||
|
instructions: &mut instructions,
|
||||||
|
map,
|
||||||
|
output,
|
||||||
|
span: self.body.span,
|
||||||
|
};
|
||||||
|
if let Some(res) = self.body.lower(&mut ctx) {
|
||||||
|
match res {
|
||||||
|
super::ExprResult::Var(v) => instructions.push(Instruction::Ret { src: v }),
|
||||||
|
super::ExprResult::Fn(_) => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Function::new(instructions)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct FnLowerCtx<'a, 'n> {
|
||||||
|
pub map: &'a mut NamespaceGuard<'n>,
|
||||||
|
pub instructions: &'a mut Instructions,
|
||||||
|
pub output: &'a mut ParserOutput,
|
||||||
|
pub span: FileSpan,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'n> FnLowerCtx<'a, 'n> {
|
||||||
|
pub fn get(&self, name: &str) -> Option<Idents> {
|
||||||
|
self.map.get(name)
|
||||||
|
}
|
||||||
|
pub fn err(&mut self, msg: String) {
|
||||||
|
self.output.err(ParserMsg::from_span(self.span, msg))
|
||||||
|
}
|
||||||
|
pub fn temp(&mut self, ty: Type) -> VarIdent {
|
||||||
|
self.map.temp_var(self.span, ty)
|
||||||
|
}
|
||||||
|
pub fn push(&mut self, i: Instruction) {
|
||||||
|
self.instructions.push(i);
|
||||||
|
}
|
||||||
|
pub fn sub<'b>(&'b mut self) -> FnLowerCtx<'b, 'n> {
|
||||||
|
FnLowerCtx {
|
||||||
|
map: self.map,
|
||||||
|
instructions: self.instructions,
|
||||||
|
output: self.output,
|
||||||
|
span: self.span,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
12
src/parser/v3/lower/mod.rs
Normal file
12
src/parser/v3/lower/mod.rs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
mod block;
|
||||||
|
mod def;
|
||||||
|
mod expr;
|
||||||
|
mod func;
|
||||||
|
mod module;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
use block::*;
|
||||||
|
use def::*;
|
||||||
|
use expr::*;
|
||||||
|
use func::*;
|
||||||
|
use module::*;
|
||||||
21
src/parser/v3/lower/module.rs
Normal file
21
src/parser/v3/lower/module.rs
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
use crate::ir::NamespaceGuard;
|
||||||
|
|
||||||
|
use super::{Module, ParserOutput};
|
||||||
|
|
||||||
|
impl Module {
|
||||||
|
pub fn lower(&self, map: &mut NamespaceGuard, output: &mut ParserOutput) {
|
||||||
|
let mut fns = Vec::new();
|
||||||
|
for f in &self.functions {
|
||||||
|
if let Some(id) = f.lower_header(map, output) {
|
||||||
|
fns.push(Some(id));
|
||||||
|
} else {
|
||||||
|
fns.push(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (f, id) in self.functions.iter().zip(fns) {
|
||||||
|
if let (Some(res), Some(id)) = (f.lower_body(map, output), id) {
|
||||||
|
map.write_fn(id, res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
use std::io::{stdout, BufRead, BufReader};
|
|
||||||
|
|
||||||
mod cursor;
|
mod cursor;
|
||||||
mod error;
|
mod error;
|
||||||
|
mod lower;
|
||||||
mod node;
|
mod node;
|
||||||
mod nodes;
|
mod nodes;
|
||||||
mod parse;
|
mod parse;
|
||||||
@@ -9,43 +8,8 @@ mod token;
|
|||||||
|
|
||||||
pub use cursor::*;
|
pub use cursor::*;
|
||||||
pub use error::*;
|
pub use error::*;
|
||||||
|
pub use lower::*;
|
||||||
pub use node::*;
|
pub use node::*;
|
||||||
pub use nodes::*;
|
pub use nodes::*;
|
||||||
pub use parse::*;
|
pub use parse::*;
|
||||||
pub use token::*;
|
pub use token::*;
|
||||||
|
|
||||||
use crate::ir::Namespace;
|
|
||||||
|
|
||||||
pub fn parse_file(file: &str) {
|
|
||||||
let mut errors = ParserErrors::new();
|
|
||||||
let res = Module::parse_node(&mut TokenCursor::from(file), &mut errors);
|
|
||||||
println!("{:?}", res.node);
|
|
||||||
let out = &mut stdout();
|
|
||||||
if let Some(module) = res.node.as_ref() {
|
|
||||||
let mut namespace = Namespace::new();
|
|
||||||
module.lower(&mut namespace, &mut errors);
|
|
||||||
println!("{:?}", namespace);
|
|
||||||
}
|
|
||||||
for err in errors.errs {
|
|
||||||
err.write_for(out, file).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn run_stdin() {
|
|
||||||
for line in BufReader::new(std::io::stdin()).lines() {
|
|
||||||
let mut errors = ParserErrors::new();
|
|
||||||
let str = &line.expect("failed to read line");
|
|
||||||
let mut cursor = TokenCursor::from(&str[..]);
|
|
||||||
if let Some(expr) = Statement::parse_node(&mut cursor, &mut errors).node.as_ref() {
|
|
||||||
if cursor.next().is_none() {
|
|
||||||
println!("{:?}", expr);
|
|
||||||
} else {
|
|
||||||
println!("uhhhh ehehe");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let out = &mut stdout();
|
|
||||||
for err in errors.errs {
|
|
||||||
err.write_for(out, str).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use std::{
|
|||||||
ops::{Deref, DerefMut},
|
ops::{Deref, DerefMut},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::FileSpan;
|
use crate::ir::FileSpan;
|
||||||
|
|
||||||
pub struct Node<T> {
|
pub struct Node<T> {
|
||||||
pub inner: Option<T>,
|
pub inner: Option<T>,
|
||||||
|
|||||||
23
src/parser/v3/nodes/asm_block.rs
Normal file
23
src/parser/v3/nodes/asm_block.rs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
use crate::compiler::riscv64::AsmInstruction;
|
||||||
|
|
||||||
|
use super::{Parsable, ParseResult, Symbol};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct AsmBlock {
|
||||||
|
pub instructions: Vec<AsmInstruction>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parsable for AsmBlock {
|
||||||
|
fn parse(
|
||||||
|
cursor: &mut super::TokenCursor,
|
||||||
|
output: &mut super::ParserOutput,
|
||||||
|
) -> ParseResult<Self> {
|
||||||
|
cursor.expect_sym(Symbol::OpenCurly)?;
|
||||||
|
let mut instructions = Vec::new();
|
||||||
|
while !cursor.expect_peek()?.is_symbol(Symbol::CloseCurly) {
|
||||||
|
instructions.push(AsmInstruction::parse(cursor, output)?);
|
||||||
|
}
|
||||||
|
cursor.expect_sym(Symbol::CloseCurly)?;
|
||||||
|
ParseResult::Ok(Self { instructions })
|
||||||
|
}
|
||||||
|
}
|
||||||
53
src/parser/v3/nodes/asm_fn.rs
Normal file
53
src/parser/v3/nodes/asm_fn.rs
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
use crate::compiler::riscv64::{AsmInstruction, Reg};
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
util::parse_list, AsmBlock, Ident, Keyword, Node, Parsable, ParseResult, SelfVar, Symbol,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct AsmFunctionHeader {
|
||||||
|
pub name: Node<Ident>,
|
||||||
|
pub sel: Option<Node<SelfVar>>,
|
||||||
|
pub args: Vec<Node<Reg>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct AsmFunction {
|
||||||
|
pub header: Node<AsmFunctionHeader>,
|
||||||
|
pub body: Node<AsmBlock>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parsable for AsmFunctionHeader {
|
||||||
|
fn parse(
|
||||||
|
cursor: &mut super::TokenCursor,
|
||||||
|
output: &mut super::ParserOutput,
|
||||||
|
) -> ParseResult<Self> {
|
||||||
|
cursor.expect_kw(Keyword::Asm)?;
|
||||||
|
cursor.expect_kw(Keyword::Fn)?;
|
||||||
|
let name = Node::parse(cursor, output)?;
|
||||||
|
cursor.expect_sym(Symbol::OpenParen)?;
|
||||||
|
let sel = Node::maybe_parse(cursor, output);
|
||||||
|
if sel.is_some() {
|
||||||
|
if let Err(err) = cursor.expect_sym(Symbol::Comma) {
|
||||||
|
output.err(err);
|
||||||
|
cursor.seek_syms(&[Symbol::Comma, Symbol::CloseParen]);
|
||||||
|
if cursor.peek().is_some_and(|i| i.is_symbol(Symbol::Comma)) {
|
||||||
|
cursor.next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let args = parse_list(cursor, output, Symbol::CloseParen)?;
|
||||||
|
ParseResult::Ok(Self { name, sel, args })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parsable for AsmFunction {
|
||||||
|
fn parse(
|
||||||
|
cursor: &mut super::TokenCursor,
|
||||||
|
output: &mut super::ParserOutput,
|
||||||
|
) -> ParseResult<Self> {
|
||||||
|
let header = Node::parse(cursor, output)?;
|
||||||
|
let body = Node::parse(cursor, output)?;
|
||||||
|
ParseResult::Ok(Self { header, body })
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,29 +1,31 @@
|
|||||||
use std::fmt::{Debug, Write};
|
use std::fmt::{Debug, Write};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
token::Symbol, Node, NodeParsable, Parsable, ParseResult, ParserError,
|
token::Symbol, Node, NodeParsable, Parsable, ParseResult, ParserMsg, ParserOutput, Statement,
|
||||||
ParserErrors, Statement, TokenCursor,
|
TokenCursor,
|
||||||
};
|
};
|
||||||
use crate::util::Padder;
|
use crate::util::Padder;
|
||||||
|
|
||||||
pub struct Body {
|
pub struct Block {
|
||||||
pub statements: Vec<Node<Statement>>,
|
pub statements: Vec<Node<Statement>>,
|
||||||
|
pub result: Option<Node<Box<Statement>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parsable for Body {
|
impl Parsable for Block {
|
||||||
fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> ParseResult<Self> {
|
fn parse(cursor: &mut TokenCursor, errors: &mut ParserOutput) -> ParseResult<Self> {
|
||||||
let mut statements = Vec::new();
|
let mut statements = Vec::new();
|
||||||
|
let mut result = None;
|
||||||
cursor.expect_sym(Symbol::OpenCurly)?;
|
cursor.expect_sym(Symbol::OpenCurly)?;
|
||||||
if cursor.expect_peek()?.is_symbol(Symbol::CloseCurly) {
|
if cursor.expect_peek()?.is_symbol(Symbol::CloseCurly) {
|
||||||
cursor.next();
|
cursor.next();
|
||||||
return ParseResult::Ok(Self { statements });
|
return ParseResult::Ok(Self { statements, result });
|
||||||
}
|
}
|
||||||
let mut expect_semi = false;
|
let mut expect_semi = false;
|
||||||
let mut recover = false;
|
let mut recover = false;
|
||||||
loop {
|
loop {
|
||||||
let Some(next) = cursor.peek() else {
|
let Some(next) = cursor.peek() else {
|
||||||
recover = true;
|
recover = true;
|
||||||
errors.add(ParserError::unexpected_end());
|
errors.err(ParserMsg::unexpected_end());
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
if next.is_symbol(Symbol::CloseCurly) {
|
if next.is_symbol(Symbol::CloseCurly) {
|
||||||
@@ -35,7 +37,7 @@ impl Parsable for Body {
|
|||||||
expect_semi = false;
|
expect_semi = false;
|
||||||
continue;
|
continue;
|
||||||
} else if expect_semi {
|
} else if expect_semi {
|
||||||
errors.add(ParserError {
|
errors.err(ParserMsg {
|
||||||
msg: "expected ';'".to_string(),
|
msg: "expected ';'".to_string(),
|
||||||
spans: vec![cursor.next_pos().char_span()],
|
spans: vec![cursor.next_pos().char_span()],
|
||||||
});
|
});
|
||||||
@@ -51,11 +53,16 @@ impl Parsable for Body {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ParseResult::from_recover(Self { statements }, recover)
|
if expect_semi {
|
||||||
|
if let Some(s) = statements.pop() {
|
||||||
|
result = Some(s.bx());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ParseResult::from_recover(Self { statements, result }, recover)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Body {
|
impl Debug for Block {
|
||||||
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.first().is_some() {
|
if self.statements.first().is_some() {
|
||||||
f.write_str("{\n ")?;
|
f.write_str("{\n ")?;
|
||||||
82
src/parser/v3/nodes/def.rs
Normal file
82
src/parser/v3/nodes/def.rs
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
use super::{Ident, MaybeParsable, Node, Parsable, ParseResult, ParserMsg, Symbol, Token, Type};
|
||||||
|
|
||||||
|
pub struct VarDef {
|
||||||
|
pub name: Node<Ident>,
|
||||||
|
pub ty: Option<Node<Type>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parsable for VarDef {
|
||||||
|
fn parse(
|
||||||
|
cursor: &mut super::TokenCursor,
|
||||||
|
errors: &mut super::ParserOutput,
|
||||||
|
) -> ParseResult<Self> {
|
||||||
|
let name = Node::parse(cursor, errors)?;
|
||||||
|
if cursor.peek().is_some_and(|n| n.is_symbol(Symbol::Colon)) {
|
||||||
|
cursor.next();
|
||||||
|
Node::parse(cursor, errors).map(|ty| Self { name, ty: Some(ty) })
|
||||||
|
} else {
|
||||||
|
ParseResult::Ok(Self { name, ty: None })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SelfVar {
|
||||||
|
pub ty: SelfType,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq)]
|
||||||
|
pub enum SelfType {
|
||||||
|
Ref,
|
||||||
|
Take,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MaybeParsable for SelfVar {
|
||||||
|
fn maybe_parse(
|
||||||
|
cursor: &mut super::TokenCursor,
|
||||||
|
errors: &mut super::ParserOutput,
|
||||||
|
) -> Result<Option<Self>, super::ParserMsg> {
|
||||||
|
if let Some(mut next) = cursor.peek() {
|
||||||
|
let mut ty = SelfType::Take;
|
||||||
|
if next.is_symbol(Symbol::Ampersand) {
|
||||||
|
cursor.next();
|
||||||
|
ty = SelfType::Ref;
|
||||||
|
next = cursor.expect_peek()?;
|
||||||
|
}
|
||||||
|
if let Token::Word(name) = &next.token {
|
||||||
|
if name == "self" {
|
||||||
|
cursor.next();
|
||||||
|
return Ok(Some(Self { ty }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ty != SelfType::Take {
|
||||||
|
return Err(ParserMsg::unexpected_token(next, "self"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for VarDef {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
self.name.fmt(f)?;
|
||||||
|
if let Some(ty) = &self.ty {
|
||||||
|
write!(f, ": {:?}", ty)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for SelfVar {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"{}",
|
||||||
|
match self.ty {
|
||||||
|
SelfType::Ref => "&self",
|
||||||
|
SelfType::Take => "self",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,10 @@
|
|||||||
use std::fmt::{Debug, Write};
|
use std::fmt::{Debug, Write};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
BinaryOperator, Body, Ident, Literal, Node, NodeParsable, Parsable, ParseResult, ParserError,
|
op::{BinaryOp, UnaryOp},
|
||||||
ParserErrors, Symbol, TokenCursor, UnaryOperator,
|
util::parse_list,
|
||||||
|
AsmBlock, Block, Ident, Keyword, Literal, Node, NodeParsable, Parsable, ParseResult, ParserMsg,
|
||||||
|
ParserOutput, Symbol, TokenCursor,
|
||||||
};
|
};
|
||||||
|
|
||||||
type BoxNode = Node<Box<Expr>>;
|
type BoxNode = Node<Box<Expr>>;
|
||||||
@@ -10,15 +12,16 @@ type BoxNode = Node<Box<Expr>>;
|
|||||||
pub enum Expr {
|
pub enum Expr {
|
||||||
Lit(Node<Literal>),
|
Lit(Node<Literal>),
|
||||||
Ident(Node<Ident>),
|
Ident(Node<Ident>),
|
||||||
BinaryOp(BinaryOperator, BoxNode, BoxNode),
|
BinaryOp(BinaryOp, BoxNode, BoxNode),
|
||||||
UnaryOp(UnaryOperator, BoxNode),
|
UnaryOp(UnaryOp, BoxNode),
|
||||||
Block(Node<Body>),
|
Block(Node<Block>),
|
||||||
Call(BoxNode, Vec<Node<Expr>>),
|
Call(BoxNode, Vec<Node<Expr>>),
|
||||||
Group(BoxNode),
|
Group(BoxNode),
|
||||||
|
AsmBlock(Node<AsmBlock>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parsable for Expr {
|
impl Parsable for Expr {
|
||||||
fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> ParseResult<Self> {
|
fn parse(cursor: &mut TokenCursor, output: &mut ParserOutput) -> ParseResult<Self> {
|
||||||
let start = cursor.next_pos();
|
let start = cursor.next_pos();
|
||||||
let next = cursor.expect_peek()?;
|
let next = cursor.expect_peek()?;
|
||||||
let mut e1 = if next.is_symbol(Symbol::OpenParen) {
|
let mut e1 = if next.is_symbol(Symbol::OpenParen) {
|
||||||
@@ -30,17 +33,20 @@ impl Parsable for Expr {
|
|||||||
cursor.next_pos().char_span(),
|
cursor.next_pos().char_span(),
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
let res = Node::parse(cursor, errors);
|
let res = Node::parse(cursor, output);
|
||||||
if res.recover {
|
if res.recover {
|
||||||
cursor.seek_sym(Symbol::CloseParen);
|
cursor.seek_sym(Symbol::CloseParen);
|
||||||
}
|
}
|
||||||
cursor.expect_sym(Symbol::CloseParen)?;
|
cursor.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(Body::parse_node(cursor, errors)?)
|
Self::Block(Block::parse_node(cursor, output)?)
|
||||||
} else if let Some(op) = UnaryOperator::from_token(next) {
|
} else if next.is_keyword(Keyword::Asm) {
|
||||||
cursor.next();
|
cursor.next();
|
||||||
return Node::parse(cursor, errors).map(|n| {
|
Self::AsmBlock(Node::parse(cursor, output)?)
|
||||||
|
} else if let Some(op) = UnaryOp::from_token(next) {
|
||||||
|
cursor.next();
|
||||||
|
return Node::parse(cursor, output).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.span.end);
|
||||||
@@ -49,15 +55,15 @@ impl Parsable for Expr {
|
|||||||
Self::UnaryOp(op, n)
|
Self::UnaryOp(op, n)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else if let Some(val) = Node::maybe_parse(cursor, errors) {
|
} else if let Some(val) = Node::maybe_parse(cursor, output) {
|
||||||
Self::Lit(val)
|
Self::Lit(val)
|
||||||
} else {
|
} else {
|
||||||
let res = Node::parse(cursor, &mut ParserErrors::new());
|
let res = Node::parse(cursor, &mut ParserOutput::new());
|
||||||
if res.node.is_some() {
|
if res.node.is_some() {
|
||||||
Self::Ident(res.node)
|
Self::Ident(res.node)
|
||||||
} else {
|
} else {
|
||||||
let next = cursor.expect_peek()?;
|
let next = cursor.expect_peek()?;
|
||||||
return ParseResult::Err(ParserError::unexpected_token(next, "an expression"));
|
return ParseResult::Err(ParserMsg::unexpected_token(next, "an expression"));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let Some(mut next) = cursor.peek() else {
|
let Some(mut next) = cursor.peek() else {
|
||||||
@@ -65,24 +71,7 @@ impl Parsable for Expr {
|
|||||||
};
|
};
|
||||||
while next.is_symbol(Symbol::OpenParen) {
|
while next.is_symbol(Symbol::OpenParen) {
|
||||||
cursor.next();
|
cursor.next();
|
||||||
let mut args = Vec::new();
|
let args = parse_list(cursor, output, Symbol::CloseParen)?;
|
||||||
loop {
|
|
||||||
let next = cursor.expect_peek()?;
|
|
||||||
if next.is_symbol(Symbol::CloseParen) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
let res = Node::<Expr>::parse(cursor, errors);
|
|
||||||
args.push(res.node);
|
|
||||||
if res.recover {
|
|
||||||
cursor.seek_syms(&[Symbol::CloseParen, Symbol::Comma]);
|
|
||||||
}
|
|
||||||
let next = cursor.expect_peek()?;
|
|
||||||
if !next.is_symbol(Symbol::Comma) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
cursor.next();
|
|
||||||
}
|
|
||||||
cursor.expect_sym(Symbol::CloseParen)?;
|
|
||||||
let end = cursor.prev_end();
|
let end = cursor.prev_end();
|
||||||
e1 = Self::Call(Node::new(Box::new(e1), start.to(end)), args);
|
e1 = Self::Call(Node::new(Box::new(e1), start.to(end)), args);
|
||||||
let Some(next2) = cursor.peek() else {
|
let Some(next2) = cursor.peek() else {
|
||||||
@@ -92,10 +81,10 @@ impl Parsable for Expr {
|
|||||||
}
|
}
|
||||||
let end = cursor.prev_end();
|
let end = cursor.prev_end();
|
||||||
let mut recover = false;
|
let mut recover = false;
|
||||||
let res = if let Some(mut op) = BinaryOperator::from_token(&next.token) {
|
let res = if let Some(mut op) = BinaryOp::from_token(&next.token) {
|
||||||
cursor.next();
|
cursor.next();
|
||||||
let mut n1 = Node::new(e1, start.to(end)).bx();
|
let mut n1 = Node::new(e1, start.to(end)).bx();
|
||||||
let res = Node::parse(cursor, errors);
|
let res = Node::parse(cursor, output);
|
||||||
let mut n2 = res.node.bx();
|
let mut n2 = res.node.bx();
|
||||||
recover = res.recover;
|
recover = res.recover;
|
||||||
if let Some(box Self::BinaryOp(op2, _, _)) = n2.as_ref() {
|
if let Some(box Self::BinaryOp(op2, _, _)) = n2.as_ref() {
|
||||||
@@ -150,6 +139,7 @@ impl Debug for Expr {
|
|||||||
write!(f, "{:?})", *e)?;
|
write!(f, "{:?})", *e)?;
|
||||||
}
|
}
|
||||||
Expr::Group(inner) => inner.fmt(f)?,
|
Expr::Group(inner) => inner.fmt(f)?,
|
||||||
|
Expr::AsmBlock(inner) => inner.fmt(f)?,
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,28 +1,90 @@
|
|||||||
use super::{Body, Ident, Keyword, Node, Parsable, ParseResult, ParserErrors, Symbol, TokenCursor};
|
use super::{
|
||||||
|
util::parse_list, Block, Ident, Keyword, Node, Parsable, ParseResult, ParserOutput, SelfVar,
|
||||||
|
Symbol, TokenCursor, Type, VarDef,
|
||||||
|
};
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
pub struct Function {
|
pub struct FunctionHeader {
|
||||||
pub name: Node<Ident>,
|
pub name: Node<Ident>,
|
||||||
pub body: Node<Body>,
|
pub sel: Option<Node<SelfVar>>,
|
||||||
|
pub args: Vec<Node<VarDef>>,
|
||||||
|
pub ret: Option<Node<Type>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Function {
|
||||||
|
pub header: Node<FunctionHeader>,
|
||||||
|
pub body: Node<Block>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parsable for FunctionHeader {
|
||||||
|
fn parse(cursor: &mut TokenCursor, output: &mut ParserOutput) -> ParseResult<Self> {
|
||||||
|
cursor.expect_kw(Keyword::Fn)?;
|
||||||
|
let name = Node::parse(cursor, output)?;
|
||||||
|
cursor.expect_sym(Symbol::OpenParen)?;
|
||||||
|
let sel = Node::maybe_parse(cursor, output);
|
||||||
|
if sel.is_some() {
|
||||||
|
if let Err(err) = cursor.expect_sym(Symbol::Comma) {
|
||||||
|
output.err(err);
|
||||||
|
cursor.seek_syms(&[Symbol::Comma, Symbol::CloseParen]);
|
||||||
|
if cursor.peek().is_some_and(|i| i.is_symbol(Symbol::Comma)) {
|
||||||
|
cursor.next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let args = parse_list(cursor, output, Symbol::CloseParen)?;
|
||||||
|
let ret = if cursor.peek().is_some_and(|i| i.is_symbol(Symbol::Arrow)) {
|
||||||
|
cursor.next();
|
||||||
|
Some(Node::parse(cursor, output)?)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
ParseResult::Ok(Self {
|
||||||
|
name,
|
||||||
|
args,
|
||||||
|
sel,
|
||||||
|
ret,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parsable for Function {
|
impl Parsable for Function {
|
||||||
fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> ParseResult<Self> {
|
fn parse(cursor: &mut TokenCursor, output: &mut ParserOutput) -> ParseResult<Self> {
|
||||||
cursor.expect_kw(Keyword::Fn)?;
|
let header = Node::parse(cursor, output)?;
|
||||||
let name = Node::parse(cursor, errors)?;
|
let body = Node::parse(cursor, output)?;
|
||||||
cursor.expect_sym(Symbol::OpenParen)?;
|
ParseResult::Ok(Self { header, body })
|
||||||
cursor.expect_sym(Symbol::CloseParen)?;
|
|
||||||
Node::parse(cursor, errors).map(|body| Self { name, body })
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Function {
|
impl Debug for FunctionHeader {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
f.write_str("fn ")?;
|
f.write_str("fn ")?;
|
||||||
self.name.fmt(f)?;
|
self.name.fmt(f)?;
|
||||||
f.write_str("() ")?;
|
f.write_str("(")?;
|
||||||
|
if let Some(s) = &self.sel {
|
||||||
|
s.fmt(f)?;
|
||||||
|
if self.args.first().is_some() {
|
||||||
|
f.write_str(", ")?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(a) = self.args.first() {
|
||||||
|
a.fmt(f)?;
|
||||||
|
}
|
||||||
|
for arg in self.args.iter().skip(1) {
|
||||||
|
f.write_str(", ")?;
|
||||||
|
arg.fmt(f)?;
|
||||||
|
}
|
||||||
|
f.write_str(")")?;
|
||||||
|
if let Some(ret) = &self.ret {
|
||||||
|
write!(f, " -> {:?}", ret)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Debug for Function {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
self.header.fmt(f)?;
|
||||||
|
f.write_str(" ")?;
|
||||||
self.body.fmt(f)?;
|
self.body.fmt(f)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use super::{Parsable, ParseResult, ParserError, Token};
|
use super::{Parsable, ParseResult, ParserMsg, Token};
|
||||||
|
|
||||||
pub struct Ident(String);
|
pub struct Ident(String);
|
||||||
|
|
||||||
@@ -10,10 +10,10 @@ impl Ident {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Parsable for Ident {
|
impl Parsable for Ident {
|
||||||
fn parse(cursor: &mut super::TokenCursor, errors: &mut super::ParserErrors) -> ParseResult<Self> {
|
fn parse(cursor: &mut super::TokenCursor, errors: &mut super::ParserOutput) -> ParseResult<Self> {
|
||||||
let next = cursor.expect_peek()?;
|
let next = cursor.expect_peek()?;
|
||||||
let Token::Ident(name) = &next.token else {
|
let Token::Word(name) = &next.token else {
|
||||||
return ParseResult::Err(ParserError::unexpected_token(next, "an identifier"));
|
return ParseResult::Err(ParserMsg::unexpected_token(next, "an identifier"));
|
||||||
};
|
};
|
||||||
let name = name.to_string();
|
let name = name.to_string();
|
||||||
cursor.next();
|
cursor.next();
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
use super::{
|
use super::{CharCursor, MaybeParsable, ParserMsg, ParserOutput, Symbol, Token, TokenCursor};
|
||||||
CharCursor, MaybeParsable, ParserError, ParserErrors, Symbol, Token, TokenCursor,
|
|
||||||
};
|
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq)]
|
#[derive(Clone, PartialEq, Eq)]
|
||||||
@@ -21,49 +19,72 @@ pub struct Number {
|
|||||||
impl MaybeParsable for Literal {
|
impl MaybeParsable for Literal {
|
||||||
fn maybe_parse(
|
fn maybe_parse(
|
||||||
cursor: &mut TokenCursor,
|
cursor: &mut TokenCursor,
|
||||||
_: &mut ParserErrors,
|
_: &mut ParserOutput,
|
||||||
) -> Result<Option<Self>, ParserError> {
|
) -> Result<Option<Self>, ParserMsg> {
|
||||||
let inst = cursor.expect_peek()?;
|
let inst = cursor.expect_peek()?;
|
||||||
let mut res = match &inst.token {
|
Ok(Some(match &inst.token {
|
||||||
Token::Symbol(Symbol::SingleQuote) => {
|
Token::Symbol(Symbol::SingleQuote) => {
|
||||||
let chars = cursor.chars();
|
let chars = cursor.chars();
|
||||||
let c = chars.expect_next()?;
|
let c = chars.expect_next()?;
|
||||||
chars.expect('\'')?;
|
chars.expect('\'')?;
|
||||||
|
cursor.next();
|
||||||
Self::Char(c)
|
Self::Char(c)
|
||||||
}
|
}
|
||||||
Token::Symbol(Symbol::DoubleQuote) => Self::String(string_from(cursor.chars())?),
|
Token::Symbol(Symbol::DoubleQuote) => {
|
||||||
Token::Ident(text) => {
|
let res = Self::String(string_from(cursor.chars())?);
|
||||||
|
cursor.next();
|
||||||
|
res
|
||||||
|
}
|
||||||
|
Token::Word(text) => {
|
||||||
let first = text.chars().next().unwrap();
|
let first = text.chars().next().unwrap();
|
||||||
if first.is_ascii_digit() {
|
if !first.is_ascii_digit() {
|
||||||
Self::Number(Number {
|
|
||||||
whole: text.to_string(),
|
|
||||||
decimal: None,
|
|
||||||
ty: None,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
}
|
let (whole, ty) = parse_whole_num(text);
|
||||||
_ => return Ok(None),
|
let mut num = Number {
|
||||||
|
whole,
|
||||||
|
decimal: None,
|
||||||
|
ty,
|
||||||
};
|
};
|
||||||
cursor.next();
|
cursor.next();
|
||||||
if let (Some(next), Self::Number(num)) = (cursor.peek(), &mut res) {
|
if num.ty.is_none() && cursor.peek().is_some_and(|i| i.is_symbol(Symbol::Dot)) {
|
||||||
if next.token.is_symbol(Symbol::Dot) {
|
|
||||||
cursor.next();
|
cursor.next();
|
||||||
if let Some(next) = cursor.peek() {
|
if let Some(next) = cursor.peek() {
|
||||||
if let Token::Ident(i) = &next.token {
|
if let Token::Word(i) = &next.token {
|
||||||
if i.chars().next().unwrap().is_ascii_digit() {
|
if i.chars().next().unwrap().is_ascii_digit() {
|
||||||
num.decimal = Some(i.to_string());
|
let (decimal, ty) = parse_whole_num(i);
|
||||||
|
num.decimal = Some(decimal);
|
||||||
|
num.ty = ty;
|
||||||
cursor.next();
|
cursor.next();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Self::Number(num)
|
||||||
}
|
}
|
||||||
Ok(Some(res))
|
_ => return Ok(None),
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn string_from(cursor: &mut CharCursor) -> Result<String, ParserError> {
|
|
||||||
|
pub fn parse_whole_num(text: &str) -> (String, Option<String>) {
|
||||||
|
let mut whole = String::new();
|
||||||
|
let mut ty = String::new();
|
||||||
|
for c in text.chars() {
|
||||||
|
if ty.is_empty() {
|
||||||
|
if c.is_ascii_digit() {
|
||||||
|
whole.push(c);
|
||||||
|
} else if c != '_' {
|
||||||
|
ty.push(c);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ty.push(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(whole, if ty.is_empty() { None } else { Some(ty) })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn string_from(cursor: &mut CharCursor) -> Result<String, ParserMsg> {
|
||||||
let mut str = String::new();
|
let mut str = String::new();
|
||||||
loop {
|
loop {
|
||||||
let c = cursor.expect_next()?;
|
let c = cursor.expect_next()?;
|
||||||
@@ -107,7 +128,7 @@ impl Debug for Number {
|
|||||||
write!(f, ".{}", d)?;
|
write!(f, ".{}", d)?;
|
||||||
}
|
}
|
||||||
if let Some(ty) = &self.ty {
|
if let Some(ty) = &self.ty {
|
||||||
write!(f, "T{}", ty)?;
|
write!(f, "_{}", ty)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
mod body;
|
mod block;
|
||||||
mod expr;
|
mod expr;
|
||||||
mod func;
|
mod func;
|
||||||
mod module;
|
mod module;
|
||||||
@@ -6,14 +6,28 @@ mod op;
|
|||||||
mod statement;
|
mod statement;
|
||||||
mod lit;
|
mod lit;
|
||||||
mod ident;
|
mod ident;
|
||||||
|
mod ty;
|
||||||
|
mod def;
|
||||||
|
mod struc;
|
||||||
|
mod util;
|
||||||
|
mod trai;
|
||||||
|
mod asm_fn;
|
||||||
|
mod asm_block;
|
||||||
|
|
||||||
pub use body::*;
|
pub use block::*;
|
||||||
pub use expr::*;
|
pub use expr::*;
|
||||||
pub use func::*;
|
pub use func::*;
|
||||||
pub use module::*;
|
pub use module::*;
|
||||||
pub use op::*;
|
|
||||||
pub use statement::*;
|
pub use statement::*;
|
||||||
pub use lit::*;
|
pub use lit::*;
|
||||||
pub use ident::*;
|
pub use ident::*;
|
||||||
|
pub use ty::*;
|
||||||
|
pub use def::*;
|
||||||
|
pub use struc::*;
|
||||||
|
pub use trai::*;
|
||||||
|
pub use op::*;
|
||||||
|
pub use asm_fn::*;
|
||||||
|
pub use asm_block::*;
|
||||||
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|||||||
@@ -1,35 +1,113 @@
|
|||||||
use super::{
|
use super::{
|
||||||
Function, Keyword, Node, Parsable, ParseResult, ParserError, ParserErrors, TokenCursor,
|
AsmFunction, Function, Impl, Keyword, Node, Parsable, ParseResult, ParserMsg, ParserOutput,
|
||||||
|
Struct, Symbol, Token, TokenCursor, Trait,
|
||||||
};
|
};
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
pub struct Module {
|
pub struct Module {
|
||||||
|
pub traits: Vec<Node<Trait>>,
|
||||||
|
pub structs: Vec<Node<Struct>>,
|
||||||
pub functions: Vec<Node<Function>>,
|
pub functions: Vec<Node<Function>>,
|
||||||
|
pub asm_fns: Vec<Node<AsmFunction>>,
|
||||||
|
pub impls: Vec<Node<Impl>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parsable for Module {
|
impl Parsable for Module {
|
||||||
fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> ParseResult<Self> {
|
fn parse(cursor: &mut TokenCursor, errors: &mut ParserOutput) -> ParseResult<Self> {
|
||||||
let mut functions = Vec::new();
|
let mut functions = Vec::new();
|
||||||
|
let mut structs = Vec::new();
|
||||||
|
let mut traits = Vec::new();
|
||||||
|
let mut impls = Vec::new();
|
||||||
|
let mut asm_fns = Vec::new();
|
||||||
loop {
|
loop {
|
||||||
let Some(next) = cursor.peek() else {
|
let Some(next) = cursor.peek() else {
|
||||||
return ParseResult::Ok(Self { functions });
|
break;
|
||||||
};
|
};
|
||||||
if next.is_keyword(Keyword::Fn) {
|
if let Token::Keyword(kw) = next.token {
|
||||||
|
match kw {
|
||||||
|
Keyword::Fn => {
|
||||||
let res = Node::parse(cursor, errors);
|
let res = Node::parse(cursor, errors);
|
||||||
functions.push(res.node);
|
functions.push(res.node);
|
||||||
if res.recover {
|
if res.recover {
|
||||||
return ParseResult::Recover(Self { functions });
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
errors.add(ParserError::unexpected_token(next, "fn"));
|
Keyword::Struct => {
|
||||||
|
let res = Node::parse(cursor, errors);
|
||||||
|
structs.push(res.node);
|
||||||
|
if res.recover {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Keyword::Trait => {
|
||||||
|
let res = Node::parse(cursor, errors);
|
||||||
|
traits.push(res.node);
|
||||||
|
if res.recover {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Keyword::Impl => {
|
||||||
|
let res = Node::parse(cursor, errors);
|
||||||
|
impls.push(res.node);
|
||||||
|
if res.recover {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Keyword::Asm => {
|
||||||
|
let res = Node::parse(cursor, errors);
|
||||||
|
asm_fns.push(res.node);
|
||||||
|
if res.recover {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
errors.err(ParserMsg::unexpected_token(next, "a definition"));
|
||||||
cursor.next();
|
cursor.next();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if next.is_symbol(Symbol::Semicolon) {
|
||||||
|
errors.hint(ParserMsg::from_instances(
|
||||||
|
&[next],
|
||||||
|
"unneeded semicolon".to_string(),
|
||||||
|
));
|
||||||
|
cursor.next();
|
||||||
|
} else {
|
||||||
|
errors.err(ParserMsg::unexpected_token(next, "a definition"));
|
||||||
|
cursor.next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ParseResult::Ok(Self {
|
||||||
|
functions,
|
||||||
|
structs,
|
||||||
|
traits,
|
||||||
|
impls,
|
||||||
|
asm_fns,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Module {
|
impl Debug for Module {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
self.functions.fmt(f)
|
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)?;
|
||||||
|
}
|
||||||
|
for func in &self.asm_fns {
|
||||||
|
func.fmt(f)?;
|
||||||
|
writeln!(f)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use super::{Symbol, Token};
|
use super::{Symbol, Token};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||||
pub enum BinaryOperator {
|
pub enum BinaryOp {
|
||||||
Add,
|
Add,
|
||||||
Sub,
|
Sub,
|
||||||
Mul,
|
Mul,
|
||||||
@@ -12,7 +12,7 @@ pub enum BinaryOperator {
|
|||||||
Assign,
|
Assign,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BinaryOperator {
|
impl BinaryOp {
|
||||||
pub fn presedence(&self) -> u32 {
|
pub fn presedence(&self) -> u32 {
|
||||||
match self {
|
match self {
|
||||||
Self::Assign => 0,
|
Self::Assign => 0,
|
||||||
@@ -37,6 +37,39 @@ impl BinaryOperator {
|
|||||||
Self::Assign => "=",
|
Self::Assign => "=",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn pad(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Self::Add => true,
|
||||||
|
Self::Sub => true,
|
||||||
|
Self::Mul => true,
|
||||||
|
Self::Div => true,
|
||||||
|
Self::LessThan => true,
|
||||||
|
Self::GreaterThan => true,
|
||||||
|
Self::Access => 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 {
|
||||||
|
Not,
|
||||||
|
Ref,
|
||||||
|
Deref,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BinaryOp {
|
||||||
pub fn from_token(token: &Token) -> Option<Self> {
|
pub fn from_token(token: &Token) -> Option<Self> {
|
||||||
let Token::Symbol(symbol) = token else {
|
let Token::Symbol(symbol) = token else {
|
||||||
return None;
|
return None;
|
||||||
@@ -55,30 +88,14 @@ impl BinaryOperator {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
pub fn pad(&self) -> bool {
|
|
||||||
match self {
|
|
||||||
Self::Add => true,
|
|
||||||
Self::Sub => true,
|
|
||||||
Self::Mul => true,
|
|
||||||
Self::Div => true,
|
|
||||||
Self::LessThan => true,
|
|
||||||
Self::GreaterThan => true,
|
|
||||||
Self::Access => false,
|
|
||||||
Self::Assign => true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum UnaryOperator {
|
impl UnaryOp {
|
||||||
Not,
|
|
||||||
Ref,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl UnaryOperator {
|
|
||||||
pub fn str(&self) -> &str {
|
pub fn str(&self) -> &str {
|
||||||
match self {
|
match self {
|
||||||
Self::Not => "!",
|
Self::Not => "!",
|
||||||
Self::Ref => "&",
|
Self::Ref => "&",
|
||||||
|
Self::Deref => "*",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn from_token(token: &Token) -> Option<Self> {
|
pub fn from_token(token: &Token) -> Option<Self> {
|
||||||
@@ -88,6 +105,7 @@ impl UnaryOperator {
|
|||||||
Some(match symbol {
|
Some(match symbol {
|
||||||
Symbol::Ampersand => Self::Ref,
|
Symbol::Ampersand => Self::Ref,
|
||||||
Symbol::Bang => Self::Not,
|
Symbol::Bang => Self::Not,
|
||||||
|
Symbol::Asterisk => Self::Deref,
|
||||||
_ => {
|
_ => {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +1,23 @@
|
|||||||
use super::{
|
use super::{
|
||||||
Expr, Ident, Keyword, Node, Parsable, ParseResult, ParserErrors, Symbol, Token, TokenCursor,
|
Expr, Keyword, Node, Parsable, ParseResult, ParserOutput, Symbol, Token, TokenCursor, VarDef,
|
||||||
};
|
};
|
||||||
use std::fmt::{Debug, Write};
|
use std::fmt::{Debug, Write};
|
||||||
|
|
||||||
pub enum Statement {
|
pub enum Statement {
|
||||||
Let(Node<Ident>, Node<Expr>),
|
Let(Node<VarDef>, Node<Expr>),
|
||||||
Return(Node<Expr>),
|
Return(Node<Expr>),
|
||||||
Expr(Node<Expr>),
|
Expr(Node<Expr>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parsable for Statement {
|
impl Parsable for Statement {
|
||||||
fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> ParseResult<Self> {
|
fn parse(cursor: &mut TokenCursor, errors: &mut ParserOutput) -> ParseResult<Self> {
|
||||||
let next = cursor.expect_peek()?;
|
let next = cursor.expect_peek()?;
|
||||||
match next.token {
|
match next.token {
|
||||||
Token::Keyword(Keyword::Let) => {
|
Token::Keyword(Keyword::Let) => {
|
||||||
cursor.next();
|
cursor.next();
|
||||||
let name = Node::parse(cursor, errors)?;
|
let def = Node::parse(cursor, errors)?;
|
||||||
cursor.expect_sym(Symbol::Equals)?;
|
cursor.expect_sym(Symbol::Equals)?;
|
||||||
Node::parse(cursor, errors).map(|expr| Self::Let(name, expr))
|
Node::parse(cursor, errors).map(|expr| Self::Let(def, expr))
|
||||||
}
|
}
|
||||||
Token::Keyword(Keyword::Return) => {
|
Token::Keyword(Keyword::Return) => {
|
||||||
cursor.next();
|
cursor.next();
|
||||||
|
|||||||
45
src/parser/v3/nodes/struc.rs
Normal file
45
src/parser/v3/nodes/struc.rs
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
util::parse_list, Ident, Keyword, Node, Parsable, ParseResult, ParserMsg, ParserOutput,
|
||||||
|
Symbol, TokenCursor, Type, VarDef,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Struct {
|
||||||
|
pub name: Node<Ident>,
|
||||||
|
pub fields: StructFields,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum StructFields {
|
||||||
|
Named(Vec<Node<VarDef>>),
|
||||||
|
Tuple(Vec<Node<Type>>),
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parsable for Struct {
|
||||||
|
fn parse(cursor: &mut TokenCursor, errors: &mut ParserOutput) -> ParseResult<Self> {
|
||||||
|
cursor.expect_kw(Keyword::Struct)?;
|
||||||
|
let name = Node::parse(cursor, errors)?;
|
||||||
|
let next = cursor.expect_peek()?;
|
||||||
|
let fields = if next.is_symbol(Symbol::Semicolon) {
|
||||||
|
cursor.next();
|
||||||
|
StructFields::None
|
||||||
|
} else if next.is_symbol(Symbol::OpenCurly) {
|
||||||
|
cursor.next();
|
||||||
|
StructFields::Named(parse_list(cursor, errors, Symbol::CloseCurly)?)
|
||||||
|
} else if next.is_symbol(Symbol::OpenParen) {
|
||||||
|
cursor.next();
|
||||||
|
StructFields::Tuple(parse_list(cursor, errors, Symbol::CloseParen)?)
|
||||||
|
} else {
|
||||||
|
errors.err(ParserMsg::unexpected_token(next, "`;`, `(`, or `{`"));
|
||||||
|
return ParseResult::Recover(Struct {
|
||||||
|
name,
|
||||||
|
fields: StructFields::None,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
ParseResult::Ok(Struct { name, fields })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
36
src/parser/v3/nodes/trai.rs
Normal file
36
src/parser/v3/nodes/trai.rs
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
use super::{util::{parse_list, parse_list_nosep}, Function, FunctionHeader, Ident, Keyword, Node, Parsable, Symbol, Type};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Trait {
|
||||||
|
pub name: Node<Ident>,
|
||||||
|
pub fns: Vec<Node<FunctionHeader>>
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Impl {
|
||||||
|
pub trait_: Node<Type>,
|
||||||
|
pub for_: Node<Type>,
|
||||||
|
pub fns: Vec<Node<Function>>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parsable for Trait {
|
||||||
|
fn parse(cursor: &mut super::TokenCursor, errors: &mut super::ParserOutput) -> super::ParseResult<Self> {
|
||||||
|
cursor.expect_kw(Keyword::Trait)?;
|
||||||
|
let name = Node::parse(cursor, errors)?;
|
||||||
|
cursor.expect_sym(Symbol::OpenCurly)?;
|
||||||
|
let fns = parse_list(cursor, errors, Symbol::CloseCurly)?;
|
||||||
|
super::ParseResult::Ok(Self {name, fns})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parsable for Impl {
|
||||||
|
fn parse(cursor: &mut super::TokenCursor, errors: &mut super::ParserOutput) -> super::ParseResult<Self> {
|
||||||
|
cursor.expect_kw(Keyword::Impl)?;
|
||||||
|
let trait_ = Node::parse(cursor, errors)?;
|
||||||
|
cursor.expect_kw(Keyword::For)?;
|
||||||
|
let for_ = Node::parse(cursor, errors)?;
|
||||||
|
cursor.expect_sym(Symbol::OpenCurly)?;
|
||||||
|
let fns = parse_list_nosep(cursor, errors, Symbol::CloseCurly)?;
|
||||||
|
super::ParseResult::Ok(Self {trait_, for_, fns})
|
||||||
|
}
|
||||||
|
}
|
||||||
61
src/parser/v3/nodes/ty.rs
Normal file
61
src/parser/v3/nodes/ty.rs
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
use super::{util::parse_list, Node, Parsable, ParseResult, ParserMsg, Symbol, Token};
|
||||||
|
|
||||||
|
pub struct Type {
|
||||||
|
pub name: String,
|
||||||
|
pub args: Vec<Node<Type>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Type {
|
||||||
|
pub fn unit() -> Self {
|
||||||
|
Self {
|
||||||
|
name: "()".to_string(),
|
||||||
|
args: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parsable for Type {
|
||||||
|
fn parse(
|
||||||
|
cursor: &mut super::TokenCursor,
|
||||||
|
errors: &mut super::ParserOutput,
|
||||||
|
) -> ParseResult<Self> {
|
||||||
|
let next = cursor.expect_peek()?;
|
||||||
|
let res = if next.is_symbol(Symbol::Ampersand) {
|
||||||
|
cursor.next();
|
||||||
|
let arg = Node::parse(cursor, errors)?;
|
||||||
|
Self {
|
||||||
|
name: "&".to_string(),
|
||||||
|
args: vec![arg],
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let Token::Word(name) = &next.token else {
|
||||||
|
return ParseResult::Err(ParserMsg::unexpected_token(next, "a type identifier"));
|
||||||
|
};
|
||||||
|
let n = name.to_string();
|
||||||
|
cursor.next();
|
||||||
|
let mut args = Vec::new();
|
||||||
|
if let Some(next) = cursor.peek() {
|
||||||
|
if next.is_symbol(Symbol::OpenAngle) {
|
||||||
|
cursor.next();
|
||||||
|
args = parse_list(cursor, errors, Symbol::CloseAngle)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Self { name: n, args }
|
||||||
|
};
|
||||||
|
ParseResult::Ok(res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for Type {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{}", self.name)?;
|
||||||
|
if self.name == "&" {
|
||||||
|
write!(f, "{:?}", self.args[0])?;
|
||||||
|
} else if !self.args.is_empty() {
|
||||||
|
write!(f, "<{:?}>", self.args)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
57
src/parser/v3/nodes/util.rs
Normal file
57
src/parser/v3/nodes/util.rs
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
use super::{Node, Parsable, ParserMsg, ParserOutput, Symbol, TokenCursor};
|
||||||
|
|
||||||
|
pub fn parse_list_sep<T: Parsable>(
|
||||||
|
cursor: &mut TokenCursor,
|
||||||
|
errors: &mut ParserOutput,
|
||||||
|
sep: Symbol,
|
||||||
|
end: Symbol,
|
||||||
|
) -> Result<Vec<Node<T>>, ParserMsg> {
|
||||||
|
let mut vals = Vec::new();
|
||||||
|
loop {
|
||||||
|
let next = cursor.expect_peek()?;
|
||||||
|
if next.is_symbol(end) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let res = Node::parse(cursor, errors);
|
||||||
|
vals.push(res.node);
|
||||||
|
if res.recover {
|
||||||
|
cursor.seek_syms(&[end, sep]);
|
||||||
|
}
|
||||||
|
let next = cursor.expect_peek()?;
|
||||||
|
if !next.is_symbol(sep) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cursor.next();
|
||||||
|
}
|
||||||
|
cursor.expect_sym(end)?;
|
||||||
|
Ok(vals)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_list<T: Parsable>(
|
||||||
|
cursor: &mut TokenCursor,
|
||||||
|
errors: &mut ParserOutput,
|
||||||
|
end: Symbol,
|
||||||
|
) -> Result<Vec<Node<T>>, ParserMsg> {
|
||||||
|
parse_list_sep(cursor, errors, Symbol::Comma, end)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_list_nosep<T: Parsable>(
|
||||||
|
cursor: &mut TokenCursor,
|
||||||
|
errors: &mut ParserOutput,
|
||||||
|
end: Symbol,
|
||||||
|
) -> Result<Vec<Node<T>>, ParserMsg> {
|
||||||
|
let mut vals = Vec::new();
|
||||||
|
loop {
|
||||||
|
let next = cursor.expect_peek()?;
|
||||||
|
if next.is_symbol(end) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let res = Node::parse(cursor, errors);
|
||||||
|
vals.push(res.node);
|
||||||
|
if res.recover {
|
||||||
|
cursor.seek_sym(end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cursor.expect_sym(end)?;
|
||||||
|
Ok(vals)
|
||||||
|
}
|
||||||
@@ -3,12 +3,14 @@ use std::{
|
|||||||
ops::{ControlFlow, FromResidual, Try},
|
ops::{ControlFlow, FromResidual, Try},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{Node, ParserError, ParserErrors, TokenCursor};
|
use crate::ir::FilePos;
|
||||||
|
|
||||||
|
use super::{Node, ParserMsg, ParserOutput, TokenCursor};
|
||||||
|
|
||||||
pub enum ParseResult<T> {
|
pub enum ParseResult<T> {
|
||||||
Ok(T),
|
Ok(T),
|
||||||
Recover(T),
|
Recover(T),
|
||||||
Err(ParserError),
|
Err(ParserMsg),
|
||||||
SubErr,
|
SubErr,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -23,18 +25,15 @@ impl<T> ParseResult<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Try for ParseResult<T> {
|
impl<T> Try for ParseResult<T> {
|
||||||
type Output = Result<T, T>;
|
type Output = T;
|
||||||
type Residual = Option<ParserError>;
|
type Residual = Option<ParserMsg>;
|
||||||
fn from_output(output: Self::Output) -> Self {
|
fn from_output(output: Self::Output) -> Self {
|
||||||
match output {
|
Self::Ok(output)
|
||||||
Ok(v) => Self::Ok(v),
|
|
||||||
Err(v) => Self::Recover(v),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {
|
fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {
|
||||||
match self {
|
match self {
|
||||||
ParseResult::Ok(v) => ControlFlow::Continue(Ok(v)),
|
ParseResult::Ok(v) => ControlFlow::Continue(v),
|
||||||
ParseResult::Recover(v) => ControlFlow::Continue(Err(v)),
|
ParseResult::Recover(v) => ControlFlow::Break(None),
|
||||||
ParseResult::Err(e) => ControlFlow::Break(Some(e)),
|
ParseResult::Err(e) => ControlFlow::Break(Some(e)),
|
||||||
ParseResult::SubErr => ControlFlow::Break(None),
|
ParseResult::SubErr => ControlFlow::Break(None),
|
||||||
}
|
}
|
||||||
@@ -50,8 +49,8 @@ impl<T> FromResidual for ParseResult<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> FromResidual<Result<Infallible, ParserError>> for ParseResult<T> {
|
impl<T> FromResidual<Result<Infallible, ParserMsg>> for ParseResult<T> {
|
||||||
fn from_residual(residual: Result<Infallible, ParserError>) -> Self {
|
fn from_residual(residual: Result<Infallible, ParserMsg>) -> Self {
|
||||||
match residual {
|
match residual {
|
||||||
Err(e) => Self::Err(e),
|
Err(e) => Self::Err(e),
|
||||||
}
|
}
|
||||||
@@ -112,24 +111,24 @@ impl<T> FromResidual for NodeParseResult<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait Parsable: Sized {
|
pub trait Parsable: Sized {
|
||||||
fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> ParseResult<Self>;
|
fn parse(cursor: &mut TokenCursor, output: &mut ParserOutput) -> ParseResult<Self>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait MaybeParsable: Sized {
|
pub trait MaybeParsable: Sized {
|
||||||
fn maybe_parse(
|
fn maybe_parse(
|
||||||
cursor: &mut TokenCursor,
|
cursor: &mut TokenCursor,
|
||||||
errors: &mut ParserErrors,
|
errors: &mut ParserOutput,
|
||||||
) -> Result<Option<Self>, ParserError>;
|
) -> Result<Option<Self>, ParserMsg>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Parsable> Node<T> {
|
impl<T: Parsable> Node<T> {
|
||||||
pub fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> NodeParseResult<T> {
|
pub fn parse(cursor: &mut TokenCursor, output: &mut ParserOutput) -> NodeParseResult<T> {
|
||||||
let start = cursor.next_pos();
|
let start = cursor.peek().map(|t| t.span.start).unwrap_or(FilePos::start());
|
||||||
let (inner, recover) = match T::parse(cursor, errors) {
|
let (inner, recover) = match T::parse(cursor, output) {
|
||||||
ParseResult::Ok(v) => (Some(v), false),
|
ParseResult::Ok(v) => (Some(v), false),
|
||||||
ParseResult::Recover(v) => (Some(v), true),
|
ParseResult::Recover(v) => (Some(v), true),
|
||||||
ParseResult::Err(e) => {
|
ParseResult::Err(e) => {
|
||||||
errors.add(e);
|
output.err(e);
|
||||||
(None, true)
|
(None, true)
|
||||||
}
|
}
|
||||||
ParseResult::SubErr => (None, true),
|
ParseResult::SubErr => (None, true),
|
||||||
@@ -146,12 +145,12 @@ impl<T: Parsable> Node<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<T: MaybeParsable> Node<T> {
|
impl<T: MaybeParsable> Node<T> {
|
||||||
pub fn maybe_parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> Option<Self> {
|
pub fn maybe_parse(cursor: &mut TokenCursor, errors: &mut ParserOutput) -> Option<Self> {
|
||||||
let start = cursor.next_pos();
|
let start = cursor.next_pos();
|
||||||
let inner = match T::maybe_parse(cursor, errors) {
|
let inner = match T::maybe_parse(cursor, errors) {
|
||||||
Ok(v) => Some(v?),
|
Ok(v) => Some(v?),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
errors.add(e);
|
errors.err(e);
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -164,12 +163,12 @@ impl<T: MaybeParsable> Node<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait NodeParsable {
|
pub trait NodeParsable {
|
||||||
fn parse_node(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> NodeParseResult<Self>
|
fn parse_node(cursor: &mut TokenCursor, errors: &mut ParserOutput) -> NodeParseResult<Self>
|
||||||
where
|
where
|
||||||
Self: Sized;
|
Self: Sized;
|
||||||
}
|
}
|
||||||
impl<T: Parsable> NodeParsable for T {
|
impl<T: Parsable> NodeParsable for T {
|
||||||
fn parse_node(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> NodeParseResult<Self>
|
fn parse_node(cursor: &mut TokenCursor, errors: &mut ParserOutput) -> NodeParseResult<Self>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use std::{iter::Peekable, str::Chars};
|
use std::{iter::Peekable, str::Chars};
|
||||||
|
|
||||||
use super::super::ParserError;
|
use crate::ir::FilePos;
|
||||||
use super::FilePos;
|
use super::super::ParserMsg;
|
||||||
|
|
||||||
pub struct CharCursor<'a> {
|
pub struct CharCursor<'a> {
|
||||||
chars: Peekable<Chars<'a>>,
|
chars: Peekable<Chars<'a>>,
|
||||||
@@ -15,12 +15,12 @@ impl CharCursor<'_> {
|
|||||||
self.advance();
|
self.advance();
|
||||||
Some(res)
|
Some(res)
|
||||||
}
|
}
|
||||||
pub fn expect(&mut self, c: char) -> Result<(), ParserError> {
|
pub fn expect(&mut self, c: char) -> Result<(), ParserMsg> {
|
||||||
let next = self.expect_next()?;
|
let next = self.expect_next()?;
|
||||||
if next == c {
|
if next == c {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(ParserError::at(
|
Err(ParserMsg::at(
|
||||||
self.prev_pos,
|
self.prev_pos,
|
||||||
format!("unexpected char '{next}'; expected '{c}'"),
|
format!("unexpected char '{next}'; expected '{c}'"),
|
||||||
))
|
))
|
||||||
@@ -46,8 +46,8 @@ impl CharCursor<'_> {
|
|||||||
self.next_pos.col += 1;
|
self.next_pos.col += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn expect_next(&mut self) -> Result<char, ParserError> {
|
pub fn expect_next(&mut self) -> Result<char, ParserMsg> {
|
||||||
self.next().ok_or(ParserError::unexpected_end())
|
self.next().ok_or(ParserMsg::unexpected_end())
|
||||||
}
|
}
|
||||||
pub fn next_pos(&self) -> FilePos {
|
pub fn next_pos(&self) -> FilePos {
|
||||||
self.next_pos
|
self.next_pos
|
||||||
|
|||||||
@@ -4,15 +4,25 @@ pub enum Keyword {
|
|||||||
Let,
|
Let,
|
||||||
If,
|
If,
|
||||||
Return,
|
Return,
|
||||||
|
Struct,
|
||||||
|
Trait,
|
||||||
|
Impl,
|
||||||
|
For,
|
||||||
|
Asm,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Keyword {
|
impl Keyword {
|
||||||
pub fn from_string(str: &str) -> Option<Self> {
|
pub fn from_string(str: &str) -> Option<Self> {
|
||||||
Some(match str {
|
Some(match str {
|
||||||
"fn" => Self::Fn,
|
"fn" => Self::Fn,
|
||||||
|
"struct" => Self::Struct,
|
||||||
"let" => Self::Let,
|
"let" => Self::Let,
|
||||||
"if" => Self::If,
|
"if" => Self::If,
|
||||||
|
"for" => Self::For,
|
||||||
"return" => Self::Return,
|
"return" => Self::Return,
|
||||||
|
"trait" => Self::Trait,
|
||||||
|
"impl" => Self::Impl,
|
||||||
|
"asm" => Self::Asm,
|
||||||
_ => return None,
|
_ => return None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
mod cursor;
|
mod cursor;
|
||||||
mod file;
|
|
||||||
mod keyword;
|
mod keyword;
|
||||||
mod symbol;
|
mod symbol;
|
||||||
|
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
pub use cursor::*;
|
pub use cursor::*;
|
||||||
pub use file::*;
|
|
||||||
pub use keyword::*;
|
pub use keyword::*;
|
||||||
pub use symbol::*;
|
pub use symbol::*;
|
||||||
|
|
||||||
|
use crate::ir::FileSpan;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
pub enum Token {
|
pub enum Token {
|
||||||
Symbol(Symbol),
|
Symbol(Symbol),
|
||||||
Ident(String),
|
Word(String),
|
||||||
Keyword(Keyword),
|
Keyword(Keyword),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ impl TokenInstance {
|
|||||||
let token = if let Some(keyword) = Keyword::from_string(&word) {
|
let token = if let Some(keyword) = Keyword::from_string(&word) {
|
||||||
Token::Keyword(keyword)
|
Token::Keyword(keyword)
|
||||||
} else {
|
} else {
|
||||||
Token::Ident(word)
|
Token::Word(word)
|
||||||
};
|
};
|
||||||
Some(Self {
|
Some(Self {
|
||||||
token,
|
token,
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ pub enum Symbol {
|
|||||||
Slash,
|
Slash,
|
||||||
DoubleSlash,
|
DoubleSlash,
|
||||||
Dot,
|
Dot,
|
||||||
|
DoubleDot,
|
||||||
OpenParen,
|
OpenParen,
|
||||||
CloseParen,
|
CloseParen,
|
||||||
OpenCurly,
|
OpenCurly,
|
||||||
@@ -100,6 +101,10 @@ impl Symbol {
|
|||||||
'&' => Self::DoublePipe,
|
'&' => Self::DoublePipe,
|
||||||
_ => return,
|
_ => return,
|
||||||
},
|
},
|
||||||
|
Self::Dot => match next {
|
||||||
|
'.' => Self::DoubleDot,
|
||||||
|
_ => return,
|
||||||
|
}
|
||||||
_ => return,
|
_ => return,
|
||||||
};
|
};
|
||||||
cursor.advance();
|
cursor.advance();
|
||||||
@@ -119,6 +124,7 @@ impl Symbol {
|
|||||||
Self::Slash => "/",
|
Self::Slash => "/",
|
||||||
Self::DoubleSlash => "//",
|
Self::DoubleSlash => "//",
|
||||||
Self::Dot => ".",
|
Self::Dot => ".",
|
||||||
|
Self::DoubleDot => "..",
|
||||||
Self::OpenParen => "(",
|
Self::OpenParen => "(",
|
||||||
Self::CloseParen => ")",
|
Self::CloseParen => ")",
|
||||||
Self::OpenCurly => "{",
|
Self::OpenCurly => "{",
|
||||||
|
|||||||
Reference in New Issue
Block a user