work
This commit is contained in:
276
src/ir/mod.rs
276
src/ir/mod.rs
@@ -1,11 +1,20 @@
|
|||||||
use std::collections::HashMap;
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
|
ops::{Deref, DerefMut},
|
||||||
|
};
|
||||||
|
|
||||||
use crate::parser::{Body, Expr, Function, Ident, Literal, ParserError, Statement, Unresolved};
|
use crate::parser::{
|
||||||
|
Body, Expr, FileSpan, Function, Ident, Literal, Module, ParserError, ParserErrors, Statement,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum IRInstruction {
|
pub enum IRInstruction {
|
||||||
Li(IRIdent, Literal),
|
Li(Var, Literal),
|
||||||
Mv(IRIdent, IRIdent),
|
Mv(Var, Var),
|
||||||
|
Not(Var, Var),
|
||||||
|
Noti(Var, Literal),
|
||||||
|
La(Var, IRIdent),
|
||||||
|
Call(FnIdent, Vec<Var>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -13,116 +22,257 @@ pub struct IRFunction {
|
|||||||
instructions: Vec<IRInstruction>,
|
instructions: Vec<IRInstruction>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Function<Unresolved> {
|
impl Module {
|
||||||
pub fn lower(&self, functions: &mut Vec<IRFunction>, map: &mut Namespace) -> Result<(), ParserError> {
|
pub fn lower(&self, map: &mut Namespace, errors: &mut ParserErrors) {
|
||||||
let Ok(name) = &self.name.inner else {
|
for f in &self.functions {
|
||||||
return Ok(());
|
if let Some(f) = f.as_ref() {
|
||||||
};
|
f.lower(map, errors);
|
||||||
if map.get(name).is_some() {
|
}
|
||||||
Err(ParserError {
|
|
||||||
msg: format!("Already something named '{:?}'", self.name),
|
|
||||||
spans: vec![self.name.span],
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
map.add(name);
|
|
||||||
let mut instructions = Vec::new();
|
|
||||||
self.body.as_ref().map(|b| b.lower(map, &mut instructions));
|
|
||||||
functions.push(IRFunction { instructions });
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Body<Unresolved> {
|
impl Function {
|
||||||
pub fn lower(&self, map: &Namespace, instructions: &mut Vec<IRInstruction>) {
|
pub fn lower(&self, map: &mut Namespace, errors: &mut ParserErrors) {
|
||||||
let mut map = map.clone();
|
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 {
|
for statement in &self.statements {
|
||||||
let Ok(statement) = &statement.inner else {
|
let Some(statement) = statement.as_ref() else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
match statement {
|
match statement {
|
||||||
Statement::Let(name, expr) => {
|
Statement::Let(name_node, expr) => {
|
||||||
let Ok(name) = &name.inner else {
|
let Some(name) = name_node.as_ref() else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
let name = map.add(name);
|
let Some(expr) = expr.as_ref() else {
|
||||||
let Ok(expr) = &expr.inner else {
|
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
if let Ok(Some(res)) = expr.lower(&map, instructions) {
|
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 {
|
instructions.push(match res {
|
||||||
ExprResult::Lit(l) => IRInstruction::Li(name, l),
|
ExprResult::Lit(l) => IRInstruction::Li(name, l),
|
||||||
ExprResult::Ident(i) => IRInstruction::Mv(name, i),
|
ExprResult::Var(i) => IRInstruction::Mv(name, i),
|
||||||
|
ExprResult::Fn(f) => todo!(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Statement::Return(e) => todo!(),
|
Statement::Return(e) => todo!(),
|
||||||
Statement::Expr(expr) => todo!(),
|
Statement::Expr(expr) => {
|
||||||
|
expr.as_ref().map(|e| e.lower(&mut map, instructions, errors));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Expr<Unresolved> {
|
impl Expr {
|
||||||
pub fn lower(
|
pub fn lower(
|
||||||
&self,
|
&self,
|
||||||
map: &Namespace,
|
map: &mut Namespace,
|
||||||
instructions: &mut Vec<IRInstruction>,
|
instructions: &mut Vec<IRInstruction>,
|
||||||
) -> Result<Option<ExprResult>, String> {
|
errors: &mut ParserErrors,
|
||||||
Ok(match self {
|
) -> Option<ExprResult> {
|
||||||
Expr::Lit(l) => {
|
match self {
|
||||||
let Ok(l) = &l.inner else {return Ok(None)};
|
Expr::Lit(l) => Some(ExprResult::Lit(l.as_ref()?.clone())),
|
||||||
Some(ExprResult::Lit(l.clone()))
|
|
||||||
},
|
|
||||||
Expr::Ident(i) => {
|
Expr::Ident(i) => {
|
||||||
let Ok(i) = &i.inner else {return Ok(None)};
|
let Some(id) = map.get(i.as_ref()?) else {
|
||||||
let Some(id) = map.get(i) else {
|
errors.add(ParserError::identifier_not_found(i));
|
||||||
return Err(format!("Identifier '{:?}' not found", i));
|
return None;
|
||||||
};
|
};
|
||||||
Some(ExprResult::Ident(id))
|
match id.ty() {
|
||||||
|
IdentTypeMatch::Var(var) => Some(ExprResult::Var(var)),
|
||||||
|
IdentTypeMatch::Fn(f) => Some(ExprResult::Fn(f)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Expr::BinaryOp(_, _, _) => todo!(),
|
Expr::BinaryOp(_, _, _) => todo!(),
|
||||||
Expr::UnaryOp(_, _) => 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::Block(_) => todo!(),
|
||||||
Expr::Call(_, _) => todo!(),
|
Expr::Call(e, args) => {
|
||||||
Expr::Group(_) => todo!(),
|
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),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ExprResult {
|
pub enum ExprResult {
|
||||||
Lit(Literal),
|
Lit(Literal),
|
||||||
Ident(IRIdent),
|
Var(Var),
|
||||||
|
Fn(FnIdent),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug)]
|
||||||
pub struct Namespace {
|
pub struct Namespace {
|
||||||
pub cur: usize,
|
pub fns: Vec<Option<IRFunction>>,
|
||||||
pub map: HashMap<String, IRIdent>,
|
pub vars: usize,
|
||||||
|
pub stack: Vec<HashMap<String, IRIdent>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Namespace {
|
impl Namespace {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
cur: 0,
|
fns: Vec::new(),
|
||||||
map: HashMap::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> {
|
pub fn get(&self, name: &Ident) -> Option<IRIdent> {
|
||||||
self.map.get(name.val()).copied()
|
for map in self.stack.iter().rev() {
|
||||||
|
let res = map.get(name.val());
|
||||||
|
if res.is_some() {
|
||||||
|
return res.copied();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
}
|
}
|
||||||
pub fn reserve(&mut self) -> IRIdent {
|
pub fn reserve_var(&mut self, origin: FileSpan) -> Var {
|
||||||
let id = IRIdent ( self.cur );
|
let i = self.vars;
|
||||||
self.cur += 1;
|
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
|
id
|
||||||
}
|
}
|
||||||
pub fn add(&mut self, name: &Ident) -> IRIdent {
|
fn insert(&mut self, name: &Ident, id: IRIdent) {
|
||||||
let id = self.reserve();
|
let last = self.stack.len() - 1;
|
||||||
self.map.insert(name.val().to_string(), id);
|
self.stack[last].insert(name.val().to_string(), id);
|
||||||
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)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct IRIdent (usize);
|
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)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,6 +7,13 @@ mod ir;
|
|||||||
mod parser;
|
mod parser;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
parser::main();
|
let arg = std::env::args_os().nth(1);
|
||||||
|
if let Some(path) = arg {
|
||||||
|
let file = std::fs::read_to_string(path).expect("failed to read file");
|
||||||
|
println!("{file}");
|
||||||
|
parser::parse_file(&file);
|
||||||
|
} else {
|
||||||
|
parser::run_stdin();
|
||||||
|
}
|
||||||
// compiler::main();
|
// compiler::main();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,5 @@
|
|||||||
mod v1;
|
mod v1;
|
||||||
mod v2;
|
mod v2;
|
||||||
|
mod v3;
|
||||||
|
|
||||||
pub use v1::*;
|
pub use v3::*;
|
||||||
|
|
||||||
pub fn main() {
|
|
||||||
let arg = std::env::args_os().nth(1);
|
|
||||||
if let Some(path) = arg {
|
|
||||||
let file = std::fs::read_to_string(path).expect("failed to read file");
|
|
||||||
println!("{file}");
|
|
||||||
v1::parse_file(&file);
|
|
||||||
// v2::parse_file(&file);
|
|
||||||
} else {
|
|
||||||
v1::run_stdin();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
91
src/parser/v3/cursor.rs
Normal file
91
src/parser/v3/cursor.rs
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
use super::error::ParserError;
|
||||||
|
use super::token::{CharCursor, Keyword, Symbol, Token, TokenInstance};
|
||||||
|
use super::FilePos;
|
||||||
|
|
||||||
|
pub struct TokenCursor<'a> {
|
||||||
|
cursor: CharCursor<'a>,
|
||||||
|
next: Option<TokenInstance>,
|
||||||
|
next_pos: FilePos,
|
||||||
|
prev_end: FilePos,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> TokenCursor<'a> {
|
||||||
|
pub fn next(&mut self) -> Option<TokenInstance> {
|
||||||
|
self.prev_end = self.cursor.prev_pos();
|
||||||
|
self.next_pos = self.cursor.next_pos();
|
||||||
|
std::mem::replace(&mut self.next, TokenInstance::parse(&mut self.cursor))
|
||||||
|
}
|
||||||
|
pub fn expect_next(&mut self) -> Result<TokenInstance, ParserError> {
|
||||||
|
self.peek().ok_or(ParserError::unexpected_end())?;
|
||||||
|
Ok(self.next().unwrap())
|
||||||
|
}
|
||||||
|
pub fn expect_token(&mut self, t: Token) -> Result<(), ParserError> {
|
||||||
|
let next = self.expect_next()?;
|
||||||
|
if t == next.token {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(ParserError::unexpected_token(&next, &format!("{t:?}")))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn expect_sym(&mut self, symbol: Symbol) -> Result<(), ParserError> {
|
||||||
|
self.expect_token(Token::Symbol(symbol))
|
||||||
|
}
|
||||||
|
pub fn seek_sym(&mut self, symbol: Symbol) {
|
||||||
|
while self
|
||||||
|
.next()
|
||||||
|
.is_some_and(|n| n.token != Token::Symbol(symbol))
|
||||||
|
{}
|
||||||
|
}
|
||||||
|
pub fn seek_syms(&mut self, syms: &[Symbol]) {
|
||||||
|
while self
|
||||||
|
.peek()
|
||||||
|
.is_some_and(|n| !syms.iter().any(|s| n.is_symbol(*s)))
|
||||||
|
{
|
||||||
|
self.next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn seek(&mut self, f: impl Fn(&TokenInstance) -> bool) -> Option<&TokenInstance> {
|
||||||
|
loop {
|
||||||
|
if f(self.peek()?) {
|
||||||
|
return self.peek();
|
||||||
|
}
|
||||||
|
self.next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn expect_kw(&mut self, kw: Keyword) -> Result<(), ParserError> {
|
||||||
|
self.expect_token(Token::Keyword(kw))
|
||||||
|
}
|
||||||
|
pub fn peek(&self) -> Option<&TokenInstance> {
|
||||||
|
self.next.as_ref()
|
||||||
|
}
|
||||||
|
pub fn expect_peek(&mut self) -> Result<&TokenInstance, ParserError> {
|
||||||
|
self.peek().ok_or(ParserError::unexpected_end())
|
||||||
|
}
|
||||||
|
pub fn chars(&mut self) -> &mut CharCursor<'a> {
|
||||||
|
&mut self.cursor
|
||||||
|
}
|
||||||
|
pub fn prev_end(&self) -> FilePos {
|
||||||
|
self.prev_end
|
||||||
|
}
|
||||||
|
pub fn next_pos(&self) -> FilePos {
|
||||||
|
self.next_pos
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a str> for TokenCursor<'a> {
|
||||||
|
fn from(string: &'a str) -> Self {
|
||||||
|
Self::from(CharCursor::from(string))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<CharCursor<'a>> for TokenCursor<'a> {
|
||||||
|
fn from(mut cursor: CharCursor<'a>) -> Self {
|
||||||
|
let cur = TokenInstance::parse(&mut cursor);
|
||||||
|
Self {
|
||||||
|
cursor,
|
||||||
|
next: cur,
|
||||||
|
next_pos: FilePos::start(),
|
||||||
|
prev_end: FilePos::start(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
74
src/parser/v3/error.rs
Normal file
74
src/parser/v3/error.rs
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
use super::{
|
||||||
|
token::{FileSpan, TokenInstance},
|
||||||
|
FilePos, Ident, Node,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct ParserError {
|
||||||
|
pub msg: String,
|
||||||
|
pub spans: Vec<FileSpan>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ParserErrors {
|
||||||
|
pub errs: Vec<ParserError>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ParserError {
|
||||||
|
pub fn from_instances(instances: &[&TokenInstance], msg: String) -> Self {
|
||||||
|
ParserError {
|
||||||
|
msg,
|
||||||
|
spans: instances.iter().map(|i| i.span).collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn from_msg(msg: String) -> Self {
|
||||||
|
Self {
|
||||||
|
msg,
|
||||||
|
spans: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn from_span(span: FileSpan, msg: String) -> Self {
|
||||||
|
Self {
|
||||||
|
msg,
|
||||||
|
spans: vec![span],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn identifier_not_found(id: &Node<Ident>) -> Self {
|
||||||
|
Self {
|
||||||
|
msg: format!("Identifier '{}' not found", id.as_ref().unwrap().val()),
|
||||||
|
spans: vec![id.span],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn at(pos: FilePos, msg: String) -> Self {
|
||||||
|
Self {
|
||||||
|
msg,
|
||||||
|
spans: vec![FileSpan::at(pos)],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn unexpected_end() -> Self {
|
||||||
|
Self::from_msg("unexpected end of input".to_string())
|
||||||
|
}
|
||||||
|
pub fn unexpected_token(inst: &TokenInstance, expected: &str) -> Self {
|
||||||
|
let t = &inst.token;
|
||||||
|
ParserError::from_instances(
|
||||||
|
&[inst],
|
||||||
|
format!("unexpected token {t:?}; expected {expected}"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
pub fn write_for(&self, writer: &mut impl std::io::Write, file: &str) -> std::io::Result<()> {
|
||||||
|
let after = if self.spans.is_empty() { "" } else { ":" };
|
||||||
|
writeln!(writer, "error: {}{}", self.msg, after)?;
|
||||||
|
for span in &self.spans {
|
||||||
|
span.write_for(writer, file)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ParserErrors {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self { errs: Vec::new() }
|
||||||
|
}
|
||||||
|
pub fn add(&mut self, err: ParserError) {
|
||||||
|
self.errs.push(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
51
src/parser/v3/mod.rs
Normal file
51
src/parser/v3/mod.rs
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
use std::io::{stdout, BufRead, BufReader};
|
||||||
|
|
||||||
|
mod cursor;
|
||||||
|
mod error;
|
||||||
|
mod node;
|
||||||
|
mod nodes;
|
||||||
|
mod parse;
|
||||||
|
mod token;
|
||||||
|
|
||||||
|
pub use cursor::*;
|
||||||
|
pub use error::*;
|
||||||
|
pub use node::*;
|
||||||
|
pub use nodes::*;
|
||||||
|
pub use parse::*;
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
49
src/parser/v3/node.rs
Normal file
49
src/parser/v3/node.rs
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
use std::{
|
||||||
|
fmt::Debug,
|
||||||
|
ops::{Deref, DerefMut},
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::FileSpan;
|
||||||
|
|
||||||
|
pub struct Node<T> {
|
||||||
|
pub inner: Option<T>,
|
||||||
|
pub span: FileSpan,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Node<T> {
|
||||||
|
pub fn new(inner: T, span: FileSpan) -> Self {
|
||||||
|
Self {
|
||||||
|
inner: Some(inner),
|
||||||
|
span,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn bx(self) -> Node<Box<T>> {
|
||||||
|
Node {
|
||||||
|
inner: self.inner.map(|v| Box::new(v)),
|
||||||
|
span: self.span,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Deref for Node<T> {
|
||||||
|
type Target = Option<T>;
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.inner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> DerefMut for Node<T> {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.inner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Debug> Debug for Node<T> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match &self.inner {
|
||||||
|
Some(v) => v.fmt(f),
|
||||||
|
None => f.write_str("{error}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
73
src/parser/v3/nodes/body.rs
Normal file
73
src/parser/v3/nodes/body.rs
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
use std::fmt::{Debug, Write};
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
token::Symbol, Node, NodeParsable, Parsable, ParseResult, ParserError,
|
||||||
|
ParserErrors, Statement, TokenCursor,
|
||||||
|
};
|
||||||
|
use crate::util::Padder;
|
||||||
|
|
||||||
|
pub struct Body {
|
||||||
|
pub statements: Vec<Node<Statement>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parsable for Body {
|
||||||
|
fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> ParseResult<Self> {
|
||||||
|
let mut statements = Vec::new();
|
||||||
|
cursor.expect_sym(Symbol::OpenCurly)?;
|
||||||
|
if cursor.expect_peek()?.is_symbol(Symbol::CloseCurly) {
|
||||||
|
cursor.next();
|
||||||
|
return ParseResult::Ok(Self { statements });
|
||||||
|
}
|
||||||
|
let mut expect_semi = false;
|
||||||
|
let mut recover = false;
|
||||||
|
loop {
|
||||||
|
let Some(next) = cursor.peek() else {
|
||||||
|
recover = true;
|
||||||
|
errors.add(ParserError::unexpected_end());
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
if next.is_symbol(Symbol::CloseCurly) {
|
||||||
|
cursor.next();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if next.is_symbol(Symbol::Semicolon) {
|
||||||
|
cursor.next();
|
||||||
|
expect_semi = false;
|
||||||
|
continue;
|
||||||
|
} else if expect_semi {
|
||||||
|
errors.add(ParserError {
|
||||||
|
msg: "expected ';'".to_string(),
|
||||||
|
spans: vec![cursor.next_pos().char_span()],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
let res = Statement::parse_node(cursor, errors);
|
||||||
|
statements.push(res.node);
|
||||||
|
expect_semi = true;
|
||||||
|
if res.recover {
|
||||||
|
cursor.seek_syms(&[Symbol::Semicolon, Symbol::CloseCurly]);
|
||||||
|
if cursor.peek().is_none() {
|
||||||
|
recover = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ParseResult::from_recover(Self { statements }, recover)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for Body {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
if self.statements.first().is_some() {
|
||||||
|
f.write_str("{\n ")?;
|
||||||
|
let mut padder = Padder::new(f);
|
||||||
|
for s in &self.statements {
|
||||||
|
// they don't expose wrap_buf :grief:
|
||||||
|
padder.write_str(&format!("{s:?}\n"))?;
|
||||||
|
}
|
||||||
|
f.write_char('}')?;
|
||||||
|
} else {
|
||||||
|
f.write_str("{}")?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
156
src/parser/v3/nodes/expr.rs
Normal file
156
src/parser/v3/nodes/expr.rs
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
use std::fmt::{Debug, Write};
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
BinaryOperator, Body, Ident, Literal, Node, NodeParsable, Parsable, ParseResult, ParserError,
|
||||||
|
ParserErrors, Symbol, TokenCursor, UnaryOperator,
|
||||||
|
};
|
||||||
|
|
||||||
|
type BoxNode = Node<Box<Expr>>;
|
||||||
|
|
||||||
|
pub enum Expr {
|
||||||
|
Lit(Node<Literal>),
|
||||||
|
Ident(Node<Ident>),
|
||||||
|
BinaryOp(BinaryOperator, BoxNode, BoxNode),
|
||||||
|
UnaryOp(UnaryOperator, BoxNode),
|
||||||
|
Block(Node<Body>),
|
||||||
|
Call(BoxNode, Vec<Node<Expr>>),
|
||||||
|
Group(BoxNode),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parsable for Expr {
|
||||||
|
fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> ParseResult<Self> {
|
||||||
|
let start = cursor.next_pos();
|
||||||
|
let next = cursor.expect_peek()?;
|
||||||
|
let mut e1 = if next.is_symbol(Symbol::OpenParen) {
|
||||||
|
cursor.next();
|
||||||
|
if cursor.expect_peek()?.is_symbol(Symbol::CloseParen) {
|
||||||
|
cursor.next();
|
||||||
|
return ParseResult::Ok(Expr::Lit(Node::new(
|
||||||
|
Literal::Unit,
|
||||||
|
cursor.next_pos().char_span(),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
let res = Node::parse(cursor, errors);
|
||||||
|
if res.recover {
|
||||||
|
cursor.seek_sym(Symbol::CloseParen);
|
||||||
|
}
|
||||||
|
cursor.expect_sym(Symbol::CloseParen)?;
|
||||||
|
Self::Group(res.node.bx())
|
||||||
|
} else if next.is_symbol(Symbol::OpenCurly) {
|
||||||
|
Self::Block(Body::parse_node(cursor, errors)?)
|
||||||
|
} else if let Some(op) = UnaryOperator::from_token(next) {
|
||||||
|
cursor.next();
|
||||||
|
return Node::parse(cursor, errors).map(|n| {
|
||||||
|
let n = n.bx();
|
||||||
|
if let Some(box Self::BinaryOp(op2, n1, n2)) = n.inner {
|
||||||
|
let span = start.to(n1.span.end);
|
||||||
|
Self::BinaryOp(op2, Node::new(Self::UnaryOp(op, n1), span).bx(), n2)
|
||||||
|
} else {
|
||||||
|
Self::UnaryOp(op, n)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if let Some(val) = Node::maybe_parse(cursor, errors) {
|
||||||
|
Self::Lit(val)
|
||||||
|
} else {
|
||||||
|
let res = Node::parse(cursor, &mut ParserErrors::new());
|
||||||
|
if res.node.is_some() {
|
||||||
|
Self::Ident(res.node)
|
||||||
|
} else {
|
||||||
|
let next = cursor.expect_peek()?;
|
||||||
|
return ParseResult::Err(ParserError::unexpected_token(next, "an expression"));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let Some(mut next) = cursor.peek() else {
|
||||||
|
return ParseResult::Ok(e1);
|
||||||
|
};
|
||||||
|
while next.is_symbol(Symbol::OpenParen) {
|
||||||
|
cursor.next();
|
||||||
|
let mut args = Vec::new();
|
||||||
|
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();
|
||||||
|
e1 = Self::Call(Node::new(Box::new(e1), start.to(end)), args);
|
||||||
|
let Some(next2) = cursor.peek() else {
|
||||||
|
return ParseResult::Ok(e1);
|
||||||
|
};
|
||||||
|
next = next2
|
||||||
|
}
|
||||||
|
let end = cursor.prev_end();
|
||||||
|
let mut recover = false;
|
||||||
|
let res = if let Some(mut op) = BinaryOperator::from_token(&next.token) {
|
||||||
|
cursor.next();
|
||||||
|
let mut n1 = Node::new(e1, start.to(end)).bx();
|
||||||
|
let res = Node::parse(cursor, errors);
|
||||||
|
let mut n2 = res.node.bx();
|
||||||
|
recover = res.recover;
|
||||||
|
if let Some(box Self::BinaryOp(op2, _, _)) = n2.as_ref() {
|
||||||
|
if op.presedence() > op2.presedence() {
|
||||||
|
let Some(box Self::BinaryOp(op2, n21, n22)) = n2.inner else {
|
||||||
|
unreachable!();
|
||||||
|
};
|
||||||
|
let end = n21.span.end;
|
||||||
|
n1 = Node::new(Self::BinaryOp(op, n1, n21), start.to(end)).bx();
|
||||||
|
op = op2;
|
||||||
|
n2 = n22;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Self::BinaryOp(op, n1, n2)
|
||||||
|
} else {
|
||||||
|
e1
|
||||||
|
};
|
||||||
|
ParseResult::from_recover(res, recover)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for Expr {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Expr::Lit(c) => c.fmt(f)?,
|
||||||
|
Expr::Ident(n) => n.fmt(f)?,
|
||||||
|
Expr::Block(b) => b.fmt(f)?,
|
||||||
|
Expr::BinaryOp(op, e1, e2) => {
|
||||||
|
write!(f, "({:?}", *e1)?;
|
||||||
|
if op.pad() {
|
||||||
|
write!(f, " {} ", op.str())?;
|
||||||
|
} else {
|
||||||
|
write!(f, "{}", op.str())?;
|
||||||
|
}
|
||||||
|
write!(f, "{:?})", *e2)?;
|
||||||
|
}
|
||||||
|
Expr::Call(n, args) => {
|
||||||
|
n.fmt(f)?;
|
||||||
|
f.write_char('(')?;
|
||||||
|
if let Some(a) = args.first() {
|
||||||
|
a.fmt(f)?;
|
||||||
|
}
|
||||||
|
for arg in args.iter().skip(1) {
|
||||||
|
f.write_str(", ")?;
|
||||||
|
arg.fmt(f)?;
|
||||||
|
}
|
||||||
|
f.write_char(')')?;
|
||||||
|
}
|
||||||
|
Expr::UnaryOp(op, e) => {
|
||||||
|
write!(f, "(")?;
|
||||||
|
write!(f, "{}", op.str())?;
|
||||||
|
write!(f, "{:?})", *e)?;
|
||||||
|
}
|
||||||
|
Expr::Group(inner) => inner.fmt(f)?,
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
28
src/parser/v3/nodes/func.rs
Normal file
28
src/parser/v3/nodes/func.rs
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
use super::{Body, Ident, Keyword, Node, Parsable, ParseResult, ParserErrors, Symbol, TokenCursor};
|
||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
pub struct Function {
|
||||||
|
pub name: Node<Ident>,
|
||||||
|
pub body: Node<Body>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parsable for Function {
|
||||||
|
fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> ParseResult<Self> {
|
||||||
|
cursor.expect_kw(Keyword::Fn)?;
|
||||||
|
let name = Node::parse(cursor, errors)?;
|
||||||
|
cursor.expect_sym(Symbol::OpenParen)?;
|
||||||
|
cursor.expect_sym(Symbol::CloseParen)?;
|
||||||
|
Node::parse(cursor, errors).map(|body| Self { name, body })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for Function {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.write_str("fn ")?;
|
||||||
|
self.name.fmt(f)?;
|
||||||
|
f.write_str("() ")?;
|
||||||
|
self.body.fmt(f)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
29
src/parser/v3/nodes/ident.rs
Normal file
29
src/parser/v3/nodes/ident.rs
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
use std::fmt::Debug;
|
||||||
|
use super::{Parsable, ParseResult, ParserError, Token};
|
||||||
|
|
||||||
|
pub struct Ident(String);
|
||||||
|
|
||||||
|
impl Ident {
|
||||||
|
pub fn val(&self) -> &String {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parsable for Ident {
|
||||||
|
fn parse(cursor: &mut super::TokenCursor, errors: &mut super::ParserErrors) -> ParseResult<Self> {
|
||||||
|
let next = cursor.expect_peek()?;
|
||||||
|
let Token::Ident(name) = &next.token else {
|
||||||
|
return ParseResult::Err(ParserError::unexpected_token(next, "an identifier"));
|
||||||
|
};
|
||||||
|
let name = name.to_string();
|
||||||
|
cursor.next();
|
||||||
|
ParseResult::Ok(Self(name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for Ident {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{}", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
114
src/parser/v3/nodes/lit.rs
Normal file
114
src/parser/v3/nodes/lit.rs
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
use super::{
|
||||||
|
CharCursor, MaybeParsable, ParserError, ParserErrors, Symbol, Token, TokenCursor,
|
||||||
|
};
|
||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Eq)]
|
||||||
|
pub enum Literal {
|
||||||
|
String(String),
|
||||||
|
Char(char),
|
||||||
|
Number(Number),
|
||||||
|
Unit,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Eq)]
|
||||||
|
pub struct Number {
|
||||||
|
pub whole: String,
|
||||||
|
pub decimal: Option<String>,
|
||||||
|
pub ty: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MaybeParsable for Literal {
|
||||||
|
fn maybe_parse(
|
||||||
|
cursor: &mut TokenCursor,
|
||||||
|
_: &mut ParserErrors,
|
||||||
|
) -> Result<Option<Self>, ParserError> {
|
||||||
|
let inst = cursor.expect_peek()?;
|
||||||
|
let mut res = match &inst.token {
|
||||||
|
Token::Symbol(Symbol::SingleQuote) => {
|
||||||
|
let chars = cursor.chars();
|
||||||
|
let c = chars.expect_next()?;
|
||||||
|
chars.expect('\'')?;
|
||||||
|
Self::Char(c)
|
||||||
|
}
|
||||||
|
Token::Symbol(Symbol::DoubleQuote) => Self::String(string_from(cursor.chars())?),
|
||||||
|
Token::Ident(text) => {
|
||||||
|
let first = text.chars().next().unwrap();
|
||||||
|
if first.is_ascii_digit() {
|
||||||
|
Self::Number(Number {
|
||||||
|
whole: text.to_string(),
|
||||||
|
decimal: None,
|
||||||
|
ty: None,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => return Ok(None),
|
||||||
|
};
|
||||||
|
cursor.next();
|
||||||
|
if let (Some(next), Self::Number(num)) = (cursor.peek(), &mut res) {
|
||||||
|
if next.token.is_symbol(Symbol::Dot) {
|
||||||
|
cursor.next();
|
||||||
|
if let Some(next) = cursor.peek() {
|
||||||
|
if let Token::Ident(i) = &next.token {
|
||||||
|
if i.chars().next().unwrap().is_ascii_digit() {
|
||||||
|
num.decimal = Some(i.to_string());
|
||||||
|
cursor.next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(Some(res))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn string_from(cursor: &mut CharCursor) -> Result<String, ParserError> {
|
||||||
|
let mut str = String::new();
|
||||||
|
loop {
|
||||||
|
let c = cursor.expect_next()?;
|
||||||
|
if c == '"' {
|
||||||
|
return Ok(str);
|
||||||
|
}
|
||||||
|
str.push(match c {
|
||||||
|
'\\' => {
|
||||||
|
let next = cursor.expect_next()?;
|
||||||
|
match next {
|
||||||
|
'"' => '"',
|
||||||
|
'\'' => '\'',
|
||||||
|
't' => '\t',
|
||||||
|
'n' => '\n',
|
||||||
|
'0' => '\0',
|
||||||
|
_ => {
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => c,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for Literal {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::String(str) => str.fmt(f),
|
||||||
|
Self::Char(c) => c.fmt(f),
|
||||||
|
Self::Number(n) => n.fmt(f),
|
||||||
|
Self::Unit => f.write_str("()"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for Number {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{}", self.whole)?;
|
||||||
|
if let Some(d) = &self.decimal {
|
||||||
|
write!(f, ".{}", d)?;
|
||||||
|
}
|
||||||
|
if let Some(ty) = &self.ty {
|
||||||
|
write!(f, "T{}", ty)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
19
src/parser/v3/nodes/mod.rs
Normal file
19
src/parser/v3/nodes/mod.rs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
mod body;
|
||||||
|
mod expr;
|
||||||
|
mod func;
|
||||||
|
mod module;
|
||||||
|
mod op;
|
||||||
|
mod statement;
|
||||||
|
mod lit;
|
||||||
|
mod ident;
|
||||||
|
|
||||||
|
pub use body::*;
|
||||||
|
pub use expr::*;
|
||||||
|
pub use func::*;
|
||||||
|
pub use module::*;
|
||||||
|
pub use op::*;
|
||||||
|
pub use statement::*;
|
||||||
|
pub use lit::*;
|
||||||
|
pub use ident::*;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
35
src/parser/v3/nodes/module.rs
Normal file
35
src/parser/v3/nodes/module.rs
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
use super::{
|
||||||
|
Function, Keyword, Node, Parsable, ParseResult, ParserError, ParserErrors, TokenCursor,
|
||||||
|
};
|
||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
pub struct Module {
|
||||||
|
pub functions: Vec<Node<Function>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parsable for Module {
|
||||||
|
fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> ParseResult<Self> {
|
||||||
|
let mut functions = Vec::new();
|
||||||
|
loop {
|
||||||
|
let Some(next) = cursor.peek() else {
|
||||||
|
return ParseResult::Ok(Self { functions });
|
||||||
|
};
|
||||||
|
if next.is_keyword(Keyword::Fn) {
|
||||||
|
let res = Node::parse(cursor, errors);
|
||||||
|
functions.push(res.node);
|
||||||
|
if res.recover {
|
||||||
|
return ParseResult::Recover(Self { functions });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
errors.add(ParserError::unexpected_token(next, "fn"));
|
||||||
|
cursor.next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for Module {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
self.functions.fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
96
src/parser/v3/nodes/op.rs
Normal file
96
src/parser/v3/nodes/op.rs
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
use super::{Symbol, Token};
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||||
|
pub enum BinaryOperator {
|
||||||
|
Add,
|
||||||
|
Sub,
|
||||||
|
Mul,
|
||||||
|
Div,
|
||||||
|
LessThan,
|
||||||
|
GreaterThan,
|
||||||
|
Access,
|
||||||
|
Assign,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BinaryOperator {
|
||||||
|
pub fn presedence(&self) -> u32 {
|
||||||
|
match self {
|
||||||
|
Self::Assign => 0,
|
||||||
|
Self::LessThan => 1,
|
||||||
|
Self::GreaterThan => 1,
|
||||||
|
Self::Add => 2,
|
||||||
|
Self::Sub => 3,
|
||||||
|
Self::Mul => 4,
|
||||||
|
Self::Div => 5,
|
||||||
|
Self::Access => 6,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn str(&self) -> &str {
|
||||||
|
match self {
|
||||||
|
Self::Add => "+",
|
||||||
|
Self::Sub => "-",
|
||||||
|
Self::Mul => "*",
|
||||||
|
Self::Div => "/",
|
||||||
|
Self::LessThan => "<",
|
||||||
|
Self::GreaterThan => ">",
|
||||||
|
Self::Access => ".",
|
||||||
|
Self::Assign => "=",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn from_token(token: &Token) -> Option<Self> {
|
||||||
|
let Token::Symbol(symbol) = token else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
Some(match symbol {
|
||||||
|
Symbol::OpenAngle => Self::LessThan,
|
||||||
|
Symbol::CloseAngle => Self::GreaterThan,
|
||||||
|
Symbol::Plus => Self::Add,
|
||||||
|
Symbol::Minus => Self::Sub,
|
||||||
|
Symbol::Asterisk => Self::Mul,
|
||||||
|
Symbol::Slash => Self::Div,
|
||||||
|
Symbol::Dot => Self::Access,
|
||||||
|
Symbol::Equals => Self::Assign,
|
||||||
|
_ => {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
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 {
|
||||||
|
Not,
|
||||||
|
Ref,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UnaryOperator {
|
||||||
|
pub fn str(&self) -> &str {
|
||||||
|
match self {
|
||||||
|
Self::Not => "!",
|
||||||
|
Self::Ref => "&",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn from_token(token: &Token) -> Option<Self> {
|
||||||
|
let Token::Symbol(symbol) = token else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
Some(match symbol {
|
||||||
|
Symbol::Ampersand => Self::Ref,
|
||||||
|
Symbol::Bang => Self::Not,
|
||||||
|
_ => {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
53
src/parser/v3/nodes/statement.rs
Normal file
53
src/parser/v3/nodes/statement.rs
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
use super::{
|
||||||
|
Expr, Ident, Keyword, Node, Parsable, ParseResult, ParserErrors, Symbol, Token, TokenCursor,
|
||||||
|
};
|
||||||
|
use std::fmt::{Debug, Write};
|
||||||
|
|
||||||
|
pub enum Statement {
|
||||||
|
Let(Node<Ident>, Node<Expr>),
|
||||||
|
Return(Node<Expr>),
|
||||||
|
Expr(Node<Expr>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parsable for Statement {
|
||||||
|
fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> ParseResult<Self> {
|
||||||
|
let next = cursor.expect_peek()?;
|
||||||
|
match next.token {
|
||||||
|
Token::Keyword(Keyword::Let) => {
|
||||||
|
cursor.next();
|
||||||
|
let name = Node::parse(cursor, errors)?;
|
||||||
|
cursor.expect_sym(Symbol::Equals)?;
|
||||||
|
Node::parse(cursor, errors).map(|expr| Self::Let(name, expr))
|
||||||
|
}
|
||||||
|
Token::Keyword(Keyword::Return) => {
|
||||||
|
cursor.next();
|
||||||
|
Node::parse(cursor, errors).map(Self::Return)
|
||||||
|
}
|
||||||
|
_ => Node::parse(cursor, errors).map(Self::Expr),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for Statement {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Statement::Let(n, e) => {
|
||||||
|
f.write_str("let ")?;
|
||||||
|
n.fmt(f);
|
||||||
|
f.write_str(" = ")?;
|
||||||
|
e.fmt(f)?;
|
||||||
|
f.write_char(';')?;
|
||||||
|
}
|
||||||
|
Statement::Return(e) => {
|
||||||
|
f.write_str("return ")?;
|
||||||
|
e.fmt(f)?;
|
||||||
|
f.write_char(';')?;
|
||||||
|
}
|
||||||
|
Statement::Expr(e) => {
|
||||||
|
e.fmt(f)?;
|
||||||
|
f.write_char(';')?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
178
src/parser/v3/parse.rs
Normal file
178
src/parser/v3/parse.rs
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
use std::{
|
||||||
|
convert::Infallible,
|
||||||
|
ops::{ControlFlow, FromResidual, Try},
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::{Node, ParserError, ParserErrors, TokenCursor};
|
||||||
|
|
||||||
|
pub enum ParseResult<T> {
|
||||||
|
Ok(T),
|
||||||
|
Recover(T),
|
||||||
|
Err(ParserError),
|
||||||
|
SubErr,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> ParseResult<T> {
|
||||||
|
pub fn from_recover(data: T, recover: bool) -> Self {
|
||||||
|
if recover {
|
||||||
|
Self::Recover(data)
|
||||||
|
} else {
|
||||||
|
Self::Ok(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Try for ParseResult<T> {
|
||||||
|
type Output = Result<T, T>;
|
||||||
|
type Residual = Option<ParserError>;
|
||||||
|
fn from_output(output: Self::Output) -> Self {
|
||||||
|
match output {
|
||||||
|
Ok(v) => Self::Ok(v),
|
||||||
|
Err(v) => Self::Recover(v),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {
|
||||||
|
match self {
|
||||||
|
ParseResult::Ok(v) => ControlFlow::Continue(Ok(v)),
|
||||||
|
ParseResult::Recover(v) => ControlFlow::Continue(Err(v)),
|
||||||
|
ParseResult::Err(e) => ControlFlow::Break(Some(e)),
|
||||||
|
ParseResult::SubErr => ControlFlow::Break(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> FromResidual for ParseResult<T> {
|
||||||
|
fn from_residual(residual: <Self as Try>::Residual) -> Self {
|
||||||
|
match residual {
|
||||||
|
Some(err) => Self::Err(err),
|
||||||
|
None => Self::SubErr,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> FromResidual<Result<Infallible, ParserError>> for ParseResult<T> {
|
||||||
|
fn from_residual(residual: Result<Infallible, ParserError>) -> Self {
|
||||||
|
match residual {
|
||||||
|
Err(e) => Self::Err(e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, U> FromResidual<ParseResult<T>> for ParseResult<U> {
|
||||||
|
fn from_residual(residual: ParseResult<T>) -> Self {
|
||||||
|
match residual {
|
||||||
|
ParseResult::Err(e) => Self::Err(e),
|
||||||
|
ParseResult::SubErr => Self::SubErr,
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct NodeParseResult<T> {
|
||||||
|
pub node: Node<T>,
|
||||||
|
pub recover: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> NodeParseResult<T> {
|
||||||
|
pub fn map<F: FnOnce(Node<T>) -> U, U>(self, op: F) -> ParseResult<U> {
|
||||||
|
let res = op(self.node);
|
||||||
|
if self.recover {
|
||||||
|
ParseResult::Recover(res)
|
||||||
|
} else {
|
||||||
|
ParseResult::Ok(res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Try for NodeParseResult<T> {
|
||||||
|
type Output = Node<T>;
|
||||||
|
type Residual = ParseResult<T>;
|
||||||
|
|
||||||
|
fn from_output(output: Self::Output) -> Self {
|
||||||
|
Self {
|
||||||
|
node: output,
|
||||||
|
recover: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {
|
||||||
|
if self.recover {
|
||||||
|
ControlFlow::Break(ParseResult::SubErr)
|
||||||
|
} else {
|
||||||
|
ControlFlow::Continue(self.node)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> FromResidual for NodeParseResult<T> {
|
||||||
|
fn from_residual(_: <Self as Try>::Residual) -> Self {
|
||||||
|
// I hope this is unreachable ???
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Parsable: Sized {
|
||||||
|
fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> ParseResult<Self>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait MaybeParsable: Sized {
|
||||||
|
fn maybe_parse(
|
||||||
|
cursor: &mut TokenCursor,
|
||||||
|
errors: &mut ParserErrors,
|
||||||
|
) -> Result<Option<Self>, ParserError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Parsable> Node<T> {
|
||||||
|
pub fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> NodeParseResult<T> {
|
||||||
|
let start = cursor.next_pos();
|
||||||
|
let (inner, recover) = match T::parse(cursor, errors) {
|
||||||
|
ParseResult::Ok(v) => (Some(v), false),
|
||||||
|
ParseResult::Recover(v) => (Some(v), true),
|
||||||
|
ParseResult::Err(e) => {
|
||||||
|
errors.add(e);
|
||||||
|
(None, true)
|
||||||
|
}
|
||||||
|
ParseResult::SubErr => (None, true),
|
||||||
|
};
|
||||||
|
let end = cursor.prev_end();
|
||||||
|
NodeParseResult {
|
||||||
|
node: Self {
|
||||||
|
inner,
|
||||||
|
span: start.to(end),
|
||||||
|
},
|
||||||
|
recover,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: MaybeParsable> Node<T> {
|
||||||
|
pub fn maybe_parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> Option<Self> {
|
||||||
|
let start = cursor.next_pos();
|
||||||
|
let inner = match T::maybe_parse(cursor, errors) {
|
||||||
|
Ok(v) => Some(v?),
|
||||||
|
Err(e) => {
|
||||||
|
errors.add(e);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let end = cursor.prev_end();
|
||||||
|
Some(Self {
|
||||||
|
inner,
|
||||||
|
span: start.to(end),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait NodeParsable {
|
||||||
|
fn parse_node(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> NodeParseResult<Self>
|
||||||
|
where
|
||||||
|
Self: Sized;
|
||||||
|
}
|
||||||
|
impl<T: Parsable> NodeParsable for T {
|
||||||
|
fn parse_node(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> NodeParseResult<Self>
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
Node::<Self>::parse(cursor, errors)
|
||||||
|
}
|
||||||
|
}
|
||||||
68
src/parser/v3/token/cursor.rs
Normal file
68
src/parser/v3/token/cursor.rs
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
use std::{iter::Peekable, str::Chars};
|
||||||
|
|
||||||
|
use super::super::ParserError;
|
||||||
|
use super::FilePos;
|
||||||
|
|
||||||
|
pub struct CharCursor<'a> {
|
||||||
|
chars: Peekable<Chars<'a>>,
|
||||||
|
next_pos: FilePos,
|
||||||
|
prev_pos: FilePos,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CharCursor<'_> {
|
||||||
|
pub fn next(&mut self) -> Option<char> {
|
||||||
|
let res = self.peek()?;
|
||||||
|
self.advance();
|
||||||
|
Some(res)
|
||||||
|
}
|
||||||
|
pub fn expect(&mut self, c: char) -> Result<(), ParserError> {
|
||||||
|
let next = self.expect_next()?;
|
||||||
|
if next == c {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(ParserError::at(
|
||||||
|
self.prev_pos,
|
||||||
|
format!("unexpected char '{next}'; expected '{c}'"),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn skip_whitespace(&mut self) {
|
||||||
|
while self.peek().is_some_and(|c| c.is_whitespace()) {
|
||||||
|
self.advance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn peek(&mut self) -> Option<char> {
|
||||||
|
self.chars.peek().copied()
|
||||||
|
}
|
||||||
|
pub fn advance(&mut self) {
|
||||||
|
let Some(next) = self.chars.next() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
self.prev_pos = self.next_pos;
|
||||||
|
if next == '\n' {
|
||||||
|
self.next_pos.col = 0;
|
||||||
|
self.next_pos.line += 1;
|
||||||
|
} else {
|
||||||
|
self.next_pos.col += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn expect_next(&mut self) -> Result<char, ParserError> {
|
||||||
|
self.next().ok_or(ParserError::unexpected_end())
|
||||||
|
}
|
||||||
|
pub fn next_pos(&self) -> FilePos {
|
||||||
|
self.next_pos
|
||||||
|
}
|
||||||
|
pub fn prev_pos(&self) -> FilePos {
|
||||||
|
self.prev_pos
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a str> for CharCursor<'a> {
|
||||||
|
fn from(value: &'a str) -> Self {
|
||||||
|
Self {
|
||||||
|
chars: value.chars().peekable(),
|
||||||
|
next_pos: FilePos::start(),
|
||||||
|
prev_pos: FilePos::start(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
80
src/parser/v3/token/file.rs
Normal file
80
src/parser/v3/token/file.rs
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub struct FilePos {
|
||||||
|
pub line: usize,
|
||||||
|
pub col: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct FileSpan {
|
||||||
|
pub start: FilePos,
|
||||||
|
pub end: FilePos,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FilePos {
|
||||||
|
pub fn start() -> Self {
|
||||||
|
Self { line: 0, col: 0 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FilePos {
|
||||||
|
pub fn to(self, end: FilePos) -> FileSpan {
|
||||||
|
FileSpan { start: self, end }
|
||||||
|
}
|
||||||
|
pub fn char_span(self) -> FileSpan {
|
||||||
|
FileSpan::at(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const BEFORE: usize = 1;
|
||||||
|
const AFTER: usize = 0;
|
||||||
|
|
||||||
|
impl FileSpan {
|
||||||
|
pub fn at(pos: FilePos) -> Self {
|
||||||
|
Self {
|
||||||
|
start: pos,
|
||||||
|
end: pos,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn write_for(&self, writer: &mut impl std::io::Write, file: &str) -> std::io::Result<()> {
|
||||||
|
let start = self.start.line.saturating_sub(BEFORE);
|
||||||
|
let num_before = self.start.line - start;
|
||||||
|
let mut lines = file.lines().skip(start);
|
||||||
|
let width = format!("{}", self.end.line + AFTER).len();
|
||||||
|
let same_line = self.start.line == self.end.line;
|
||||||
|
for i in 0..num_before {
|
||||||
|
writeln!(writer, "{:>width$} | {}", start + i, lines.next().unwrap())?;
|
||||||
|
}
|
||||||
|
let line = lines.next().unwrap();
|
||||||
|
writeln!(writer, "{:>width$} | {}", self.start.line, line)?;
|
||||||
|
let len = if same_line {
|
||||||
|
self.end.col - self.start.col + 1
|
||||||
|
} else {
|
||||||
|
line.len() - self.start.col
|
||||||
|
};
|
||||||
|
writeln!(
|
||||||
|
writer,
|
||||||
|
"{} | {}",
|
||||||
|
" ".repeat(width),
|
||||||
|
" ".repeat(self.start.col) + &"^".repeat(len)
|
||||||
|
)?;
|
||||||
|
if !same_line {
|
||||||
|
for _ in 0..self.end.line - self.start.line - 1 {
|
||||||
|
lines.next();
|
||||||
|
}
|
||||||
|
let line = lines.next().unwrap();
|
||||||
|
writeln!(writer, "{:>width$} | {}", self.end.line, line)?;
|
||||||
|
writeln!(
|
||||||
|
writer,
|
||||||
|
"{} | {}",
|
||||||
|
" ".repeat(width),
|
||||||
|
"^".repeat(self.end.col + 1)
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
// for i in 0..AFTER {
|
||||||
|
// if let Some(next) = lines.next() {
|
||||||
|
// writeln!(writer, "{:>width$} | {}", self.end.line + i + 1, next)?;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
19
src/parser/v3/token/keyword.rs
Normal file
19
src/parser/v3/token/keyword.rs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||||
|
pub enum Keyword {
|
||||||
|
Fn,
|
||||||
|
Let,
|
||||||
|
If,
|
||||||
|
Return,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Keyword {
|
||||||
|
pub fn from_string(str: &str) -> Option<Self> {
|
||||||
|
Some(match str {
|
||||||
|
"fn" => Self::Fn,
|
||||||
|
"let" => Self::Let,
|
||||||
|
"if" => Self::If,
|
||||||
|
"return" => Self::Return,
|
||||||
|
_ => return None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
90
src/parser/v3/token/mod.rs
Normal file
90
src/parser/v3/token/mod.rs
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
mod cursor;
|
||||||
|
mod file;
|
||||||
|
mod keyword;
|
||||||
|
mod symbol;
|
||||||
|
|
||||||
|
use std::ops::Deref;
|
||||||
|
|
||||||
|
pub use cursor::*;
|
||||||
|
pub use file::*;
|
||||||
|
pub use keyword::*;
|
||||||
|
pub use symbol::*;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
|
pub enum Token {
|
||||||
|
Symbol(Symbol),
|
||||||
|
Ident(String),
|
||||||
|
Keyword(Keyword),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct TokenInstance {
|
||||||
|
pub token: Token,
|
||||||
|
pub span: FileSpan,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TokenInstance {
|
||||||
|
pub fn parse(cursor: &mut CharCursor) -> Option<TokenInstance> {
|
||||||
|
cursor.skip_whitespace();
|
||||||
|
cursor.peek()?;
|
||||||
|
let start = cursor.next_pos();
|
||||||
|
if let Some(s) = Symbol::parse(cursor) {
|
||||||
|
if s == Symbol::DoubleSlash {
|
||||||
|
while cursor.next() != Some('\n') {}
|
||||||
|
return Self::parse(cursor);
|
||||||
|
}
|
||||||
|
let end = cursor.prev_pos();
|
||||||
|
return Some(Self {
|
||||||
|
token: Token::Symbol(s),
|
||||||
|
span: FileSpan { start, end },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
let mut word = String::new();
|
||||||
|
while let Some(c) = cursor.peek() {
|
||||||
|
if c.is_whitespace() || Symbol::from_char(c).is_some() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
word.push(c);
|
||||||
|
cursor.advance();
|
||||||
|
}
|
||||||
|
let end = cursor.prev_pos();
|
||||||
|
let token = if let Some(keyword) = Keyword::from_string(&word) {
|
||||||
|
Token::Keyword(keyword)
|
||||||
|
} else {
|
||||||
|
Token::Ident(word)
|
||||||
|
};
|
||||||
|
Some(Self {
|
||||||
|
token,
|
||||||
|
span: FileSpan { start, end },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Token {
|
||||||
|
pub fn is_symbol(&self, symbol: Symbol) -> bool {
|
||||||
|
match self {
|
||||||
|
Token::Symbol(s) => *s == symbol,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn is_symbol_and(&self, f: impl Fn(Symbol) -> bool) -> bool {
|
||||||
|
match self {
|
||||||
|
Token::Symbol(s) => f(*s),
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn is_keyword(&self, kw: Keyword) -> bool {
|
||||||
|
match self {
|
||||||
|
Token::Keyword(k) => *k == kw,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for TokenInstance {
|
||||||
|
type Target = Token;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.token
|
||||||
|
}
|
||||||
|
}
|
||||||
146
src/parser/v3/token/symbol.rs
Normal file
146
src/parser/v3/token/symbol.rs
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
use super::CharCursor;
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, Clone, Copy)]
|
||||||
|
pub enum Symbol {
|
||||||
|
Semicolon,
|
||||||
|
Colon,
|
||||||
|
DoubleColon,
|
||||||
|
Equals,
|
||||||
|
DoubleEquals,
|
||||||
|
Arrow,
|
||||||
|
DoubleArrow,
|
||||||
|
Plus,
|
||||||
|
Minus,
|
||||||
|
Asterisk,
|
||||||
|
Slash,
|
||||||
|
DoubleSlash,
|
||||||
|
Dot,
|
||||||
|
OpenParen,
|
||||||
|
CloseParen,
|
||||||
|
OpenCurly,
|
||||||
|
CloseCurly,
|
||||||
|
OpenSquare,
|
||||||
|
CloseSquare,
|
||||||
|
OpenAngle,
|
||||||
|
CloseAngle,
|
||||||
|
SingleQuote,
|
||||||
|
DoubleQuote,
|
||||||
|
Bang,
|
||||||
|
Ampersand,
|
||||||
|
DoubleAmpersand,
|
||||||
|
Pipe,
|
||||||
|
DoublePipe,
|
||||||
|
Comma,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Symbol {
|
||||||
|
pub fn parse(cursor: &mut CharCursor) -> Option<Self> {
|
||||||
|
Self::from_char(cursor.peek()?).map(|mut s| {
|
||||||
|
cursor.advance();
|
||||||
|
s.finish(cursor);
|
||||||
|
s
|
||||||
|
})
|
||||||
|
}
|
||||||
|
pub fn from_char(c: char) -> Option<Self> {
|
||||||
|
Some(match c {
|
||||||
|
'(' => Self::OpenParen,
|
||||||
|
')' => Self::CloseParen,
|
||||||
|
'[' => Self::OpenSquare,
|
||||||
|
']' => Self::CloseSquare,
|
||||||
|
'{' => Self::OpenCurly,
|
||||||
|
'}' => Self::CloseCurly,
|
||||||
|
'<' => Self::OpenAngle,
|
||||||
|
'>' => Self::CloseAngle,
|
||||||
|
';' => Self::Semicolon,
|
||||||
|
':' => Self::Colon,
|
||||||
|
'+' => Self::Plus,
|
||||||
|
'-' => Self::Minus,
|
||||||
|
'*' => Self::Asterisk,
|
||||||
|
'/' => Self::Slash,
|
||||||
|
'=' => Self::Equals,
|
||||||
|
'.' => Self::Dot,
|
||||||
|
'\'' => Self::SingleQuote,
|
||||||
|
'"' => Self::DoubleQuote,
|
||||||
|
'!' => Self::Bang,
|
||||||
|
'&' => Self::Ampersand,
|
||||||
|
'|' => Self::Pipe,
|
||||||
|
',' => Self::Comma,
|
||||||
|
_ => return None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
pub fn finish(&mut self, cursor: &mut CharCursor) {
|
||||||
|
let Some(next) = cursor.peek() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
*self = match self {
|
||||||
|
Self::Colon => match next {
|
||||||
|
':' => Self::DoubleColon,
|
||||||
|
_ => return,
|
||||||
|
},
|
||||||
|
Self::Minus => match next {
|
||||||
|
'>' => Self::Arrow,
|
||||||
|
_ => return,
|
||||||
|
},
|
||||||
|
Self::Equals => match next {
|
||||||
|
'=' => Self::DoubleEquals,
|
||||||
|
'>' => Self::DoubleArrow,
|
||||||
|
_ => return,
|
||||||
|
},
|
||||||
|
Self::Slash => match next {
|
||||||
|
'/' => Self::DoubleSlash,
|
||||||
|
_ => return,
|
||||||
|
},
|
||||||
|
Self::Ampersand => match next {
|
||||||
|
'&' => Self::DoubleAmpersand,
|
||||||
|
_ => return,
|
||||||
|
},
|
||||||
|
Self::Pipe => match next {
|
||||||
|
'&' => Self::DoublePipe,
|
||||||
|
_ => return,
|
||||||
|
},
|
||||||
|
_ => return,
|
||||||
|
};
|
||||||
|
cursor.advance();
|
||||||
|
}
|
||||||
|
pub fn str(&self) -> &str {
|
||||||
|
match self {
|
||||||
|
Self::Semicolon => ";",
|
||||||
|
Self::Colon => ":",
|
||||||
|
Self::DoubleColon => "::",
|
||||||
|
Self::Equals => "=",
|
||||||
|
Self::DoubleEquals => "==",
|
||||||
|
Self::Arrow => "->",
|
||||||
|
Self::DoubleArrow => "=>",
|
||||||
|
Self::Plus => "+",
|
||||||
|
Self::Minus => "-",
|
||||||
|
Self::Asterisk => "*",
|
||||||
|
Self::Slash => "/",
|
||||||
|
Self::DoubleSlash => "//",
|
||||||
|
Self::Dot => ".",
|
||||||
|
Self::OpenParen => "(",
|
||||||
|
Self::CloseParen => ")",
|
||||||
|
Self::OpenCurly => "{",
|
||||||
|
Self::CloseCurly => "}",
|
||||||
|
Self::OpenSquare => "[",
|
||||||
|
Self::CloseSquare => "]",
|
||||||
|
Self::OpenAngle => "<",
|
||||||
|
Self::CloseAngle => ">",
|
||||||
|
Self::SingleQuote => "'",
|
||||||
|
Self::DoubleQuote => "\"",
|
||||||
|
Self::Bang => "!",
|
||||||
|
Self::Comma => ",",
|
||||||
|
Self::Ampersand => "&",
|
||||||
|
Self::DoubleAmpersand => "&&",
|
||||||
|
Self::Pipe => "|",
|
||||||
|
Self::DoublePipe => "||",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for Symbol {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "'{}'", self.str())
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user