Add OR support for filters
This commit is contained in:
parent
d23495a5ef
commit
592a5d035b
6 changed files with 221 additions and 18 deletions
|
@ -33,7 +33,7 @@ impl MpsLanguageError for SyntaxError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct RuntimeError {
|
pub struct RuntimeError {
|
||||||
pub line: usize,
|
pub line: usize,
|
||||||
pub op: PseudoOp,
|
pub op: PseudoOp,
|
||||||
|
|
|
@ -7,12 +7,15 @@ use crate::lang::utility::{assert_token, assert_token_raw};
|
||||||
use crate::lang::MpsLanguageDictionary;
|
use crate::lang::MpsLanguageDictionary;
|
||||||
use crate::lang::{BoxedMpsOpFactory, MpsOp, PseudoOp};
|
use crate::lang::{BoxedMpsOpFactory, MpsOp, PseudoOp};
|
||||||
use crate::lang::{RuntimeError, SyntaxError};
|
use crate::lang::{RuntimeError, SyntaxError};
|
||||||
|
use crate::lang::SingleItem;
|
||||||
use crate::processing::general::MpsType;
|
use crate::processing::general::MpsType;
|
||||||
use crate::processing::OpGetter;
|
use crate::processing::OpGetter;
|
||||||
use crate::tokens::MpsToken;
|
use crate::tokens::MpsToken;
|
||||||
use crate::MpsContext;
|
use crate::MpsContext;
|
||||||
use crate::MpsMusicItem;
|
use crate::MpsMusicItem;
|
||||||
|
|
||||||
|
const INNER_VARIABLE_NAME: &str = "[inner variable]";
|
||||||
|
|
||||||
pub trait MpsFilterPredicate: Clone + Debug + Display {
|
pub trait MpsFilterPredicate: Clone + Debug + Display {
|
||||||
fn matches(
|
fn matches(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -56,6 +59,7 @@ pub struct MpsFilterStatement<P: MpsFilterPredicate + 'static> {
|
||||||
predicate: P,
|
predicate: P,
|
||||||
iterable: VariableOrOp,
|
iterable: VariableOrOp,
|
||||||
context: Option<MpsContext>,
|
context: Option<MpsContext>,
|
||||||
|
other_filters: Option<PseudoOp>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P: MpsFilterPredicate + 'static> std::clone::Clone for MpsFilterStatement<P> {
|
impl<P: MpsFilterPredicate + 'static> std::clone::Clone for MpsFilterStatement<P> {
|
||||||
|
@ -64,6 +68,7 @@ impl<P: MpsFilterPredicate + 'static> std::clone::Clone for MpsFilterStatement<P
|
||||||
predicate: self.predicate.clone(),
|
predicate: self.predicate.clone(),
|
||||||
iterable: self.iterable.clone(),
|
iterable: self.iterable.clone(),
|
||||||
context: None,
|
context: None,
|
||||||
|
other_filters: self.other_filters.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -134,7 +139,7 @@ impl<P: MpsFilterPredicate + 'static> Iterator for MpsFilterStatement<P> {
|
||||||
type Item = Result<MpsMusicItem, RuntimeError>;
|
type Item = Result<MpsMusicItem, RuntimeError>;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
if self.predicate.is_complete() {
|
if self.predicate.is_complete() && self.other_filters.is_none() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let self_clone = self.clone();
|
let self_clone = self.clone();
|
||||||
|
@ -155,7 +160,7 @@ impl<P: MpsFilterPredicate + 'static> Iterator for MpsFilterStatement<P> {
|
||||||
maybe_result = Some(Err(e));
|
maybe_result = Some(Err(e));
|
||||||
self.context = Some(ctx);
|
self.context = Some(ctx);
|
||||||
break;
|
break;
|
||||||
}
|
},
|
||||||
Ok(item) => {
|
Ok(item) => {
|
||||||
let matches_result =
|
let matches_result =
|
||||||
self.predicate.matches(&item, &mut ctx, &mut op_getter);
|
self.predicate.matches(&item, &mut ctx, &mut op_getter);
|
||||||
|
@ -167,6 +172,58 @@ impl<P: MpsFilterPredicate + 'static> Iterator for MpsFilterStatement<P> {
|
||||||
}
|
}
|
||||||
Ok(b) => b,
|
Ok(b) => b,
|
||||||
};
|
};
|
||||||
|
if let Some(inner) = &mut self.other_filters {
|
||||||
|
// handle other filters
|
||||||
|
// make fake inner item
|
||||||
|
let single_op = SingleItem::new_ok(item.clone());
|
||||||
|
match ctx.variables.declare(INNER_VARIABLE_NAME, MpsType::Op(Box::new(single_op)), &mut op_getter) {
|
||||||
|
Ok(x) => x,
|
||||||
|
Err(e) => {
|
||||||
|
//self.context = Some(op.escape());
|
||||||
|
maybe_result = Some(Err(e));
|
||||||
|
self.context = Some(ctx);
|
||||||
|
break;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let inner_real = match inner.try_real() {
|
||||||
|
Ok(x) => x,
|
||||||
|
Err(e) => {
|
||||||
|
//self.context = Some(op.escape());
|
||||||
|
maybe_result = Some(Err(e));
|
||||||
|
self.context = Some(ctx);
|
||||||
|
break;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
inner_real.enter(ctx);
|
||||||
|
match inner_real.next() {
|
||||||
|
Some(item) => {
|
||||||
|
maybe_result = Some(item);
|
||||||
|
ctx = inner_real.escape();
|
||||||
|
match ctx.variables.remove(INNER_VARIABLE_NAME, &mut op_getter) {
|
||||||
|
Ok(_) => {},
|
||||||
|
Err(e) => match maybe_result {
|
||||||
|
Some(Ok(_)) => maybe_result = Some(Err(e)),
|
||||||
|
Some(Err(e2)) => maybe_result = Some(Err(e2)), // already failing, do not replace error,
|
||||||
|
None => {}, // impossible
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.context = Some(ctx);
|
||||||
|
break;
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
ctx = inner_real.escape(); // move ctx back to expected spot
|
||||||
|
match ctx.variables.remove(INNER_VARIABLE_NAME, &mut op_getter) {
|
||||||
|
Ok(_) => {},
|
||||||
|
Err(e) => {
|
||||||
|
//self.context = Some(op.escape());
|
||||||
|
maybe_result = Some(Err(e));
|
||||||
|
self.context = Some(ctx);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if matches {
|
if matches {
|
||||||
//self.context = Some(op.escape());
|
//self.context = Some(op.escape());
|
||||||
maybe_result = Some(Ok(item));
|
maybe_result = Some(Ok(item));
|
||||||
|
@ -281,9 +338,16 @@ impl<P: MpsFilterPredicate + 'static, F: MpsFilterFactory<P> + 'static> BoxedMps
|
||||||
if start_of_predicate > tokens_len - 1 {
|
if start_of_predicate > tokens_len - 1 {
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
let tokens2: VecDeque<&MpsToken> =
|
if let Some(pipe_location) = first_double_pipe(tokens) {
|
||||||
VecDeque::from_iter(tokens.range(start_of_predicate..tokens_len - 1));
|
let tokens2: VecDeque<&MpsToken> =
|
||||||
self.filter_factory.is_filter(&tokens2)
|
VecDeque::from_iter(tokens.range(start_of_predicate..pipe_location));
|
||||||
|
self.filter_factory.is_filter(&tokens2)
|
||||||
|
} else {
|
||||||
|
let tokens2: VecDeque<&MpsToken> =
|
||||||
|
VecDeque::from_iter(tokens.range(start_of_predicate..tokens_len - 1));
|
||||||
|
self.filter_factory.is_filter(&tokens2)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
|
@ -318,13 +382,31 @@ impl<P: MpsFilterPredicate + 'static, F: MpsFilterFactory<P> + 'static> BoxedMps
|
||||||
}
|
}
|
||||||
assert_token_raw(MpsToken::Dot, tokens)?;
|
assert_token_raw(MpsToken::Dot, tokens)?;
|
||||||
assert_token_raw(MpsToken::OpenBracket, tokens)?;
|
assert_token_raw(MpsToken::OpenBracket, tokens)?;
|
||||||
let mut end_tokens = tokens.split_off(tokens.len()-1); // don't parse closing bracket in filter
|
let mut another_filter = None;
|
||||||
|
let (has_or, end_tokens) = if let Some(pipe_location) = first_double_pipe(tokens) {
|
||||||
|
(true, tokens.split_off(pipe_location)) // parse up to OR operator
|
||||||
|
} else {
|
||||||
|
(false, tokens.split_off(tokens.len()-1)) // don't parse closing bracket in filter
|
||||||
|
};
|
||||||
let filter = self.filter_factory.build_filter(tokens, dict)?;
|
let filter = self.filter_factory.build_filter(tokens, dict)?;
|
||||||
assert_token_raw(MpsToken::CloseBracket, &mut end_tokens)?;
|
tokens.extend(end_tokens);
|
||||||
|
if has_or {
|
||||||
|
// recursively build other filters for OR operation
|
||||||
|
assert_token_raw(MpsToken::Pipe, tokens)?;
|
||||||
|
assert_token_raw(MpsToken::Pipe, tokens)?;
|
||||||
|
// emit fake filter syntax
|
||||||
|
tokens.push_front(MpsToken::OpenBracket);
|
||||||
|
tokens.push_front(MpsToken::Dot);
|
||||||
|
tokens.push_front(MpsToken::Name(INNER_VARIABLE_NAME.into())); // impossible to obtain through parsing on purpose
|
||||||
|
another_filter = Some(dict.try_build_statement(tokens)?.into());
|
||||||
|
} else {
|
||||||
|
assert_token_raw(MpsToken::CloseBracket, tokens)?; // remove closing bracket
|
||||||
|
}
|
||||||
Ok(Box::new(MpsFilterStatement {
|
Ok(Box::new(MpsFilterStatement {
|
||||||
predicate: filter,
|
predicate: filter,
|
||||||
iterable: op,
|
iterable: op,
|
||||||
context: None,
|
context: None,
|
||||||
|
other_filters: another_filter,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -360,3 +442,19 @@ fn last_dot_before_open_bracket(tokens: &VecDeque<MpsToken>) -> usize {
|
||||||
}
|
}
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn first_double_pipe(tokens: &VecDeque<MpsToken>) -> Option<usize> {
|
||||||
|
let mut pipe_found = false;
|
||||||
|
for i in 0..tokens.len() {
|
||||||
|
if tokens[i].is_pipe() {
|
||||||
|
if pipe_found {
|
||||||
|
return Some(i-1);
|
||||||
|
} else {
|
||||||
|
pipe_found = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pipe_found = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ mod lookup;
|
||||||
mod operation;
|
mod operation;
|
||||||
mod pseudo_op;
|
mod pseudo_op;
|
||||||
mod repeated_meme;
|
mod repeated_meme;
|
||||||
|
mod single_op;
|
||||||
//mod statement;
|
//mod statement;
|
||||||
mod type_primitives;
|
mod type_primitives;
|
||||||
pub(crate) mod utility;
|
pub(crate) mod utility;
|
||||||
|
@ -21,6 +22,7 @@ pub use lookup::Lookup;
|
||||||
pub use operation::{BoxedMpsOpFactory, MpsOp, MpsOpFactory, SimpleMpsOpFactory};
|
pub use operation::{BoxedMpsOpFactory, MpsOp, MpsOpFactory, SimpleMpsOpFactory};
|
||||||
pub use pseudo_op::PseudoOp;
|
pub use pseudo_op::PseudoOp;
|
||||||
pub use repeated_meme::{repeated_tokens, RepeatedTokens};
|
pub use repeated_meme::{repeated_tokens, RepeatedTokens};
|
||||||
|
pub use single_op::SingleItem;
|
||||||
//pub(crate) use statement::MpsStatement;
|
//pub(crate) use statement::MpsStatement;
|
||||||
pub use type_primitives::MpsTypePrimitive;
|
pub use type_primitives::MpsTypePrimitive;
|
||||||
|
|
||||||
|
|
82
mps-interpreter/src/lang/single_op.rs
Normal file
82
mps-interpreter/src/lang/single_op.rs
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
use std::fmt::{Debug, Display, Error, Formatter};
|
||||||
|
use std::iter::Iterator;
|
||||||
|
|
||||||
|
use crate::lang::{MpsOp, RuntimeError};
|
||||||
|
use crate::MpsContext;
|
||||||
|
use crate::MpsMusicItem;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct SingleItem {
|
||||||
|
context: Option<MpsContext>,
|
||||||
|
item: Result<MpsMusicItem, RuntimeError>,
|
||||||
|
is_complete: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SingleItem {
|
||||||
|
pub fn new(item: Result<MpsMusicItem, RuntimeError>) -> Self {
|
||||||
|
Self {
|
||||||
|
context: None,
|
||||||
|
item: item,
|
||||||
|
is_complete: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_ok(item: MpsMusicItem) -> Self {
|
||||||
|
Self::new(Ok(item))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn replace(&mut self, new_item: Result<MpsMusicItem, RuntimeError>) {
|
||||||
|
self.item = new_item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for SingleItem {
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||||
|
match &self.item {
|
||||||
|
Ok(item) => write!(f, "*single item*[Ok({})]", item.filename),
|
||||||
|
Err(e) => write!(f, "*single-item*[Err({})]", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::clone::Clone for SingleItem {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self {
|
||||||
|
context: None,
|
||||||
|
item: self.item.clone(),
|
||||||
|
is_complete: self.is_complete,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Iterator for SingleItem {
|
||||||
|
type Item = Result<MpsMusicItem, RuntimeError>;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
if self.is_complete {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
self.is_complete = true;
|
||||||
|
Some(self.item.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MpsOp for SingleItem {
|
||||||
|
fn enter(&mut self, ctx: MpsContext) {
|
||||||
|
self.context = Some(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn escape(&mut self) -> MpsContext {
|
||||||
|
self.context.take().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_resetable(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reset(&mut self) -> Result<(), RuntimeError> {
|
||||||
|
self.is_complete = false;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,6 +17,8 @@ pub enum MpsToken {
|
||||||
Dot,
|
Dot,
|
||||||
Exclamation,
|
Exclamation,
|
||||||
Interrogation,
|
Interrogation,
|
||||||
|
Pipe,
|
||||||
|
Ampersand,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MpsToken {
|
impl MpsToken {
|
||||||
|
@ -34,10 +36,12 @@ impl MpsToken {
|
||||||
"." => Ok(Self::Dot),
|
"." => Ok(Self::Dot),
|
||||||
"!" => Ok(Self::Exclamation),
|
"!" => Ok(Self::Exclamation),
|
||||||
"?" => Ok(Self::Interrogation),
|
"?" => Ok(Self::Interrogation),
|
||||||
|
"|" => Ok(Self::Pipe),
|
||||||
|
"&" => Ok(Self::Ampersand),
|
||||||
_ => {
|
_ => {
|
||||||
// name validation
|
// name validation
|
||||||
let mut ok = true;
|
let mut ok = true;
|
||||||
for invalid_c in ["-", "+", ",", " ", "/", "\n", "\r", "!", "?", "=", "."] {
|
for invalid_c in ["-", "+", ",", " ", "/", "\n", "\r", "!", "?", "=", ".", "&", "|"] {
|
||||||
if s.contains(invalid_c) {
|
if s.contains(invalid_c) {
|
||||||
ok = false;
|
ok = false;
|
||||||
break;
|
break;
|
||||||
|
@ -156,6 +160,20 @@ impl MpsToken {
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_pipe(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Self::Pipe => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_ampersand(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Self::Ampersand => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for MpsToken {
|
impl Display for MpsToken {
|
||||||
|
@ -176,6 +194,8 @@ impl Display for MpsToken {
|
||||||
Self::Dot => write!(f, "."),
|
Self::Dot => write!(f, "."),
|
||||||
Self::Exclamation => write!(f, "!"),
|
Self::Exclamation => write!(f, "!"),
|
||||||
Self::Interrogation => write!(f, "?"),
|
Self::Interrogation => write!(f, "?"),
|
||||||
|
Self::Pipe => write!(f, "|"),
|
||||||
|
Self::Ampersand => write!(f, "&"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,7 +79,7 @@ where
|
||||||
.map_err(|e| self.error(format!("UTF-8 encoding error: {}", e)))?;
|
.map_err(|e| self.error(format!("UTF-8 encoding error: {}", e)))?;
|
||||||
buf.push_back(
|
buf.push_back(
|
||||||
MpsToken::parse_from_string(token)
|
MpsToken::parse_from_string(token)
|
||||||
.map_err(|e| self.error(format!("Invalid token {}", e)))?,
|
.map_err(|e| self.error(format!("invalid token `{}`", e)))?,
|
||||||
);
|
);
|
||||||
bigger_buf.clear();
|
bigger_buf.clear();
|
||||||
}
|
}
|
||||||
|
@ -92,7 +92,7 @@ where
|
||||||
.map_err(|e| self.error(format!("UTF-8 encoding error: {}", e)))?;
|
.map_err(|e| self.error(format!("UTF-8 encoding error: {}", e)))?;
|
||||||
buf.push_back(
|
buf.push_back(
|
||||||
MpsToken::parse_from_string(token)
|
MpsToken::parse_from_string(token)
|
||||||
.map_err(|e| self.error(format!("Invalid token {}", e)))?,
|
.map_err(|e| self.error(format!("invalid token `{}`", e)))?,
|
||||||
);
|
);
|
||||||
bigger_buf.clear();
|
bigger_buf.clear();
|
||||||
}
|
}
|
||||||
|
@ -102,7 +102,7 @@ where
|
||||||
.map_err(|e| self.error(format!("UTF-8 encoding error: {}", e)))?;
|
.map_err(|e| self.error(format!("UTF-8 encoding error: {}", e)))?;
|
||||||
buf.push_back(
|
buf.push_back(
|
||||||
MpsToken::parse_from_string(token)
|
MpsToken::parse_from_string(token)
|
||||||
.map_err(|e| self.error(format!("Invalid token {}", e)))?,
|
.map_err(|e| self.error(format!("invalid token `{}`", e)))?,
|
||||||
);
|
);
|
||||||
bigger_buf.clear();
|
bigger_buf.clear();
|
||||||
}
|
}
|
||||||
|
@ -146,7 +146,7 @@ where
|
||||||
.map_err(|e| self.error(format!("UTF-8 encoding error: {}", e)))?;
|
.map_err(|e| self.error(format!("UTF-8 encoding error: {}", e)))?;
|
||||||
buf.push_back(
|
buf.push_back(
|
||||||
MpsToken::parse_from_string(token)
|
MpsToken::parse_from_string(token)
|
||||||
.map_err(|e| self.error(format!("invalid token {}", e)))?,
|
.map_err(|e| self.error(format!("invalid token `{}`", e)))?,
|
||||||
);
|
);
|
||||||
bigger_buf.clear();
|
bigger_buf.clear();
|
||||||
}
|
}
|
||||||
|
@ -158,7 +158,7 @@ where
|
||||||
if input as char == '\n' {
|
if input as char == '\n' {
|
||||||
self.line += 1;
|
self.line += 1;
|
||||||
self.column = 0;
|
self.column = 0;
|
||||||
} else {
|
} else if input != 0 {
|
||||||
self.column += 1; // TODO correctly track columns with utf-8 characters longer than one byte
|
self.column += 1; // TODO correctly track columns with utf-8 characters longer than one byte
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -182,6 +182,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn current_column(&self) -> usize {
|
fn current_column(&self) -> usize {
|
||||||
|
println!("Current column: {}", self.column);
|
||||||
self.column
|
self.column
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -257,10 +258,10 @@ impl ReaderStateMachine {
|
||||||
'#' => Self::Octothorpe { out: input },
|
'#' => Self::Octothorpe { out: input },
|
||||||
'`' => Self::StartTickLiteral {},
|
'`' => Self::StartTickLiteral {},
|
||||||
'"' => Self::StartQuoteLiteral {},
|
'"' => Self::StartQuoteLiteral {},
|
||||||
' ' => Self::EndToken {},
|
'\n'| '\r' | '\t' | ' ' => Self::EndToken {},
|
||||||
'\n' | ';' => Self::EndStatement {},
|
';' => Self::EndStatement {},
|
||||||
'\0' => Self::EndOfFile {},
|
'\0' => Self::EndOfFile {},
|
||||||
'(' | ')' | ',' | '=' | '<' | '>' | '.' | '!' | '?' => Self::SingleCharToken { out: input },
|
'(' | ')' | ',' | '=' | '<' | '>' | '.' | '!' | '?' | '|' => Self::SingleCharToken { out: input },
|
||||||
_ => Self::Regular { out: input },
|
_ => Self::Regular { out: input },
|
||||||
},
|
},
|
||||||
Self::Escaped { inside } => match inside {
|
Self::Escaped { inside } => match inside {
|
||||||
|
@ -284,7 +285,7 @@ impl ReaderStateMachine {
|
||||||
'/' => Self::Comment { out: input },
|
'/' => Self::Comment { out: input },
|
||||||
' ' => Self::EndToken {},
|
' ' => Self::EndToken {},
|
||||||
'\0' => Self::EndOfFile {},
|
'\0' => Self::EndOfFile {},
|
||||||
'\n' | ';' => Self::EndStatement {},
|
';' => Self::EndStatement {},
|
||||||
_ => Self::Regular { out: input },
|
_ => Self::Regular { out: input },
|
||||||
},
|
},
|
||||||
Self::Octothorpe { .. } => match input_char {
|
Self::Octothorpe { .. } => match input_char {
|
||||||
|
|
Loading…
Reference in a new issue