added unary ops and control flow for parser
This commit is contained in:
@@ -29,3 +29,6 @@ fn test() {
|
|||||||
fn test2() {
|
fn test2() {
|
||||||
let a anerit;
|
let a anerit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn test3() {
|
||||||
|
let x = 3
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
fn main() {
|
fn main() {
|
||||||
let x = 3;
|
let x = &"Hello World!";
|
||||||
print(x);
|
print(x);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
pub enum IRInstruction {
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#![feature(box_patterns)]
|
#![feature(box_patterns)]
|
||||||
|
#![feature(try_trait_v2)]
|
||||||
|
|
||||||
mod util;
|
mod util;
|
||||||
mod compiler;
|
mod compiler;
|
||||||
|
|||||||
@@ -1,33 +1,25 @@
|
|||||||
use std::io::{stdout, BufRead, BufReader};
|
use std::io::{stdout, BufRead, BufReader};
|
||||||
|
|
||||||
mod body;
|
|
||||||
mod cursor;
|
mod cursor;
|
||||||
mod error;
|
mod error;
|
||||||
mod expr;
|
|
||||||
mod module;
|
|
||||||
mod node;
|
mod node;
|
||||||
mod op;
|
mod nodes;
|
||||||
|
mod parse;
|
||||||
mod token;
|
mod token;
|
||||||
mod val;
|
|
||||||
mod statement;
|
|
||||||
mod func;
|
|
||||||
|
|
||||||
pub use body::*;
|
|
||||||
pub use cursor::*;
|
pub use cursor::*;
|
||||||
pub use error::*;
|
pub use error::*;
|
||||||
pub use expr::*;
|
|
||||||
pub use module::*;
|
|
||||||
pub use node::*;
|
pub use node::*;
|
||||||
pub use op::*;
|
pub use nodes::*;
|
||||||
|
pub use parse::*;
|
||||||
use token::*;
|
use token::*;
|
||||||
pub use val::*;
|
|
||||||
pub use statement::*;
|
|
||||||
|
|
||||||
pub fn parse_file(file: &str) {
|
pub fn parse_file(file: &str) {
|
||||||
let mut errors = ParserErrors::new();
|
let mut errors = ParserErrors::new();
|
||||||
let node = Module::parse_node(&mut TokenCursor::from(file), &mut errors);
|
let res = Module::parse_node(&mut TokenCursor::from(file), &mut errors);
|
||||||
|
println!("{:?}", res.node);
|
||||||
if errors.errs.is_empty() {
|
if errors.errs.is_empty() {
|
||||||
let module = node.resolve().expect("what");
|
let module = res.node.resolve().expect("what");
|
||||||
}
|
}
|
||||||
let out = &mut stdout();
|
let out = &mut stdout();
|
||||||
for err in errors.errs {
|
for err in errors.errs {
|
||||||
@@ -40,8 +32,12 @@ pub fn run_stdin() {
|
|||||||
let mut errors = ParserErrors::new();
|
let mut errors = ParserErrors::new();
|
||||||
let str = &line.expect("failed to read line");
|
let str = &line.expect("failed to read line");
|
||||||
let mut cursor = TokenCursor::from(&str[..]);
|
let mut cursor = TokenCursor::from(&str[..]);
|
||||||
if let Ok(expr) = Statement::parse_node(&mut cursor, &mut errors).as_ref() {
|
if let Ok(expr) = Statement::parse_node(&mut cursor, &mut errors).node.as_ref() {
|
||||||
println!("{:?}", expr);
|
if cursor.next().is_none() {
|
||||||
|
println!("{:?}", expr);
|
||||||
|
} else {
|
||||||
|
println!("uhhhh ehehe");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let out = &mut stdout();
|
let out = &mut stdout();
|
||||||
for err in errors.errs {
|
for err in errors.errs {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use std::{
|
|||||||
ops::{Deref, DerefMut},
|
ops::{Deref, DerefMut},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{FileSpan, ParserError, ParserErrors, TokenCursor};
|
use super::FileSpan;
|
||||||
|
|
||||||
pub trait MaybeResolved {
|
pub trait MaybeResolved {
|
||||||
type Inner<T>;
|
type Inner<T>;
|
||||||
@@ -24,63 +24,8 @@ pub struct Node<T, R: MaybeResolved> {
|
|||||||
pub span: FileSpan,
|
pub span: FileSpan,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Parsable: Sized {
|
|
||||||
fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> Result<Self, ParserError>;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait MaybeParsable: Sized {
|
|
||||||
fn maybe_parse(
|
|
||||||
cursor: &mut TokenCursor,
|
|
||||||
errors: &mut ParserErrors,
|
|
||||||
) -> Result<Option<Self>, ParserError>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Parsable> Node<T, Unresolved> {
|
|
||||||
pub fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> Self {
|
|
||||||
let start = cursor.next_pos();
|
|
||||||
let inner = T::parse(cursor, errors).map_err(|e| errors.add(e));
|
|
||||||
let end = cursor.prev_end();
|
|
||||||
Self {
|
|
||||||
inner,
|
|
||||||
span: start.to(end),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: MaybeParsable> Node<T, Unresolved> {
|
|
||||||
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) => Ok(v?),
|
|
||||||
Err(e) => {
|
|
||||||
errors.add(e);
|
|
||||||
Err(())
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let end = cursor.prev_end();
|
|
||||||
Some(Self {
|
|
||||||
inner,
|
|
||||||
span: start.to(end),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait NodeParsable {
|
|
||||||
fn parse_node(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> Node<Self, Unresolved>
|
|
||||||
where
|
|
||||||
Self: Sized;
|
|
||||||
}
|
|
||||||
impl<T: Parsable> NodeParsable for T {
|
|
||||||
fn parse_node(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> Node<Self, Unresolved>
|
|
||||||
where
|
|
||||||
Self: Sized,
|
|
||||||
{
|
|
||||||
Node::<Self, Unresolved>::parse(cursor, errors)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Node<T, Unresolved> {
|
impl<T> Node<T, Unresolved> {
|
||||||
pub fn new_unres(inner: T, span: FileSpan) -> Self {
|
pub fn new(inner: T, span: FileSpan) -> Self {
|
||||||
Self {
|
Self {
|
||||||
inner: Ok(inner),
|
inner: Ok(inner),
|
||||||
span,
|
span,
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use std::fmt::{Debug, Write};
|
use std::fmt::{Debug, Write};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
token::Symbol, MaybeResolved, Node, NodeParsable, Parsable, ParserError, ParserErrors,
|
token::Symbol, MaybeResolved, Node, NodeParsable, Parsable, ParseResult, ParserError,
|
||||||
Resolvable, Resolved, Statement, TokenCursor, Unresolved,
|
ParserErrors, Resolvable, Resolved, Statement, TokenCursor, Unresolved,
|
||||||
};
|
};
|
||||||
use crate::util::Padder;
|
use crate::util::Padder;
|
||||||
|
|
||||||
@@ -11,20 +11,25 @@ pub struct Body<R: MaybeResolved> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Parsable for Body<Unresolved> {
|
impl Parsable for Body<Unresolved> {
|
||||||
fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> Result<Self, ParserError> {
|
fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> ParseResult<Self> {
|
||||||
let mut statements = Vec::new();
|
let mut statements = Vec::new();
|
||||||
let statement_end = &[Symbol::Semicolon, Symbol::CloseCurly];
|
let statement_end = &[Symbol::Semicolon, Symbol::CloseCurly];
|
||||||
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 Ok(Self { statements });
|
return ParseResult::Ok(Self { statements });
|
||||||
}
|
}
|
||||||
let mut expect_semi = false;
|
let mut expect_semi = false;
|
||||||
|
let mut recover = false;
|
||||||
loop {
|
loop {
|
||||||
let next = cursor.expect_peek()?;
|
let Some(next) = cursor.peek() else {
|
||||||
|
recover = true;
|
||||||
|
errors.add(ParserError::unexpected_end());
|
||||||
|
break;
|
||||||
|
};
|
||||||
if next.is_symbol(Symbol::CloseCurly) {
|
if next.is_symbol(Symbol::CloseCurly) {
|
||||||
cursor.next();
|
cursor.next();
|
||||||
return Ok(Self { statements });
|
break;
|
||||||
}
|
}
|
||||||
if next.is_symbol(Symbol::Semicolon) {
|
if next.is_symbol(Symbol::Semicolon) {
|
||||||
cursor.next();
|
cursor.next();
|
||||||
@@ -36,15 +41,19 @@ impl Parsable for Body<Unresolved> {
|
|||||||
spans: vec![cursor.next_pos().char_span()],
|
spans: vec![cursor.next_pos().char_span()],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
let statement = Statement::parse_node(cursor, errors);
|
let res = Statement::parse_node(cursor, errors);
|
||||||
|
statements.push(res.node);
|
||||||
expect_semi = true;
|
expect_semi = true;
|
||||||
if statement.is_err() || statement.as_ref().is_ok_and(|s| s.ended_with_error()) {
|
if res.recover
|
||||||
let res = cursor
|
&& cursor
|
||||||
.seek(|t| t.is_symbol_and(|s| statement_end.contains(&s)))
|
.seek(|t| t.is_symbol_and(|s| statement_end.contains(&s)))
|
||||||
.ok_or(ParserError::unexpected_end())?;
|
.is_none()
|
||||||
|
{
|
||||||
|
recover = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
statements.push(statement);
|
|
||||||
}
|
}
|
||||||
|
ParseResult::from_recover(Self { statements }, recover)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2,8 +2,8 @@ use std::fmt::{Debug, Write};
|
|||||||
|
|
||||||
use super::token::{Symbol, Token};
|
use super::token::{Symbol, Token};
|
||||||
use super::{
|
use super::{
|
||||||
Body, Literal, MaybeResolved, Node, Operator, Parsable, ParserError, ParserErrors, Resolvable,
|
BinaryOperator, Body, Literal, MaybeResolved, Node, NodeParsable, Parsable, ParseResult,
|
||||||
Resolved, TokenCursor, Unresolved,
|
ParserError, ParserErrors, Resolvable, Resolved, TokenCursor, UnaryOperator, Unresolved,
|
||||||
};
|
};
|
||||||
|
|
||||||
type BoxNode<R> = Node<Box<Expr<R>>, R>;
|
type BoxNode<R> = Node<Box<Expr<R>>, R>;
|
||||||
@@ -11,46 +11,45 @@ type BoxNode<R> = Node<Box<Expr<R>>, R>;
|
|||||||
pub enum Expr<R: MaybeResolved> {
|
pub enum Expr<R: MaybeResolved> {
|
||||||
Lit(Node<Literal, R>),
|
Lit(Node<Literal, R>),
|
||||||
Ident(String),
|
Ident(String),
|
||||||
BinaryOp(Operator, BoxNode<R>, BoxNode<R>),
|
BinaryOp(BinaryOperator, BoxNode<R>, BoxNode<R>),
|
||||||
|
UnaryOp(UnaryOperator, BoxNode<R>),
|
||||||
Block(Node<Body<R>, R>),
|
Block(Node<Body<R>, R>),
|
||||||
Call(BoxNode<R>, Vec<Node<Expr<R>, R>>),
|
Call(BoxNode<R>, Vec<Node<Expr<R>, R>>),
|
||||||
Group(BoxNode<R>),
|
Group(BoxNode<R>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Expr<Unresolved> {
|
|
||||||
pub fn ended_with_error(&self) -> bool {
|
|
||||||
match self {
|
|
||||||
Expr::Lit(_) => false,
|
|
||||||
Expr::Ident(_) => false,
|
|
||||||
Expr::BinaryOp(_, _, e) => e.is_err() || e.as_ref().is_ok_and(|e| e.ended_with_error()),
|
|
||||||
Expr::Block(b) => b.is_err(),
|
|
||||||
Expr::Call(_, _) => false,
|
|
||||||
Expr::Group(_) => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Parsable for Expr<Unresolved> {
|
impl Parsable for Expr<Unresolved> {
|
||||||
fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> Result<Self, ParserError> {
|
fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> 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) {
|
||||||
cursor.next();
|
cursor.next();
|
||||||
if cursor.expect_peek()?.is_symbol(Symbol::CloseParen) {
|
if cursor.expect_peek()?.is_symbol(Symbol::CloseParen) {
|
||||||
cursor.next();
|
cursor.next();
|
||||||
return Ok(Expr::Lit(Node::new_unres(
|
return ParseResult::Ok(Expr::Lit(Node::new(
|
||||||
Literal::Unit,
|
Literal::Unit,
|
||||||
cursor.next_pos().char_span(),
|
cursor.next_pos().char_span(),
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
let expr = Node::parse(cursor, errors).bx();
|
let res = Node::parse(cursor, errors);
|
||||||
if expr.is_err() {
|
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(expr)
|
Self::Group(res.node.bx())
|
||||||
} else if next.is_symbol(Symbol::OpenCurly) {
|
} else if next.is_symbol(Symbol::OpenCurly) {
|
||||||
Self::Block(Node::parse(cursor, errors))
|
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 Ok(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) {
|
} else if let Some(val) = Node::maybe_parse(cursor, errors) {
|
||||||
Self::Lit(val)
|
Self::Lit(val)
|
||||||
} else {
|
} else {
|
||||||
@@ -62,36 +61,47 @@ impl Parsable for Expr<Unresolved> {
|
|||||||
Self::Ident(name)
|
Self::Ident(name)
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Err(ParserError::unexpected_token(next, "an expression"));
|
return ParseResult::Err(ParserError::unexpected_token(next, "an expression"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let Some(mut next) = cursor.peek() else {
|
let Some(mut next) = cursor.peek() else {
|
||||||
return Ok(e1);
|
return ParseResult::Ok(e1);
|
||||||
};
|
};
|
||||||
while next.is_symbol(Symbol::OpenParen) {
|
while next.is_symbol(Symbol::OpenParen) {
|
||||||
cursor.next();
|
cursor.next();
|
||||||
let inner = Node::parse(cursor, errors);
|
let mut args = Vec::new();
|
||||||
|
while !cursor.expect_peek()?.is_symbol(Symbol::CloseParen) {
|
||||||
|
let res = Node::<Expr<Unresolved>, Unresolved>::parse(cursor, errors);
|
||||||
|
args.push(res.node);
|
||||||
|
if res.recover {
|
||||||
|
cursor.seek_sym(Symbol::CloseParen);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
cursor.expect_sym(Symbol::CloseParen)?;
|
cursor.expect_sym(Symbol::CloseParen)?;
|
||||||
let end = cursor.prev_end();
|
let end = cursor.prev_end();
|
||||||
e1 = Self::Call(Node::new_unres(Box::new(e1), start.to(end)), vec![inner]);
|
e1 = Self::Call(Node::new(Box::new(e1), start.to(end)), args);
|
||||||
let Some(next2) = cursor.peek() else {
|
let Some(next2) = cursor.peek() else {
|
||||||
return Ok(e1);
|
return ParseResult::Ok(e1);
|
||||||
};
|
};
|
||||||
next = next2
|
next = next2
|
||||||
}
|
}
|
||||||
let end = cursor.prev_end();
|
let end = cursor.prev_end();
|
||||||
Ok(if let Some(mut op) = Operator::from_token(&next.token) {
|
let mut recover = false;
|
||||||
|
let res = if let Some(mut op) = BinaryOperator::from_token(&next.token) {
|
||||||
cursor.next();
|
cursor.next();
|
||||||
let mut n1 = Node::new_unres(e1, start.to(end)).bx();
|
let mut n1 = Node::new(e1, start.to(end)).bx();
|
||||||
let mut n2 = Node::parse(cursor, errors).bx();
|
let res = Node::parse(cursor, errors);
|
||||||
|
let mut n2 = res.node.bx();
|
||||||
|
recover = res.recover;
|
||||||
if let Ok(box Self::BinaryOp(op2, _, _)) = n2.as_ref() {
|
if let Ok(box Self::BinaryOp(op2, _, _)) = n2.as_ref() {
|
||||||
if op.presedence() > op2.presedence() {
|
if op.presedence() > op2.presedence() {
|
||||||
let Ok(box Self::BinaryOp(op2, n21, n22)) = n2.inner else {
|
let Ok(box Self::BinaryOp(op2, n21, n22)) = n2.inner else {
|
||||||
unreachable!();
|
unreachable!();
|
||||||
};
|
};
|
||||||
let end = n21.span.end;
|
let end = n21.span.end;
|
||||||
n1 = Node::new_unres(Self::BinaryOp(op, n1, n21), start.to(end)).bx();
|
n1 = Node::new(Self::BinaryOp(op, n1, n21), start.to(end)).bx();
|
||||||
op = op2;
|
op = op2;
|
||||||
n2 = n22;
|
n2 = n22;
|
||||||
}
|
}
|
||||||
@@ -99,7 +109,8 @@ impl Parsable for Expr<Unresolved> {
|
|||||||
Self::BinaryOp(op, n1, n2)
|
Self::BinaryOp(op, n1, n2)
|
||||||
} else {
|
} else {
|
||||||
e1
|
e1
|
||||||
})
|
};
|
||||||
|
ParseResult::from_recover(res, recover)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,6 +120,7 @@ impl Resolvable<Expr<Resolved>> for Expr<Unresolved> {
|
|||||||
Expr::Lit(l) => Expr::Lit(l.resolve()?),
|
Expr::Lit(l) => Expr::Lit(l.resolve()?),
|
||||||
Expr::Ident(n) => Expr::Ident(n),
|
Expr::Ident(n) => Expr::Ident(n),
|
||||||
Expr::BinaryOp(o, e1, e2) => Expr::BinaryOp(o, e1.resolve()?, e2.resolve()?),
|
Expr::BinaryOp(o, e1, e2) => Expr::BinaryOp(o, e1.resolve()?, e2.resolve()?),
|
||||||
|
Expr::UnaryOp(o, e) => Expr::UnaryOp(o, e.resolve()?),
|
||||||
Expr::Block(b) => Expr::Block(b.resolve()?),
|
Expr::Block(b) => Expr::Block(b.resolve()?),
|
||||||
Expr::Call(f, args) => Expr::Call(
|
Expr::Call(f, args) => Expr::Call(
|
||||||
f.resolve()?,
|
f.resolve()?,
|
||||||
@@ -148,6 +160,11 @@ impl Debug for Expr<Unresolved> {
|
|||||||
}
|
}
|
||||||
f.write_char(')')?;
|
f.write_char(')')?;
|
||||||
}
|
}
|
||||||
|
Expr::UnaryOp(op, e) => {
|
||||||
|
write!(f, "(")?;
|
||||||
|
write!(f, "{}", op.str())?;
|
||||||
|
write!(f, "{:?})", *e)?;
|
||||||
|
}
|
||||||
Expr::Group(inner) => inner.fmt(f)?,
|
Expr::Group(inner) => inner.fmt(f)?,
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
use super::{
|
use super::{
|
||||||
Body, Keyword, MaybeResolved, Node, Parsable, ParserError, ParserErrors, Resolvable, Resolved, Symbol, TokenCursor, Unresolved
|
Body, Keyword, MaybeResolved, Node, Parsable, ParseResult, ParserErrors, Resolvable, Resolved,
|
||||||
|
Symbol, TokenCursor, Unresolved,
|
||||||
};
|
};
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
@@ -9,13 +10,12 @@ pub struct Function<R: MaybeResolved> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Parsable for Function<Unresolved> {
|
impl Parsable for Function<Unresolved> {
|
||||||
fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> Result<Self, ParserError> {
|
fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> ParseResult<Self> {
|
||||||
cursor.expect_kw(Keyword::Fn)?;
|
cursor.expect_kw(Keyword::Fn)?;
|
||||||
let name = cursor.expect_ident()?;
|
let name = cursor.expect_ident()?;
|
||||||
cursor.expect_sym(Symbol::OpenParen)?;
|
cursor.expect_sym(Symbol::OpenParen)?;
|
||||||
cursor.expect_sym(Symbol::CloseParen)?;
|
cursor.expect_sym(Symbol::CloseParen)?;
|
||||||
let body = Node::parse(cursor, errors);
|
Node::parse(cursor, errors).map(|body| Self {name, body})
|
||||||
Ok(Self { name, body })
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,7 +33,7 @@ impl Resolvable<Function<Resolved>> for Function<Unresolved> {
|
|||||||
fn resolve(self) -> Result<Function<Resolved>, ()> {
|
fn resolve(self) -> Result<Function<Resolved>, ()> {
|
||||||
Ok(Function {
|
Ok(Function {
|
||||||
name: self.name,
|
name: self.name,
|
||||||
body: self.body.resolve()?
|
body: self.body.resolve()?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
17
src/parser/v1/nodes/mod.rs
Normal file
17
src/parser/v1/nodes/mod.rs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
mod body;
|
||||||
|
mod expr;
|
||||||
|
mod func;
|
||||||
|
mod module;
|
||||||
|
mod op;
|
||||||
|
mod statement;
|
||||||
|
mod val;
|
||||||
|
|
||||||
|
pub use body::*;
|
||||||
|
pub use expr::*;
|
||||||
|
pub use func::*;
|
||||||
|
pub use module::*;
|
||||||
|
pub use op::*;
|
||||||
|
pub use statement::*;
|
||||||
|
pub use val::*;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
use super::{
|
use super::{
|
||||||
func::Function, Keyword, MaybeResolved, Node, Parsable, ParserError, ParserErrors, Resolvable,
|
Function, Keyword, MaybeResolved, Node, Parsable, ParseResult, ParserError, ParserErrors,
|
||||||
Resolved, TokenCursor, Unresolved,
|
Resolvable, Resolved, TokenCursor, Unresolved,
|
||||||
};
|
};
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
@@ -9,14 +9,18 @@ pub struct Module<R: MaybeResolved> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Parsable for Module<Unresolved> {
|
impl Parsable for Module<Unresolved> {
|
||||||
fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> Result<Self, ParserError> {
|
fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> ParseResult<Self> {
|
||||||
let mut functions = Vec::new();
|
let mut functions = Vec::new();
|
||||||
loop {
|
loop {
|
||||||
let Some(next) = cursor.peek() else {
|
let Some(next) = cursor.peek() else {
|
||||||
return Ok(Self { functions });
|
return ParseResult::Ok(Self { functions });
|
||||||
};
|
};
|
||||||
if next.is_keyword(Keyword::Fn) {
|
if next.is_keyword(Keyword::Fn) {
|
||||||
functions.push(Node::parse(cursor, errors));
|
let res = Node::parse(cursor, errors);
|
||||||
|
functions.push(res.node);
|
||||||
|
if res.recover {
|
||||||
|
return ParseResult::Recover(Self { functions });
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
errors.add(ParserError::unexpected_token(next, "fn"));
|
errors.add(ParserError::unexpected_token(next, "fn"));
|
||||||
cursor.next();
|
cursor.next();
|
||||||
96
src/parser/v1/nodes/op.rs
Normal file
96
src/parser/v1/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;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
use std::fmt::{Debug, Write};
|
use std::fmt::{Debug, Write};
|
||||||
use super::{
|
use super::{
|
||||||
Expr, Keyword, MaybeResolved, Node, Parsable, ParserError, ParserErrors, Resolvable, Resolved,
|
Expr, Keyword, MaybeResolved, Node, Parsable, ParseResult, ParserErrors, Resolvable, Resolved, Symbol, Token, TokenCursor, Unresolved
|
||||||
Symbol, Token, TokenCursor, Unresolved,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub enum Statement<R: MaybeResolved> {
|
pub enum Statement<R: MaybeResolved> {
|
||||||
@@ -10,34 +9,22 @@ pub enum Statement<R: MaybeResolved> {
|
|||||||
Expr(Node<Expr<R>, R>),
|
Expr(Node<Expr<R>, R>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Statement<Unresolved> {
|
|
||||||
pub fn ended_with_error(&self) -> bool {
|
|
||||||
let expr = match self {
|
|
||||||
Statement::Let(_, e) => e,
|
|
||||||
Statement::Return(e) => e,
|
|
||||||
Statement::Expr(e) => e,
|
|
||||||
};
|
|
||||||
expr.is_err() || expr.as_ref().is_ok_and(|e| e.ended_with_error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Parsable for Statement<Unresolved> {
|
impl Parsable for Statement<Unresolved> {
|
||||||
fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> Result<Self, ParserError> {
|
fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> ParseResult<Self> {
|
||||||
let next = cursor.expect_peek()?;
|
let next = cursor.expect_peek()?;
|
||||||
Ok(match next.token {
|
match next.token {
|
||||||
Token::Keyword(Keyword::Let) => {
|
Token::Keyword(Keyword::Let) => {
|
||||||
cursor.next();
|
cursor.next();
|
||||||
let name = cursor.expect_ident()?;
|
let name = cursor.expect_ident()?;
|
||||||
cursor.expect_sym(Symbol::Equals)?;
|
cursor.expect_sym(Symbol::Equals)?;
|
||||||
let expr = Node::parse(cursor, errors);
|
Node::parse(cursor, errors).map(|expr| Self::Let(name, expr))
|
||||||
Self::Let(name, expr)
|
|
||||||
}
|
}
|
||||||
Token::Keyword(Keyword::Return) => {
|
Token::Keyword(Keyword::Return) => {
|
||||||
cursor.next();
|
cursor.next();
|
||||||
Self::Return(Node::parse(cursor, errors))
|
Node::parse(cursor, errors).map(Self::Return)
|
||||||
}
|
}
|
||||||
_ => Self::Expr(Node::parse(cursor, errors)),
|
_ => Node::parse(cursor, errors).map(Self::Expr),
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
use super::{Symbol, Token};
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
|
||||||
pub enum Operator {
|
|
||||||
Add,
|
|
||||||
Sub,
|
|
||||||
Mul,
|
|
||||||
Div,
|
|
||||||
LessThan,
|
|
||||||
GreaterThan,
|
|
||||||
Access,
|
|
||||||
Assign,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Operator {
|
|
||||||
pub fn presedence(&self) -> u32 {
|
|
||||||
match self {
|
|
||||||
Operator::Assign => 0,
|
|
||||||
Operator::LessThan => 1,
|
|
||||||
Operator::GreaterThan => 1,
|
|
||||||
Operator::Add => 2,
|
|
||||||
Operator::Sub => 3,
|
|
||||||
Operator::Mul => 4,
|
|
||||||
Operator::Div => 5,
|
|
||||||
Operator::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 => Operator::LessThan,
|
|
||||||
Symbol::CloseAngle => Operator::GreaterThan,
|
|
||||||
Symbol::Plus => Operator::Add,
|
|
||||||
Symbol::Minus => Operator::Sub,
|
|
||||||
Symbol::Asterisk => Operator::Mul,
|
|
||||||
Symbol::Slash => Operator::Div,
|
|
||||||
Symbol::Dot => Operator::Access,
|
|
||||||
Symbol::Equals => Operator::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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
189
src/parser/v1/parse.rs
Normal file
189
src/parser/v1/parse.rs
Normal file
@@ -0,0 +1,189 @@
|
|||||||
|
use std::{
|
||||||
|
convert::Infallible,
|
||||||
|
ops::{ControlFlow, FromResidual, Try},
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::{Node, ParserError, ParserErrors, TokenCursor, Unresolved};
|
||||||
|
|
||||||
|
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!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> ParseResult<T> {
|
||||||
|
pub fn map<U, F: FnOnce(T) -> U>(self, op: F) -> ParseResult<U> {
|
||||||
|
match self {
|
||||||
|
Self::Ok(v) => ParseResult::Ok(op(v)),
|
||||||
|
Self::Recover(v) => ParseResult::Recover(op(v)),
|
||||||
|
Self::Err(e) => ParseResult::Err(e),
|
||||||
|
Self::SubErr => ParseResult::SubErr,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct NodeParseResult<T> {
|
||||||
|
pub node: Node<T, Unresolved>,
|
||||||
|
pub recover: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> NodeParseResult<T> {
|
||||||
|
pub fn map<F: FnOnce(Node<T, Unresolved>) -> 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, Unresolved>;
|
||||||
|
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(residual: <Self as Try>::Residual) -> Self {
|
||||||
|
// ???
|
||||||
|
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, Unresolved> {
|
||||||
|
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) => (Ok(v), false),
|
||||||
|
ParseResult::Recover(v) => (Ok(v), true),
|
||||||
|
ParseResult::Err(e) => {
|
||||||
|
errors.add(e);
|
||||||
|
(Err(()), true)
|
||||||
|
}
|
||||||
|
ParseResult::SubErr => (Err(()), true),
|
||||||
|
};
|
||||||
|
let end = cursor.prev_end();
|
||||||
|
NodeParseResult {
|
||||||
|
node: Self {
|
||||||
|
inner,
|
||||||
|
span: start.to(end),
|
||||||
|
},
|
||||||
|
recover,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: MaybeParsable> Node<T, Unresolved> {
|
||||||
|
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) => Ok(v?),
|
||||||
|
Err(e) => {
|
||||||
|
errors.add(e);
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
};
|
||||||
|
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, Unresolved>::parse(cursor, errors)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -46,15 +46,6 @@ impl CharCursor<'_> {
|
|||||||
self.next_pos.col += 1;
|
self.next_pos.col += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn advance_if(&mut self, c: char) -> bool {
|
|
||||||
if let Some(c2) = self.peek() {
|
|
||||||
if c2 == c {
|
|
||||||
self.advance();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
|
||||||
pub fn expect_next(&mut self) -> Result<char, ParserError> {
|
pub fn expect_next(&mut self) -> Result<char, ParserError> {
|
||||||
self.next().ok_or(ParserError::unexpected_end())
|
self.next().ok_or(ParserError::unexpected_end())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,12 +16,4 @@ impl Keyword {
|
|||||||
_ => return None,
|
_ => return None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
pub const fn str(&self) -> &str {
|
|
||||||
match self {
|
|
||||||
Keyword::Fn => "fn",
|
|
||||||
Keyword::Let => "let",
|
|
||||||
Keyword::If => "if",
|
|
||||||
Keyword::Return => "return",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,10 @@ pub enum Symbol {
|
|||||||
SingleQuote,
|
SingleQuote,
|
||||||
DoubleQuote,
|
DoubleQuote,
|
||||||
Bang,
|
Bang,
|
||||||
|
Ampersand,
|
||||||
|
DoubleAmpersand,
|
||||||
|
Pipe,
|
||||||
|
DoublePipe,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Symbol {
|
impl Symbol {
|
||||||
@@ -59,6 +63,8 @@ impl Symbol {
|
|||||||
'\'' => Self::SingleQuote,
|
'\'' => Self::SingleQuote,
|
||||||
'"' => Self::DoubleQuote,
|
'"' => Self::DoubleQuote,
|
||||||
'!' => Self::Bang,
|
'!' => Self::Bang,
|
||||||
|
'&' => Self::Ampersand,
|
||||||
|
'|' => Self::Pipe,
|
||||||
_ => return None,
|
_ => return None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -79,10 +85,18 @@ impl Symbol {
|
|||||||
'=' => Self::DoubleEquals,
|
'=' => Self::DoubleEquals,
|
||||||
'>' => Self::DoubleArrow,
|
'>' => Self::DoubleArrow,
|
||||||
_ => return,
|
_ => return,
|
||||||
}
|
},
|
||||||
Self::Slash => match next {
|
Self::Slash => match next {
|
||||||
'/' => Self::DoubleSlash,
|
'/' => Self::DoubleSlash,
|
||||||
_ => return,
|
_ => return,
|
||||||
|
},
|
||||||
|
Self::Ampersand => match next {
|
||||||
|
'&' => Self::DoubleAmpersand,
|
||||||
|
_ => return,
|
||||||
|
}
|
||||||
|
Self::Pipe => match next {
|
||||||
|
'&' => Self::DoublePipe,
|
||||||
|
_ => return,
|
||||||
}
|
}
|
||||||
_ => return,
|
_ => return,
|
||||||
};
|
};
|
||||||
@@ -114,6 +128,10 @@ impl Symbol {
|
|||||||
Self::SingleQuote => "'",
|
Self::SingleQuote => "'",
|
||||||
Self::DoubleQuote => "\"",
|
Self::DoubleQuote => "\"",
|
||||||
Self::Bang => "!",
|
Self::Bang => "!",
|
||||||
|
Self::Ampersand => "&",
|
||||||
|
Self::DoubleAmpersand => "&&",
|
||||||
|
Self::Pipe => "|",
|
||||||
|
Self::DoublePipe => "||",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user