rhai/src/parser.rs

2711 lines
88 KiB
Rust
Raw Normal View History

2020-03-08 12:54:02 +01:00
//! Main module defining the lexer and parser.
use crate::any::{Any, AnyExt, Dynamic};
use crate::engine::Engine;
2020-03-04 15:00:01 +01:00
use crate::error::{LexError, ParseError, ParseErrorType};
2020-03-25 04:27:18 +01:00
use crate::scope::{EntryType as ScopeEntryType, Scope};
2020-03-11 04:03:18 +01:00
#[cfg(not(feature = "no_optimize"))]
2020-03-18 11:41:18 +01:00
use crate::optimize::optimize_into_ast;
2020-03-17 19:26:11 +01:00
use crate::stdlib::{
borrow::Cow,
boxed::Box,
2020-03-29 17:53:35 +02:00
char,
collections::HashMap,
fmt, format,
2020-03-17 19:26:11 +01:00
iter::Peekable,
2020-03-27 04:50:24 +01:00
ops::Add,
2020-03-17 19:26:11 +01:00
str::Chars,
str::FromStr,
string::{String, ToString},
sync::Arc,
usize, vec,
vec::Vec,
2020-03-12 05:40:28 +01:00
};
2016-02-29 22:43:45 +01:00
2020-03-11 04:03:18 +01:00
/// The system integer type.
///
/// If the `only_i32` feature is enabled, this will be `i32` instead.
#[cfg(not(feature = "only_i32"))]
pub type INT = i64;
2020-03-18 03:36:50 +01:00
/// The system integer type.
2020-03-11 04:03:18 +01:00
///
/// If the `only_i32` feature is not enabled, this will be `i64` instead.
#[cfg(feature = "only_i32")]
pub type INT = i32;
2020-03-18 03:36:50 +01:00
/// The system floating-point type.
#[cfg(not(feature = "no_float"))]
pub type FLOAT = f64;
type LERR = LexError;
2020-03-01 06:30:22 +01:00
type PERR = ParseErrorType;
2020-03-04 15:00:01 +01:00
/// A location (line number + character position) in the input script.
#[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)]
2020-02-29 13:12:10 +01:00
pub struct Position {
2020-03-18 03:36:50 +01:00
/// Line number - 0 = none, MAX = EOF
line: usize,
2020-03-18 03:36:50 +01:00
/// Character position - 0 = BOL, MAX = EOF
pos: usize,
2020-02-29 13:12:10 +01:00
}
impl Position {
2020-03-04 15:00:01 +01:00
/// Create a new `Position`.
pub fn new(line: usize, position: usize) -> Self {
2020-03-16 16:51:32 +01:00
assert!(line != 0, "line cannot be zero");
assert!(
line != usize::MAX || position != usize::MAX,
"invalid position"
);
2020-03-04 15:00:01 +01:00
Self {
line,
pos: position,
}
2020-02-29 13:12:10 +01:00
}
/// Get the line number (1-based), or `None` if no position or EOF.
2020-03-04 15:00:01 +01:00
pub fn line(&self) -> Option<usize> {
if self.is_none() || self.is_eof() {
None
} else {
Some(self.line)
2020-03-04 15:00:01 +01:00
}
}
2020-03-04 15:00:01 +01:00
/// Get the character position (1-based), or `None` if at beginning of a line.
pub fn position(&self) -> Option<usize> {
2020-03-24 09:46:47 +01:00
if self.is_none() || self.is_eof() || self.pos == 0 {
None
} else {
Some(self.pos)
2020-03-04 15:00:01 +01:00
}
}
2020-03-04 15:00:01 +01:00
/// Advance by one character position.
pub(crate) fn advance(&mut self) {
self.pos += 1;
2020-02-29 13:12:10 +01:00
}
2020-03-04 15:00:01 +01:00
/// Go backwards by one character position.
///
/// # Panics
///
/// Panics if already at beginning of a line - cannot rewind to a previous line.
///
pub(crate) fn rewind(&mut self) {
2020-03-04 16:06:05 +01:00
assert!(self.pos > 0, "cannot rewind at position 0");
self.pos -= 1;
}
2020-03-04 15:00:01 +01:00
/// Advance to the next line.
pub(crate) fn new_line(&mut self) {
self.line += 1;
self.pos = 0;
}
/// Create a `Position` representing no position.
pub(crate) fn none() -> Self {
Self { line: 0, pos: 0 }
}
2020-03-04 15:00:01 +01:00
/// Create a `Position` at EOF.
pub(crate) fn eof() -> Self {
Self {
line: usize::MAX,
pos: usize::MAX,
}
}
/// Is there no `Position`?
pub fn is_none(&self) -> bool {
self.line == 0 && self.pos == 0
2020-02-29 13:12:10 +01:00
}
2020-03-04 15:00:01 +01:00
/// Is the `Position` at EOF?
pub fn is_eof(&self) -> bool {
self.line == usize::MAX && self.pos == usize::MAX
}
}
2020-03-04 15:00:01 +01:00
impl Default for Position {
fn default() -> Self {
Self::new(1, 0)
}
}
2020-03-08 12:54:02 +01:00
impl fmt::Display for Position {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.is_eof() {
write!(f, "EOF")
} else if self.is_none() {
write!(f, "none")
} else {
write!(f, "line {}, position {}", self.line, self.pos)
}
}
}
2020-03-08 12:54:02 +01:00
impl fmt::Debug for Position {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.is_eof() {
write!(f, "(EOF)")
} else {
write!(f, "({}:{})", self.line, self.pos)
}
}
2020-02-29 13:12:10 +01:00
}
2020-03-04 15:00:01 +01:00
/// Compiled AST (abstract syntax tree) of a Rhai script.
2020-03-11 16:43:04 +01:00
#[derive(Debug, Clone)]
pub struct AST(pub(crate) Vec<Stmt>, pub(crate) Vec<Arc<FnDef>>);
2020-03-27 04:50:24 +01:00
impl AST {
/// Merge two `AST` into one. Both `AST`'s are consumed and a new, merged, version
/// is returned.
///
/// The second `AST` is simply appended to the end of the first _without any processing_.
/// Thus, the return value of the first `AST` (if using expression-statement syntax) is buried.
/// Of course, if the first `AST` uses a `return` statement at the end, then
/// the second `AST` will essentially be dead code.
///
/// All script-defined functions in the second `AST` overwrite similarly-named functions
/// in the first `AST` with the same number of parameters.
///
/// # Example
///
/// ```
/// # fn main() -> Result<(), rhai::EvalAltResult> {
/// use rhai::Engine;
///
/// let mut engine = Engine::new();
///
/// let ast1 = engine.compile(r#"fn foo(x) { 42 + x } foo(1)"#)?;
/// let ast2 = engine.compile(r#"fn foo(n) { "hello" + n } foo(2)"#)?;
///
/// let ast = ast1.merge(ast2); // Merge 'ast2' into 'ast1'
///
/// // Notice that using the '+' operator also works:
/// // let ast = ast1 + ast2;
///
/// // 'ast' is essentially:
/// //
/// // fn foo(n) { "hello" + n } // <- definition of first 'foo' is overwritten
/// // foo(1) // <- notice this will be "hello1" instead of 43,
/// // // but it is no longer the return value
/// // foo(2) // returns "hello2"
///
/// // Evaluate it
/// assert_eq!(engine.eval_ast::<String>(&ast)?, "hello2");
/// # Ok(())
/// # }
/// ```
pub fn merge(self, mut other: Self) -> Self {
let Self(mut ast, mut functions) = self;
ast.append(&mut other.0);
for fn_def in other.1 {
if let Some((n, _)) = functions
.iter()
.enumerate()
.find(|(_, f)| f.name == fn_def.name && f.params.len() == fn_def.params.len())
{
functions[n] = fn_def;
} else {
functions.push(fn_def);
}
}
Self(ast, functions)
}
}
impl Add<Self> for AST {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
self.merge(rhs)
}
}
2020-03-18 03:36:50 +01:00
/// A script-function definition.
#[derive(Debug, Clone)]
2020-03-11 16:43:04 +01:00
pub struct FnDef {
2020-03-18 03:36:50 +01:00
/// Function name.
2020-03-11 16:43:04 +01:00
pub name: String,
2020-03-18 03:36:50 +01:00
/// Names of function parameters.
2020-03-11 16:43:04 +01:00
pub params: Vec<String>,
2020-03-18 03:36:50 +01:00
/// Function body.
2020-03-09 14:57:07 +01:00
pub body: Stmt,
2020-03-18 03:36:50 +01:00
/// Position of the function definition.
pub pos: Position,
}
2020-03-18 03:36:50 +01:00
/// `return`/`throw` statement.
2020-03-11 16:43:04 +01:00
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub enum ReturnType {
2020-03-18 03:36:50 +01:00
/// `return` statement.
2020-03-11 16:43:04 +01:00
Return,
2020-03-18 03:36:50 +01:00
/// `throw` statement.
2020-03-11 16:43:04 +01:00
Exception,
}
2020-03-18 03:36:50 +01:00
/// A statement.
#[derive(Debug, Clone)]
pub enum Stmt {
2020-03-18 03:36:50 +01:00
/// No-op.
2020-03-09 14:57:07 +01:00
Noop(Position),
2020-03-18 03:36:50 +01:00
/// if expr { stmt } else { stmt }
2020-03-22 03:18:16 +01:00
IfThenElse(Box<Expr>, Box<Stmt>, Option<Box<Stmt>>),
2020-03-18 03:36:50 +01:00
/// while expr { stmt }
While(Box<Expr>, Box<Stmt>),
2020-03-18 03:36:50 +01:00
/// loop { stmt }
2017-10-30 16:08:44 +01:00
Loop(Box<Stmt>),
2020-03-18 03:36:50 +01:00
/// for id in expr { stmt }
For(String, Box<Expr>, Box<Stmt>),
2020-03-18 03:36:50 +01:00
/// let id = expr
Let(String, Option<Box<Expr>>, Position),
2020-03-18 03:36:50 +01:00
/// const id = expr
2020-03-13 11:12:41 +01:00
Const(String, Box<Expr>, Position),
2020-03-18 03:36:50 +01:00
/// { stmt; ... }
2020-03-09 14:57:07 +01:00
Block(Vec<Stmt>, Position),
2020-03-18 03:36:50 +01:00
/// { stmt }
Expr(Box<Expr>),
2020-03-18 03:36:50 +01:00
/// break
Break(Position),
2020-03-18 03:36:50 +01:00
/// `return`/`throw`
2020-03-11 16:43:04 +01:00
ReturnWithVal(Option<Box<Expr>>, ReturnType, Position),
}
2016-02-29 22:43:45 +01:00
2020-03-09 14:57:07 +01:00
impl Stmt {
2020-03-18 03:36:50 +01:00
/// Get the `Position` of this statement.
2020-03-17 10:33:37 +01:00
pub fn position(&self) -> Position {
match self {
Stmt::Noop(pos)
| Stmt::Let(_, _, pos)
| Stmt::Const(_, _, pos)
| Stmt::Block(_, pos)
| Stmt::Break(pos)
| Stmt::ReturnWithVal(_, _, pos) => *pos,
2020-03-22 03:18:16 +01:00
Stmt::IfThenElse(expr, _, _) | Stmt::Expr(expr) => expr.position(),
2020-03-17 10:33:37 +01:00
Stmt::While(_, stmt) | Stmt::Loop(stmt) | Stmt::For(_, _, stmt) => stmt.position(),
}
}
2020-03-18 03:36:50 +01:00
/// Is this statement self-terminated (i.e. no need for a semicolon terminator)?
pub fn is_self_terminated(&self) -> bool {
match self {
2020-03-22 03:18:16 +01:00
Stmt::IfThenElse(_, _, _)
| Stmt::While(_, _)
| Stmt::Loop(_)
| Stmt::For(_, _, _)
| Stmt::Block(_, _) => true,
2020-03-18 11:41:18 +01:00
// A No-op requires a semicolon in order to know it is an empty statement!
Stmt::Noop(_) => false,
Stmt::Let(_, _, _)
| Stmt::Const(_, _, _)
| Stmt::Expr(_)
| Stmt::Break(_)
| Stmt::ReturnWithVal(_, _, _) => false,
}
}
2020-03-18 03:36:50 +01:00
/// Is this statement _pure_?
2020-03-17 10:33:37 +01:00
pub fn is_pure(&self) -> bool {
2020-03-11 16:43:04 +01:00
match self {
2020-03-17 10:33:37 +01:00
Stmt::Noop(_) => true,
Stmt::Expr(expr) => expr.is_pure(),
2020-03-22 03:18:16 +01:00
Stmt::IfThenElse(guard, if_block, Some(else_block)) => {
2020-03-17 10:33:37 +01:00
guard.is_pure() && if_block.is_pure() && else_block.is_pure()
}
2020-03-22 03:18:16 +01:00
Stmt::IfThenElse(guard, block, None) | Stmt::While(guard, block) => {
2020-03-17 10:33:37 +01:00
guard.is_pure() && block.is_pure()
}
Stmt::Loop(block) => block.is_pure(),
Stmt::For(_, range, block) => range.is_pure() && block.is_pure(),
Stmt::Let(_, _, _) | Stmt::Const(_, _, _) => false,
Stmt::Block(statements, _) => statements.iter().all(Stmt::is_pure),
Stmt::Break(_) | Stmt::ReturnWithVal(_, _, _) => false,
2020-03-11 16:43:04 +01:00
}
}
2020-03-09 14:57:07 +01:00
}
2020-03-18 03:36:50 +01:00
/// An expression.
#[derive(Debug, Clone)]
pub enum Expr {
2020-03-18 03:36:50 +01:00
/// Integer constant.
IntegerConstant(INT, Position),
2020-03-18 03:36:50 +01:00
/// Floating-point constant.
#[cfg(not(feature = "no_float"))]
FloatConstant(FLOAT, Position),
2020-03-18 03:36:50 +01:00
/// Character constant.
CharConstant(char, Position),
2020-03-18 03:36:50 +01:00
/// String constant.
StringConstant(String, Position),
2020-03-18 03:36:50 +01:00
/// Variable access.
Variable(String, Position),
/// Property access.
Property(String, Position),
/// { stmt }
2020-03-09 14:57:07 +01:00
Stmt(Box<Stmt>, Position),
2020-03-18 03:36:50 +01:00
/// func(expr, ... )
FunctionCall(String, Vec<Expr>, Option<Dynamic>, Position),
2020-03-18 03:36:50 +01:00
/// expr = expr
Assignment(Box<Expr>, Box<Expr>, Position),
2020-03-18 03:36:50 +01:00
/// lhs.rhs
#[cfg(not(feature = "no_object"))]
Dot(Box<Expr>, Box<Expr>, Position),
2020-03-18 03:36:50 +01:00
/// expr[expr]
#[cfg(not(feature = "no_index"))]
Index(Box<Expr>, Box<Expr>, Position),
#[cfg(not(feature = "no_index"))]
2020-03-18 03:36:50 +01:00
/// [ expr, ... ]
Array(Vec<Expr>, Position),
2020-03-29 17:53:35 +02:00
#[cfg(not(feature = "no_object"))]
/// ${ name:expr, ... }
Map(Vec<(String, Expr, Position)>, Position),
2020-03-18 03:36:50 +01:00
/// lhs && rhs
2020-03-02 05:08:03 +01:00
And(Box<Expr>, Box<Expr>),
2020-03-18 03:36:50 +01:00
/// lhs || rhs
2020-03-02 05:08:03 +01:00
Or(Box<Expr>, Box<Expr>),
2020-03-18 03:36:50 +01:00
/// true
True(Position),
2020-03-18 03:36:50 +01:00
/// false
False(Position),
2020-03-18 03:36:50 +01:00
/// ()
Unit(Position),
}
impl Expr {
2020-03-18 03:36:50 +01:00
/// Get the `Dynamic` value of a constant expression.
///
/// # Panics
///
/// Panics when the expression is not constant.
pub fn get_constant_value(&self) -> Dynamic {
match self {
Expr::IntegerConstant(i, _) => i.into_dynamic(),
Expr::CharConstant(c, _) => c.into_dynamic(),
Expr::StringConstant(s, _) => s.into_dynamic(),
Expr::True(_) => true.into_dynamic(),
Expr::False(_) => false.into_dynamic(),
Expr::Unit(_) => ().into_dynamic(),
#[cfg(not(feature = "no_index"))]
Expr::Array(items, _) if items.iter().all(Expr::is_constant) => items
.iter()
.map(Expr::get_constant_value)
.collect::<Vec<_>>()
.into_dynamic(),
2020-03-29 17:53:35 +02:00
#[cfg(not(feature = "no_object"))]
Expr::Map(items, _) if items.iter().all(|(_, v, _)| v.is_constant()) => items
.iter()
.map(|(k, v, _)| (k.clone(), v.get_constant_value()))
.collect::<HashMap<_, _>>()
.into_dynamic(),
#[cfg(not(feature = "no_float"))]
Expr::FloatConstant(f, _) => f.into_dynamic(),
_ => panic!("cannot get value of non-constant expression"),
}
}
2020-03-18 03:36:50 +01:00
/// Get the display value of a constant expression.
///
/// # Panics
///
/// Panics when the expression is not constant.
pub fn get_constant_str(&self) -> String {
2020-03-13 11:12:41 +01:00
match self {
Expr::IntegerConstant(i, _) => i.to_string(),
Expr::CharConstant(c, _) => c.to_string(),
Expr::StringConstant(_, _) => "string".to_string(),
Expr::True(_) => "true".to_string(),
Expr::False(_) => "false".to_string(),
Expr::Unit(_) => "()".to_string(),
#[cfg(not(feature = "no_index"))]
Expr::Array(items, _) if items.iter().all(Expr::is_constant) => "array".to_string(),
2020-03-13 11:12:41 +01:00
#[cfg(not(feature = "no_float"))]
Expr::FloatConstant(f, _) => f.to_string(),
_ => panic!("cannot get value of non-constant expression"),
2020-03-13 11:12:41 +01:00
}
}
2020-03-18 03:36:50 +01:00
/// Get the `Position` of the expression.
pub fn position(&self) -> Position {
match self {
Expr::IntegerConstant(_, pos)
| Expr::CharConstant(_, pos)
| Expr::StringConstant(_, pos)
2020-03-13 11:12:41 +01:00
| Expr::Variable(_, pos)
| Expr::Property(_, pos)
2020-03-09 14:57:07 +01:00
| Expr::Stmt(_, pos)
2020-03-11 04:03:18 +01:00
| Expr::FunctionCall(_, _, _, pos)
| Expr::True(pos)
| Expr::False(pos)
| Expr::Unit(pos) => *pos,
Expr::Assignment(expr, _, _) | Expr::And(expr, _) | Expr::Or(expr, _) => {
expr.position()
}
#[cfg(not(feature = "no_object"))]
Expr::Dot(expr, _, _) => expr.position(),
#[cfg(not(feature = "no_float"))]
Expr::FloatConstant(_, pos) => *pos,
#[cfg(not(feature = "no_index"))]
Expr::Array(_, pos) => *pos,
2020-03-29 17:53:35 +02:00
#[cfg(not(feature = "no_object"))]
Expr::Map(_, pos) => *pos,
#[cfg(not(feature = "no_index"))]
2020-03-16 16:51:32 +01:00
Expr::Index(expr, _, _) => expr.position(),
}
}
2020-03-10 04:22:41 +01:00
2020-03-18 03:36:50 +01:00
/// Is the expression pure?
2020-03-11 16:43:04 +01:00
///
/// A pure expression has no side effects.
pub fn is_pure(&self) -> bool {
2020-03-10 04:22:41 +01:00
match self {
#[cfg(not(feature = "no_index"))]
2020-03-12 05:40:28 +01:00
Expr::Array(expressions, _) => expressions.iter().all(Expr::is_pure),
#[cfg(not(feature = "no_index"))]
Expr::Index(x, y, _) => x.is_pure() && y.is_pure(),
Expr::And(x, y) | Expr::Or(x, y) => x.is_pure() && y.is_pure(),
2020-03-17 10:33:37 +01:00
Expr::Stmt(stmt, _) => stmt.is_pure(),
2020-03-14 16:41:15 +01:00
expr => expr.is_constant() || matches!(expr, Expr::Variable(_, _)),
2020-03-12 05:40:28 +01:00
}
}
2020-03-18 03:36:50 +01:00
/// Is the expression a constant?
2020-03-12 05:40:28 +01:00
pub fn is_constant(&self) -> bool {
match self {
Expr::IntegerConstant(_, _)
2020-03-10 04:22:41 +01:00
| Expr::CharConstant(_, _)
| Expr::StringConstant(_, _)
| Expr::True(_)
| Expr::False(_)
| Expr::Unit(_) => true,
#[cfg(not(feature = "no_float"))]
Expr::FloatConstant(_, _) => true,
2020-03-18 03:36:50 +01:00
// An array literal is constant if all items are constant
#[cfg(not(feature = "no_index"))]
Expr::Array(expressions, _) => expressions.iter().all(Expr::is_constant),
_ => false,
}
}
}
2016-02-29 22:43:45 +01:00
2020-03-18 03:36:50 +01:00
/// Tokens.
#[derive(Debug, PartialEq, Clone)]
pub enum Token {
IntegerConstant(INT),
#[cfg(not(feature = "no_float"))]
FloatConstant(FLOAT),
Identifier(String),
CharConstant(char),
StringConst(String),
LeftBrace,
RightBrace,
LeftParen,
RightParen,
#[cfg(not(feature = "no_index"))]
LeftBracket,
#[cfg(not(feature = "no_index"))]
RightBracket,
Plus,
2017-10-30 16:08:44 +01:00
UnaryPlus,
Minus,
2017-10-30 16:08:44 +01:00
UnaryMinus,
Multiply,
Divide,
2020-03-19 12:53:42 +01:00
Modulo,
PowerOf,
LeftShift,
RightShift,
SemiColon,
Colon,
Comma,
Period,
2020-03-29 17:53:35 +02:00
#[cfg(not(feature = "no_object"))]
MapStart,
Equals,
True,
False,
Let,
2020-03-13 11:12:41 +01:00
Const,
If,
Else,
While,
2017-10-30 16:08:44 +01:00
Loop,
2020-03-19 12:53:42 +01:00
For,
In,
LessThan,
GreaterThan,
LessThanEqualsTo,
GreaterThanEqualsTo,
EqualsTo,
NotEqualsTo,
2020-03-19 12:53:42 +01:00
Bang,
Pipe,
Or,
2020-03-19 12:53:42 +01:00
XOr,
Ampersand,
And,
#[cfg(not(feature = "no_function"))]
Fn,
Break,
Return,
2020-03-03 11:15:20 +01:00
Throw,
PlusAssign,
MinusAssign,
MultiplyAssign,
DivideAssign,
LeftShiftAssign,
RightShiftAssign,
AndAssign,
OrAssign,
XOrAssign,
ModuloAssign,
PowerOfAssign,
2020-03-24 02:49:37 +01:00
LexError(Box<LexError>),
}
2016-02-29 22:43:45 +01:00
2017-10-30 16:08:44 +01:00
impl Token {
2020-03-18 03:36:50 +01:00
/// Get the syntax of the token.
2020-03-24 09:46:47 +01:00
pub fn syntax(&self) -> Cow<str> {
use self::Token::*;
2020-03-16 16:51:32 +01:00
match self {
IntegerConstant(i) => i.to_string().into(),
#[cfg(not(feature = "no_float"))]
2020-03-16 16:51:32 +01:00
FloatConstant(f) => f.to_string().into(),
Identifier(s) => s.into(),
CharConstant(c) => c.to_string().into(),
LexError(err) => err.to_string().into(),
2020-03-16 16:51:32 +01:00
token => (match token {
StringConst(_) => "string",
LeftBrace => "{",
RightBrace => "}",
LeftParen => "(",
RightParen => ")",
#[cfg(not(feature = "no_index"))]
LeftBracket => "[",
#[cfg(not(feature = "no_index"))]
RightBracket => "]",
Plus => "+",
UnaryPlus => "+",
Minus => "-",
UnaryMinus => "-",
Multiply => "*",
Divide => "/",
SemiColon => ";",
Colon => ":",
Comma => ",",
Period => ".",
2020-03-29 17:53:35 +02:00
#[cfg(not(feature = "no_object"))]
MapStart => "${",
Equals => "=",
True => "true",
False => "false",
Let => "let",
2020-03-13 11:12:41 +01:00
Const => "const",
If => "if",
Else => "else",
While => "while",
Loop => "loop",
LessThan => "<",
GreaterThan => ">",
Bang => "!",
LessThanEqualsTo => "<=",
GreaterThanEqualsTo => ">=",
EqualsTo => "==",
NotEqualsTo => "!=",
Pipe => "|",
Or => "||",
Ampersand => "&",
And => "&&",
#[cfg(not(feature = "no_function"))]
Fn => "fn",
Break => "break",
Return => "return",
2020-03-03 11:15:20 +01:00
Throw => "throw",
PlusAssign => "+=",
MinusAssign => "-=",
MultiplyAssign => "*=",
DivideAssign => "/=",
LeftShiftAssign => "<<=",
RightShiftAssign => ">>=",
AndAssign => "&=",
OrAssign => "|=",
XOrAssign => "^=",
LeftShift => "<<",
RightShift => ">>",
XOr => "^",
Modulo => "%",
ModuloAssign => "%=",
PowerOf => "~",
PowerOfAssign => "~=",
For => "for",
In => "in",
2020-03-07 03:15:42 +01:00
_ => panic!("operator should be match in outer scope"),
})
.into(),
}
}
2020-03-18 03:36:50 +01:00
// If another operator is after these, it's probably an unary operator
// (not sure about fn name).
2017-10-30 16:08:44 +01:00
pub fn is_next_unary(&self) -> bool {
use self::Token::*;
2020-03-16 16:51:32 +01:00
match self {
LexError(_) |
LeftBrace | // (+expr) - is unary
// RightBrace | {expr} - expr not unary & is closing
LeftParen | // {-expr} - is unary
// RightParen | (expr) - expr not unary & is closing
2017-10-30 16:08:44 +01:00
Plus |
UnaryPlus |
Minus |
UnaryMinus |
Multiply |
Divide |
Colon |
Comma |
Period |
Equals |
LessThan |
GreaterThan |
Bang |
LessThanEqualsTo |
GreaterThanEqualsTo |
EqualsTo |
NotEqualsTo |
2017-10-30 16:08:44 +01:00
Pipe |
Or |
Ampersand |
And |
If |
While |
PlusAssign |
MinusAssign |
MultiplyAssign |
DivideAssign |
LeftShiftAssign |
RightShiftAssign |
AndAssign |
OrAssign |
XOrAssign |
LeftShift |
RightShift |
XOr |
Modulo |
ModuloAssign |
2017-11-24 08:56:22 +01:00
Return |
2020-03-03 11:15:20 +01:00
Throw |
2017-11-24 08:56:22 +01:00
PowerOf |
In |
PowerOfAssign => true,
#[cfg(not(feature = "no_index"))]
LeftBracket => true, // [-expr] - is unary
// RightBracket | [expr] - expr not unary & is closing
2017-10-30 16:08:44 +01:00
_ => false,
}
}
2020-03-18 03:36:50 +01:00
/// Get the precedence number of the token.
2020-03-16 16:51:32 +01:00
pub fn precedence(&self) -> u8 {
match self {
Self::Equals
| Self::PlusAssign
| Self::MinusAssign
| Self::MultiplyAssign
| Self::DivideAssign
| Self::LeftShiftAssign
| Self::RightShiftAssign
| Self::AndAssign
| Self::OrAssign
| Self::XOrAssign
| Self::ModuloAssign
| Self::PowerOfAssign => 10,
2017-10-30 16:08:44 +01:00
2020-03-16 16:51:32 +01:00
Self::Or | Self::XOr | Self::Pipe => 50,
2020-03-16 16:51:32 +01:00
Self::And | Self::Ampersand => 60,
2020-03-16 16:51:32 +01:00
Self::LessThan
| Self::LessThanEqualsTo
| Self::GreaterThan
| Self::GreaterThanEqualsTo
| Self::EqualsTo
| Self::NotEqualsTo => 70,
Self::Plus | Self::Minus => 80,
Self::Divide | Self::Multiply | Self::PowerOf => 90,
Self::LeftShift | Self::RightShift => 100,
Self::Modulo => 110,
Self::Period => 120,
_ => 0,
2017-10-30 16:08:44 +01:00
}
}
2020-03-18 03:36:50 +01:00
/// Does an expression bind to the right (instead of left)?
2020-03-16 16:51:32 +01:00
pub fn is_bind_right(&self) -> bool {
match self {
2020-03-18 03:36:50 +01:00
// Assignments bind to the right
2020-03-16 16:51:32 +01:00
Self::Equals
| Self::PlusAssign
| Self::MinusAssign
| Self::MultiplyAssign
| Self::DivideAssign
| Self::LeftShiftAssign
| Self::RightShiftAssign
| Self::AndAssign
| Self::OrAssign
| Self::XOrAssign
| Self::ModuloAssign
| Self::PowerOfAssign => true,
2020-03-18 03:36:50 +01:00
// Property access binds to the right
2020-03-16 16:51:32 +01:00
Self::Period => true,
2017-10-30 16:08:44 +01:00
_ => false,
}
}
}
2020-03-18 03:36:50 +01:00
/// An iterator on a `Token` stream.
2016-02-29 22:43:45 +01:00
pub struct TokenIterator<'a> {
2020-03-24 04:21:20 +01:00
/// Can the next token be a unary operator?
can_be_unary: bool,
2020-03-18 03:36:50 +01:00
/// Current position.
2020-02-29 13:12:10 +01:00
pos: Position,
2020-03-18 03:36:50 +01:00
/// The input characters stream.
2020-03-24 04:21:20 +01:00
stream: Peekable<Chars<'a>>,
}
impl<'a> TokenIterator<'a> {
2020-03-29 17:53:35 +02:00
/// Consume the next character.
fn eat_next(&mut self) {
self.stream.next();
self.advance();
}
2020-03-18 03:36:50 +01:00
/// Move the current position one character ahead.
fn advance(&mut self) {
self.pos.advance();
}
2020-03-18 03:36:50 +01:00
/// Move the current position back one character.
///
/// # Panics
///
/// Panics if already at the beginning of a line - cannot rewind to the previous line.
fn rewind(&mut self) {
self.pos.rewind();
}
2020-03-18 03:36:50 +01:00
/// Move the current position to the next line.
fn new_line(&mut self) {
self.pos.new_line()
}
2020-03-18 03:36:50 +01:00
/// Parse a string literal wrapped by `enclosing_char`.
pub fn parse_string_literal(
&mut self,
enclosing_char: char,
2020-02-29 13:12:10 +01:00
) -> Result<String, (LexError, Position)> {
let mut result = Vec::new();
2020-03-03 14:39:25 +01:00
let mut escape = String::with_capacity(12);
loop {
2020-03-24 04:21:20 +01:00
let next_char = self.stream.next();
self.advance();
2020-03-12 05:40:28 +01:00
match next_char.ok_or((LERR::UnterminatedString, Position::eof()))? {
2020-03-18 03:36:50 +01:00
// \...
2020-03-03 14:39:25 +01:00
'\\' if escape.is_empty() => {
escape.push('\\');
}
2020-03-18 03:36:50 +01:00
// \\
2020-03-03 14:39:25 +01:00
'\\' if !escape.is_empty() => {
escape.clear();
result.push('\\');
}
2020-03-18 03:36:50 +01:00
// \t
2020-03-03 14:39:25 +01:00
't' if !escape.is_empty() => {
escape.clear();
result.push('\t');
}
2020-03-18 03:36:50 +01:00
// \n
2020-03-03 14:39:25 +01:00
'n' if !escape.is_empty() => {
escape.clear();
result.push('\n');
}
2020-03-18 03:36:50 +01:00
// \r
2020-03-03 14:39:25 +01:00
'r' if !escape.is_empty() => {
escape.clear();
result.push('\r');
}
2020-03-18 03:36:50 +01:00
// \x??, \u????, \U????????
2020-03-16 16:51:32 +01:00
ch @ 'x' | ch @ 'u' | ch @ 'U' if !escape.is_empty() => {
2020-03-03 14:39:25 +01:00
let mut seq = escape.clone();
2020-03-16 16:51:32 +01:00
seq.push(ch);
2020-03-03 14:39:25 +01:00
escape.clear();
let mut out_val: u32 = 0;
2020-03-16 16:51:32 +01:00
let len = match ch {
'x' => 2,
'u' => 4,
'U' => 8,
_ => panic!("should be 'x', 'u' or 'U'"),
};
for _ in 0..len {
2020-03-24 04:21:20 +01:00
let c = self.stream.next().ok_or_else(|| {
2020-03-16 16:51:32 +01:00
(LERR::MalformedEscapeSequence(seq.to_string()), self.pos)
})?;
seq.push(c);
self.advance();
2020-03-03 14:39:25 +01:00
2020-03-16 16:51:32 +01:00
out_val *= 16;
out_val += c.to_digit(16).ok_or_else(|| {
(LERR::MalformedEscapeSequence(seq.to_string()), self.pos)
})?;
}
2020-03-16 16:51:32 +01:00
result.push(
char::from_u32(out_val)
.ok_or_else(|| (LERR::MalformedEscapeSequence(seq), self.pos))?,
);
}
2020-03-18 03:36:50 +01:00
// \{enclosing_char} - escaped
2020-03-16 16:51:32 +01:00
ch if enclosing_char == ch && !escape.is_empty() => result.push(ch),
2020-03-18 03:36:50 +01:00
// Close wrapper
2020-03-16 16:51:32 +01:00
ch if enclosing_char == ch && escape.is_empty() => break,
2020-03-18 03:36:50 +01:00
// Unknown escape sequence
2020-03-03 14:39:25 +01:00
_ if !escape.is_empty() => {
return Err((LERR::MalformedEscapeSequence(escape), self.pos))
}
2020-03-18 03:36:50 +01:00
// Cannot have new-lines inside string literals
'\n' => {
self.rewind();
return Err((LERR::UnterminatedString, self.pos));
}
2020-03-18 03:36:50 +01:00
// All other characters
2020-03-16 16:51:32 +01:00
ch => {
2020-03-03 14:39:25 +01:00
escape.clear();
2020-03-16 16:51:32 +01:00
result.push(ch);
}
}
}
2020-03-07 03:15:42 +01:00
Ok(result.iter().collect())
}
2016-02-29 22:43:45 +01:00
2020-03-18 03:36:50 +01:00
/// Get the next token.
2020-02-29 13:12:10 +01:00
fn inner_next(&mut self) -> Option<(Token, Position)> {
let mut negated = false;
2020-03-24 04:21:20 +01:00
while let Some(c) = self.stream.next() {
self.advance();
let pos = self.pos;
2020-03-24 09:46:47 +01:00
match (c, self.stream.peek().copied().unwrap_or('\0')) {
2020-03-18 03:36:50 +01:00
// \n
2020-03-24 09:46:47 +01:00
('\n', _) => self.new_line(),
2020-03-18 03:36:50 +01:00
// digit ...
2020-03-24 09:46:47 +01:00
('0'..='9', _) => {
2016-02-29 22:43:45 +01:00
let mut result = Vec::new();
2017-11-01 06:10:46 +01:00
let mut radix_base: Option<u32> = None;
2016-02-29 22:43:45 +01:00
result.push(c);
2020-03-24 04:21:20 +01:00
while let Some(&next_char) = self.stream.peek() {
match next_char {
2020-03-03 14:39:25 +01:00
'0'..='9' | '_' => {
result.push(next_char);
2020-03-29 17:53:35 +02:00
self.eat_next();
}
#[cfg(not(feature = "no_float"))]
'.' => {
result.push(next_char);
2020-03-29 17:53:35 +02:00
self.eat_next();
2020-03-24 04:21:20 +01:00
while let Some(&next_char_in_float) = self.stream.peek() {
match next_char_in_float {
2020-03-03 14:39:25 +01:00
'0'..='9' | '_' => {
result.push(next_char_in_float);
2020-03-29 17:53:35 +02:00
self.eat_next();
}
_ => break,
}
}
}
2020-03-18 03:36:50 +01:00
// 0x????, 0o????, 0b????
2020-03-16 16:51:32 +01:00
ch @ 'x' | ch @ 'X' | ch @ 'o' | ch @ 'O' | ch @ 'b' | ch @ 'B'
if c == '0' =>
{
result.push(next_char);
2020-03-29 17:53:35 +02:00
self.eat_next();
2020-03-16 16:51:32 +01:00
let valid = match ch {
'x' | 'X' => [
'a', 'b', 'c', 'd', 'e', 'f', 'A', 'B', 'C', 'D', 'E', 'F',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '_',
],
'o' | 'O' => [
'0', '1', '2', '3', '4', '5', '6', '7', '_', '_', '_', '_',
'_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_',
],
'b' | 'B' => [
'0', '1', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_',
'_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_',
],
_ => panic!("unexpected character {}", ch),
};
radix_base = Some(match ch {
'x' | 'X' => 16,
'o' | 'O' => 8,
'b' | 'B' => 2,
_ => panic!("unexpected character {}", ch),
});
2020-03-24 04:21:20 +01:00
while let Some(&next_char_in_hex) = self.stream.peek() {
2020-03-16 16:51:32 +01:00
if !valid.contains(&next_char_in_hex) {
break;
2017-11-01 06:02:36 +01:00
}
2020-03-16 16:51:32 +01:00
result.push(next_char_in_hex);
2020-03-29 17:53:35 +02:00
self.eat_next();
2017-11-01 06:02:36 +01:00
}
}
2020-03-16 16:51:32 +01:00
_ => break,
2016-02-29 22:43:45 +01:00
}
}
if negated {
result.insert(0, '-');
}
2020-03-18 03:36:50 +01:00
// Parse number
2017-11-01 06:10:46 +01:00
if let Some(radix) = radix_base {
2020-03-03 14:39:25 +01:00
let out: String = result.iter().skip(2).filter(|&&c| c != '_').collect();
return Some((
INT::from_str_radix(&out, radix)
2020-03-09 14:57:07 +01:00
.map(Token::IntegerConstant)
.unwrap_or_else(|_| {
2020-03-24 02:49:37 +01:00
Token::LexError(Box::new(LERR::MalformedNumber(
result.iter().collect(),
)))
2020-03-09 14:57:07 +01:00
}),
2020-03-03 14:39:25 +01:00
pos,
));
2020-03-07 03:15:42 +01:00
} else {
let out: String = result.iter().filter(|&&c| c != '_').collect();
2020-03-16 16:51:32 +01:00
let num = INT::from_str(&out).map(Token::IntegerConstant);
2020-03-18 03:36:50 +01:00
// If integer parsing is unnecessary, try float instead
#[cfg(not(feature = "no_float"))]
2020-03-16 16:51:32 +01:00
let num = num.or_else(|_| FLOAT::from_str(&out).map(Token::FloatConstant));
2020-03-07 03:15:42 +01:00
return Some((
2020-03-16 16:51:32 +01:00
num.unwrap_or_else(|_| {
2020-03-24 02:49:37 +01:00
Token::LexError(Box::new(LERR::MalformedNumber(
result.iter().collect(),
)))
2020-03-16 16:51:32 +01:00
}),
2020-03-07 03:15:42 +01:00
pos,
));
}
}
2020-03-24 09:46:47 +01:00
// letter or underscore ...
('A'..='Z', _) | ('a'..='z', _) | ('_', _) => {
2016-02-29 22:43:45 +01:00
let mut result = Vec::new();
result.push(c);
2020-03-24 04:21:20 +01:00
while let Some(&next_char) = self.stream.peek() {
match next_char {
x if x.is_ascii_alphanumeric() || x == '_' => {
2017-10-14 19:46:22 +02:00
result.push(x);
2020-03-29 17:53:35 +02:00
self.eat_next();
}
_ => break,
2016-02-29 22:43:45 +01:00
}
}
let is_valid_identifier = result
.iter()
.find(|&ch| char::is_ascii_alphanumeric(ch)) // first alpha-numeric character
.map(char::is_ascii_alphabetic) // is a letter
.unwrap_or(false); // if no alpha-numeric at all - syntax error
2020-03-16 05:38:01 +01:00
let identifier: String = result.iter().collect();
if !is_valid_identifier {
2020-03-24 02:49:37 +01:00
return Some((
Token::LexError(Box::new(LERR::MalformedIdentifier(identifier))),
pos,
));
}
return Some((
2020-03-16 05:38:01 +01:00
match identifier.as_str() {
"true" => Token::True,
"false" => Token::False,
"let" => Token::Let,
2020-03-13 11:12:41 +01:00
"const" => Token::Const,
"if" => Token::If,
"else" => Token::Else,
"while" => Token::While,
"loop" => Token::Loop,
"break" => Token::Break,
"return" => Token::Return,
2020-03-03 11:15:20 +01:00
"throw" => Token::Throw,
"for" => Token::For,
"in" => Token::In,
#[cfg(not(feature = "no_function"))]
"fn" => Token::Fn,
_ => Token::Identifier(identifier),
},
pos,
));
}
2020-03-24 09:46:47 +01:00
2020-03-18 03:36:50 +01:00
// " - string literal
2020-03-24 09:46:47 +01:00
('"', _) => {
return self.parse_string_literal('"').map_or_else(
|err| Some((Token::LexError(Box::new(err.0)), err.1)),
|out| Some((Token::StringConst(out), pos)),
);
}
2019-09-18 12:21:07 +02:00
2020-03-24 09:46:47 +01:00
// ' - character literal
('\'', '\'') => {
return Some((
Token::LexError(Box::new(LERR::MalformedChar("".to_string()))),
pos,
));
}
('\'', _) => {
return Some(self.parse_string_literal('\'').map_or_else(
|err| (Token::LexError(Box::new(err.0)), err.1),
|result| {
let mut chars = result.chars();
let first = chars.next();
if chars.next().is_some() {
(Token::LexError(Box::new(LERR::MalformedChar(result))), pos)
} else {
2020-03-24 09:46:47 +01:00
(Token::CharConstant(first.expect("should be Some")), pos)
}
},
));
}
2020-03-18 03:36:50 +01:00
// Braces
2020-03-24 09:46:47 +01:00
('{', _) => return Some((Token::LeftBrace, pos)),
('}', _) => return Some((Token::RightBrace, pos)),
2020-03-18 03:36:50 +01:00
// Parentheses
2020-03-24 09:46:47 +01:00
('(', _) => return Some((Token::LeftParen, pos)),
(')', _) => return Some((Token::RightParen, pos)),
2020-03-18 03:36:50 +01:00
// Indexing
#[cfg(not(feature = "no_index"))]
2020-03-24 09:46:47 +01:00
('[', _) => return Some((Token::LeftBracket, pos)),
#[cfg(not(feature = "no_index"))]
2020-03-24 09:46:47 +01:00
(']', _) => return Some((Token::RightBracket, pos)),
2020-03-29 17:53:35 +02:00
// Map literal
#[cfg(not(feature = "no_object"))]
('$', '{') => {
self.eat_next();
return Some((Token::MapStart, pos));
}
2020-03-18 03:36:50 +01:00
// Operators
2020-03-24 09:46:47 +01:00
('+', '=') => {
2020-03-29 17:53:35 +02:00
self.eat_next();
2020-03-24 09:46:47 +01:00
return Some((Token::PlusAssign, pos));
2019-09-18 12:21:07 +02:00
}
2020-03-24 09:46:47 +01:00
('+', _) if self.can_be_unary => return Some((Token::UnaryPlus, pos)),
('+', _) => return Some((Token::Plus, pos)),
('-', '0'..='9') if self.can_be_unary => negated = true,
('-', '0'..='9') => return Some((Token::Minus, pos)),
('-', '=') => {
2020-03-29 17:53:35 +02:00
self.eat_next();
2020-03-24 09:46:47 +01:00
return Some((Token::MinusAssign, pos));
2019-09-18 12:21:07 +02:00
}
2020-03-24 09:46:47 +01:00
('-', _) if self.can_be_unary => return Some((Token::UnaryMinus, pos)),
('-', _) => return Some((Token::Minus, pos)),
2020-03-24 09:46:47 +01:00
('*', '=') => {
2020-03-29 17:53:35 +02:00
self.eat_next();
2020-03-24 09:46:47 +01:00
return Some((Token::MultiplyAssign, pos));
}
('*', _) => return Some((Token::Multiply, pos)),
2017-10-30 16:08:44 +01:00
2020-03-24 09:46:47 +01:00
// Comments
('/', '/') => {
2020-03-29 17:53:35 +02:00
self.eat_next();
2020-03-24 09:46:47 +01:00
while let Some(c) = self.stream.next() {
if c == '\n' {
self.new_line();
break;
2017-10-30 16:08:44 +01:00
}
2020-03-24 09:46:47 +01:00
self.advance();
2019-09-18 12:21:07 +02:00
}
2020-03-24 09:46:47 +01:00
}
('/', '*') => {
let mut level = 1;
2020-03-29 17:53:35 +02:00
self.eat_next();
2020-03-24 09:46:47 +01:00
while let Some(c) = self.stream.next() {
self.advance();
2020-03-24 09:46:47 +01:00
match c {
'/' => {
if self.stream.next() == Some('*') {
level += 1;
}
self.advance();
}
2020-03-24 09:46:47 +01:00
'*' => {
if self.stream.next() == Some('/') {
level -= 1;
}
self.advance();
2019-09-18 12:21:07 +02:00
}
2020-03-24 09:46:47 +01:00
'\n' => self.new_line(),
_ => (),
}
if level == 0 {
break;
}
2016-03-01 15:40:48 +01:00
}
}
2020-03-24 09:46:47 +01:00
('/', '=') => {
2020-03-29 17:53:35 +02:00
self.eat_next();
2020-03-24 09:46:47 +01:00
return Some((Token::DivideAssign, pos));
}
2020-03-24 09:46:47 +01:00
('/', _) => return Some((Token::Divide, pos)),
(';', _) => return Some((Token::SemiColon, pos)),
(':', _) => return Some((Token::Colon, pos)),
(',', _) => return Some((Token::Comma, pos)),
('.', _) => return Some((Token::Period, pos)),
('=', '=') => {
2020-03-29 17:53:35 +02:00
self.eat_next();
2020-03-24 09:46:47 +01:00
return Some((Token::EqualsTo, pos));
}
2020-03-24 09:46:47 +01:00
('=', _) => return Some((Token::Equals, pos)),
('<', '=') => {
2020-03-29 17:53:35 +02:00
self.eat_next();
2020-03-24 09:46:47 +01:00
return Some((Token::LessThanEqualsTo, pos));
}
2020-03-24 09:46:47 +01:00
('<', '<') => {
2020-03-29 17:53:35 +02:00
self.eat_next();
2020-03-24 09:46:47 +01:00
return Some((
2020-03-24 09:46:47 +01:00
if self.stream.peek() == Some(&'=') {
2020-03-29 17:53:35 +02:00
self.eat_next();
2020-03-24 09:46:47 +01:00
Token::LeftShiftAssign
} else {
Token::LeftShift
},
pos,
2020-03-24 09:46:47 +01:00
));
}
2020-03-24 09:46:47 +01:00
('<', _) => return Some((Token::LessThan, pos)),
('>', '=') => {
2020-03-29 17:53:35 +02:00
self.eat_next();
2020-03-24 09:46:47 +01:00
return Some((Token::GreaterThanEqualsTo, pos));
}
2020-03-24 09:46:47 +01:00
('>', '>') => {
2020-03-29 17:53:35 +02:00
self.eat_next();
2020-03-24 09:46:47 +01:00
return Some((
2020-03-24 09:46:47 +01:00
if self.stream.peek() == Some(&'=') {
2020-03-29 17:53:35 +02:00
self.eat_next();
2020-03-24 09:46:47 +01:00
Token::RightShiftAssign
} else {
Token::RightShift
},
pos,
2020-03-24 09:46:47 +01:00
));
}
('>', _) => return Some((Token::GreaterThan, pos)),
('!', '=') => {
2020-03-29 17:53:35 +02:00
self.eat_next();
2020-03-24 09:46:47 +01:00
return Some((Token::NotEqualsTo, pos));
}
('!', _) => return Some((Token::Bang, pos)),
('|', '|') => {
2020-03-29 17:53:35 +02:00
self.eat_next();
2020-03-24 09:46:47 +01:00
return Some((Token::Or, pos));
}
('|', '=') => {
2020-03-29 17:53:35 +02:00
self.eat_next();
2020-03-24 09:46:47 +01:00
return Some((Token::OrAssign, pos));
}
('|', _) => return Some((Token::Pipe, pos)),
('&', '&') => {
2020-03-29 17:53:35 +02:00
self.eat_next();
2020-03-24 09:46:47 +01:00
return Some((Token::And, pos));
}
('&', '=') => {
2020-03-29 17:53:35 +02:00
self.eat_next();
2020-03-24 09:46:47 +01:00
return Some((Token::AndAssign, pos));
}
('&', _) => return Some((Token::Ampersand, pos)),
('^', '=') => {
2020-03-29 17:53:35 +02:00
self.eat_next();
2020-03-24 09:46:47 +01:00
return Some((Token::XOrAssign, pos));
}
('^', _) => return Some((Token::XOr, pos)),
('%', '=') => {
2020-03-29 17:53:35 +02:00
self.eat_next();
2020-03-24 09:46:47 +01:00
return Some((Token::ModuloAssign, pos));
}
('%', _) => return Some((Token::Modulo, pos)),
('~', '=') => {
2020-03-29 17:53:35 +02:00
self.eat_next();
2020-03-24 09:46:47 +01:00
return Some((Token::PowerOfAssign, pos));
}
2020-03-24 09:46:47 +01:00
('~', _) => return Some((Token::PowerOf, pos)),
(ch, _) if ch.is_whitespace() => (),
(ch, _) => return Some((Token::LexError(Box::new(LERR::UnexpectedChar(ch))), pos)),
2016-02-29 22:43:45 +01:00
}
}
None
}
}
2017-10-30 16:08:44 +01:00
impl<'a> Iterator for TokenIterator<'a> {
2020-02-29 13:12:10 +01:00
type Item = (Token, Position);
2017-10-30 16:08:44 +01:00
fn next(&mut self) -> Option<Self::Item> {
self.inner_next().map(|x| {
2020-03-24 04:21:20 +01:00
// Save the last token
self.can_be_unary = x.0.is_next_unary();
x
})
2017-10-30 16:08:44 +01:00
}
}
2020-03-18 03:36:50 +01:00
/// Tokenize an input text stream.
2019-09-18 12:21:07 +02:00
pub fn lex(input: &str) -> TokenIterator<'_> {
TokenIterator {
2020-03-24 04:21:20 +01:00
can_be_unary: true,
2020-03-04 15:00:01 +01:00
pos: Position::new(1, 0),
2020-03-24 04:21:20 +01:00
stream: input.chars().peekable(),
2019-09-18 12:21:07 +02:00
}
2016-02-29 22:43:45 +01:00
}
2020-03-18 03:36:50 +01:00
/// Parse ( expr )
fn parse_paren_expr<'a>(
input: &mut Peekable<TokenIterator<'a>>,
begin: Position,
2020-03-22 14:03:58 +01:00
allow_stmt_expr: bool,
) -> Result<Expr, ParseError> {
2020-03-24 09:46:47 +01:00
if matches!(input.peek(), Some((Token::RightParen, _))) {
input.next();
return Ok(Expr::Unit(begin));
}
2020-03-22 14:03:58 +01:00
let expr = parse_expr(input, allow_stmt_expr)?;
2016-02-29 22:43:45 +01:00
match input.next() {
2020-03-18 03:36:50 +01:00
// ( xxx )
2020-02-29 13:12:10 +01:00
Some((Token::RightParen, _)) => Ok(expr),
2020-03-18 03:36:50 +01:00
// ( xxx ???
Some((_, pos)) => Err(PERR::MissingToken(
")".into(),
"for a matching ( in this expression".into(),
)
.into_err(pos)),
2020-03-18 03:36:50 +01:00
// ( xxx
None => Err(
PERR::MissingToken(")".into(), "for a matching ( in this expression".into())
.into_err_eof(),
),
2016-02-29 22:43:45 +01:00
}
}
2020-03-18 03:36:50 +01:00
/// Parse a function call.
2019-09-18 12:21:07 +02:00
fn parse_call_expr<'a>(
id: String,
input: &mut Peekable<TokenIterator<'a>>,
begin: Position,
2020-03-22 14:03:58 +01:00
allow_stmt_expr: bool,
2019-09-18 12:21:07 +02:00
) -> Result<Expr, ParseError> {
let mut args_expr_list = Vec::new();
2017-10-28 05:30:12 +02:00
2020-03-18 03:36:50 +01:00
// id()
2020-03-16 16:51:32 +01:00
if let (Token::RightParen, _) = input.peek().ok_or_else(|| {
PERR::MissingToken(
")".into(),
format!("to close the arguments list of this function call '{}'", id),
)
2020-03-24 09:46:47 +01:00
.into_err_eof()
2020-03-16 16:51:32 +01:00
})? {
2017-10-02 23:44:45 +02:00
input.next();
return Ok(Expr::FunctionCall(id, args_expr_list, None, begin));
2016-02-29 22:43:45 +01:00
}
loop {
2020-03-22 14:03:58 +01:00
args_expr_list.push(parse_expr(input, allow_stmt_expr)?);
2016-02-29 22:43:45 +01:00
2020-03-16 16:51:32 +01:00
match input.peek().ok_or_else(|| {
PERR::MissingToken(
")".into(),
format!("to close the arguments list of this function call '{}'", id),
)
2020-03-24 09:46:47 +01:00
.into_err_eof()
2020-03-16 16:51:32 +01:00
})? {
(Token::RightParen, _) => {
input.next();
return Ok(Expr::FunctionCall(id, args_expr_list, None, begin));
}
2020-03-16 16:51:32 +01:00
(Token::Comma, _) => (),
(_, pos) => {
return Err(PERR::MissingToken(
",".into(),
format!("to separate the arguments to function call '{}'", id),
)
2020-03-24 09:46:47 +01:00
.into_err(*pos))
}
2016-02-29 22:43:45 +01:00
}
input.next();
}
}
2020-03-29 17:53:35 +02:00
/// Parse an indexing expression.
#[cfg(not(feature = "no_index"))]
2019-09-18 12:21:07 +02:00
fn parse_index_expr<'a>(
2020-03-05 13:28:03 +01:00
lhs: Box<Expr>,
2019-09-18 12:21:07 +02:00
input: &mut Peekable<TokenIterator<'a>>,
pos: Position,
2020-03-22 14:03:58 +01:00
allow_stmt_expr: bool,
2019-09-18 12:21:07 +02:00
) -> Result<Expr, ParseError> {
2020-03-22 14:03:58 +01:00
let idx_expr = parse_expr(input, allow_stmt_expr)?;
2020-03-09 03:41:17 +01:00
2020-03-29 17:53:35 +02:00
// Check type of indexing - must be integer or string
2020-03-09 03:41:17 +01:00
match &idx_expr {
2020-03-18 03:36:50 +01:00
// lhs[int]
2020-03-09 03:41:17 +01:00
Expr::IntegerConstant(i, pos) if *i < 0 => {
2020-03-24 09:46:47 +01:00
return Err(PERR::MalformedIndexExpr(format!(
"Array access expects non-negative index: {} < 0",
i
2020-03-09 03:41:17 +01:00
))
2020-03-24 09:46:47 +01:00
.into_err(*pos))
2020-03-09 03:41:17 +01:00
}
2020-03-29 17:53:35 +02:00
Expr::IntegerConstant(_, pos) => match *lhs {
Expr::Array(_, _) | Expr::StringConstant(_, _) => (),
#[cfg(not(feature = "no_object"))]
Expr::Map(_, _) => {
return Err(PERR::MalformedIndexExpr(
"Object map access expects string index, not a number".into(),
)
.into_err(*pos))
}
Expr::FloatConstant(_, pos)
| Expr::CharConstant(_, pos)
| Expr::Assignment(_, _, pos)
| Expr::Unit(pos)
| Expr::True(pos)
| Expr::False(pos) => {
return Err(PERR::MalformedIndexExpr(
"Only arrays, object maps and strings can be indexed".into(),
)
.into_err(pos))
}
Expr::And(lhs, _) | Expr::Or(lhs, _) => {
return Err(PERR::MalformedIndexExpr(
"Only arrays, object maps and strings can be indexed".into(),
)
.into_err(lhs.position()))
}
_ => (),
},
// lhs[string]
Expr::StringConstant(_, pos) => match *lhs {
#[cfg(not(feature = "no_object"))]
Expr::Map(_, _) => (),
Expr::Array(_, _) | Expr::StringConstant(_, _) => {
return Err(PERR::MalformedIndexExpr(
"Array or string expects numeric index, not a string".into(),
)
.into_err(*pos))
}
Expr::FloatConstant(_, pos)
| Expr::CharConstant(_, pos)
| Expr::Assignment(_, _, pos)
| Expr::Unit(pos)
| Expr::True(pos)
| Expr::False(pos) => {
return Err(PERR::MalformedIndexExpr(
"Only arrays, object maps and strings can be indexed".into(),
)
.into_err(pos))
}
Expr::And(lhs, _) | Expr::Or(lhs, _) => {
return Err(PERR::MalformedIndexExpr(
"Only arrays, object maps and strings can be indexed".into(),
)
.into_err(lhs.position()))
}
_ => (),
},
2020-03-18 03:36:50 +01:00
// lhs[float]
#[cfg(not(feature = "no_float"))]
2020-03-09 03:41:17 +01:00
Expr::FloatConstant(_, pos) => {
2020-03-24 09:46:47 +01:00
return Err(PERR::MalformedIndexExpr(
"Array access expects integer index, not a float".into(),
)
.into_err(*pos))
2020-03-09 03:41:17 +01:00
}
2020-03-18 03:36:50 +01:00
// lhs[char]
2020-03-09 03:41:17 +01:00
Expr::CharConstant(_, pos) => {
2020-03-24 09:46:47 +01:00
return Err(PERR::MalformedIndexExpr(
"Array access expects integer index, not a character".into(),
)
.into_err(*pos))
2020-03-09 03:41:17 +01:00
}
2020-03-18 03:36:50 +01:00
// lhs[??? = ??? ], lhs[()]
2020-03-09 03:41:17 +01:00
Expr::Assignment(_, _, pos) | Expr::Unit(pos) => {
2020-03-24 09:46:47 +01:00
return Err(PERR::MalformedIndexExpr(
"Array access expects integer index, not ()".into(),
)
.into_err(*pos))
2020-03-09 03:41:17 +01:00
}
2020-03-18 03:36:50 +01:00
// lhs[??? && ???], lhs[??? || ???]
2020-03-09 03:41:17 +01:00
Expr::And(lhs, _) | Expr::Or(lhs, _) => {
2020-03-24 09:46:47 +01:00
return Err(PERR::MalformedIndexExpr(
"Array access expects integer index, not a boolean".into(),
)
.into_err(lhs.position()))
2020-03-09 03:41:17 +01:00
}
2020-03-18 03:36:50 +01:00
// lhs[true], lhs[false]
2020-03-09 03:41:17 +01:00
Expr::True(pos) | Expr::False(pos) => {
2020-03-24 09:46:47 +01:00
return Err(PERR::MalformedIndexExpr(
"Array access expects integer index, not a boolean".into(),
)
.into_err(*pos))
2020-03-09 03:41:17 +01:00
}
2020-03-18 03:36:50 +01:00
// All other expressions
2020-03-09 03:41:17 +01:00
_ => (),
}
// Check if there is a closing bracket
match input.peek().ok_or_else(|| {
PERR::MissingToken(
"]".into(),
"for a matching [ in this index expression".into(),
)
.into_err_eof()
})? {
2020-03-16 16:51:32 +01:00
(Token::RightBracket, _) => {
input.next();
2020-03-24 09:46:47 +01:00
Ok(Expr::Index(lhs, Box::new(idx_expr), pos))
}
(_, pos) => Err(PERR::MissingToken(
"]".into(),
"for a matching [ in this index expression".into(),
)
.into_err(*pos)),
2020-03-09 03:41:17 +01:00
}
2016-03-26 18:46:28 +01:00
}
2020-03-18 03:36:50 +01:00
/// Parse an expression that begins with an identifier.
2019-09-18 12:21:07 +02:00
fn parse_ident_expr<'a>(
id: String,
input: &mut Peekable<TokenIterator<'a>>,
begin: Position,
2020-03-22 14:03:58 +01:00
allow_stmt_expr: bool,
2019-09-18 12:21:07 +02:00
) -> Result<Expr, ParseError> {
2016-03-26 18:46:28 +01:00
match input.peek() {
2020-03-18 03:36:50 +01:00
// id(...) - function call
2020-03-16 16:51:32 +01:00
Some((Token::LeftParen, _)) => {
input.next();
2020-03-22 14:03:58 +01:00
parse_call_expr(id, input, begin, allow_stmt_expr)
}
2020-03-18 03:36:50 +01:00
// id[...] - indexing
#[cfg(not(feature = "no_index"))]
2020-03-16 16:51:32 +01:00
Some((Token::LeftBracket, pos)) => {
let pos = *pos;
input.next();
2020-03-22 14:03:58 +01:00
parse_index_expr(
Box::new(Expr::Variable(id, begin)),
input,
pos,
allow_stmt_expr,
)
}
2020-03-18 03:36:50 +01:00
// id - variable
2020-03-13 11:12:41 +01:00
Some(_) => Ok(Expr::Variable(id, begin)),
2020-03-18 03:36:50 +01:00
// EOF
2020-03-22 14:03:58 +01:00
None => Ok(Expr::Variable(id, begin)),
2016-03-26 18:46:28 +01:00
}
}
2020-03-18 03:36:50 +01:00
/// Parse an array literal.
#[cfg(not(feature = "no_index"))]
2020-03-18 03:36:50 +01:00
fn parse_array_literal<'a>(
input: &mut Peekable<TokenIterator<'a>>,
begin: Position,
2020-03-22 14:03:58 +01:00
allow_stmt_expr: bool,
) -> Result<Expr, ParseError> {
2016-03-26 18:46:28 +01:00
let mut arr = Vec::new();
2020-03-16 16:51:32 +01:00
if !matches!(input.peek(), Some((Token::RightBracket, _))) {
while input.peek().is_some() {
2020-03-22 14:03:58 +01:00
arr.push(parse_expr(input, allow_stmt_expr)?);
2020-03-16 16:51:32 +01:00
match input.peek().ok_or_else(|| {
PERR::MissingToken("]".into(), "to end this array literal".into()).into_err_eof()
2020-03-16 16:51:32 +01:00
})? {
(Token::Comma, _) => {
input.next();
}
2020-03-16 16:51:32 +01:00
(Token::RightBracket, _) => break,
(_, pos) => {
return Err(PERR::MissingToken(
",".into(),
2020-03-29 17:53:35 +02:00
"to separate the items of this array literal".into(),
2020-03-27 16:47:23 +01:00
)
.into_err(*pos))
}
2019-09-18 12:21:07 +02:00
}
}
2016-03-26 18:46:28 +01:00
}
2020-03-16 16:51:32 +01:00
match input.peek().ok_or_else(|| {
PERR::MissingToken("]".into(), "to end this array literal".into()).into_err_eof()
2020-03-16 16:51:32 +01:00
})? {
(Token::RightBracket, _) => {
input.next();
Ok(Expr::Array(arr, begin))
}
2020-03-24 09:46:47 +01:00
(_, pos) => {
Err(PERR::MissingToken("]".into(), "to end this array literal".into()).into_err(*pos))
2020-03-24 09:46:47 +01:00
}
2016-03-26 18:46:28 +01:00
}
}
2020-03-29 17:53:35 +02:00
/// Parse a map literal.
#[cfg(not(feature = "no_object"))]
fn parse_map_literal<'a>(
input: &mut Peekable<TokenIterator<'a>>,
begin: Position,
allow_stmt_expr: bool,
) -> Result<Expr, ParseError> {
let mut map = Vec::new();
if !matches!(input.peek(), Some((Token::RightBrace, _))) {
while input.peek().is_some() {
let (name, pos) = match input.next().ok_or_else(|| {
PERR::MissingToken("}".into(), "to end this object map literal".into())
.into_err_eof()
})? {
(Token::Identifier(s), pos) => (s.clone(), pos),
(Token::StringConst(s), pos) => (s.clone(), pos),
2020-03-29 17:53:35 +02:00
(_, pos) if map.is_empty() => {
return Err(PERR::MissingToken(
"}".into(),
"to end this object map literal".into(),
)
.into_err(pos))
}
(_, pos) => return Err(PERR::PropertyExpected.into_err(pos)),
};
match input.next().ok_or_else(|| {
PERR::MissingToken(
":".into(),
format!(
"to follow the property '{}' in this object map literal",
name
),
)
.into_err_eof()
})? {
(Token::Colon, _) => (),
(_, pos) => {
return Err(PERR::MissingToken(
":".into(),
format!(
"to follow the property '{}' in this object map literal",
name
),
)
.into_err(pos))
}
};
let expr = parse_expr(input, allow_stmt_expr)?;
map.push((name, expr, pos));
match input.peek().ok_or_else(|| {
PERR::MissingToken("}".into(), "to end this object map literal".into())
.into_err_eof()
})? {
(Token::Comma, _) => {
input.next();
}
(Token::RightBrace, _) => break,
(Token::Identifier(_), pos) => {
return Err(PERR::MissingToken(
",".into(),
"to separate the items of this object map literal".into(),
)
.into_err(*pos))
}
(_, pos) => {
return Err(PERR::MissingToken(
"}".into(),
"to end this object map literal".into(),
)
.into_err(*pos))
}
}
}
}
// Check for duplicating properties
map.iter()
.enumerate()
.try_for_each(|(i, (k1, _, _))| {
map.iter()
.skip(i + 1)
.find(|(k2, _, _)| k2 == k1)
.map_or_else(|| Ok(()), |(k2, _, pos)| Err((k2, *pos)))
})
.map_err(|(key, pos)| PERR::DuplicatedProperty(key.to_string()).into_err(pos))?;
// Ending brace
match input.peek().ok_or_else(|| {
PERR::MissingToken("}".into(), "to end this object map literal".into()).into_err_eof()
})? {
(Token::RightBrace, _) => {
input.next();
Ok(Expr::Map(map, begin))
}
(_, pos) => Err(
PERR::MissingToken("]".into(), "to end this object map literal".into()).into_err(*pos),
),
}
}
2020-03-18 03:36:50 +01:00
/// Parse a primary expression.
2020-03-22 14:03:58 +01:00
fn parse_primary<'a>(
input: &mut Peekable<TokenIterator<'a>>,
allow_stmt_expr: bool,
) -> Result<Expr, ParseError> {
let token = match input
.peek()
2020-03-24 09:46:47 +01:00
.ok_or_else(|| PERR::UnexpectedEOF.into_err_eof())?
{
// { - block statement as expression
2020-03-22 14:03:58 +01:00
(Token::LeftBrace, pos) if allow_stmt_expr => {
2020-03-16 16:51:32 +01:00
let pos = *pos;
2020-03-22 14:03:58 +01:00
return parse_block(input, false, allow_stmt_expr)
.map(|block| Expr::Stmt(Box::new(block), pos));
2020-03-07 03:39:00 +01:00
}
_ => input.next().expect("should be a token"),
};
2020-03-05 13:28:03 +01:00
let mut can_be_indexed = false;
2020-03-05 13:28:03 +01:00
let mut root_expr = match token {
2020-03-17 10:33:37 +01:00
#[cfg(not(feature = "no_float"))]
(Token::FloatConstant(x), pos) => Ok(Expr::FloatConstant(x, pos)),
2020-03-17 10:33:37 +01:00
(Token::IntegerConstant(x), pos) => Ok(Expr::IntegerConstant(x, pos)),
(Token::CharConstant(c), pos) => Ok(Expr::CharConstant(c, pos)),
(Token::StringConst(s), pos) => {
can_be_indexed = true;
Ok(Expr::StringConstant(s, pos))
}
(Token::Identifier(s), pos) => {
can_be_indexed = true;
2020-03-22 14:03:58 +01:00
parse_ident_expr(s, input, pos, allow_stmt_expr)
2020-03-17 10:33:37 +01:00
}
(Token::LeftParen, pos) => {
can_be_indexed = true;
2020-03-22 14:03:58 +01:00
parse_paren_expr(input, pos, allow_stmt_expr)
2020-03-17 10:33:37 +01:00
}
#[cfg(not(feature = "no_index"))]
(Token::LeftBracket, pos) => {
can_be_indexed = true;
2020-03-22 14:03:58 +01:00
parse_array_literal(input, pos, allow_stmt_expr)
2020-03-17 10:33:37 +01:00
}
2020-03-29 17:53:35 +02:00
#[cfg(not(feature = "no_object"))]
(Token::MapStart, pos) => {
can_be_indexed = true;
parse_map_literal(input, pos, allow_stmt_expr)
}
2020-03-17 10:33:37 +01:00
(Token::True, pos) => Ok(Expr::True(pos)),
(Token::False, pos) => Ok(Expr::False(pos)),
2020-03-24 09:46:47 +01:00
(Token::LexError(err), pos) => Err(PERR::BadInput(err.to_string()).into_err(pos)),
(token, pos) => {
Err(PERR::BadInput(format!("Unexpected '{}'", token.syntax())).into_err(pos))
}
2020-03-17 10:33:37 +01:00
}?;
2020-03-05 13:28:03 +01:00
if can_be_indexed {
// Tail processing all possible indexing
#[cfg(not(feature = "no_index"))]
2020-03-16 16:51:32 +01:00
while let Some((Token::LeftBracket, pos)) = input.peek() {
let pos = *pos;
input.next();
2020-03-22 14:03:58 +01:00
root_expr = parse_index_expr(Box::new(root_expr), input, pos, allow_stmt_expr)?;
}
2016-02-29 22:43:45 +01:00
}
Ok(root_expr)
2016-02-29 22:43:45 +01:00
}
2020-03-18 03:36:50 +01:00
/// Parse a potential unary operator.
2020-03-22 14:03:58 +01:00
fn parse_unary<'a>(
input: &mut Peekable<TokenIterator<'a>>,
allow_stmt_expr: bool,
) -> Result<Expr, ParseError> {
2020-03-16 16:51:32 +01:00
match input
.peek()
2020-03-24 09:46:47 +01:00
.ok_or_else(|| PERR::UnexpectedEOF.into_err_eof())?
2020-03-16 16:51:32 +01:00
{
2020-03-27 16:47:23 +01:00
// If statement is allowed to act as expressions
(Token::If, pos) => {
let pos = *pos;
Ok(Expr::Stmt(
Box::new(parse_if(input, false, allow_stmt_expr)?),
pos,
))
}
2020-03-18 03:36:50 +01:00
// -expr
2020-03-16 16:51:32 +01:00
(Token::UnaryMinus, pos) => {
let pos = *pos;
2019-09-18 12:21:07 +02:00
input.next();
2020-03-22 14:03:58 +01:00
match parse_unary(input, allow_stmt_expr)? {
// Negative integer
2020-03-16 16:51:32 +01:00
Expr::IntegerConstant(i, _) => i
.checked_neg()
.map(|x| Expr::IntegerConstant(x, pos))
2020-03-11 16:43:04 +01:00
.or_else(|| {
#[cfg(not(feature = "no_float"))]
return Some(Expr::FloatConstant(-(i as FLOAT), pos));
#[cfg(feature = "no_float")]
return None;
})
.ok_or_else(|| {
2020-03-24 09:46:47 +01:00
PERR::BadInput(LERR::MalformedNumber(format!("-{}", i)).to_string())
.into_err(pos)
}),
// Negative float
#[cfg(not(feature = "no_float"))]
2020-03-16 16:51:32 +01:00
Expr::FloatConstant(f, pos) => Ok(Expr::FloatConstant(-f, pos)),
// Call negative function
2020-03-16 16:51:32 +01:00
expr => Ok(Expr::FunctionCall("-".into(), vec![expr], None, pos)),
}
2019-09-18 12:21:07 +02:00
}
2020-03-18 03:36:50 +01:00
// +expr
2020-03-16 16:51:32 +01:00
(Token::UnaryPlus, _) => {
2019-09-18 12:21:07 +02:00
input.next();
2020-03-22 14:03:58 +01:00
parse_unary(input, allow_stmt_expr)
2019-09-18 12:21:07 +02:00
}
2020-03-18 03:36:50 +01:00
// !expr
2020-03-16 16:51:32 +01:00
(Token::Bang, pos) => {
let pos = *pos;
2019-09-18 12:21:07 +02:00
input.next();
Ok(Expr::FunctionCall(
"!".into(),
2020-03-22 14:03:58 +01:00
vec![parse_primary(input, allow_stmt_expr)?],
Some(Box::new(false)), // NOT operator, when operating on invalid operand, defaults to false
pos,
))
2019-09-18 12:21:07 +02:00
}
2020-03-18 03:36:50 +01:00
// All other tokens
2020-03-22 14:03:58 +01:00
_ => parse_primary(input, allow_stmt_expr),
2017-10-30 16:08:44 +01:00
}
}
2020-03-18 03:36:50 +01:00
/// Parse an assignment.
fn parse_assignment(lhs: Expr, rhs: Expr, pos: Position) -> Result<Expr, ParseError> {
2020-03-18 11:41:18 +01:00
// Is the LHS in a valid format for an assignment target?
2020-03-13 11:12:41 +01:00
fn valid_assignment_chain(expr: &Expr, is_top: bool) -> Option<ParseError> {
match expr {
2020-03-18 03:36:50 +01:00
// var
2020-03-13 11:12:41 +01:00
Expr::Variable(_, _) => {
assert!(is_top, "property expected but gets variable");
None
}
2020-03-18 03:36:50 +01:00
// property
2020-03-13 11:12:41 +01:00
Expr::Property(_, _) => {
assert!(!is_top, "variable expected but gets property");
None
}
2020-03-18 03:36:50 +01:00
// var[...]
#[cfg(not(feature = "no_index"))]
2020-03-14 16:41:15 +01:00
Expr::Index(idx_lhs, _, _) if matches!(idx_lhs.as_ref(), &Expr::Variable(_, _)) => {
2020-03-13 11:12:41 +01:00
assert!(is_top, "property expected but gets variable");
None
}
2020-03-18 03:36:50 +01:00
// property[...]
#[cfg(not(feature = "no_index"))]
2020-03-14 16:41:15 +01:00
Expr::Index(idx_lhs, _, _) if matches!(idx_lhs.as_ref(), &Expr::Property(_, _)) => {
2020-03-13 11:12:41 +01:00
assert!(!is_top, "variable expected but gets property");
None
}
2020-03-18 03:36:50 +01:00
// idx_lhs[...]
2020-03-13 11:12:41 +01:00
#[cfg(not(feature = "no_index"))]
2020-03-24 09:46:47 +01:00
Expr::Index(idx_lhs, _, pos) => match idx_lhs.as_ref() {
Expr::Index(_, _, _) => Some(ParseErrorType::AssignmentToCopy.into_err(*pos)),
_ => Some(ParseErrorType::AssignmentToInvalidLHS.into_err(*pos)),
},
2020-03-18 03:36:50 +01:00
// dot_lhs.dot_rhs
#[cfg(not(feature = "no_object"))]
Expr::Dot(dot_lhs, dot_rhs, _) => match dot_lhs.as_ref() {
2020-03-18 03:36:50 +01:00
// var.dot_rhs
2020-03-13 11:12:41 +01:00
Expr::Variable(_, _) if is_top => valid_assignment_chain(dot_rhs, false),
2020-03-18 03:36:50 +01:00
// property.dot_rhs
2020-03-13 11:12:41 +01:00
Expr::Property(_, _) if !is_top => valid_assignment_chain(dot_rhs, false),
2020-03-18 03:36:50 +01:00
// var[...]
#[cfg(not(feature = "no_index"))]
2020-03-13 11:12:41 +01:00
Expr::Index(idx_lhs, _, _)
2020-03-14 16:41:15 +01:00
if matches!(idx_lhs.as_ref(), &Expr::Variable(_, _)) && is_top =>
{
valid_assignment_chain(dot_rhs, false)
}
2020-03-18 03:36:50 +01:00
// property[...]
2020-03-14 16:41:15 +01:00
#[cfg(not(feature = "no_index"))]
Expr::Index(idx_lhs, _, _)
if matches!(idx_lhs.as_ref(), &Expr::Property(_, _)) && !is_top =>
2020-03-13 11:12:41 +01:00
{
valid_assignment_chain(dot_rhs, false)
2020-03-11 16:43:04 +01:00
}
2020-03-18 03:36:50 +01:00
// idx_lhs[...]
2020-03-11 16:43:04 +01:00
#[cfg(not(feature = "no_index"))]
2020-03-24 09:46:47 +01:00
Expr::Index(idx_lhs, _, _) => {
Some(ParseErrorType::AssignmentToCopy.into_err(idx_lhs.position()))
}
2020-03-13 11:12:41 +01:00
expr => panic!("unexpected dot expression {:#?}", expr),
},
2020-03-24 09:46:47 +01:00
_ => Some(ParseErrorType::AssignmentToInvalidLHS.into_err(expr.position())),
2020-03-07 03:15:42 +01:00
}
}
2020-03-07 03:15:42 +01:00
2020-03-13 11:12:41 +01:00
match valid_assignment_chain(&lhs, true) {
None => Ok(Expr::Assignment(Box::new(lhs), Box::new(rhs), pos)),
Some(err) => Err(err),
}
2020-03-07 03:15:42 +01:00
}
2020-03-18 03:36:50 +01:00
/// Parse an operator-assignment expression.
2020-03-18 11:41:18 +01:00
fn parse_op_assignment(op: &str, lhs: Expr, rhs: Expr, pos: Position) -> Result<Expr, ParseError> {
2020-03-07 06:39:28 +01:00
let lhs_copy = lhs.clone();
2020-03-18 11:41:18 +01:00
// lhs op= rhs -> lhs = op(lhs, rhs)
2020-03-07 06:39:28 +01:00
parse_assignment(
lhs,
2020-03-18 11:41:18 +01:00
Expr::FunctionCall(op.into(), vec![lhs_copy, rhs], None, pos),
2020-03-07 06:39:28 +01:00
pos,
)
}
2020-03-18 03:36:50 +01:00
/// Parse a binary expression.
fn parse_binary_op<'a>(
2019-09-18 12:21:07 +02:00
input: &mut Peekable<TokenIterator<'a>>,
2020-03-14 04:51:45 +01:00
parent_precedence: u8,
2019-09-18 12:21:07 +02:00
lhs: Expr,
2020-03-22 14:03:58 +01:00
allow_stmt_expr: bool,
2019-09-18 12:21:07 +02:00
) -> Result<Expr, ParseError> {
let mut current_lhs = lhs;
2016-02-29 22:43:45 +01:00
loop {
2020-03-16 16:51:32 +01:00
let (current_precedence, bind_right) = if let Some((ref current_op, _)) = input.peek() {
(current_op.precedence(), current_op.is_bind_right())
2020-03-14 04:51:45 +01:00
} else {
(0, false)
};
// Bind left to the parent lhs expression if precedence is higher
// If same precedence, then check if the operator binds right
if current_precedence < parent_precedence
|| (current_precedence == parent_precedence && !bind_right)
{
return Ok(current_lhs);
2016-02-29 22:43:45 +01:00
}
2020-02-29 13:12:10 +01:00
if let Some((op_token, pos)) = input.next() {
input.peek();
2020-03-22 14:03:58 +01:00
let rhs = parse_unary(input, allow_stmt_expr)?;
2020-03-16 16:51:32 +01:00
let next_precedence = if let Some((next_op, _)) = input.peek() {
next_op.precedence()
2020-03-14 04:51:45 +01:00
} else {
0
};
2016-02-29 22:43:45 +01:00
2020-03-14 04:51:45 +01:00
// Bind to right if the next operator has higher precedence
// If same precedence, then check if the operator binds right
let rhs = if (current_precedence == next_precedence && bind_right)
|| current_precedence < next_precedence
{
2020-03-22 14:03:58 +01:00
parse_binary_op(input, current_precedence, rhs, allow_stmt_expr)?
2020-03-14 04:51:45 +01:00
} else {
// Otherwise bind to left (even if next operator has the same precedence)
rhs
};
2016-02-29 22:43:45 +01:00
current_lhs = match op_token {
Token::Plus => Expr::FunctionCall("+".into(), vec![current_lhs, rhs], None, pos),
Token::Minus => Expr::FunctionCall("-".into(), vec![current_lhs, rhs], None, pos),
Token::Multiply => {
Expr::FunctionCall("*".into(), vec![current_lhs, rhs], None, pos)
}
Token::Divide => Expr::FunctionCall("/".into(), vec![current_lhs, rhs], None, pos),
Token::Equals => parse_assignment(current_lhs, rhs, pos)?,
2020-03-07 06:39:28 +01:00
Token::PlusAssign => parse_op_assignment("+", current_lhs, rhs, pos)?,
Token::MinusAssign => parse_op_assignment("-", current_lhs, rhs, pos)?,
#[cfg(not(feature = "no_object"))]
2020-03-13 11:12:41 +01:00
Token::Period => {
fn check_property(expr: Expr) -> Result<Expr, ParseError> {
2020-03-13 11:12:41 +01:00
match expr {
// xxx.lhs.rhs
Expr::Dot(lhs, rhs, pos) => Ok(Expr::Dot(
Box::new(check_property(*lhs)?),
Box::new(check_property(*rhs)?),
2020-03-13 11:12:41 +01:00
pos,
)),
// xxx.lhs[idx]
#[cfg(not(feature = "no_index"))]
2020-03-13 11:12:41 +01:00
Expr::Index(lhs, idx, pos) => {
Ok(Expr::Index(Box::new(check_property(*lhs)?), idx, pos))
2020-03-13 11:12:41 +01:00
}
// xxx.id
Expr::Variable(id, pos) => Ok(Expr::Property(id, pos)),
// xxx.prop
expr @ Expr::Property(_, _) => Ok(expr),
// xxx.fn()
expr @ Expr::FunctionCall(_, _, _, _) => Ok(expr),
expr => Err(PERR::PropertyExpected.into_err(expr.position())),
2020-03-13 11:12:41 +01:00
}
}
Expr::Dot(Box::new(current_lhs), Box::new(check_property(rhs)?), pos)
2020-03-13 11:12:41 +01:00
}
// Comparison operators default to false when passed invalid operands
Token::EqualsTo => Expr::FunctionCall(
"==".into(),
vec![current_lhs, rhs],
Some(Box::new(false)),
pos,
),
Token::NotEqualsTo => Expr::FunctionCall(
"!=".into(),
vec![current_lhs, rhs],
Some(Box::new(false)),
pos,
),
Token::LessThan => Expr::FunctionCall(
"<".into(),
vec![current_lhs, rhs],
Some(Box::new(false)),
pos,
),
Token::LessThanEqualsTo => Expr::FunctionCall(
"<=".into(),
vec![current_lhs, rhs],
Some(Box::new(false)),
pos,
),
Token::GreaterThan => Expr::FunctionCall(
">".into(),
vec![current_lhs, rhs],
Some(Box::new(false)),
pos,
),
Token::GreaterThanEqualsTo => Expr::FunctionCall(
">=".into(),
vec![current_lhs, rhs],
Some(Box::new(false)),
pos,
),
Token::Or => Expr::Or(Box::new(current_lhs), Box::new(rhs)),
Token::And => Expr::And(Box::new(current_lhs), Box::new(rhs)),
Token::XOr => Expr::FunctionCall("^".into(), vec![current_lhs, rhs], None, pos),
2020-03-07 06:39:28 +01:00
Token::OrAssign => parse_op_assignment("|", current_lhs, rhs, pos)?,
Token::AndAssign => parse_op_assignment("&", current_lhs, rhs, pos)?,
Token::XOrAssign => parse_op_assignment("^", current_lhs, rhs, pos)?,
Token::MultiplyAssign => parse_op_assignment("*", current_lhs, rhs, pos)?,
Token::DivideAssign => parse_op_assignment("/", current_lhs, rhs, pos)?,
Token::Pipe => Expr::FunctionCall("|".into(), vec![current_lhs, rhs], None, pos),
Token::LeftShift => {
Expr::FunctionCall("<<".into(), vec![current_lhs, rhs], None, pos)
}
Token::RightShift => {
Expr::FunctionCall(">>".into(), vec![current_lhs, rhs], None, pos)
}
2020-03-07 06:39:28 +01:00
Token::LeftShiftAssign => parse_op_assignment("<<", current_lhs, rhs, pos)?,
Token::RightShiftAssign => parse_op_assignment(">>", current_lhs, rhs, pos)?,
Token::Ampersand => {
Expr::FunctionCall("&".into(), vec![current_lhs, rhs], None, pos)
}
Token::Modulo => Expr::FunctionCall("%".into(), vec![current_lhs, rhs], None, pos),
2020-03-07 06:39:28 +01:00
Token::ModuloAssign => parse_op_assignment("%", current_lhs, rhs, pos)?,
Token::PowerOf => Expr::FunctionCall("~".into(), vec![current_lhs, rhs], None, pos),
2020-03-07 06:39:28 +01:00
Token::PowerOfAssign => parse_op_assignment("~", current_lhs, rhs, pos)?,
2020-03-24 09:46:47 +01:00
token => return Err(PERR::UnknownOperator(token.syntax().into()).into_err(pos)),
2016-02-29 22:43:45 +01:00
};
}
}
}
2020-03-18 03:36:50 +01:00
/// Parse an expression.
2020-03-22 14:03:58 +01:00
fn parse_expr<'a>(
input: &mut Peekable<TokenIterator<'a>>,
allow_stmt_expr: bool,
) -> Result<Expr, ParseError> {
2020-03-27 16:47:23 +01:00
// Parse a real expression
2020-03-22 14:03:58 +01:00
let lhs = parse_unary(input, allow_stmt_expr)?;
parse_binary_op(input, 1, lhs, allow_stmt_expr)
2016-02-29 22:43:45 +01:00
}
/// Make sure that the expression is not a statement expression (i.e. wrapped in {})
fn ensure_not_statement_expr<'a>(
input: &mut Peekable<TokenIterator<'a>>,
type_name: &str,
) -> Result<(), ParseError> {
match input
.peek()
2020-03-27 16:47:23 +01:00
.ok_or_else(|| PERR::ExprExpected(type_name.to_string()).into_err_eof())?
{
// Disallow statement expressions
2020-03-27 16:47:23 +01:00
(Token::LeftBrace, pos) => Err(PERR::ExprExpected(type_name.to_string()).into_err(*pos)),
// No need to check for others at this time - leave it for the expr parser
_ => Ok(()),
}
}
2020-03-18 03:36:50 +01:00
/// Parse an if statement.
2020-03-17 10:33:37 +01:00
fn parse_if<'a>(
input: &mut Peekable<TokenIterator<'a>>,
breakable: bool,
2020-03-22 14:03:58 +01:00
allow_stmt_expr: bool,
2020-03-17 10:33:37 +01:00
) -> Result<Stmt, ParseError> {
2020-03-18 11:41:18 +01:00
// if ...
2016-02-29 22:43:45 +01:00
input.next();
// if guard { if_body }
ensure_not_statement_expr(input, "a boolean")?;
2020-03-22 14:03:58 +01:00
let guard = parse_expr(input, allow_stmt_expr)?;
let if_body = parse_block(input, breakable, allow_stmt_expr)?;
2016-02-29 22:43:45 +01:00
// if guard { if_body } else ...
2020-03-16 16:51:32 +01:00
let else_body = if matches!(input.peek(), Some((Token::Else, _))) {
input.next();
2020-03-02 10:04:56 +01:00
2020-03-16 16:51:32 +01:00
Some(Box::new(if matches!(input.peek(), Some((Token::If, _))) {
// if guard { if_body } else if ...
2020-03-22 14:03:58 +01:00
parse_if(input, breakable, allow_stmt_expr)?
2020-03-16 16:51:32 +01:00
} else {
// if guard { if_body } else { else-body }
2020-03-22 14:03:58 +01:00
parse_block(input, breakable, allow_stmt_expr)?
2020-03-16 16:51:32 +01:00
}))
} else {
None
};
2020-03-02 10:04:56 +01:00
2020-03-22 03:18:16 +01:00
Ok(Stmt::IfThenElse(
Box::new(guard),
Box::new(if_body),
else_body,
))
2016-02-29 22:43:45 +01:00
}
2020-03-18 03:36:50 +01:00
/// Parse a while loop.
2020-03-22 14:03:58 +01:00
fn parse_while<'a>(
input: &mut Peekable<TokenIterator<'a>>,
allow_stmt_expr: bool,
) -> Result<Stmt, ParseError> {
2020-03-18 11:41:18 +01:00
// while ...
2016-02-29 22:43:45 +01:00
input.next();
2020-03-18 11:41:18 +01:00
// while guard { body }
ensure_not_statement_expr(input, "a boolean")?;
2020-03-22 14:03:58 +01:00
let guard = parse_expr(input, allow_stmt_expr)?;
let body = parse_block(input, true, allow_stmt_expr)?;
2016-02-29 22:43:45 +01:00
Ok(Stmt::While(Box::new(guard), Box::new(body)))
}
2020-03-18 03:36:50 +01:00
/// Parse a loop statement.
2020-03-22 14:03:58 +01:00
fn parse_loop<'a>(
input: &mut Peekable<TokenIterator<'a>>,
allow_stmt_expr: bool,
) -> Result<Stmt, ParseError> {
2020-03-18 11:41:18 +01:00
// loop ...
2017-10-30 16:08:44 +01:00
input.next();
2020-03-18 11:41:18 +01:00
// loop { body }
2020-03-22 14:03:58 +01:00
let body = parse_block(input, true, allow_stmt_expr)?;
2017-10-30 16:08:44 +01:00
Ok(Stmt::Loop(Box::new(body)))
}
2020-03-18 03:36:50 +01:00
/// Parse a for loop.
2020-03-22 14:03:58 +01:00
fn parse_for<'a>(
input: &mut Peekable<TokenIterator<'a>>,
allow_stmt_expr: bool,
) -> Result<Stmt, ParseError> {
2020-03-18 11:41:18 +01:00
// for ...
input.next();
2020-03-18 11:41:18 +01:00
// for name ...
2020-03-16 16:51:32 +01:00
let name = match input
.next()
2020-03-24 09:46:47 +01:00
.ok_or_else(|| PERR::VariableExpected.into_err_eof())?
2020-03-16 16:51:32 +01:00
{
2020-03-18 11:41:18 +01:00
// Variable name
2020-03-16 16:51:32 +01:00
(Token::Identifier(s), _) => s,
2020-03-18 11:41:18 +01:00
// Bad identifier
2020-03-24 09:46:47 +01:00
(Token::LexError(err), pos) => return Err(PERR::BadInput(err.to_string()).into_err(pos)),
2020-03-18 11:41:18 +01:00
// Not a variable name
2020-03-24 09:46:47 +01:00
(_, pos) => return Err(PERR::VariableExpected.into_err(pos)),
};
2020-03-18 11:41:18 +01:00
// for name in ...
match input.next().ok_or_else(|| {
PERR::MissingToken("in".into(), "after the iteration variable".into()).into_err_eof()
})? {
2020-03-16 16:51:32 +01:00
(Token::In, _) => (),
(_, pos) => {
return Err(
PERR::MissingToken("in".into(), "after the iteration variable".into())
.into_err(pos),
)
}
}
2020-03-18 11:41:18 +01:00
// for name in expr { body }
ensure_not_statement_expr(input, "a boolean")?;
2020-03-22 14:03:58 +01:00
let expr = parse_expr(input, allow_stmt_expr)?;
let body = parse_block(input, true, allow_stmt_expr)?;
Ok(Stmt::For(name, Box::new(expr), Box::new(body)))
}
2020-03-18 03:36:50 +01:00
/// Parse a variable definition statement.
fn parse_let<'a>(
2020-03-13 11:12:41 +01:00
input: &mut Peekable<TokenIterator<'a>>,
2020-03-25 04:27:18 +01:00
var_type: ScopeEntryType,
2020-03-22 14:03:58 +01:00
allow_stmt_expr: bool,
2020-03-13 11:12:41 +01:00
) -> Result<Stmt, ParseError> {
2020-03-18 11:41:18 +01:00
// let/const... (specified in `var_type`)
input.next();
2020-03-16 16:51:32 +01:00
2020-03-18 11:41:18 +01:00
// let name ...
let (name, pos) = match input
2020-03-16 16:51:32 +01:00
.next()
2020-03-24 09:46:47 +01:00
.ok_or_else(|| PERR::VariableExpected.into_err_eof())?
2020-03-16 16:51:32 +01:00
{
2020-03-18 11:41:18 +01:00
(Token::Identifier(s), pos) => (s, pos),
2020-03-24 09:46:47 +01:00
(Token::LexError(err), pos) => return Err(PERR::BadInput(err.to_string()).into_err(pos)),
(_, pos) => return Err(PERR::VariableExpected.into_err(pos)),
2016-02-29 22:43:45 +01:00
};
2020-03-18 11:41:18 +01:00
// let name = ...
2020-03-16 16:51:32 +01:00
if matches!(input.peek(), Some((Token::Equals, _))) {
2020-03-14 16:41:15 +01:00
input.next();
2020-03-18 11:41:18 +01:00
// let name = expr
2020-03-22 14:03:58 +01:00
let init_value = parse_expr(input, allow_stmt_expr)?;
2020-03-13 11:12:41 +01:00
2020-03-14 16:41:15 +01:00
match var_type {
2020-03-18 11:41:18 +01:00
// let name = expr
2020-03-25 04:27:18 +01:00
ScopeEntryType::Normal => Ok(Stmt::Let(name, Some(Box::new(init_value)), pos)),
2020-03-18 11:41:18 +01:00
// const name = { expr:constant }
2020-03-25 04:27:18 +01:00
ScopeEntryType::Constant if init_value.is_constant() => {
2020-03-14 16:41:15 +01:00
Ok(Stmt::Const(name, Box::new(init_value), pos))
2020-03-13 11:12:41 +01:00
}
2020-03-18 11:41:18 +01:00
// const name = expr - error
2020-03-27 16:47:23 +01:00
ScopeEntryType::Constant => {
Err(PERR::ForbiddenConstantExpr(name).into_err(init_value.position()))
}
2016-02-29 22:43:45 +01:00
}
2020-03-14 16:41:15 +01:00
} else {
2020-03-18 11:41:18 +01:00
// let name
2020-03-14 16:41:15 +01:00
Ok(Stmt::Let(name, None, pos))
2016-02-29 22:43:45 +01:00
}
}
2020-03-18 03:36:50 +01:00
/// Parse a statement block.
2020-03-17 10:33:37 +01:00
fn parse_block<'a>(
input: &mut Peekable<TokenIterator<'a>>,
breakable: bool,
2020-03-22 14:03:58 +01:00
allow_stmt_expr: bool,
2020-03-17 10:33:37 +01:00
) -> Result<Stmt, ParseError> {
2020-03-18 11:41:18 +01:00
// Must start with {
2020-03-16 16:51:32 +01:00
let pos = match input
.next()
.ok_or_else(|| PERR::UnexpectedEOF.into_err_eof())?
2020-03-16 16:51:32 +01:00
{
(Token::LeftBrace, pos) => pos,
(_, pos) => {
return Err(
PERR::MissingToken("{".into(), "to start a statement block".into()).into_err(pos),
)
}
2020-03-12 05:40:28 +01:00
};
2016-02-29 22:43:45 +01:00
let mut statements = Vec::new();
2020-03-17 10:33:37 +01:00
while !matches!(input.peek(), Some((Token::RightBrace, _))) {
// Parse statements inside the block
2020-03-22 14:03:58 +01:00
let stmt = parse_stmt(input, breakable, allow_stmt_expr)?;
2020-03-17 10:33:37 +01:00
// See if it needs a terminating semicolon
let need_semicolon = !stmt.is_self_terminated();
2017-10-02 23:44:45 +02:00
2020-03-17 10:33:37 +01:00
statements.push(stmt);
2020-03-17 10:33:37 +01:00
match input.peek() {
2020-03-18 11:41:18 +01:00
// EOF
2020-03-17 10:33:37 +01:00
None => break,
2020-03-18 11:41:18 +01:00
// { ... stmt }
2020-03-17 10:33:37 +01:00
Some((Token::RightBrace, _)) => break,
2020-03-18 11:41:18 +01:00
// { ... stmt;
Some((Token::SemiColon, _)) if need_semicolon => {
2020-03-17 10:33:37 +01:00
input.next();
}
2020-03-18 11:41:18 +01:00
// { ... { stmt } ;
Some((Token::SemiColon, _)) if !need_semicolon => (),
// { ... { stmt } ???
2020-03-17 10:33:37 +01:00
Some((_, _)) if !need_semicolon => (),
2020-03-18 11:41:18 +01:00
// { ... stmt ??? - error
2020-03-17 10:33:37 +01:00
Some((_, pos)) => {
// Semicolons are not optional between statements
return Err(
PERR::MissingToken(";".into(), "to terminate this statement".into())
.into_err(*pos),
);
2019-09-18 12:21:07 +02:00
}
}
}
2016-02-29 22:43:45 +01:00
match input.peek().ok_or_else(|| {
PERR::MissingToken("}".into(), "to end this statement block".into()).into_err_eof()
})? {
2020-03-16 16:51:32 +01:00
(Token::RightBrace, _) => {
input.next();
2020-03-09 14:57:07 +01:00
Ok(Stmt::Block(statements, pos))
}
(_, pos) => {
Err(PERR::MissingToken("}".into(), "to end this statement block".into()).into_err(*pos))
}
2016-02-29 22:43:45 +01:00
}
}
2020-03-18 03:36:50 +01:00
/// Parse an expression as a statement.
2020-03-22 14:03:58 +01:00
fn parse_expr_stmt<'a>(
input: &mut Peekable<TokenIterator<'a>>,
allow_stmt_expr: bool,
) -> Result<Stmt, ParseError> {
Ok(Stmt::Expr(Box::new(parse_expr(input, allow_stmt_expr)?)))
2016-02-29 22:43:45 +01:00
}
2020-03-18 03:36:50 +01:00
/// Parse a single statement.
2020-03-17 10:33:37 +01:00
fn parse_stmt<'a>(
input: &mut Peekable<TokenIterator<'a>>,
breakable: bool,
2020-03-22 14:03:58 +01:00
allow_stmt_expr: bool,
2020-03-17 10:33:37 +01:00
) -> Result<Stmt, ParseError> {
let token = match input.peek() {
Some(token) => token,
None => return Ok(Stmt::Noop(Position::eof())),
};
match token {
2020-03-18 11:41:18 +01:00
// Semicolon - empty statement
(Token::SemiColon, pos) => Ok(Stmt::Noop(*pos)),
// fn ...
#[cfg(not(feature = "no_function"))]
2020-03-24 09:46:47 +01:00
(Token::Fn, pos) => Err(PERR::WrongFnDefinition.into_err(*pos)),
2020-03-22 14:03:58 +01:00
(Token::If, _) => parse_if(input, breakable, allow_stmt_expr),
(Token::While, _) => parse_while(input, allow_stmt_expr),
(Token::Loop, _) => parse_loop(input, allow_stmt_expr),
(Token::For, _) => parse_for(input, allow_stmt_expr),
2020-03-17 10:33:37 +01:00
(Token::Break, pos) if breakable => {
2020-03-16 16:51:32 +01:00
let pos = *pos;
input.next();
Ok(Stmt::Break(pos))
}
2020-03-24 09:46:47 +01:00
(Token::Break, pos) => Err(PERR::LoopBreak.into_err(*pos)),
2020-03-19 12:53:42 +01:00
(token @ Token::Return, pos) | (token @ Token::Throw, pos) => {
2020-03-11 16:43:04 +01:00
let return_type = match token {
Token::Return => ReturnType::Return,
Token::Throw => ReturnType::Exception,
_ => panic!("token should be return or throw"),
2020-03-03 11:15:20 +01:00
};
2020-03-19 12:53:42 +01:00
let pos = *pos;
input.next();
2020-03-03 11:15:20 +01:00
match input.peek() {
2020-03-18 03:36:50 +01:00
// `return`/`throw` at EOF
2020-03-11 16:43:04 +01:00
None => Ok(Stmt::ReturnWithVal(None, return_type, Position::eof())),
2020-03-18 03:36:50 +01:00
// `return;` or `throw;`
2020-03-19 12:53:42 +01:00
Some((Token::SemiColon, _)) => Ok(Stmt::ReturnWithVal(None, return_type, pos)),
2020-03-18 03:36:50 +01:00
// `return` or `throw` with expression
2020-03-19 12:53:42 +01:00
Some((_, _)) => {
2020-03-22 14:03:58 +01:00
let expr = parse_expr(input, allow_stmt_expr)?;
2020-03-19 12:53:42 +01:00
let pos = expr.position();
Ok(Stmt::ReturnWithVal(Some(Box::new(expr)), return_type, pos))
}
}
}
2020-03-22 14:03:58 +01:00
(Token::LeftBrace, _) => parse_block(input, breakable, allow_stmt_expr),
2020-03-25 04:27:18 +01:00
(Token::Let, _) => parse_let(input, ScopeEntryType::Normal, allow_stmt_expr),
(Token::Const, _) => parse_let(input, ScopeEntryType::Constant, allow_stmt_expr),
2020-03-22 14:03:58 +01:00
_ => parse_expr_stmt(input, allow_stmt_expr),
2016-02-29 22:43:45 +01:00
}
}
2020-03-18 03:36:50 +01:00
/// Parse a function definition.
#[cfg(not(feature = "no_function"))]
2020-03-22 14:03:58 +01:00
fn parse_fn<'a>(
input: &mut Peekable<TokenIterator<'a>>,
allow_stmt_expr: bool,
) -> Result<FnDef, ParseError> {
let pos = input.next().expect("should be fn").1;
2020-03-16 16:51:32 +01:00
let name = match input
.next()
2020-03-24 09:46:47 +01:00
.ok_or_else(|| PERR::FnMissingName.into_err_eof())?
2020-03-16 16:51:32 +01:00
{
(Token::Identifier(s), _) => s,
2020-03-24 09:46:47 +01:00
(_, pos) => return Err(PERR::FnMissingName.into_err(pos)),
};
2020-03-16 16:51:32 +01:00
match input
.peek()
2020-03-24 09:46:47 +01:00
.ok_or_else(|| PERR::FnMissingParams(name.clone()).into_err_eof())?
2020-03-16 16:51:32 +01:00
{
(Token::LeftParen, _) => {
input.next();
}
2020-03-24 09:46:47 +01:00
(_, pos) => return Err(PERR::FnMissingParams(name).into_err(*pos)),
}
let mut params = Vec::new();
2020-03-16 16:51:32 +01:00
if matches!(input.peek(), Some((Token::RightParen, _))) {
2020-03-14 16:41:15 +01:00
input.next();
} else {
let end_err = format!("to close the parameters list of function '{}'", name);
let sep_err = format!("to separate the parameters of function '{}'", name);
2020-03-24 09:46:47 +01:00
2020-03-14 16:41:15 +01:00
loop {
2020-03-24 09:46:47 +01:00
match input
.next()
.ok_or_else(|| PERR::MissingToken(")".into(), end_err.to_string()).into_err_eof())?
2020-03-24 09:46:47 +01:00
{
(Token::Identifier(s), pos) => {
params.push((s, pos));
2020-03-09 03:41:17 +01:00
}
(_, pos) => return Err(PERR::MissingToken(")".into(), end_err).into_err(pos)),
2020-03-16 16:51:32 +01:00
}
2020-03-24 09:46:47 +01:00
match input
.next()
.ok_or_else(|| PERR::MissingToken(")".into(), end_err.to_string()).into_err_eof())?
2020-03-24 09:46:47 +01:00
{
2020-03-16 16:51:32 +01:00
(Token::RightParen, _) => break,
(Token::Comma, _) => (),
(Token::Identifier(_), pos) => {
return Err(PERR::MissingToken(",".into(), sep_err).into_err(pos))
}
(_, pos) => return Err(PERR::MissingToken(",".into(), sep_err).into_err(pos)),
}
2020-03-14 16:41:15 +01:00
}
2016-02-29 22:43:45 +01:00
}
// Check for duplicating parameters
params
.iter()
.enumerate()
.try_for_each(|(i, (p1, _))| {
params
.iter()
.skip(i + 1)
.find(|(p2, _)| p2 == p1)
.map_or_else(|| Ok(()), |(p2, pos)| Err((p2, *pos)))
})
.map_err(|(p, pos)| {
PERR::FnDuplicatedParam(name.to_string(), p.to_string()).into_err(pos)
})?;
// Parse function body
2020-03-17 10:33:37 +01:00
let body = match input.peek() {
2020-03-22 14:03:58 +01:00
Some((Token::LeftBrace, _)) => parse_block(input, false, allow_stmt_expr)?,
2020-03-24 09:46:47 +01:00
Some((_, pos)) => return Err(PERR::FnMissingBody(name).into_err(*pos)),
None => return Err(PERR::FnMissingBody(name).into_err_eof()),
2020-03-17 10:33:37 +01:00
};
Ok(FnDef {
2020-03-11 16:43:04 +01:00
name,
params: params.into_iter().map(|(p, _)| p).collect(),
2020-03-09 14:57:07 +01:00
body,
pos,
})
}
2020-03-22 14:03:58 +01:00
pub fn parse_global_expr<'a, 'e>(
input: &mut Peekable<TokenIterator<'a>>,
engine: &Engine<'e>,
scope: &Scope,
) -> Result<AST, ParseError> {
let expr = parse_expr(input, false)?;
if let Some((token, pos)) = input.peek() {
// Return error if the expression doesn't end
2020-03-24 09:46:47 +01:00
return Err(PERR::BadInput(format!("Unexpected '{}'", token.syntax())).into_err(*pos));
2020-03-22 14:03:58 +01:00
}
Ok(
// Optimize AST
#[cfg(not(feature = "no_optimize"))]
optimize_into_ast(engine, scope, vec![Stmt::Expr(Box::new(expr))], vec![]),
//
// Do not optimize AST if `no_optimize`
#[cfg(feature = "no_optimize")]
AST(vec![Stmt::Expr(Box::new(expr))], vec![]),
)
}
2020-03-18 03:36:50 +01:00
/// Parse the global level statements.
2020-03-22 14:03:58 +01:00
fn parse_global_level<'a>(
2020-03-09 14:57:07 +01:00
input: &mut Peekable<TokenIterator<'a>>,
) -> Result<(Vec<Stmt>, Vec<FnDef>), ParseError> {
let mut statements = Vec::<Stmt>::new();
let mut functions = Vec::<FnDef>::new();
while input.peek().is_some() {
#[cfg(not(feature = "no_function"))]
{
2020-03-18 11:41:18 +01:00
// Collect all the function definitions
if matches!(input.peek().expect("should not be None"), (Token::Fn, _)) {
2020-03-22 14:03:58 +01:00
let f = parse_fn(input, true)?;
2020-03-12 06:02:13 +01:00
// Ensure list is sorted
match functions.binary_search_by(|fn_def| fn_def.compare(&f.name, f.params.len())) {
Ok(n) => functions[n] = f, // Override previous definition
Err(n) => functions.insert(n, f), // New function definition
}
continue;
2020-03-12 06:02:13 +01:00
}
2016-02-29 22:43:45 +01:00
}
2020-03-18 11:41:18 +01:00
// Actual statement
2020-03-22 14:03:58 +01:00
let stmt = parse_stmt(input, false, true)?;
let need_semicolon = !stmt.is_self_terminated();
statements.push(stmt);
match input.peek() {
2020-03-18 11:41:18 +01:00
// EOF
None => break,
2020-03-18 11:41:18 +01:00
// stmt ;
Some((Token::SemiColon, _)) if need_semicolon => {
input.next();
}
2020-03-18 11:41:18 +01:00
// stmt ;
Some((Token::SemiColon, _)) if !need_semicolon => (),
// { stmt } ???
Some((_, _)) if !need_semicolon => (),
2020-03-18 11:41:18 +01:00
// stmt ??? - error
Some((_, pos)) => {
// Semicolons are not optional between statements
return Err(
PERR::MissingToken(";".into(), "to terminate this statement".into())
.into_err(*pos),
);
}
2016-02-29 22:43:45 +01:00
}
}
Ok((statements, functions))
}
2020-03-18 03:36:50 +01:00
/// Run the parser on an input stream, returning an AST.
pub fn parse<'a, 'e>(
input: &mut Peekable<TokenIterator<'a>>,
engine: &Engine<'e>,
scope: &Scope,
) -> Result<AST, ParseError> {
let (statements, functions) = parse_global_level(input)?;
Ok(
2020-03-18 11:41:18 +01:00
// Optimize AST
#[cfg(not(feature = "no_optimize"))]
2020-03-18 11:41:18 +01:00
optimize_into_ast(engine, scope, statements, functions),
//
// Do not optimize AST if `no_optimize`
#[cfg(feature = "no_optimize")]
AST(statements, functions.into_iter().map(Arc::new).collect()),
)
2016-02-29 22:43:45 +01:00
}
2020-03-18 03:36:50 +01:00
/// Map a `Dynamic` value to an expression.
///
/// Returns Some(expression) if conversion is successful. Otherwise None.
pub fn map_dynamic_to_expr(value: Dynamic, pos: Position) -> (Option<Expr>, Dynamic) {
if value.is::<INT>() {
let value2 = value.clone();
(
Some(Expr::IntegerConstant(
*value.downcast::<INT>().expect("value should be INT"),
pos,
)),
value2,
)
} else if value.is::<char>() {
let value2 = value.clone();
(
Some(Expr::CharConstant(
*value.downcast::<char>().expect("value should be char"),
pos,
)),
value2,
)
} else if value.is::<String>() {
let value2 = value.clone();
(
Some(Expr::StringConstant(
*value.downcast::<String>().expect("value should be String"),
pos,
)),
value2,
)
} else if value.is::<bool>() {
let value2 = value.clone();
(
Some(
if *value.downcast::<bool>().expect("value should be bool") {
Expr::True(pos)
} else {
Expr::False(pos)
},
),
value2,
)
} else {
#[cfg(not(feature = "no_float"))]
{
if value.is::<FLOAT>() {
let value2 = value.clone();
return (
Some(Expr::FloatConstant(
*value.downcast::<FLOAT>().expect("value should be FLOAT"),
pos,
)),
value2,
);
}
}
(None, value)
}
2016-02-29 22:43:45 +01:00
}