Add Token::Unit.
This commit is contained in:
parent
299d6ef308
commit
5e4f27ae25
@ -832,6 +832,7 @@ impl Expr {
|
|||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Token::LeftBracket => true,
|
Token::LeftBracket => true,
|
||||||
Token::LeftParen => true,
|
Token::LeftParen => true,
|
||||||
|
Token::Unit => true,
|
||||||
Token::Bang => true,
|
Token::Bang => true,
|
||||||
Token::DoubleColon => true,
|
Token::DoubleColon => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
|
@ -426,10 +426,6 @@ impl Engine {
|
|||||||
let mut settings = settings;
|
let mut settings = settings;
|
||||||
settings.pos = eat_token(input, Token::LeftParen);
|
settings.pos = eat_token(input, Token::LeftParen);
|
||||||
|
|
||||||
if match_token(input, Token::RightParen).0 {
|
|
||||||
return Ok(Expr::Unit(settings.pos));
|
|
||||||
}
|
|
||||||
|
|
||||||
let expr = self.parse_expr(input, state, lib, settings.level_up())?;
|
let expr = self.parse_expr(input, state, lib, settings.level_up())?;
|
||||||
|
|
||||||
match input.next().expect(NEVER_ENDS) {
|
match input.next().expect(NEVER_ENDS) {
|
||||||
@ -453,6 +449,7 @@ impl Engine {
|
|||||||
state: &mut ParseState,
|
state: &mut ParseState,
|
||||||
lib: &mut FnLib,
|
lib: &mut FnLib,
|
||||||
id: Identifier,
|
id: Identifier,
|
||||||
|
no_args: bool,
|
||||||
capture_parent_scope: bool,
|
capture_parent_scope: bool,
|
||||||
#[cfg(not(feature = "no_module"))] namespace: crate::ast::Namespace,
|
#[cfg(not(feature = "no_module"))] namespace: crate::ast::Namespace,
|
||||||
settings: ParseSettings,
|
settings: ParseSettings,
|
||||||
@ -460,7 +457,11 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
let (token, token_pos) = input.peek().expect(NEVER_ENDS);
|
let (token, token_pos) = if no_args {
|
||||||
|
&(Token::RightParen, Position::NONE)
|
||||||
|
} else {
|
||||||
|
input.peek().expect(NEVER_ENDS)
|
||||||
|
};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
let mut namespace = namespace;
|
let mut namespace = namespace;
|
||||||
@ -479,7 +480,9 @@ impl Engine {
|
|||||||
Token::LexError(err) => return Err(err.clone().into_err(*token_pos)),
|
Token::LexError(err) => return Err(err.clone().into_err(*token_pos)),
|
||||||
// id()
|
// id()
|
||||||
Token::RightParen => {
|
Token::RightParen => {
|
||||||
eat_token(input, Token::RightParen);
|
if !no_args {
|
||||||
|
eat_token(input, Token::RightParen);
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
let hash = if !namespace.is_empty() {
|
let hash = if !namespace.is_empty() {
|
||||||
@ -897,7 +900,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let (name, pos) = match input.next().expect(NEVER_ENDS) {
|
let (name, pos) = match input.next().expect(NEVER_ENDS) {
|
||||||
(Token::Identifier(s), pos) | (Token::StringConstant(s), pos) => {
|
(Token::Identifier(s) | Token::StringConstant(s), pos) => {
|
||||||
if map.iter().any(|(p, ..)| **p == s) {
|
if map.iter().any(|(p, ..)| **p == s) {
|
||||||
return Err(PERR::DuplicatedProperty(s.to_string()).into_err(pos));
|
return Err(PERR::DuplicatedProperty(s.to_string()).into_err(pos));
|
||||||
}
|
}
|
||||||
@ -1201,6 +1204,11 @@ impl Engine {
|
|||||||
let root_expr = match token {
|
let root_expr = match token {
|
||||||
Token::EOF => return Err(PERR::UnexpectedEOF.into_err(settings.pos)),
|
Token::EOF => return Err(PERR::UnexpectedEOF.into_err(settings.pos)),
|
||||||
|
|
||||||
|
Token::Unit => {
|
||||||
|
input.next();
|
||||||
|
Expr::Unit(settings.pos)
|
||||||
|
}
|
||||||
|
|
||||||
Token::IntegerConstant(..)
|
Token::IntegerConstant(..)
|
||||||
| Token::CharConstant(..)
|
| Token::CharConstant(..)
|
||||||
| Token::StringConstant(..)
|
| Token::StringConstant(..)
|
||||||
@ -1218,13 +1226,13 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
Token::FloatConstant(x) => {
|
Token::FloatConstant(x) => {
|
||||||
let x = *x;
|
let x = *x;
|
||||||
input.next().expect(NEVER_ENDS);
|
input.next();
|
||||||
Expr::FloatConstant(x, settings.pos)
|
Expr::FloatConstant(x, settings.pos)
|
||||||
}
|
}
|
||||||
#[cfg(feature = "decimal")]
|
#[cfg(feature = "decimal")]
|
||||||
Token::DecimalConstant(x) => {
|
Token::DecimalConstant(x) => {
|
||||||
let x = (*x).into();
|
let x = (*x).into();
|
||||||
input.next().expect(NEVER_ENDS);
|
input.next();
|
||||||
Expr::DynamicConstant(Box::new(x), settings.pos)
|
Expr::DynamicConstant(Box::new(x), settings.pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1235,6 +1243,7 @@ impl Engine {
|
|||||||
stmt => unreachable!("Stmt::Block expected but gets {:?}", stmt),
|
stmt => unreachable!("Stmt::Block expected but gets {:?}", stmt),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ( - grouped expression
|
// ( - grouped expression
|
||||||
Token::LeftParen => self.parse_paren_expr(input, state, lib, settings.level_up())?,
|
Token::LeftParen => self.parse_paren_expr(input, state, lib, settings.level_up())?,
|
||||||
|
|
||||||
@ -1401,7 +1410,7 @@ impl Engine {
|
|||||||
|
|
||||||
match input.peek().expect(NEVER_ENDS).0 {
|
match input.peek().expect(NEVER_ENDS).0 {
|
||||||
// Function call
|
// Function call
|
||||||
Token::LeftParen | Token::Bang => {
|
Token::LeftParen | Token::Bang | Token::Unit => {
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
{
|
{
|
||||||
// Once the identifier consumed we must enable next variables capturing
|
// Once the identifier consumed we must enable next variables capturing
|
||||||
@ -1467,11 +1476,13 @@ impl Engine {
|
|||||||
|
|
||||||
match input.peek().expect(NEVER_ENDS).0 {
|
match input.peek().expect(NEVER_ENDS).0 {
|
||||||
// Function call is allowed to have reserved keyword
|
// Function call is allowed to have reserved keyword
|
||||||
Token::LeftParen | Token::Bang if is_keyword_function(&s) => Expr::Variable(
|
Token::LeftParen | Token::Bang | Token::Unit if is_keyword_function(&s) => {
|
||||||
(None, ns, 0, state.get_identifier("", s)).into(),
|
Expr::Variable(
|
||||||
None,
|
(None, ns, 0, state.get_identifier("", s)).into(),
|
||||||
settings.pos,
|
None,
|
||||||
),
|
settings.pos,
|
||||||
|
)
|
||||||
|
}
|
||||||
// Access to `this` as a variable is OK within a function scope
|
// Access to `this` as a variable is OK within a function scope
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
_ if &*s == KEYWORD_THIS && settings.is_function_scope => Expr::Variable(
|
_ if &*s == KEYWORD_THIS && settings.is_function_scope => Expr::Variable(
|
||||||
@ -1531,30 +1542,33 @@ impl Engine {
|
|||||||
// Qualified function call with !
|
// Qualified function call with !
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
(Expr::Variable(x, ..), Token::Bang) if !x.1.is_empty() => {
|
(Expr::Variable(x, ..), Token::Bang) if !x.1.is_empty() => {
|
||||||
return if !match_token(input, Token::LeftParen).0 {
|
return match input.peek().expect(NEVER_ENDS) {
|
||||||
Err(LexError::UnexpectedInput(Token::Bang.syntax().to_string())
|
(Token::LeftParen | Token::Unit, ..) => {
|
||||||
.into_err(tail_pos))
|
Err(LexError::UnexpectedInput(Token::Bang.syntax().to_string())
|
||||||
} else {
|
.into_err(tail_pos))
|
||||||
Err(LexError::ImproperSymbol(
|
}
|
||||||
|
_ => Err(LexError::ImproperSymbol(
|
||||||
"!".to_string(),
|
"!".to_string(),
|
||||||
"'!' cannot be used to call module functions".to_string(),
|
"'!' cannot be used to call module functions".to_string(),
|
||||||
)
|
)
|
||||||
.into_err(tail_pos))
|
.into_err(tail_pos)),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
// Function call with !
|
// Function call with !
|
||||||
(Expr::Variable(x, .., pos), Token::Bang) => {
|
(Expr::Variable(x, .., pos), Token::Bang) => {
|
||||||
match match_token(input, Token::LeftParen) {
|
match input.peek().expect(NEVER_ENDS) {
|
||||||
(false, pos) => {
|
(Token::LeftParen | Token::Unit, ..) => (),
|
||||||
|
(_, pos) => {
|
||||||
return Err(PERR::MissingToken(
|
return Err(PERR::MissingToken(
|
||||||
Token::LeftParen.syntax().into(),
|
Token::LeftParen.syntax().into(),
|
||||||
"to start arguments list of function call".into(),
|
"to start arguments list of function call".into(),
|
||||||
)
|
)
|
||||||
.into_err(pos))
|
.into_err(*pos))
|
||||||
}
|
}
|
||||||
_ => (),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let no_args = input.next().expect(NEVER_ENDS).0 == Token::Unit;
|
||||||
|
|
||||||
let (.., _ns, _, name) = *x;
|
let (.., _ns, _, name) = *x;
|
||||||
settings.pos = pos;
|
settings.pos = pos;
|
||||||
self.parse_fn_call(
|
self.parse_fn_call(
|
||||||
@ -1562,6 +1576,7 @@ impl Engine {
|
|||||||
state,
|
state,
|
||||||
lib,
|
lib,
|
||||||
name,
|
name,
|
||||||
|
no_args,
|
||||||
true,
|
true,
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
_ns,
|
_ns,
|
||||||
@ -1569,7 +1584,7 @@ impl Engine {
|
|||||||
)?
|
)?
|
||||||
}
|
}
|
||||||
// Function call
|
// Function call
|
||||||
(Expr::Variable(x, .., pos), Token::LeftParen) => {
|
(Expr::Variable(x, .., pos), t @ (Token::LeftParen | Token::Unit)) => {
|
||||||
let (.., _ns, _, name) = *x;
|
let (.., _ns, _, name) = *x;
|
||||||
settings.pos = pos;
|
settings.pos = pos;
|
||||||
self.parse_fn_call(
|
self.parse_fn_call(
|
||||||
@ -1577,6 +1592,7 @@ impl Engine {
|
|||||||
state,
|
state,
|
||||||
lib,
|
lib,
|
||||||
name,
|
name,
|
||||||
|
t == Token::Unit,
|
||||||
false,
|
false,
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
_ns,
|
_ns,
|
||||||
@ -1992,7 +2008,7 @@ impl Engine {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
// lhs.dot_lhs.dot_rhs or lhs.dot_lhs[idx_rhs]
|
// lhs.dot_lhs.dot_rhs or lhs.dot_lhs[idx_rhs]
|
||||||
(lhs, rhs @ Expr::Dot(..)) | (lhs, rhs @ Expr::Index(..)) => {
|
(lhs, rhs @ (Expr::Dot(..) | Expr::Index(..))) => {
|
||||||
let (x, term, pos, is_dot) = match rhs {
|
let (x, term, pos, is_dot) = match rhs {
|
||||||
Expr::Dot(x, term, pos) => (x, term, pos, true),
|
Expr::Dot(x, term, pos) => (x, term, pos, true),
|
||||||
Expr::Index(x, term, pos) => (x, term, pos, false),
|
Expr::Index(x, term, pos) => (x, term, pos, false),
|
||||||
@ -2324,7 +2340,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
CUSTOM_SYNTAX_MARKER_BOOL => match input.next().expect(NEVER_ENDS) {
|
CUSTOM_SYNTAX_MARKER_BOOL => match input.next().expect(NEVER_ENDS) {
|
||||||
(b @ Token::True, pos) | (b @ Token::False, pos) => {
|
(b @ (Token::True | Token::False), pos) => {
|
||||||
inputs.push(Expr::BoolConstant(b == Token::True, pos));
|
inputs.push(Expr::BoolConstant(b == Token::True, pos));
|
||||||
segments.push(state.get_interned_string("", b.literal_syntax()));
|
segments.push(state.get_interned_string("", b.literal_syntax()));
|
||||||
tokens.push(state.get_identifier("", CUSTOM_SYNTAX_MARKER_BOOL));
|
tokens.push(state.get_identifier("", CUSTOM_SYNTAX_MARKER_BOOL));
|
||||||
@ -2999,7 +3015,7 @@ impl Engine {
|
|||||||
comments.push(comment);
|
comments.push(comment);
|
||||||
|
|
||||||
match input.peek().expect(NEVER_ENDS) {
|
match input.peek().expect(NEVER_ENDS) {
|
||||||
(Token::Fn, ..) | (Token::Private, ..) => break,
|
(Token::Fn | Token::Private, ..) => break,
|
||||||
(Token::Comment(..), ..) => (),
|
(Token::Comment(..), ..) => (),
|
||||||
_ => return Err(PERR::WrongDocComment.into_err(comments_pos)),
|
_ => return Err(PERR::WrongDocComment.into_err(comments_pos)),
|
||||||
}
|
}
|
||||||
@ -3269,14 +3285,21 @@ impl Engine {
|
|||||||
Err(_) => return Err(PERR::FnMissingName.into_err(pos)),
|
Err(_) => return Err(PERR::FnMissingName.into_err(pos)),
|
||||||
};
|
};
|
||||||
|
|
||||||
match input.peek().expect(NEVER_ENDS) {
|
let no_params = match input.peek().expect(NEVER_ENDS) {
|
||||||
(Token::LeftParen, ..) => eat_token(input, Token::LeftParen),
|
(Token::LeftParen, ..) => {
|
||||||
|
eat_token(input, Token::LeftParen);
|
||||||
|
match_token(input, Token::RightParen).0
|
||||||
|
}
|
||||||
|
(Token::Unit, ..) => {
|
||||||
|
eat_token(input, Token::Unit);
|
||||||
|
true
|
||||||
|
}
|
||||||
(.., pos) => return Err(PERR::FnMissingParams(name.to_string()).into_err(*pos)),
|
(.., pos) => return Err(PERR::FnMissingParams(name.to_string()).into_err(*pos)),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut params = StaticVec::new_const();
|
let mut params = StaticVec::new_const();
|
||||||
|
|
||||||
if !match_token(input, Token::RightParen).0 {
|
if !no_params {
|
||||||
let sep_err = format!("to separate the parameters of function '{}'", name);
|
let sep_err = format!("to separate the parameters of function '{}'", name);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
@ -382,6 +382,8 @@ pub enum Token {
|
|||||||
LeftBracket,
|
LeftBracket,
|
||||||
/// `]`
|
/// `]`
|
||||||
RightBracket,
|
RightBracket,
|
||||||
|
/// `()`
|
||||||
|
Unit,
|
||||||
/// `+`
|
/// `+`
|
||||||
Plus,
|
Plus,
|
||||||
/// `+` (unary)
|
/// `+` (unary)
|
||||||
@ -558,6 +560,7 @@ impl Token {
|
|||||||
RightParen => ")",
|
RightParen => ")",
|
||||||
LeftBracket => "[",
|
LeftBracket => "[",
|
||||||
RightBracket => "]",
|
RightBracket => "]",
|
||||||
|
Unit => "()",
|
||||||
Plus => "+",
|
Plus => "+",
|
||||||
UnaryPlus => "+",
|
UnaryPlus => "+",
|
||||||
Minus => "-",
|
Minus => "-",
|
||||||
@ -754,6 +757,7 @@ impl Token {
|
|||||||
")" => RightParen,
|
")" => RightParen,
|
||||||
"[" => LeftBracket,
|
"[" => LeftBracket,
|
||||||
"]" => RightBracket,
|
"]" => RightBracket,
|
||||||
|
"()" => Unit,
|
||||||
"+" => Plus,
|
"+" => Plus,
|
||||||
"-" => Minus,
|
"-" => Minus,
|
||||||
"*" => Multiply,
|
"*" => Multiply,
|
||||||
@ -1702,6 +1706,12 @@ fn get_next_token_inner(
|
|||||||
('{', ..) => return Some((Token::LeftBrace, start_pos)),
|
('{', ..) => return Some((Token::LeftBrace, start_pos)),
|
||||||
('}', ..) => return Some((Token::RightBrace, start_pos)),
|
('}', ..) => return Some((Token::RightBrace, start_pos)),
|
||||||
|
|
||||||
|
// Unit
|
||||||
|
('(', ')') => {
|
||||||
|
eat_next(stream, pos);
|
||||||
|
return Some((Token::Unit, start_pos));
|
||||||
|
}
|
||||||
|
|
||||||
// Parentheses
|
// Parentheses
|
||||||
('(', '*') => {
|
('(', '*') => {
|
||||||
eat_next(stream, pos);
|
eat_next(stream, pos);
|
||||||
|
@ -51,7 +51,8 @@ impl fmt::Display for LexError {
|
|||||||
Self::ImproperSymbol(s, d) if d.is_empty() => {
|
Self::ImproperSymbol(s, d) if d.is_empty() => {
|
||||||
write!(f, "Invalid symbol encountered: '{}'", s)
|
write!(f, "Invalid symbol encountered: '{}'", s)
|
||||||
}
|
}
|
||||||
Self::ImproperSymbol(.., d) => f.write_str(d),
|
Self::ImproperSymbol(s, d) if s.is_empty() => f.write_str(d),
|
||||||
|
Self::ImproperSymbol(s, d) => write!(f, "{}: '{}'", d, s),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,6 @@ fn test_unit_eq() -> Result<(), Box<EvalAltResult>> {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_unit_with_spaces() -> Result<(), Box<EvalAltResult>> {
|
fn test_unit_with_spaces() -> Result<(), Box<EvalAltResult>> {
|
||||||
let engine = Engine::new();
|
let engine = Engine::new();
|
||||||
engine.run("let x = ( ); x")?;
|
engine.run("let x = ( ); x").expect_err("should error");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user