use crate::error::Error;
use crate::slab::ParseSlab;
use std::ptr;
use std::str::{from_utf8, from_utf8_unchecked};
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub struct ExpressionI(pub usize);
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub struct ValueI(pub usize);
#[derive(Debug, PartialEq, Default)]
pub struct Expression {
pub(crate) first: Value,
pub(crate) pairs: Vec<ExprPair>, }
#[derive(Debug, PartialEq)]
pub(crate) struct ExprPair(pub(crate) BinaryOp, pub(crate) Value);
#[derive(Debug, PartialEq)]
pub enum Value {
EConstant(f64),
EUnaryOp(UnaryOp),
EStdFunc(StdFunc),
EPrintFunc(PrintFunc),
}
use self::Value::{EConstant, EPrintFunc, EStdFunc, EUnaryOp};
#[derive(Debug, PartialEq, Eq)]
pub enum UnaryOp {
EPos(ValueI),
ENeg(ValueI),
ENot(ValueI),
EParentheses(ExpressionI),
}
use self::UnaryOp::{ENeg, ENot, EParentheses, EPos};
#[derive(Debug, PartialEq, Eq, PartialOrd, Copy, Clone)]
pub enum BinaryOp {
EOR = 1, EAND = 2,
ENE = 3,
EEQ = 4,
EGTE = 5,
ELTE = 6,
EGT = 7,
ELT = 8,
EAdd = 9,
ESub = 10,
EMul = 11,
EDiv = 12,
EMod = 13,
EExp = 14, }
use self::BinaryOp::{EAdd, EDiv, EExp, EMod, EMul, ESub, EAND, EEQ, EGT, EGTE, ELT, ELTE, ENE, EOR};
#[derive(Debug, PartialEq, Eq)]
pub enum StdFunc {
EVar(String),
#[cfg(feature = "unsafe-vars")]
EUnsafeVar {
name: String,
ptr: *const f64,
},
EFunc {
name: String,
args: Vec<ExpressionI>,
},
EFuncInt(ExpressionI),
EFuncCeil(ExpressionI),
EFuncFloor(ExpressionI),
EFuncAbs(ExpressionI),
EFuncSign(ExpressionI),
EFuncLog {
base: Option<ExpressionI>,
expr: ExpressionI,
},
EFuncRound {
modulus: Option<ExpressionI>,
expr: ExpressionI,
},
EFuncMin {
first: ExpressionI,
rest: Vec<ExpressionI>,
}, EFuncMax {
first: ExpressionI,
rest: Vec<ExpressionI>,
},
EFuncE,
EFuncPi,
EFuncSin(ExpressionI),
EFuncCos(ExpressionI),
EFuncTan(ExpressionI),
EFuncASin(ExpressionI),
EFuncACos(ExpressionI),
EFuncATan(ExpressionI),
EFuncSinH(ExpressionI),
EFuncCosH(ExpressionI),
EFuncTanH(ExpressionI),
EFuncASinH(ExpressionI),
EFuncACosH(ExpressionI),
EFuncATanH(ExpressionI),
}
#[cfg(feature = "unsafe-vars")]
use StdFunc::EUnsafeVar;
use StdFunc::{
EFunc, EFuncACos, EFuncACosH, EFuncASin, EFuncASinH, EFuncATan, EFuncATanH, EFuncAbs,
EFuncCeil, EFuncCos, EFuncCosH, EFuncE, EFuncFloor, EFuncInt, EFuncLog, EFuncMax, EFuncMin,
EFuncPi, EFuncRound, EFuncSign, EFuncSin, EFuncSinH, EFuncTan, EFuncTanH, EVar,
};
#[derive(Debug, PartialEq, Eq)]
pub struct PrintFunc(pub Vec<ExpressionOrString>);
#[derive(Debug, PartialEq, Eq)]
pub enum ExpressionOrString {
EExpr(ExpressionI),
EStr(String), }
use ExpressionOrString::{EExpr, EStr};
impl Clone for PrintFunc {
fn clone(&self) -> Self {
let mut vec = Vec::<ExpressionOrString>::with_capacity(self.0.len());
for x_or_s in &self.0 {
vec.push(match x_or_s {
EExpr(i) => EExpr(*i),
EStr(s) => EStr(s.clone()),
});
}
Self(vec)
}
}
enum Token<T> {
Pass,
Bite(T),
}
use Token::{Bite, Pass};
macro_rules! peek {
($bs:ident) => {
$bs.first().copied()
};
}
macro_rules! peek_n {
($bs:ident, $skip:literal) => {
$bs.get($skip).copied()
};
($bs:ident, $skip:ident) => {
$bs.get($skip).copied()
};
($bs:ident, $skip:expr) => {
$bs.get($skip).copied()
};
}
macro_rules! peek_is {
($bs:ident, $skip:literal, $val:literal) => {
peek_n!($bs, $skip) == Some($val)
};
($bs:ident, $skip:expr, $val:literal) => {
peek_n!($bs, $skip) == Some($val)
};
}
macro_rules! read {
($bs:ident) => {
match $bs.first() {
Some(b) => {
*$bs = &$bs[1..];
Ok(*b)
}
None => Err(Error::EOF),
}
};
($bs:ident, $parsing:literal) => {
match $bs.first() {
Some(b) => {
*$bs = &$bs[1..];
Ok(*b)
}
None => Err(Error::EofWhileParsing($parsing.to_owned())),
}
};
}
macro_rules! skip {
($bs:ident) => {
*$bs = &$bs[1..];
};
}
macro_rules! skip_n {
($bs:ident, $n:literal) => {
*$bs = &$bs[$n..];
};
($bs:ident, $n:ident) => {
*$bs = &$bs[$n..];
};
}
macro_rules! is_space {
($b:ident) => {
if $b > b' ' {
false
} else {
$b == b' ' || $b == b'\n' || $b == b'\t' || $b == b'\r'
}
};
}
macro_rules! spaces {
($bs:ident) => {
while let Some(b) = peek!($bs) {
if !is_space!(b) { break }
skip!($bs); }
};
}
pub const DEFAULT_EXPR_LEN_LIMIT: usize = 4096;
pub const DEFAULT_EXPR_DEPTH_LIMIT: usize = 32;
pub struct Parser {
pub expr_len_limit: usize,
pub expr_depth_limit: usize,
}
impl Parser {
#[inline]
pub const fn new() -> Self {
Self {
expr_len_limit: DEFAULT_EXPR_LEN_LIMIT,
expr_depth_limit: DEFAULT_EXPR_DEPTH_LIMIT,
}
}
const fn is_varname_byte(b: u8, i: usize) -> bool {
b.is_ascii_uppercase() || b.is_ascii_lowercase() || b == b'_' || ( i > 0 && b.is_ascii_digit())
}
fn is_varname_byte_opt(bo: Option<u8>, i: usize) -> bool {
bo.map_or(false, |byte| Self::is_varname_byte(byte, i))
}
#[inline]
pub fn parse(&self, expr_str: &str, slab: &mut ParseSlab) -> Result<ExpressionI, Error> {
slab.clear();
self.parse_noclear(expr_str, slab)
}
#[inline]
pub fn parse_noclear(
&self,
expr_str: &str,
slab: &mut ParseSlab,
) -> Result<ExpressionI, Error> {
if expr_str.len() > self.expr_len_limit {
return Err(Error::TooLong);
} let mut bs = expr_str.as_bytes();
self.read_expression(slab, &mut bs, 0, true)
}
fn read_expression(
&self,
slab: &mut ParseSlab,
bs: &mut &[u8],
depth: usize,
expect_eof: bool,
) -> Result<ExpressionI, Error> {
if depth > self.expr_depth_limit {
return Err(Error::TooDeep);
}
let first = self.read_value(slab, bs, depth)?;
let mut pairs = Vec::<ExprPair>::with_capacity(8);
loop {
match Self::read_binaryop(bs)? {
Pass => break,
Bite(bop) => {
let val = self.read_value(slab, bs, depth)?;
pairs.push(ExprPair(bop, val));
}
}
}
spaces!(bs);
if expect_eof && !bs.is_empty() {
let bs_str = match from_utf8(bs) {
Ok(s) => s,
Err(..) => "Utf8Error while handling UnparsedTokensRemaining error",
};
return Err(Error::UnparsedTokensRemaining(bs_str.to_owned()));
}
slab.push_expr(Expression { first, pairs })
}
fn read_value(
&self,
slab: &mut ParseSlab,
bs: &mut &[u8],
depth: usize,
) -> Result<Value, Error> {
if depth > self.expr_depth_limit {
return Err(Error::TooDeep);
}
match Self::read_const(slab, bs)? {
Pass => {}
Bite(c) => return Ok(EConstant(c)),
}
match self.read_unaryop(slab, bs, depth)? {
Pass => {}
Bite(u) => return Ok(EUnaryOp(u)),
}
match self.read_callable(slab, bs, depth)? {
Pass => {}
Bite(c) => return Ok(c),
}
if bs.is_empty() {
return Err(Error::EofWhileParsing(String::from("value")));
}
Err(Error::InvalidValue)
}
fn read_const(slab: &mut ParseSlab, bs: &mut &[u8]) -> Result<Token<f64>, Error> {
spaces!(bs);
let mut toklen = 0;
let mut sign_ok = true;
let mut specials_ok = true;
let mut suffix_ok = true;
let mut saw_val = false;
loop {
match peek_n!(bs, toklen) {
None => break,
Some(b) => {
if b.is_ascii_digit() || b == b'.' {
saw_val = true;
sign_ok = false;
specials_ok = false;
toklen += 1;
} else if sign_ok && (b == b'-' || b == b'+') {
sign_ok = false;
toklen += 1;
} else if saw_val && (b == b'e' || b == b'E') {
suffix_ok = false;
sign_ok = true;
toklen += 1;
} else if specials_ok
&& (b == b'N'
&& peek_is!(bs, toklen + 1, b'a')
&& peek_is!(bs, toklen + 2, b'N')
|| b == b'i'
&& peek_is!(bs, toklen + 1, b'n')
&& peek_is!(bs, toklen + 2, b'f'))
{
#[cfg(feature = "alpha-keywords")]
{
saw_val = true;
suffix_ok = false;
toklen += 3;
}
break;
} else {
break;
}
}
}
}
if !saw_val {
return Ok(Pass);
}
let mut tok = unsafe { from_utf8_unchecked(&bs[..toklen]) };
if suffix_ok {
match peek_n!(bs, toklen) {
None => (),
Some(b) => {
let (exp, suffixlen) = match b {
b'k' | b'K' => (3, 1),
b'M' => (6, 1),
b'G' => (9, 1),
b'T' => (12, 1),
b'm' => (-3, 1),
b'u' | b'\xb5' => (-6, 1), b'\xc2' if peek_is!(bs, toklen + 1, b'\xb5') => (-6, 2), b'n' => (-9, 1),
b'p' => (-12, 1),
_ => (0, 0),
};
if exp != 0 {
slab.char_buf.clear();
slab.char_buf.push_str(tok);
slab.char_buf.push('e');
slab.char_buf.push_str(&exp.to_string());
tok = &slab.char_buf;
toklen += suffixlen;
}
}
}
}
let val = tok
.parse::<f64>()
.map_err(|_| Error::ParseF64(tok.to_owned()))?;
skip_n!(bs, toklen);
Ok(Bite(val))
}
fn read_unaryop(
&self,
slab: &mut ParseSlab,
bs: &mut &[u8],
depth: usize,
) -> Result<Token<UnaryOp>, Error> {
spaces!(bs);
match peek!(bs) {
None => Ok(Pass), Some(b) => match b {
b'+' => {
skip!(bs);
let v = self.read_value(slab, bs, depth + 1)?;
Ok(Bite(EPos(slab.push_val(v)?)))
}
b'-' => {
skip!(bs);
let v = self.read_value(slab, bs, depth + 1)?;
Ok(Bite(ENeg(slab.push_val(v)?)))
}
b'(' => {
skip!(bs);
let xi = self.read_expression(slab, bs, depth + 1, false)?;
spaces!(bs);
if read!(bs, "parentheses")? != b')' {
return Err(Error::Expected(String::from(")")));
}
Ok(Bite(EParentheses(xi)))
}
b'[' => {
skip!(bs);
let xi = self.read_expression(slab, bs, depth + 1, false)?;
spaces!(bs);
if read!(bs, "square brackets")? != b']' {
return Err(Error::Expected(String::from("]")));
}
Ok(Bite(EParentheses(xi)))
}
b'!' => {
skip!(bs);
let v = self.read_value(slab, bs, depth + 1)?;
Ok(Bite(ENot(slab.push_val(v)?)))
}
_ => Ok(Pass),
},
}
}
fn read_binaryop(bs: &mut &[u8]) -> Result<Token<BinaryOp>, Error> {
spaces!(bs);
peek!(bs).map_or(Ok(Pass), |b| match b {
b'+' => {
skip!(bs);
Ok(Bite(EAdd))
}
b'-' => {
skip!(bs);
Ok(Bite(ESub))
}
b'*' => {
skip!(bs);
Ok(Bite(EMul))
}
b'/' => {
skip!(bs);
Ok(Bite(EDiv))
}
b'%' => {
skip!(bs);
Ok(Bite(EMod))
}
b'^' => {
skip!(bs);
Ok(Bite(EExp))
}
b'<' => {
skip!(bs);
if peek_is!(bs, 0, b'=') {
skip!(bs);
Ok(Bite(ELTE))
} else {
Ok(Bite(ELT))
}
}
b'>' => {
skip!(bs);
if peek_is!(bs, 0, b'=') {
skip!(bs);
Ok(Bite(EGTE))
} else {
Ok(Bite(EGT))
}
}
b'=' if peek_is!(bs, 1, b'=') => {
skip_n!(bs, 2);
Ok(Bite(EEQ))
}
b'!' if peek_is!(bs, 1, b'=') => {
skip_n!(bs, 2);
Ok(Bite(ENE))
}
#[cfg(feature = "alpha-keywords")]
b'o' if peek_is!(bs, 1, b'r') => {
skip_n!(bs, 2);
Ok(Bite(EOR))
}
b'|' if peek_is!(bs, 1, b'|') => {
skip_n!(bs, 2);
Ok(Bite(EOR))
}
#[cfg(feature = "alpha-keywords")]
b'a' if peek_is!(bs, 1, b'n') && peek_is!(bs, 2, b'd') => {
skip_n!(bs, 3);
Ok(Bite(EAND))
}
b'&' if peek_is!(bs, 1, b'&') => {
skip_n!(bs, 2);
Ok(Bite(EAND))
}
_ => Ok(Pass),
})
}
fn read_callable(
&self,
slab: &mut ParseSlab,
bs: &mut &[u8],
depth: usize,
) -> Result<Token<Value>, Error> {
match Self::read_varname(bs)? {
Pass => Ok(Pass),
Bite(varname) => {
match Self::read_open_parenthesis(bs)? {
Pass => {
#[cfg(feature = "unsafe-vars")]
match slab.unsafe_vars.get(&varname) {
None => Ok(Bite(EStdFunc(EVar(varname)))),
Some(&ptr) => Ok(Bite(EStdFunc(EUnsafeVar { name: varname, ptr }))),
}
#[cfg(not(feature = "unsafe-vars"))]
Ok(Bite(EStdFunc(EVar(varname))))
}
Bite(open_parenth) => {
match varname.as_ref() {
"print" => Ok(Bite(EPrintFunc(self.read_printfunc(
slab,
bs,
depth,
open_parenth,
)?))),
_ => Ok(Bite(EStdFunc(self.read_func(
varname,
slab,
bs,
depth,
open_parenth,
)?))),
}
}
}
}
}
}
fn read_varname(bs: &mut &[u8]) -> Result<Token<String>, Error> {
spaces!(bs);
let mut toklen = 0;
while Self::is_varname_byte_opt(peek_n!(bs, toklen), toklen) {
toklen += 1;
}
if toklen == 0 {
return Ok(Pass);
}
let out = unsafe { from_utf8_unchecked(&bs[..toklen]) }.to_owned();
skip_n!(bs, toklen);
Ok(Bite(out))
}
fn read_open_parenthesis(bs: &mut &[u8]) -> Result<Token<u8>, Error> {
spaces!(bs);
match peek!(bs) {
Some(b'(' | b'[') => Ok(Bite(match read!(bs) {
Ok(b) => b,
Err(..) => return Err(Error::Unreachable),
})),
_ => Ok(Pass),
}
}
#[allow(clippy::cognitive_complexity, clippy::too_many_lines)] fn read_func(
&self,
fname: String,
slab: &mut ParseSlab,
bs: &mut &[u8],
depth: usize,
open_parenth: u8,
) -> Result<StdFunc, Error> {
let close_parenth = match open_parenth {
b'(' => b')',
b'[' => b']',
_ => return Err(Error::Expected(String::from("'(' or '['"))),
};
let mut args = Vec::<ExpressionI>::with_capacity(4);
loop {
spaces!(bs);
match peek!(bs) {
Some(b) => {
if b == close_parenth {
skip!(bs);
break;
}
}
None => return Err(Error::EofWhileParsing(fname)),
}
if !args.is_empty() {
match read!(bs) {
Ok(b',' | b';') => {}
_ => return Err(Error::Expected(String::from("',' or ';'"))),
}
}
args.push(self.read_expression(slab, bs, depth + 1, false)?);
}
let fname_str = fname.as_str();
match fname_str {
"int" => {
if args.len() == 1 {
Ok(EFuncInt(match args.pop() {
Some(xi) => xi,
None => return Err(Error::Unreachable),
}))
} else {
Err(Error::WrongArgs(String::from("int: expected one arg")))
}
}
"ceil" => {
if args.len() == 1 {
Ok(EFuncCeil(match args.pop() {
Some(xi) => xi,
None => return Err(Error::Unreachable),
}))
} else {
Err(Error::WrongArgs(String::from("ceil: expected one arg")))
}
}
"floor" => {
if args.len() == 1 {
Ok(EFuncFloor(match args.pop() {
Some(xi) => xi,
None => return Err(Error::Unreachable),
}))
} else {
Err(Error::WrongArgs(String::from("floor: expected one arg")))
}
}
"abs" => {
if args.len() == 1 {
Ok(EFuncAbs(match args.pop() {
Some(xi) => xi,
None => return Err(Error::Unreachable),
}))
} else {
Err(Error::WrongArgs(String::from("abs: expected one arg")))
}
}
"sign" => {
if args.len() == 1 {
Ok(EFuncSign(match args.pop() {
Some(xi) => xi,
None => return Err(Error::Unreachable),
}))
} else {
Err(Error::WrongArgs(String::from("sign: expected one arg")))
}
}
"log" => {
if args.len() == 1 {
Ok(EFuncLog {
base: None,
expr: match args.pop() {
Some(xi) => xi,
None => return Err(Error::Unreachable),
},
})
} else if args.len() == 2 {
let Some(expr) = args.pop() else { return Err(Error::Unreachable) };
Ok(EFuncLog {
base: Some(match args.pop() {
Some(xi) => xi,
None => return Err(Error::Unreachable),
}),
expr,
})
} else {
Err(Error::WrongArgs(
String::from("expected log(x) or log(base,x)"),
))
}
}
"round" => {
if args.len() == 1 {
Ok(EFuncRound {
modulus: None,
expr: match args.pop() {
Some(xi) => xi,
None => return Err(Error::Unreachable),
},
})
} else if args.len() == 2 {
let Some(expr) = args.pop() else { return Err(Error::Unreachable) };
Ok(EFuncRound {
modulus: Some(match args.pop() {
Some(xi) => xi,
None => return Err(Error::Unreachable),
}),
expr,
})
} else {
Err(Error::WrongArgs(
String::from("round: expected round(x) or round(modulus,x)"),
))
}
}
"min" => {
if args.is_empty() {
Err(Error::WrongArgs(
String::from("min: expected one or more args"),
))
} else {
remove_no_panic(&mut args, 0).map_or(Err(Error::Unreachable), |first| Ok(EFuncMin { first, rest: args }))
}
}
"max" => {
if args.is_empty() {
Err(Error::WrongArgs(
String::from("max: expected one or more args"),
))
} else {
remove_no_panic(&mut args, 0).map_or(Err(Error::Unreachable), |first| Ok(EFuncMax { first, rest: args }))
}
}
"e" => {
if args.is_empty() {
Ok(EFuncE)
} else {
Err(Error::WrongArgs(String::from("e: expected no args")))
}
}
"pi" => {
if args.is_empty() {
Ok(EFuncPi)
} else {
Err(Error::WrongArgs(String::from("pi: expected no args")))
}
}
"sin" => {
if args.len() == 1 {
Ok(EFuncSin(match args.pop() {
Some(xi) => xi,
None => return Err(Error::Unreachable),
}))
} else {
Err(Error::WrongArgs(String::from("sin: expected one arg")))
}
}
"cos" => {
if args.len() == 1 {
Ok(EFuncCos(match args.pop() {
Some(xi) => xi,
None => return Err(Error::Unreachable),
}))
} else {
Err(Error::WrongArgs(String::from("cos: expected one arg")))
}
}
"tan" => {
if args.len() == 1 {
Ok(EFuncTan(match args.pop() {
Some(xi) => xi,
None => return Err(Error::Unreachable),
}))
} else {
Err(Error::WrongArgs(String::from("tan: expected one arg")))
}
}
"asin" => {
if args.len() == 1 {
Ok(EFuncASin(match args.pop() {
Some(xi) => xi,
None => return Err(Error::Unreachable),
}))
} else {
Err(Error::WrongArgs(String::from("asin: expected one arg")))
}
}
"acos" => {
if args.len() == 1 {
Ok(EFuncACos(match args.pop() {
Some(xi) => xi,
None => return Err(Error::Unreachable),
}))
} else {
Err(Error::WrongArgs(String::from("acos: expected one arg")))
}
}
"atan" => {
if args.len() == 1 {
Ok(EFuncATan(match args.pop() {
Some(xi) => xi,
None => return Err(Error::Unreachable),
}))
} else {
Err(Error::WrongArgs(String::from("atan: expected one arg")))
}
}
"sinh" => {
if args.len() == 1 {
Ok(EFuncSinH(match args.pop() {
Some(xi) => xi,
None => return Err(Error::Unreachable),
}))
} else {
Err(Error::WrongArgs(String::from("sinh: expected one arg")))
}
}
"cosh" => {
if args.len() == 1 {
Ok(EFuncCosH(match args.pop() {
Some(xi) => xi,
None => return Err(Error::Unreachable),
}))
} else {
Err(Error::WrongArgs(String::from("cosh: expected one arg")))
}
}
"tanh" => {
if args.len() == 1 {
Ok(EFuncTanH(match args.pop() {
Some(xi) => xi,
None => return Err(Error::Unreachable),
}))
} else {
Err(Error::WrongArgs(String::from("tanh: expected one arg")))
}
}
"asinh" => {
if args.len() == 1 {
Ok(EFuncASinH(match args.pop() {
Some(xi) => xi,
None => return Err(Error::Unreachable),
}))
} else {
Err(Error::WrongArgs(String::from("asinh: expected one arg")))
}
}
"acosh" => {
if args.len() == 1 {
Ok(EFuncACosH(match args.pop() {
Some(xi) => xi,
None => return Err(Error::Unreachable),
}))
} else {
Err(Error::WrongArgs(String::from("acosh: expected one arg")))
}
}
"atanh" => {
if args.len() == 1 {
Ok(EFuncATanH(match args.pop() {
Some(xi) => xi,
None => return Err(Error::Unreachable),
}))
} else {
Err(Error::WrongArgs(String::from("atanh: expected one arg")))
}
}
_ => {
#[cfg(feature = "unsafe-vars")]
match slab.unsafe_vars.get(fname_str) {
None => Ok(EFunc { name: fname, args }),
Some(&ptr) => Ok(EUnsafeVar { name: fname, ptr }),
}
#[cfg(not(feature = "unsafe-vars"))]
Ok(EFunc { name: fname, args })
}
}
}
fn read_printfunc(
&self,
slab: &mut ParseSlab,
bs: &mut &[u8],
depth: usize,
open_parenth: u8,
) -> Result<PrintFunc, Error> {
let close_parenth = match open_parenth {
b'(' => b')',
b'[' => b']',
_ => return Err(Error::Expected(String::from("'(' or '['"))),
};
let mut args = Vec::<ExpressionOrString>::with_capacity(8);
loop {
spaces!(bs);
match peek!(bs) {
Some(b) => {
if b == close_parenth {
skip!(bs);
break;
}
}
None => {
return Err(Error::EofWhileParsing(String::from("print")));
}
}
if !args.is_empty() {
match read!(bs) {
Ok(b',' | b';') => {}
_ => {
return Err(Error::Expected(String::from("',' or ';'")));
}
}
}
args.push(self.read_expressionorstring(slab, bs, depth + 1)?);
}
Ok(PrintFunc(args))
}
fn read_expressionorstring(
&self,
slab: &mut ParseSlab,
bs: &mut &[u8],
depth: usize,
) -> Result<ExpressionOrString, Error> {
match Self::read_string(bs)? {
Pass => {}
Bite(s) => return Ok(EStr(s)),
}
Ok(EExpr(self.read_expression(slab, bs, depth + 1, false)?))
}
fn read_string(bs: &mut &[u8]) -> Result<Token<String>, Error> {
spaces!(bs);
match peek!(bs) {
None => {
return Err(Error::EofWhileParsing(
String::from("opening quote of string"),
))
}
Some(b'"') => {
skip!(bs);
}
Some(_) => return Ok(Pass),
}
let mut toklen = 0;
while match peek_n!(bs, toklen) {
None | Some(b'"') => false,
Some(_) => true,
} {
toklen += 1;
}
let out = from_utf8(&bs[..toklen])
.map_err(|_| Error::Utf8ErrorWhileParsing(String::from("string")))?;
skip_n!(bs, toklen);
match read!(bs) {
Err(Error::EOF) => Err(Error::EofWhileParsing(String::from("string"))),
Ok(b'"') => Ok(Bite(out.to_owned())),
Err(_) | Ok(_) => Err(Error::Unreachable),
}
}
}
impl Default for Parser {
fn default() -> Self {
Self::new()
}
}
impl Default for Value {
fn default() -> Self {
EConstant(std::f64::NAN)
}
}
pub(crate) fn remove_no_panic<T>(vself: &mut Vec<T>, index: usize) -> Option<T> {
let len = vself.len();
if index >= len {
return None;
}
unsafe {
let ret;
{
let ptr = vself.as_mut_ptr().add(index);
ret = ptr::read(ptr);
ptr::copy(ptr.offset(1), ptr, len - index - 1);
}
vself.set_len(len - 1);
Some(ret)
}
}
#[cfg(test)]
mod internal_tests {
use super::*;
use crate::slab::Slab;
#[test]
fn rem_no_panic() {
let mut v = vec![1u8, 2, 3];
assert_eq!(format!("{v:?}"), "[1, 2, 3]");
assert_eq!(remove_no_panic(&mut v, 1), Some(2));
assert_eq!(remove_no_panic(&mut v, 10), None);
assert_eq!(format!("{v:?}"), "[1, 3]");
}
#[test]
fn util() {
match (|| -> Result<(), Error> {
let bsarr = [1, 2, 3];
let bs = &mut &bsarr[..];
assert_eq!(peek!(bs), Some(1));
assert_eq!(peek_n!(bs, 1), Some(2));
assert_eq!(peek_n!(bs, 2), Some(3));
assert_eq!(peek_n!(bs, 3), None);
assert_eq!(read!(bs)?, 1);
skip!(bs);
assert_eq!(read!(bs)?, 3);
match read!(bs).err() {
Some(Error::EOF) => {}
_ => panic!("I expected an EOF"),
}
Ok(())
})() {
Ok(()) => {}
Err(_) => {
unimplemented!();
}
}
assert!(([0u8; 0]).is_empty());
assert!(!([1]).is_empty());
assert!((b"").is_empty());
assert!(!(b"x").is_empty());
let b = b' ';
assert!(is_space!(b));
let b = b'\t';
assert!(is_space!(b));
let b = b'\r';
assert!(is_space!(b));
let b = b'\n';
assert!(is_space!(b));
let b = b'a';
assert!(!is_space!(b));
let b = b'1';
assert!(!is_space!(b));
let b = b'.';
assert!(!is_space!(b));
{
let bsarr = b" abc 123 ";
let bs = &mut &bsarr[..];
spaces!(bs);
assert_eq!(bs, b"abc 123 ");
}
}
#[test]
fn priv_tests() {
assert!(Parser::is_varname_byte_opt(Some(b'a'), 0));
let mut slab = Slab::new();
{
let bsarr = b"12.34";
let bs = &mut &bsarr[..];
assert_eq!(
Parser::new().read_value(&mut slab.ps, bs, 0),
Ok(EConstant(12.34))
);
}
}
}