diff --git a/src/engine.rs b/src/engine.rs index 8f4f418f..cd4f4b2c 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -1191,7 +1191,7 @@ impl Engine<'_> { Expr::FloatConstant(f, _) => Ok(f.into_dynamic()), Expr::IntegerConstant(i, _) => Ok(i.into_dynamic()), - Expr::StringConstant(s, _) => Ok(s.into_dynamic()), + Expr::StringConstant(s, _) => Ok(s.clone().into_owned().into_dynamic()), Expr::CharConstant(c, _) => Ok(c.into_dynamic()), Expr::Variable(id, pos) => Self::search_scope(scope, id, *pos).map(|(_, val)| val), Expr::Property(_, _) => panic!("unexpected property."), @@ -1213,7 +1213,9 @@ impl Engine<'_> { // name = rhs Expr::Variable(name, pos) => match scope .get(name) - .ok_or_else(|| EvalAltResult::ErrorVariableNotFound(name.clone(), *pos))? + .ok_or_else(|| { + EvalAltResult::ErrorVariableNotFound(name.clone().into_owned(), *pos) + })? .0 { entry @@ -1328,7 +1330,7 @@ impl Engine<'_> { && engine.fn_lib.as_ref().unwrap().has_function(name, 1)) } - match fn_name.as_str() { + match fn_name.as_ref() { // Dump AST KEYWORD_DUMP_AST => { let pos = if args_expr_list.is_empty() { diff --git a/src/optimize.rs b/src/optimize.rs index ec5d3688..22693977 100644 --- a/src/optimize.rs +++ b/src/optimize.rs @@ -444,7 +444,7 @@ fn optimize_expr<'a>(expr: Expr, state: &mut State<'a>) -> Expr { Expr::FunctionCall(id, args, def_value, pos), // Do not call some special keywords - Expr::FunctionCall(id, args, def_value, pos) if DONT_EVAL_KEYWORDS.contains(&id.as_str())=> + Expr::FunctionCall(id, args, def_value, pos) if DONT_EVAL_KEYWORDS.contains(&id.as_ref())=> Expr::FunctionCall(id, args.into_iter().map(|a| optimize_expr(a, state)).collect(), def_value, pos), // Eagerly call functions diff --git a/src/parser.rs b/src/parser.rs index 8dcbbc98..b592af43 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -13,7 +13,9 @@ use crate::stdlib::{ boxed::Box, char, collections::HashMap, - fmt, format, + fmt, + fmt::Display, + format, iter::Peekable, ops::Add, rc::Rc, @@ -316,11 +318,11 @@ pub enum Stmt { /// loop { stmt } Loop(Box), /// for id in expr { stmt } - For(String, Box, Box), + For(Cow<'static, str>, Box, Box), /// let id = expr - Let(String, Option>, Position), + Let(Cow<'static, str>, Option>, Position), /// const id = expr - Const(String, Box, Position), + Const(Cow<'static, str>, Box, Position), /// { stmt; ... } Block(Vec, Position), /// { stmt } @@ -401,15 +403,15 @@ pub enum Expr { /// Character constant. CharConstant(char, Position), /// String constant. - StringConstant(String, Position), + StringConstant(Cow<'static, str>, Position), /// Variable access. - Variable(String, Position), + Variable(Cow<'static, str>, Position), /// Property access. - Property(String, Position), + Property(Cow<'static, str>, Position), /// { stmt } Stmt(Box, Position), /// func(expr, ... ) - FunctionCall(String, Vec, Option, Position), + FunctionCall(Cow<'static, str>, Vec, Option, Position), /// expr = expr Assignment(Box, Box, Position), /// lhs.rhs @@ -446,7 +448,7 @@ impl Expr { match self { Expr::IntegerConstant(i, _) => i.into_dynamic(), Expr::CharConstant(c, _) => c.into_dynamic(), - Expr::StringConstant(s, _) => s.into_dynamic(), + Expr::StringConstant(s, _) => s.clone().into_owned().into_dynamic(), Expr::True(_) => true.into_dynamic(), Expr::False(_) => false.into_dynamic(), Expr::Unit(_) => ().into_dynamic(), @@ -1448,42 +1450,49 @@ fn parse_paren_expr<'a>( } /// Parse a function call. -fn parse_call_expr<'a>( - id: String, +fn parse_call_expr<'a, S: Into> + Display>( + id: S, input: &mut Peekable>, begin: Position, allow_stmt_expr: bool, ) -> Result { let mut args_expr_list = Vec::new(); - // id() - if let (Token::RightParen, _) = input.peek().ok_or_else(|| { - PERR::MissingToken( - ")".into(), - format!("to close the arguments list of this function call '{}'", id), - ) - .into_err_eof() - })? { - input.next(); - return Ok(Expr::FunctionCall(id, args_expr_list, None, begin)); + match input.peek() { + //id {EOF} + None => { + return Err(PERR::MissingToken( + ")".into(), + format!("to close the arguments list of this function call '{}'", id), + ) + .into_err_eof()) + } + // id() + Some((Token::RightParen, _)) => { + input.next(); + return Ok(Expr::FunctionCall(id.into(), args_expr_list, None, begin)); + } + // id... + _ => (), } loop { args_expr_list.push(parse_expr(input, allow_stmt_expr)?); - match input.peek().ok_or_else(|| { - PERR::MissingToken( - ")".into(), - format!("to close the arguments list of this function call '{}'", id), - ) - .into_err_eof() - })? { - (Token::RightParen, _) => { - input.next(); - return Ok(Expr::FunctionCall(id, args_expr_list, None, begin)); + match input.peek() { + None => { + return Err(PERR::MissingToken( + ")".into(), + format!("to close the arguments list of this function call '{}'", id), + ) + .into_err_eof()) } - (Token::Comma, _) => (), - (_, pos) => { + Some((Token::RightParen, _)) => { + input.next(); + return Ok(Expr::FunctionCall(id.into(), args_expr_list, None, begin)); + } + Some((Token::Comma, _)) => (), + Some((_, pos)) => { return Err(PERR::MissingToken( ",".into(), format!("to separate the arguments to function call '{}'", id), @@ -1643,8 +1652,8 @@ fn parse_index_expr<'a>( } /// Parse an expression that begins with an identifier. -fn parse_ident_expr<'a>( - id: String, +fn parse_ident_expr<'a, S: Into> + Display>( + id: S, input: &mut Peekable>, begin: Position, allow_stmt_expr: bool, @@ -1661,16 +1670,16 @@ fn parse_ident_expr<'a>( let pos = *pos; input.next(); parse_index_expr( - Box::new(Expr::Variable(id, begin)), + Box::new(Expr::Variable(id.into(), begin)), input, pos, allow_stmt_expr, ) } // id - variable - Some(_) => Ok(Expr::Variable(id, begin)), + Some(_) => Ok(Expr::Variable(id.into(), begin)), // EOF - None => Ok(Expr::Variable(id, begin)), + None => Ok(Expr::Variable(id.into(), begin)), } } @@ -1851,7 +1860,7 @@ fn parse_primary<'a>( (Token::CharConstant(c), pos) => Ok(Expr::CharConstant(c, pos)), (Token::StringConst(s), pos) => { can_be_indexed = true; - Ok(Expr::StringConstant(s, pos)) + Ok(Expr::StringConstant(s.into(), pos)) } (Token::Identifier(s), pos) => { can_be_indexed = true; @@ -2040,7 +2049,12 @@ fn parse_assignment(lhs: Expr, rhs: Expr, pos: Position) -> Result Result { +fn parse_op_assignment>>( + op: S, + lhs: Expr, + rhs: Expr, + pos: Position, +) -> Result { let lhs_copy = lhs.clone(); // lhs op= rhs -> lhs = op(lhs, rhs) @@ -2336,7 +2350,7 @@ fn parse_for<'a>( 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))) + Ok(Stmt::For(name.into(), Box::new(expr), Box::new(body))) } /// Parse a variable definition statement. @@ -2367,10 +2381,10 @@ fn parse_let<'a>( match var_type { // let name = expr - ScopeEntryType::Normal => Ok(Stmt::Let(name, Some(Box::new(init_value)), pos)), + ScopeEntryType::Normal => Ok(Stmt::Let(name.into(), Some(Box::new(init_value)), pos)), // const name = { expr:constant } ScopeEntryType::Constant if init_value.is_constant() => { - Ok(Stmt::Const(name, Box::new(init_value), pos)) + Ok(Stmt::Const(name.into(), Box::new(init_value), pos)) } // const name = expr - error ScopeEntryType::Constant => { @@ -2379,7 +2393,7 @@ fn parse_let<'a>( } } else { // let name - Ok(Stmt::Let(name, None, pos)) + Ok(Stmt::Let(name.into(), None, pos)) } } @@ -2733,7 +2747,7 @@ pub fn map_dynamic_to_expr(value: Dynamic, pos: Position) -> Option { } else if value.is::() { Some(Expr::CharConstant(value.cast(), pos)) } else if value.is::() { - Some(Expr::StringConstant(value.cast(), pos)) + Some(Expr::StringConstant(value.cast::().into(), pos)) } else if value.is::() { Some(if value.cast::() { Expr::True(pos)