Fix bug in constant interpolated string.

This commit is contained in:
Stephen Chung 2022-07-29 10:49:03 +08:00
parent fc976172e7
commit 1073a7bd54
4 changed files with 22 additions and 5 deletions

View File

@ -12,6 +12,7 @@ Bug fixes
* `switch` cases with conditions that evaluate to constant `()` no longer optimize to `false` (should raise a type error during runtime). * `switch` cases with conditions that evaluate to constant `()` no longer optimize to `false` (should raise a type error during runtime).
* Fixes concatenation of BLOB's and strings, where the BLOB's should be interpreted as UTF-8 encoded strings. * Fixes concatenation of BLOB's and strings, where the BLOB's should be interpreted as UTF-8 encoded strings.
* Capturing an unknown variable in a closure no longer panics. * Capturing an unknown variable in a closure no longer panics.
* Fixes panic in interpolated strings with constant expressions.
New features New features
------------ ------------

View File

@ -5,12 +5,16 @@ use crate::engine::{KEYWORD_FN_PTR, OP_EXCLUSIVE_RANGE, OP_INCLUSIVE_RANGE};
use crate::func::hashing::ALT_ZERO_HASH; use crate::func::hashing::ALT_ZERO_HASH;
use crate::tokenizer::Token; use crate::tokenizer::Token;
use crate::types::dynamic::Union; use crate::types::dynamic::Union;
use crate::{calc_fn_hash, Dynamic, FnPtr, Identifier, ImmutableString, Position, StaticVec, INT}; use crate::{
calc_fn_hash, Dynamic, FnPtr, Identifier, ImmutableString, Position, SmartString, StaticVec,
INT,
};
#[cfg(feature = "no_std")] #[cfg(feature = "no_std")]
use std::prelude::v1::*; use std::prelude::v1::*;
use std::{ use std::{
collections::BTreeMap, collections::BTreeMap,
fmt, fmt,
fmt::Write,
hash::Hash, hash::Hash,
iter::once, iter::once,
num::{NonZeroU8, NonZeroUsize}, num::{NonZeroU8, NonZeroUsize},
@ -576,6 +580,16 @@ impl Expr {
})) }))
} }
// Interpolated string
Self::InterpolatedString(x, ..) if self.is_constant() => {
let mut s = SmartString::new_const();
for segment in x.iter() {
let v = segment.get_literal_value().unwrap();
write!(&mut s, "{}", v).unwrap();
}
s.into()
}
// Fn // Fn
Self::FnCall(ref x, ..) Self::FnCall(ref x, ..)
if !x.is_qualified() && x.args.len() == 1 && x.name == KEYWORD_FN_PTR => if !x.is_qualified() && x.args.len() == 1 && x.name == KEYWORD_FN_PTR =>

View File

@ -12,7 +12,7 @@ use crate::tokenizer::{Span, Token};
use crate::types::dynamic::AccessMode; use crate::types::dynamic::AccessMode;
use crate::{ use crate::{
calc_fn_hash, calc_fn_params_hash, combine_hashes, Dynamic, Engine, FnPtr, Identifier, calc_fn_hash, calc_fn_params_hash, combine_hashes, Dynamic, Engine, FnPtr, Identifier,
Position, Scope, StaticVec, AST, INT, Position, Scope, StaticVec, AST, INT, ImmutableString,
}; };
#[cfg(feature = "no_std")] #[cfg(feature = "no_std")]
use std::prelude::v1::*; use std::prelude::v1::*;
@ -1052,10 +1052,10 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, _chaining: bool) {
state.set_dirty(); state.set_dirty();
*expr = Expr::StringConstant(state.engine.const_empty_string(), *pos); *expr = Expr::StringConstant(state.engine.const_empty_string(), *pos);
} }
// `...` // `... ${const} ...`
Expr::InterpolatedString(x, ..) if x.len() == 1 && matches!(x[0], Expr::StringConstant(..)) => { Expr::InterpolatedString(..) if expr.is_constant() => {
state.set_dirty(); state.set_dirty();
*expr = mem::take(&mut x[0]); *expr = Expr::StringConstant(expr.get_literal_value().unwrap().cast::<ImmutableString>(), expr.position());
} }
// `... ${ ... } ...` // `... ${ ... } ...`
Expr::InterpolatedString(x, ..) => { Expr::InterpolatedString(x, ..) => {

View File

@ -334,6 +334,8 @@ fn test_string_split() -> Result<(), Box<EvalAltResult>> {
fn test_string_interpolated() -> Result<(), Box<EvalAltResult>> { fn test_string_interpolated() -> Result<(), Box<EvalAltResult>> {
let engine = Engine::new(); let engine = Engine::new();
assert_eq!(engine.eval::<String>("`${}`")?, "");
assert_eq!( assert_eq!(
engine.eval::<String>( engine.eval::<String>(
" "