Streamline parsing.
This commit is contained in:
parent
48af8719e7
commit
6b8d78d64c
@ -7,6 +7,11 @@ Version 0.19.9
|
|||||||
This version removes the confusing differences between _packages_ and _modules_
|
This version removes the confusing differences between _packages_ and _modules_
|
||||||
by unifying the terminology and API under the global umbrella of _modules_.
|
by unifying the terminology and API under the global umbrella of _modules_.
|
||||||
|
|
||||||
|
Bug fixes
|
||||||
|
---------
|
||||||
|
|
||||||
|
* Property access in
|
||||||
|
|
||||||
Breaking changes
|
Breaking changes
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
|
14
src/ast.rs
14
src/ast.rs
@ -1176,6 +1176,12 @@ impl Expr {
|
|||||||
}
|
}
|
||||||
/// Is a particular [token][Token] allowed as a postfix operator to this expression?
|
/// Is a particular [token][Token] allowed as a postfix operator to this expression?
|
||||||
pub fn is_valid_postfix(&self, token: &Token) -> bool {
|
pub fn is_valid_postfix(&self, token: &Token) -> bool {
|
||||||
|
match token {
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
Token::Period => return true,
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
Self::Expr(x) => x.is_valid_postfix(token),
|
Self::Expr(x) => x.is_valid_postfix(token),
|
||||||
|
|
||||||
@ -1193,24 +1199,20 @@ impl Expr {
|
|||||||
| Self::Unit(_) => false,
|
| Self::Unit(_) => false,
|
||||||
|
|
||||||
Self::StringConstant(_, _)
|
Self::StringConstant(_, _)
|
||||||
| Self::Stmt(_, _)
|
|
||||||
| Self::FnCall(_, _)
|
| Self::FnCall(_, _)
|
||||||
|
| Self::Stmt(_, _)
|
||||||
| Self::Dot(_, _)
|
| Self::Dot(_, _)
|
||||||
| Self::Index(_, _)
|
| Self::Index(_, _)
|
||||||
| Self::Array(_, _)
|
| Self::Array(_, _)
|
||||||
| Self::Map(_, _) => match token {
|
| Self::Map(_, _) => match token {
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Token::LeftBracket => true,
|
Token::LeftBracket => true,
|
||||||
#[cfg(not(feature = "no_object"))]
|
|
||||||
Token::Period => true,
|
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
|
|
||||||
Self::Variable(_) => match token {
|
Self::Variable(_) => match token {
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Token::LeftBracket => true,
|
Token::LeftBracket => true,
|
||||||
#[cfg(not(feature = "no_object"))]
|
|
||||||
Token::Period => true,
|
|
||||||
Token::LeftParen => true,
|
Token::LeftParen => true,
|
||||||
Token::Bang => true,
|
Token::Bang => true,
|
||||||
Token::DoubleColon => true,
|
Token::DoubleColon => true,
|
||||||
@ -1220,8 +1222,6 @@ impl Expr {
|
|||||||
Self::Property(_) => match token {
|
Self::Property(_) => match token {
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Token::LeftBracket => true,
|
Token::LeftBracket => true,
|
||||||
#[cfg(not(feature = "no_object"))]
|
|
||||||
Token::Period => true,
|
|
||||||
Token::LeftParen => true,
|
Token::LeftParen => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
|
252
src/parser.rs
252
src/parser.rs
@ -278,8 +278,11 @@ fn parse_paren_expr(
|
|||||||
input: &mut TokenStream,
|
input: &mut TokenStream,
|
||||||
state: &mut ParseState,
|
state: &mut ParseState,
|
||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
settings: ParseSettings,
|
mut settings: ParseSettings,
|
||||||
) -> Result<Expr, ParseError> {
|
) -> Result<Expr, ParseError> {
|
||||||
|
// ( ...
|
||||||
|
settings.pos = eat_token(input, Token::LeftParen);
|
||||||
|
|
||||||
#[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)?;
|
||||||
|
|
||||||
@ -637,8 +640,11 @@ fn parse_array_literal(
|
|||||||
input: &mut TokenStream,
|
input: &mut TokenStream,
|
||||||
state: &mut ParseState,
|
state: &mut ParseState,
|
||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
settings: ParseSettings,
|
mut settings: ParseSettings,
|
||||||
) -> Result<Expr, ParseError> {
|
) -> Result<Expr, ParseError> {
|
||||||
|
// [ ...
|
||||||
|
settings.pos = eat_token(input, Token::LeftBracket);
|
||||||
|
|
||||||
#[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)?;
|
||||||
|
|
||||||
@ -704,8 +710,11 @@ fn parse_map_literal(
|
|||||||
input: &mut TokenStream,
|
input: &mut TokenStream,
|
||||||
state: &mut ParseState,
|
state: &mut ParseState,
|
||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
settings: ParseSettings,
|
mut settings: ParseSettings,
|
||||||
) -> Result<Expr, ParseError> {
|
) -> Result<Expr, ParseError> {
|
||||||
|
// #{ ...
|
||||||
|
settings.pos = eat_token(input, Token::MapStart);
|
||||||
|
|
||||||
#[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)?;
|
||||||
|
|
||||||
@ -947,31 +956,107 @@ fn parse_primary(
|
|||||||
#[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, _) = match token {
|
|
||||||
// { - block statement as expression
|
|
||||||
Token::LeftBrace if settings.allow_stmt_expr => {
|
|
||||||
return parse_block(input, state, lib, settings.level_up()).map(|block| match block {
|
|
||||||
Stmt::Block(statements, pos) => Expr::Stmt(Box::new(statements.into()), pos),
|
|
||||||
_ => unreachable!(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
Token::EOF => return Err(PERR::UnexpectedEOF.into_err(settings.pos)),
|
|
||||||
_ => input.next().unwrap(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let (next_token, _) = input.peek().unwrap();
|
|
||||||
|
|
||||||
let mut root_expr = match token {
|
let mut root_expr = match token {
|
||||||
|
Token::EOF => return Err(PERR::UnexpectedEOF.into_err(settings.pos)),
|
||||||
|
|
||||||
|
Token::IntegerConstant(_)
|
||||||
|
| Token::CharConstant(_)
|
||||||
|
| Token::StringConstant(_)
|
||||||
|
| Token::True
|
||||||
|
| Token::False => match input.next().unwrap().0 {
|
||||||
Token::IntegerConstant(x) => Expr::IntegerConstant(x, settings.pos),
|
Token::IntegerConstant(x) => Expr::IntegerConstant(x, settings.pos),
|
||||||
#[cfg(not(feature = "no_float"))]
|
|
||||||
Token::FloatConstant(x) => Expr::FloatConstant(x, settings.pos),
|
|
||||||
Token::CharConstant(c) => Expr::CharConstant(c, settings.pos),
|
Token::CharConstant(c) => Expr::CharConstant(c, settings.pos),
|
||||||
Token::StringConstant(s) => {
|
Token::StringConstant(s) => {
|
||||||
Expr::StringConstant(state.get_interned_string(s), settings.pos)
|
Expr::StringConstant(state.get_interned_string(s), settings.pos)
|
||||||
}
|
}
|
||||||
|
Token::True => Expr::BoolConstant(true, settings.pos),
|
||||||
|
Token::False => Expr::BoolConstant(false, settings.pos),
|
||||||
|
_ => unreachable!(),
|
||||||
|
},
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
Token::FloatConstant(x) => {
|
||||||
|
let x = *x;
|
||||||
|
input.next().unwrap();
|
||||||
|
Expr::FloatConstant(x, settings.pos)
|
||||||
|
}
|
||||||
|
|
||||||
|
// { - block statement as expression
|
||||||
|
Token::LeftBrace if settings.allow_stmt_expr => {
|
||||||
|
match parse_block(input, state, lib, settings.level_up())? {
|
||||||
|
Stmt::Block(statements, pos) => Expr::Stmt(Box::new(statements.into()), pos),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ( - grouped expression
|
||||||
|
Token::LeftParen => parse_paren_expr(input, state, lib, settings.level_up())?,
|
||||||
|
|
||||||
|
// If statement is allowed to act as expressions
|
||||||
|
Token::If if settings.allow_if_expr => Expr::Stmt(
|
||||||
|
Box::new(vec![parse_if(input, state, lib, settings.level_up())?].into()),
|
||||||
|
settings.pos,
|
||||||
|
),
|
||||||
|
// Switch statement is allowed to act as expressions
|
||||||
|
Token::Switch if settings.allow_switch_expr => Expr::Stmt(
|
||||||
|
Box::new(vec![parse_switch(input, state, lib, settings.level_up())?].into()),
|
||||||
|
settings.pos,
|
||||||
|
),
|
||||||
|
// | ...
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
Token::Pipe | Token::Or if settings.allow_anonymous_fn => {
|
||||||
|
let mut new_state = ParseState::new(
|
||||||
|
state.engine,
|
||||||
|
state.script_hash,
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
state.max_function_expr_depth,
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
state.max_function_expr_depth,
|
||||||
|
);
|
||||||
|
|
||||||
|
let settings = ParseSettings {
|
||||||
|
allow_if_expr: true,
|
||||||
|
allow_switch_expr: true,
|
||||||
|
allow_stmt_expr: true,
|
||||||
|
allow_anonymous_fn: true,
|
||||||
|
is_global: false,
|
||||||
|
is_function_scope: true,
|
||||||
|
is_breakable: false,
|
||||||
|
level: 0,
|
||||||
|
pos: settings.pos,
|
||||||
|
};
|
||||||
|
|
||||||
|
let (expr, func) = parse_anon_fn(input, &mut new_state, lib, settings)?;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_closure"))]
|
||||||
|
new_state.externals.iter().for_each(|(closure, pos)| {
|
||||||
|
state.access_var(closure, *pos);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Qualifiers (none) + function name + number of arguments.
|
||||||
|
let hash = calc_script_fn_hash(empty(), &func.name, func.params.len()).unwrap();
|
||||||
|
|
||||||
|
lib.insert(hash, func);
|
||||||
|
|
||||||
|
expr
|
||||||
|
}
|
||||||
|
|
||||||
|
// Array literal
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
Token::LeftBracket => parse_array_literal(input, state, lib, settings.level_up())?,
|
||||||
|
|
||||||
|
// Map literal
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
Token::MapStart => parse_map_literal(input, state, lib, settings.level_up())?,
|
||||||
|
|
||||||
|
// Identifier
|
||||||
|
Token::Identifier(_) => {
|
||||||
|
let s = match input.next().unwrap().0 {
|
||||||
|
Token::Identifier(s) => s,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
match input.peek().unwrap().0 {
|
||||||
// Function call
|
// Function call
|
||||||
Token::Identifier(s) if *next_token == Token::LeftParen || *next_token == Token::Bang => {
|
Token::LeftParen | Token::Bang => {
|
||||||
// Once the identifier consumed we must enable next variables capturing
|
// Once the identifier consumed we must enable next variables capturing
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
{
|
{
|
||||||
@ -985,7 +1070,7 @@ fn parse_primary(
|
|||||||
}
|
}
|
||||||
// Namespace qualification
|
// Namespace qualification
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
Token::Identifier(s) if *next_token == Token::DoubleColon => {
|
Token::DoubleColon => {
|
||||||
// Once the identifier consumed we must enable next variables capturing
|
// Once the identifier consumed we must enable next variables capturing
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
{
|
{
|
||||||
@ -998,7 +1083,7 @@ fn parse_primary(
|
|||||||
Expr::Variable(Box::new((None, None, var_name_def)))
|
Expr::Variable(Box::new((None, None, var_name_def)))
|
||||||
}
|
}
|
||||||
// Normal variable access
|
// Normal variable access
|
||||||
Token::Identifier(s) => {
|
_ => {
|
||||||
let index = state.access_var(&s, settings.pos);
|
let index = state.access_var(&s, settings.pos);
|
||||||
let var_name_def = Ident {
|
let var_name_def = Ident {
|
||||||
name: state.get_interned_string(s),
|
name: state.get_interned_string(s),
|
||||||
@ -1006,10 +1091,22 @@ fn parse_primary(
|
|||||||
};
|
};
|
||||||
Expr::Variable(Box::new((index, None, var_name_def)))
|
Expr::Variable(Box::new((index, None, var_name_def)))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reserved keyword or symbol
|
||||||
|
Token::Reserved(_) => {
|
||||||
|
let s = match input.next().unwrap().0 {
|
||||||
|
Token::Reserved(s) => s,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
match input.peek().unwrap().0 {
|
||||||
// Function call is allowed to have reserved keyword
|
// Function call is allowed to have reserved keyword
|
||||||
Token::Reserved(s) if *next_token == Token::LeftParen || *next_token == Token::Bang => {
|
Token::LeftParen | Token::Bang => {
|
||||||
if is_keyword_function(&s) {
|
if s == KEYWORD_THIS {
|
||||||
|
return Err(PERR::Reserved(s).into_err(settings.pos));
|
||||||
|
} else if is_keyword_function(&s) {
|
||||||
let var_name_def = Ident {
|
let var_name_def = Ident {
|
||||||
name: state.get_interned_string(s),
|
name: state.get_interned_string(s),
|
||||||
pos: settings.pos,
|
pos: settings.pos,
|
||||||
@ -1019,9 +1116,8 @@ fn parse_primary(
|
|||||||
return Err(PERR::Reserved(s).into_err(settings.pos));
|
return Err(PERR::Reserved(s).into_err(settings.pos));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Access to `this` as a variable is OK
|
// Access to `this` as a variable is OK
|
||||||
Token::Reserved(s) if s == KEYWORD_THIS && *next_token != Token::LeftParen => {
|
_ if s == KEYWORD_THIS => {
|
||||||
if !settings.is_function_scope {
|
if !settings.is_function_scope {
|
||||||
let msg = format!("'{}' can only be used in functions", s);
|
let msg = format!("'{}' can only be used in functions", s);
|
||||||
return Err(LexError::ImproperSymbol(s, msg).into_err(settings.pos));
|
return Err(LexError::ImproperSymbol(s, msg).into_err(settings.pos));
|
||||||
@ -1033,19 +1129,23 @@ fn parse_primary(
|
|||||||
Expr::Variable(Box::new((None, None, var_name_def)))
|
Expr::Variable(Box::new((None, None, var_name_def)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
_ if is_valid_identifier(s.chars()) => {
|
||||||
Token::Reserved(s) if is_valid_identifier(s.chars()) => {
|
|
||||||
return Err(PERR::Reserved(s).into_err(settings.pos));
|
return Err(PERR::Reserved(s).into_err(settings.pos));
|
||||||
}
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(LexError::UnexpectedInput(s).into_err(settings.pos));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Token::LeftParen => parse_paren_expr(input, state, lib, settings.level_up())?,
|
Token::LexError(_) => {
|
||||||
#[cfg(not(feature = "no_index"))]
|
let err = match input.next().unwrap().0 {
|
||||||
Token::LeftBracket => parse_array_literal(input, state, lib, settings.level_up())?,
|
Token::LexError(err) => err,
|
||||||
#[cfg(not(feature = "no_object"))]
|
_ => unreachable!(),
|
||||||
Token::MapStart => parse_map_literal(input, state, lib, settings.level_up())?,
|
};
|
||||||
Token::True => Expr::BoolConstant(true, settings.pos),
|
|
||||||
Token::False => Expr::BoolConstant(false, settings.pos),
|
return Err(err.into_err(settings.pos));
|
||||||
Token::LexError(err) => return Err(err.into_err(settings.pos)),
|
}
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
return Err(
|
return Err(
|
||||||
@ -1056,26 +1156,26 @@ fn parse_primary(
|
|||||||
|
|
||||||
// Tail processing all possible postfix operators
|
// Tail processing all possible postfix operators
|
||||||
loop {
|
loop {
|
||||||
let (token, _) = input.peek().unwrap();
|
let (tail_token, _) = input.peek().unwrap();
|
||||||
|
|
||||||
if !root_expr.is_valid_postfix(token) {
|
if !root_expr.is_valid_postfix(tail_token) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
let (token, token_pos) = input.next().unwrap();
|
let (tail_token, tail_pos) = input.next().unwrap();
|
||||||
settings.pos = token_pos;
|
settings.pos = tail_pos;
|
||||||
|
|
||||||
root_expr = match (root_expr, token) {
|
root_expr = match (root_expr, tail_token) {
|
||||||
// Qualified function call with !
|
// Qualified function call with !
|
||||||
(Expr::Variable(x), Token::Bang) if x.1.is_some() => {
|
(Expr::Variable(x), Token::Bang) if x.1.is_some() => {
|
||||||
return Err(if !match_token(input, Token::LeftParen).0 {
|
return Err(if !match_token(input, Token::LeftParen).0 {
|
||||||
LexError::UnexpectedInput(Token::Bang.syntax().to_string()).into_err(token_pos)
|
LexError::UnexpectedInput(Token::Bang.syntax().to_string()).into_err(tail_pos)
|
||||||
} else {
|
} else {
|
||||||
LexError::ImproperSymbol(
|
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(token_pos)
|
.into_err(tail_pos)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// Function call with !
|
// Function call with !
|
||||||
@ -1132,7 +1232,7 @@ fn parse_primary(
|
|||||||
(expr, Token::LeftBracket) => {
|
(expr, Token::LeftBracket) => {
|
||||||
parse_index_chain(input, state, lib, expr, settings.level_up())?
|
parse_index_chain(input, state, lib, expr, settings.level_up())?
|
||||||
}
|
}
|
||||||
// Method access
|
// Property access
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
(expr, Token::Period) => {
|
(expr, Token::Period) => {
|
||||||
// prevents capturing of the object properties as vars: xxx.<var>
|
// prevents capturing of the object properties as vars: xxx.<var>
|
||||||
@ -1142,7 +1242,7 @@ fn parse_primary(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let rhs = parse_unary(input, state, lib, settings.level_up())?;
|
let rhs = parse_unary(input, state, lib, settings.level_up())?;
|
||||||
make_dot_expr(state, expr, rhs, token_pos)?
|
make_dot_expr(state, expr, rhs, tail_pos)?
|
||||||
}
|
}
|
||||||
// Unknown postfix operator
|
// Unknown postfix operator
|
||||||
(expr, token) => unreachable!(
|
(expr, token) => unreachable!(
|
||||||
@ -1193,16 +1293,6 @@ fn parse_unary(
|
|||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
match token {
|
match token {
|
||||||
// If statement is allowed to act as expressions
|
|
||||||
Token::If if settings.allow_if_expr => Ok(Expr::Stmt(
|
|
||||||
Box::new(vec![parse_if(input, state, lib, settings.level_up())?].into()),
|
|
||||||
settings.pos,
|
|
||||||
)),
|
|
||||||
// Switch statement is allowed to act as expressions
|
|
||||||
Token::Switch if settings.allow_switch_expr => Ok(Expr::Stmt(
|
|
||||||
Box::new(vec![parse_switch(input, state, lib, settings.level_up())?].into()),
|
|
||||||
settings.pos,
|
|
||||||
)),
|
|
||||||
// -expr
|
// -expr
|
||||||
Token::UnaryMinus => {
|
Token::UnaryMinus => {
|
||||||
let pos = eat_token(input, Token::UnaryMinus);
|
let pos = eat_token(input, Token::UnaryMinus);
|
||||||
@ -1286,44 +1376,6 @@ fn parse_unary(
|
|||||||
pos,
|
pos,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
// | ...
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
|
||||||
Token::Pipe | Token::Or if settings.allow_anonymous_fn => {
|
|
||||||
let mut new_state = ParseState::new(
|
|
||||||
state.engine,
|
|
||||||
state.script_hash,
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
|
||||||
state.max_function_expr_depth,
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
|
||||||
state.max_function_expr_depth,
|
|
||||||
);
|
|
||||||
|
|
||||||
let settings = ParseSettings {
|
|
||||||
allow_if_expr: true,
|
|
||||||
allow_switch_expr: true,
|
|
||||||
allow_stmt_expr: true,
|
|
||||||
allow_anonymous_fn: true,
|
|
||||||
is_global: false,
|
|
||||||
is_function_scope: true,
|
|
||||||
is_breakable: false,
|
|
||||||
level: 0,
|
|
||||||
pos: *token_pos,
|
|
||||||
};
|
|
||||||
|
|
||||||
let (expr, func) = parse_anon_fn(input, &mut new_state, lib, settings)?;
|
|
||||||
|
|
||||||
#[cfg(not(feature = "no_closure"))]
|
|
||||||
new_state.externals.iter().for_each(|(closure, pos)| {
|
|
||||||
state.access_var(closure, *pos);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Qualifiers (none) + function name + number of arguments.
|
|
||||||
let hash = calc_script_fn_hash(empty(), &func.name, func.params.len()).unwrap();
|
|
||||||
|
|
||||||
lib.insert(hash, func);
|
|
||||||
|
|
||||||
Ok(expr)
|
|
||||||
}
|
|
||||||
// <EOF>
|
// <EOF>
|
||||||
Token::EOF => Err(PERR::UnexpectedEOF.into_err(settings.pos)),
|
Token::EOF => Err(PERR::UnexpectedEOF.into_err(settings.pos)),
|
||||||
// All other tokens
|
// All other tokens
|
||||||
@ -1816,13 +1868,12 @@ fn parse_binary_op(
|
|||||||
make_in_expr(current_lhs, rhs, pos)?
|
make_in_expr(current_lhs, rhs, pos)?
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
// #[cfg(not(feature = "no_object"))]
|
||||||
Token::Period => {
|
// Token::Period => {
|
||||||
let rhs = args.pop().unwrap();
|
// let rhs = args.pop().unwrap();
|
||||||
let current_lhs = args.pop().unwrap();
|
// let current_lhs = args.pop().unwrap();
|
||||||
make_dot_expr(state, current_lhs, rhs, pos)?
|
// make_dot_expr(state, current_lhs, rhs, pos)?
|
||||||
}
|
// }
|
||||||
|
|
||||||
Token::Custom(s)
|
Token::Custom(s)
|
||||||
if state
|
if state
|
||||||
.engine
|
.engine
|
||||||
@ -2583,6 +2634,7 @@ fn parse_stmt(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Token::If => parse_if(input, state, lib, settings.level_up()).map(Some),
|
Token::If => parse_if(input, state, lib, settings.level_up()).map(Some),
|
||||||
|
Token::Switch => parse_switch(input, state, lib, settings.level_up()).map(Some),
|
||||||
Token::While | Token::Loop => {
|
Token::While | Token::Loop => {
|
||||||
parse_while_loop(input, state, lib, settings.level_up()).map(Some)
|
parse_while_loop(input, state, lib, settings.level_up()).map(Some)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user