String Template Expression Evaluator
Implement an interpreter for a domain-specific string macro and expression language. The language supports string literals, variable bindings with lexical scoping, and four built-in string manipulation functions.
Syntax & Rules
- Whitespace: Spaces, tabs, and newlines between tokens are ignored (except inside quoted string literals).
- String Literals: Enclosed in double quotes
"...". They can contain escaped double quotes\"and escaped backslashes\\. - Keywords & Identifiers:
- Keywords:
let,in - Built-in functions:
concat,repeat,slice,reverse - Variable names: Valid identifiers containing letters, digits, and underscores, starting with a letter or underscore. Variable names cannot match keywords or built-in function names.
- Keywords:
- Expressions (
Expr):- String Literal: e.g.,
"hello" - Variable Reference: e.g.,
x. Unbound variable references evaluate to the empty string"". - Let Binding:
let <ident> = <Expr1> in <Expr2>Evaluates<Expr1>, binds the resulting string to<ident>in a new lexical scope, and evaluates<Expr2>. Inner bindings shadow outer bindings of the same variable name. - Function Calls:
concat(Expr1, Expr2, ...): Evaluates all arguments in order and concatenates their resulting strings. Accepts 0 or more comma-separated arguments.concat()returns"".repeat(Expr_str, Expr_count): EvaluatesExpr_strto string $S$, andExpr_countto string $K_{str}$. Parses $K_{str}$ as a base-10 integer $K$. Returns $S$ repeated $K$ times. If $K \le 0$ or if $K_{str}$ is not a valid integer format (an optional leading-followed by standard decimal digits), returns"".slice(Expr_str, Expr_start, Expr_end): EvaluatesExpr_strto string $S$ of length $N$,Expr_startto integer $A$, andExpr_endto integer $B$ (invalid integer strings default to $0$). Computes 0-based indexing:- If $A < 0$, $A = \max(0, N + A)$; else $A = \min(N, A)$.
- If $B < 0$, $B = \max(0, N + B)$; else $B = \min(N, B)$.
- If $A \ge B$, returns
"". - Otherwise, returns the substring from index $A$ up to index $B - 1$.
reverse(Expr_str): EvaluatesExpr_strand returns the reversed string.
- String Literal: e.g.,
Given a string expr representing a single expression, parse and evaluate it to return the output string.
[ "let x = \"hello\" in concat(x, \" \", \"world\")" ]
Explanation. Evaluates variable x to 'hello' and concatenates 'hello', ' ', and 'world'.
[ "let a = \"abc\" in let a = repeat(a, \"2\") in concat(a, \"!\", reverse(a))" ]
Explanation. Outer 'a' is 'abc'. Inner 'a' shadows outer 'a' and becomes 'abcabc'. Reverse of inner 'a' is 'cbacba'. Concatenation yields 'abcabc!cbacba'.
[ "let s = \"programming\" in slice(s, \"-7\", \"-4\")" ]
Explanation. Length of 'programming' is 11. Negative index -7 resolves to 11 - 7 = 4, and -4 resolves to 11 - 4 = 7. Substring from 4 to 7 is 'ram'.
[ "let x = \"cat\" in concat(x, y, let y = \"dog\" in concat(x, y))" ]
Explanation. In outer scope, x='cat' and y is unbound (''). The second argument evaluates to ''. The third argument evaluates let y='dog' in concat('cat', 'dog') -> 'catdog'. Result: 'cat' + '' + 'catdog' = 'catcatdog'.
[ "concat(\"prefix:\", reverse(slice(\"hello world\", \"0\", \"5\")))" ]
Explanation. slice('hello world', 0, 5) gives 'hello'. reverse('hello') gives 'olleh'. concat('prefix:', 'olleh') gives 'prefix:olleh'.
[ "let count = \"3\" in let str = \"Hi\" in concat(repeat(str, count), repeat(str, \"-1\"), repeat(str, \"invalid\"))" ]
Explanation. repeat('Hi', '3') produces 'HiHiHi'. repeat with count '-1' and invalid integer 'invalid' produce empty strings.
Follow-up: How would you modify your parser and interpreter to support lazy evaluation of variables and user-defined functions with parameters?
1 <= expr.length <= 2000. The input expression is guaranteed to be syntactically valid. Function names and keywords are case-sensitive (all lowercase). Max depth of nested expressions is at most 50.
- Views
- 4