random spot with parser rewrite (still broken)
This commit is contained in:
@@ -4,7 +4,7 @@ use crate::common::FileID;
|
||||
|
||||
use super::{
|
||||
CompilerMsg, CompilerOutput, MaybeParsable, Node, NodeParseResult, Parsable, ParsableWith,
|
||||
TokenCursor,
|
||||
ParseResult, TokenCursor,
|
||||
};
|
||||
|
||||
pub struct ParserCtx<'a> {
|
||||
|
||||
+14
-14
@@ -1,7 +1,7 @@
|
||||
use super::{func::FnLowerCtx, FnLowerable, PExpr, UnaryOp};
|
||||
use super::{func::FnLowerCtx, FnLowerable, PExpr, PostfixOp};
|
||||
use crate::{
|
||||
ir::{FieldRef, Type, UData, UInstruction, VarInst},
|
||||
parser::PInfixOp,
|
||||
parser::InfixOp,
|
||||
};
|
||||
|
||||
impl FnLowerable for PExpr {
|
||||
@@ -56,13 +56,13 @@ impl FnLowerable for PExpr {
|
||||
},
|
||||
PExpr::Ident(i) => ctx.get_var(i)?,
|
||||
PExpr::BinaryOp(op, e1, e2) => match op {
|
||||
PInfixOp::Add => todo!(),
|
||||
PInfixOp::Sub => todo!(),
|
||||
PInfixOp::Mul => todo!(),
|
||||
PInfixOp::Div => todo!(),
|
||||
PInfixOp::LessThan => todo!(),
|
||||
PInfixOp::GreaterThan => todo!(),
|
||||
PInfixOp::Member => {
|
||||
InfixOp::Add => todo!(),
|
||||
InfixOp::Sub => todo!(),
|
||||
InfixOp::Mul => todo!(),
|
||||
InfixOp::Div => todo!(),
|
||||
InfixOp::LessThan => todo!(),
|
||||
InfixOp::GreaterThan => todo!(),
|
||||
InfixOp::Member => {
|
||||
let res1 = e1.lower(ctx)?;
|
||||
let Some(box PExpr::Ident(ident)) = &e2.inner else {
|
||||
ctx.err("Field accessors must be identifiers".to_string());
|
||||
@@ -74,7 +74,7 @@ impl FnLowerable for PExpr {
|
||||
name: fname,
|
||||
}))
|
||||
}
|
||||
PInfixOp::Assign => {
|
||||
InfixOp::Assign => {
|
||||
let res1 = e1.lower(ctx)?;
|
||||
let res2 = e2.lower(ctx)?;
|
||||
ctx.push(UInstruction::Mv {
|
||||
@@ -84,10 +84,10 @@ impl FnLowerable for PExpr {
|
||||
res1
|
||||
}
|
||||
},
|
||||
PExpr::UnaryOp(op, e) => {
|
||||
PExpr::PostfixOp(op, e) => {
|
||||
let res = e.lower(ctx)?;
|
||||
match op {
|
||||
UnaryOp::Ref => {
|
||||
PostfixOp::Ref => {
|
||||
let temp = ctx.temp(ctx.program.expect(res.id).ty.clone().rf());
|
||||
ctx.push(UInstruction::Ref {
|
||||
dest: temp,
|
||||
@@ -95,7 +95,7 @@ impl FnLowerable for PExpr {
|
||||
});
|
||||
temp
|
||||
}
|
||||
UnaryOp::Deref => {
|
||||
PostfixOp::Deref => {
|
||||
let t = &ctx.program.expect(res.id).ty;
|
||||
let Type::Ref(_) = t else {
|
||||
ctx.err(format!(
|
||||
@@ -106,7 +106,7 @@ impl FnLowerable for PExpr {
|
||||
};
|
||||
todo!();
|
||||
}
|
||||
UnaryOp::Not => todo!(),
|
||||
PostfixOp::Not => todo!(),
|
||||
}
|
||||
}
|
||||
PExpr::Block(b) => b.lower(ctx)?,
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
use crate::{
|
||||
common::{CompilerOutput, FileSpan},
|
||||
ir::{StructField, StructID, UInstruction, UProgram, UStruct, VarInst},
|
||||
parser::{Node, PConstruct, PConstructFields, PStruct, PStructFields},
|
||||
parser::{Node, PMap, PConstructFields, PStruct, PStructFields},
|
||||
};
|
||||
|
||||
use super::{FnLowerCtx, FnLowerable};
|
||||
|
||||
impl FnLowerable for PConstruct {
|
||||
impl FnLowerable for PMap {
|
||||
type Output = VarInst;
|
||||
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<VarInst> {
|
||||
let ty = self.name.lower(ctx.program, ctx.output);
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
use crate::{
|
||||
ir::{GenericID, StructTy, Type, UGeneric, UProgram, UStruct},
|
||||
ir::{StructInst, Type, TypeID, UGeneric, UProgram, UStruct},
|
||||
parser::PGenericDef,
|
||||
};
|
||||
|
||||
use super::{CompilerMsg, CompilerOutput, FileSpan, Node, PType};
|
||||
|
||||
impl Node<PType> {
|
||||
pub fn lower(&self, namespace: &mut UProgram, output: &mut CompilerOutput) -> Type {
|
||||
pub fn lower(&self, namespace: &mut UProgram, output: &mut CompilerOutput) -> TypeID {
|
||||
self.as_ref()
|
||||
.map(|t| t.lower(namespace, output, self.origin))
|
||||
.unwrap_or(Type::Error)
|
||||
@@ -14,17 +14,17 @@ impl Node<PType> {
|
||||
}
|
||||
|
||||
impl PType {
|
||||
pub fn lower(&self, p: &mut UProgram, output: &mut CompilerOutput, span: FileSpan) -> Type {
|
||||
pub fn lower(&self, p: &mut UProgram, output: &mut CompilerOutput, span: FileSpan) -> TypeID {
|
||||
let Some(name) = self.name.as_ref() else {
|
||||
return Type::Error;
|
||||
return p.error_type();
|
||||
};
|
||||
let ids = p.get_idents(name);
|
||||
// TODO: should generics always take precedence?
|
||||
if let Some(id) = ids.and_then(|ids| ids.get::<UGeneric>()) {
|
||||
if let Some(id) = ids.and_then(|ids| ids.get::<Type>()) {
|
||||
Type::Generic { id }
|
||||
} else if let Some(id) = ids.and_then(|ids| ids.get::<UStruct>()) {
|
||||
let args = self.args.iter().map(|n| n.lower(p, output)).collect();
|
||||
Type::Struct(StructTy { id, args })
|
||||
Type::Struct(StructInst { id, args })
|
||||
} else if let Ok(num) = name.parse::<u32>() {
|
||||
Type::Bits(num)
|
||||
} else {
|
||||
|
||||
+66
-61
@@ -3,10 +3,10 @@ use std::fmt::{Debug, Write};
|
||||
use crate::{common::FilePos, parser::NodeParsableWith};
|
||||
|
||||
use super::{
|
||||
op::{PInfixOp, UnaryOp},
|
||||
op::{InfixOp, PostfixOp},
|
||||
util::parse_list,
|
||||
CompilerMsg, Keyword, Node, PAsmBlock, PBlock, PConstruct, PIdent, PLiteral,
|
||||
Parsable, ParseResult, ParserCtx, Symbol,
|
||||
CompilerMsg, Keyword, Node, PAsmBlock, PBlock, PIdent, PLiteral, PMap, Parsable, ParseResult,
|
||||
ParserCtx, Symbol,
|
||||
};
|
||||
|
||||
type BoxNode = Node<Box<PExpr>>;
|
||||
@@ -14,13 +14,14 @@ type BoxNode = Node<Box<PExpr>>;
|
||||
pub enum PExpr {
|
||||
Lit(Node<PLiteral>),
|
||||
Ident(Node<PIdent>),
|
||||
BinaryOp(PInfixOp, BoxNode, BoxNode),
|
||||
UnaryOp(UnaryOp, BoxNode),
|
||||
BinaryOp(InfixOp, BoxNode, BoxNode),
|
||||
PostfixOp(BoxNode, PostfixOp),
|
||||
Block(Node<PBlock>),
|
||||
Call(BoxNode, Vec<Node<PExpr>>),
|
||||
Group(BoxNode),
|
||||
Access(BoxNode, Node<PIdent>),
|
||||
AsmBlock(Node<PAsmBlock>),
|
||||
Construct(Node<PConstruct>),
|
||||
Construct(BoxNode, Node<PMap>),
|
||||
If(BoxNode, BoxNode),
|
||||
Loop(BoxNode),
|
||||
Break,
|
||||
@@ -30,8 +31,58 @@ pub enum PExpr {
|
||||
impl Parsable for PExpr {
|
||||
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||
let start = ctx.next_start();
|
||||
let mut e1 = Self::parse_unit_postfix(ctx)?;
|
||||
while let Some(op) = ctx
|
||||
.peek()
|
||||
.map(|next| InfixOp::from_token(&next.token))
|
||||
.flatten()
|
||||
{
|
||||
let span = start.to(ctx.prev_end());
|
||||
ctx.next();
|
||||
let n2 = ctx.parse()?.bx();
|
||||
let (n1, op, n2) = fix_precedence(Node::new(e1, span).bx(), op, n2, start);
|
||||
e1 = Self::BinaryOp(op, n1, n2);
|
||||
}
|
||||
return ParseResult::Ok(e1);
|
||||
}
|
||||
}
|
||||
|
||||
impl PExpr {
|
||||
fn parse_unit_postfix(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||
let start = ctx.next_start();
|
||||
// first get unit
|
||||
let mut e1 = Self::parse_unit(ctx)?;
|
||||
// then apply post ops
|
||||
loop {
|
||||
let span = start.to(ctx.prev_end());
|
||||
let Some(next) = ctx.peek() else {
|
||||
break;
|
||||
};
|
||||
if next.is_symbol(Symbol::OpenParen) {
|
||||
ctx.next();
|
||||
let args = parse_list(ctx, Symbol::CloseParen)?;
|
||||
e1 = Self::Call(Node::new(e1, span).bx(), args);
|
||||
continue;
|
||||
} else if next.is_symbol(Symbol::OpenCurly) {
|
||||
let map = ctx.parse()?;
|
||||
e1 = Self::Construct(Node::new(e1, span).bx(), map);
|
||||
continue;
|
||||
} else if next.is_symbol(Symbol::Dot) {
|
||||
let field = ctx.parse()?;
|
||||
e1 = Self::Access(Node::new(e1, span).bx(), field);
|
||||
continue;
|
||||
} else if let Some(op) = PostfixOp::from_token(next) {
|
||||
ctx.next();
|
||||
e1 = Self::PostfixOp(Node::new(e1, span).bx(), op);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return ParseResult::Ok(e1);
|
||||
}
|
||||
fn parse_unit(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||
let next = ctx.expect_peek()?;
|
||||
let mut e1 = if next.is_symbol(Symbol::OpenParen) {
|
||||
return ParseResult::Ok(if next.is_symbol(Symbol::OpenParen) {
|
||||
ctx.next();
|
||||
if ctx.expect_peek()?.is_symbol(Symbol::CloseParen) {
|
||||
ctx.next();
|
||||
@@ -67,75 +118,28 @@ impl Parsable for PExpr {
|
||||
} else if next.is_keyword(Keyword::Asm) {
|
||||
ctx.next();
|
||||
Self::AsmBlock(ctx.parse()?)
|
||||
} else if let Some(op) = UnaryOp::from_token(next) {
|
||||
ctx.next();
|
||||
return ctx.parse().map(|n| {
|
||||
let n = n.bx();
|
||||
if let Some(box Self::BinaryOp(op2, n1, n2)) = n.inner {
|
||||
let span = start.to(n1.origin.end);
|
||||
Self::BinaryOp(op2, Node::new(Self::UnaryOp(op, n1), span).bx(), n2)
|
||||
} else {
|
||||
Self::UnaryOp(op, n)
|
||||
}
|
||||
});
|
||||
} else if let Some(val) = ctx.maybe_parse() {
|
||||
Self::Lit(val)
|
||||
} else {
|
||||
let res = ctx.parse();
|
||||
if res.node.is_some() {
|
||||
// TODO: this is extremely limiting
|
||||
// maybe parse generically and then during lowering figure out what's a function vs
|
||||
// struct vs etc like mentioned in main.rs
|
||||
if let Some(next) = ctx.peek()
|
||||
&& next.is_symbol(Symbol::OpenCurly)
|
||||
{
|
||||
Self::Construct(ctx.parse_with(res.node)?)
|
||||
} else {
|
||||
Self::Ident(res.node)
|
||||
}
|
||||
Self::Ident(res.node)
|
||||
} else {
|
||||
let next = ctx.expect_peek()?;
|
||||
return ParseResult::Err(CompilerMsg::unexpected_token(next, "an expression"));
|
||||
}
|
||||
};
|
||||
let Some(mut next) = ctx.peek() else {
|
||||
return ParseResult::Ok(e1);
|
||||
};
|
||||
while next.is_symbol(Symbol::OpenParen) {
|
||||
ctx.next();
|
||||
let args = parse_list(ctx, Symbol::CloseParen)?;
|
||||
let end = ctx.prev_end();
|
||||
e1 = Self::Call(Node::new(Box::new(e1), start.to(end)), args);
|
||||
let Some(next2) = ctx.peek() else {
|
||||
return ParseResult::Ok(e1);
|
||||
};
|
||||
next = next2
|
||||
}
|
||||
let end = ctx.prev_end();
|
||||
let mut recover = false;
|
||||
let res = if let Some(op) = PInfixOp::from_token(&next.token) {
|
||||
ctx.next();
|
||||
let n1 = Node::new(e1, start.to(end)).bx();
|
||||
let res = ctx.parse();
|
||||
let n2 = res.node.bx();
|
||||
recover = res.recover;
|
||||
let (n1, op, n2) = fix_precedence(n1, op, n2, start);
|
||||
Self::BinaryOp(op, n1, n2)
|
||||
} else {
|
||||
e1
|
||||
};
|
||||
ParseResult::from_recover(res, recover)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fix_precedence(
|
||||
mut n1: BoxNode,
|
||||
mut op: PInfixOp,
|
||||
mut op: InfixOp,
|
||||
mut n2: BoxNode,
|
||||
start: FilePos,
|
||||
) -> (BoxNode, PInfixOp, BoxNode) {
|
||||
) -> (BoxNode, InfixOp, BoxNode) {
|
||||
if let Some(box PExpr::BinaryOp(op2, _, _)) = n2.as_ref() {
|
||||
if op.precedence() >= op2.precedence() {
|
||||
if op.precedence() > op2.precedence() {
|
||||
let Some(box PExpr::BinaryOp(op2, n21, n22)) = n2.inner else {
|
||||
unreachable!();
|
||||
};
|
||||
@@ -176,14 +180,15 @@ impl Debug for PExpr {
|
||||
}
|
||||
f.write_char(')')?;
|
||||
}
|
||||
PExpr::UnaryOp(op, e) => write!(f, "({}{:?})", op.str(), e)?,
|
||||
PExpr::PostfixOp(e, op) => write!(f, "({:?}{})", e, op.str())?,
|
||||
PExpr::Group(inner) => inner.fmt(f)?,
|
||||
PExpr::AsmBlock(inner) => inner.fmt(f)?,
|
||||
PExpr::Construct(inner) => inner.fmt(f)?,
|
||||
PExpr::Construct(node, inner) => inner.fmt(f)?,
|
||||
PExpr::If(cond, res) => write!(f, "if {cond:?} then {res:?}")?,
|
||||
PExpr::Loop(res) => write!(f, "loop -> {res:?}")?,
|
||||
PExpr::Break => write!(f, "break")?,
|
||||
PExpr::Continue => write!(f, "continue")?,
|
||||
PExpr::Access(e1, name) => write!(f, "{:?}.{:?}", e1, name)?,
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
use super::{Symbol, Token};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub enum PInfixOp {
|
||||
pub enum InfixOp {
|
||||
Add,
|
||||
Sub,
|
||||
Mul,
|
||||
Div,
|
||||
LessThan,
|
||||
GreaterThan,
|
||||
Member,
|
||||
Assign,
|
||||
}
|
||||
|
||||
impl PInfixOp {
|
||||
impl InfixOp {
|
||||
pub fn precedence(&self) -> u32 {
|
||||
match self {
|
||||
Self::Assign => 0,
|
||||
@@ -22,7 +21,6 @@ impl PInfixOp {
|
||||
Self::Sub => 3,
|
||||
Self::Mul => 4,
|
||||
Self::Div => 5,
|
||||
Self::Member => 6,
|
||||
}
|
||||
}
|
||||
pub fn str(&self) -> &str {
|
||||
@@ -33,7 +31,6 @@ impl PInfixOp {
|
||||
Self::Div => "/",
|
||||
Self::LessThan => "<",
|
||||
Self::GreaterThan => ">",
|
||||
Self::Member => ".",
|
||||
Self::Assign => "=",
|
||||
}
|
||||
}
|
||||
@@ -45,19 +42,18 @@ impl PInfixOp {
|
||||
Self::Div => true,
|
||||
Self::LessThan => true,
|
||||
Self::GreaterThan => true,
|
||||
Self::Member => false,
|
||||
Self::Assign => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum UnaryOp {
|
||||
pub enum PostfixOp {
|
||||
Not,
|
||||
Ref,
|
||||
Deref,
|
||||
}
|
||||
|
||||
impl PInfixOp {
|
||||
impl InfixOp {
|
||||
pub fn from_token(token: &Token) -> Option<Self> {
|
||||
let Token::Symbol(symbol) = token else {
|
||||
return None;
|
||||
@@ -69,7 +65,6 @@ impl PInfixOp {
|
||||
Symbol::Minus => Self::Sub,
|
||||
Symbol::Asterisk => Self::Mul,
|
||||
Symbol::Slash => Self::Div,
|
||||
Symbol::Dot => Self::Member,
|
||||
Symbol::Equals => Self::Assign,
|
||||
_ => {
|
||||
return None;
|
||||
@@ -78,11 +73,11 @@ impl PInfixOp {
|
||||
}
|
||||
}
|
||||
|
||||
impl UnaryOp {
|
||||
impl PostfixOp {
|
||||
pub fn str(&self) -> &str {
|
||||
match self {
|
||||
Self::Not => "!",
|
||||
Self::Ref => "&",
|
||||
Self::Ref => "@",
|
||||
Self::Deref => "*",
|
||||
}
|
||||
}
|
||||
@@ -91,7 +86,7 @@ impl UnaryOp {
|
||||
return None;
|
||||
};
|
||||
Some(match symbol {
|
||||
Symbol::Ampersand => Self::Ref,
|
||||
Symbol::At => Self::Ref,
|
||||
Symbol::Bang => Self::Not,
|
||||
Symbol::Asterisk => Self::Deref,
|
||||
_ => {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use std::fmt::Debug;
|
||||
use std::fmt::{Debug, Write};
|
||||
|
||||
use crate::parser::ParsableWith;
|
||||
use crate::{parser::ParsableWith, util::Padder};
|
||||
|
||||
use super::{
|
||||
util::parse_list, CompilerMsg, Keyword, Node, PExpr, PFieldDef, PIdent, PType, PGenericDef,
|
||||
PVarDef, Parsable, ParseResult, ParserCtx, Symbol,
|
||||
util::parse_list, CompilerMsg, Node, PFieldDef, PGenericDef, PIdent, PType, PVarDef, Parsable,
|
||||
ParseResult, ParserCtx, Symbol,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -14,11 +14,7 @@ pub struct PStruct {
|
||||
pub fields: PStructFields,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PConstruct {
|
||||
pub name: Node<PType>,
|
||||
pub fields: PConstructFields,
|
||||
}
|
||||
pub struct PMap(Vec<Node<PFieldDef>>);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum PStructFields {
|
||||
@@ -27,13 +23,6 @@ pub enum PStructFields {
|
||||
None,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum PConstructFields {
|
||||
Named(Vec<Node<PFieldDef>>),
|
||||
Tuple(Vec<Node<PExpr>>),
|
||||
None,
|
||||
}
|
||||
|
||||
impl Parsable for PStruct {
|
||||
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||
let name = ctx.parse()?;
|
||||
@@ -64,41 +53,29 @@ impl Parsable for PStruct {
|
||||
fields: PStructFields::None,
|
||||
});
|
||||
};
|
||||
ParseResult::Ok(PStruct { name, generics: args, fields })
|
||||
ParseResult::Ok(PStruct {
|
||||
name,
|
||||
generics: args,
|
||||
fields,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ParsableWith for PConstruct {
|
||||
type Data = Node<PIdent>;
|
||||
fn parse(ctx: &mut ParserCtx, name_node: Self::Data) -> ParseResult<Self> {
|
||||
let next = ctx.expect_peek()?;
|
||||
// TODO: this is not correct span; type should also span generics, which aren't even in
|
||||
// here yet
|
||||
let span = name_node.origin;
|
||||
let name = Node::new(
|
||||
PType {
|
||||
name: name_node,
|
||||
args: Vec::new(),
|
||||
},
|
||||
span,
|
||||
);
|
||||
let fields = if next.is_symbol(Symbol::Semicolon) {
|
||||
ctx.next();
|
||||
PConstructFields::None
|
||||
} else if next.is_symbol(Symbol::OpenCurly) {
|
||||
ctx.next();
|
||||
PConstructFields::Named(parse_list(ctx, Symbol::CloseCurly)?)
|
||||
} else if next.is_symbol(Symbol::OpenParen) {
|
||||
ctx.next();
|
||||
PConstructFields::Tuple(parse_list(ctx, Symbol::CloseParen)?)
|
||||
} else {
|
||||
let msg = CompilerMsg::unexpected_token(next, "`;`, `(`, or `{`");
|
||||
ctx.err(msg);
|
||||
return ParseResult::Recover(PConstruct {
|
||||
name,
|
||||
fields: PConstructFields::None,
|
||||
});
|
||||
};
|
||||
ParseResult::Ok(PConstruct { name, fields })
|
||||
impl Parsable for PMap {
|
||||
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||
ctx.expect_sym(Symbol::OpenCurly);
|
||||
ParseResult::Ok(Self(parse_list(ctx, Symbol::CloseCurly)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for PMap {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
writeln!(f, "{{")?;
|
||||
let mut padder = Padder::new(f);
|
||||
for arg in &self.0 {
|
||||
padder.write_str(&format!("{arg:?},\n"))?;
|
||||
}
|
||||
writeln!(f, "}}")?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,7 +133,10 @@ impl<T: Parsable> ParsableWith for T {
|
||||
|
||||
impl<T: ParsableWith> Node<T> {
|
||||
pub fn parse_with(ctx: &mut ParserCtx, data: T::Data) -> NodeParseResult<T> {
|
||||
let start = ctx.peek().map(|t| t.span.start).unwrap_or(FilePos::start(ctx.cursor.file()));
|
||||
let start = ctx
|
||||
.peek()
|
||||
.map(|t| t.span.start)
|
||||
.unwrap_or(FilePos::start(ctx.cursor.file()));
|
||||
let (inner, recover) = match T::parse(ctx, data) {
|
||||
ParseResult::Ok(v) => (Some(v), false),
|
||||
ParseResult::Recover(v) => (Some(v), true),
|
||||
|
||||
@@ -35,6 +35,7 @@ pub enum Symbol {
|
||||
DoublePipe,
|
||||
Comma,
|
||||
Hash,
|
||||
At,
|
||||
}
|
||||
|
||||
impl Symbol {
|
||||
@@ -70,6 +71,7 @@ impl Symbol {
|
||||
'|' => Self::Pipe,
|
||||
',' => Self::Comma,
|
||||
'#' => Self::Hash,
|
||||
'@' => Self::At,
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
@@ -144,6 +146,7 @@ impl Symbol {
|
||||
Self::Pipe => "|",
|
||||
Self::DoublePipe => "||",
|
||||
Self::Hash => "#",
|
||||
Self::At => "@",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user