@@ -5,7 +5,7 @@ import { concat, unquote } from "../helpers/misc";
55import { parseNumber } from "../helpers/numbers" ;
66import { _t } from "../translation" ;
77import { CoreGetters } from "../types/core_getters" ;
8- import { BadExpressionError , UnknownFunctionError } from "../types/errors" ;
8+ import { BadExpressionError , EvaluationError , UnknownFunctionError } from "../types/errors" ;
99import { DEFAULT_LOCALE } from "../types/locale" ;
1010import {
1111 ApplyRangeChange ,
@@ -16,7 +16,13 @@ import {
1616 UID ,
1717} from "../types/misc" ;
1818import { Range , RangeStringOptions } from "../types/range" ;
19- import { FunctionCode , FunctionCodeBuilder , Scope } from "./code_builder" ;
19+ import {
20+ dangerouslyCreateJsStr ,
21+ FunctionCode ,
22+ FunctionCodeBuilder ,
23+ jsStr ,
24+ Scope ,
25+ } from "./code_builder" ;
2026import { AST , ASTFuncall , iterateAstNodes , parseTokens } from "./parser" ;
2127import { rangeTokenize } from "./range_tokenizer" ;
2228import { Token } from "./tokenizer" ;
@@ -364,6 +370,9 @@ function compileTokens(tokens: Token[]): ICompiledFormula {
364370 try {
365371 return compileTokensOrThrow ( tokens ) ;
366372 } catch ( error ) {
373+ if ( ! ( error instanceof EvaluationError ) ) {
374+ throw error ;
375+ }
367376 return {
368377 tokens,
369378 literalValues : { numbers : [ ] , strings : [ ] } ,
@@ -398,7 +407,7 @@ function compileTokensOrThrow(tokens: Token[]): ICompiledFormula {
398407 const compiledAST = compileAST ( ast ) ;
399408 const code = new FunctionCodeBuilder ( ) ;
400409 code . append ( compiledAST ) ;
401- code . append ( `return ${ compiledAST . returnExpression } ;` ) ;
410+ code . append ( jsStr `return ${ compiledAST . returnExpression } ;` ) ;
402411 const baseFunction = new Function (
403412 "deps" , // the dependencies in the current formula
404413 "ref" , // a function to access a certain dependency at a given index
@@ -455,25 +464,31 @@ function compileTokensOrThrow(tokens: Token[]): ICompiledFormula {
455464 function compileAST ( ast : AST , hasRange = false ) : FunctionCode {
456465 const code = new FunctionCodeBuilder ( scope ) ;
457466 if ( ast . debug ) {
458- code . append ( " debugger;" ) ;
459- code . append ( `ctx["debug"] = true;` ) ;
467+ code . append ( jsStr ` debugger;` ) ;
468+ code . append ( jsStr `ctx["debug"] = true;` ) ;
460469 }
461470 switch ( ast . type ) {
462471 case "BOOLEAN" :
463- return code . return ( `{ value: ${ ast . value } }` ) ;
472+ return code . return ( jsStr `{ value: ${ ast . value } }` ) ;
464473 case "NUMBER" :
465- return code . return ( `this.literalValues.numbers[${ numberCount ++ } ]` ) ;
474+ return code . return ( jsStr `this.literalValues.numbers[${ numberCount ++ } ]` ) ;
466475 case "STRING" :
467- return code . return ( `this.literalValues.strings[${ stringCount ++ } ]` ) ;
476+ return code . return ( jsStr `this.literalValues.strings[${ stringCount ++ } ]` ) ;
468477 case "REFERENCE" :
469478 return code . return (
470- `${ ast . value . includes ( ":" ) || hasRange ? `range` : `ref` } (deps[${ dependencyCount ++ } ])`
479+ jsStr `${
480+ ast . value . includes ( ":" ) || hasRange ? jsStr `range` : jsStr `ref`
481+ } (deps[${ dependencyCount ++ } ])`
471482 ) ;
472483 case "FUNCALL" :
473484 const args = compileFunctionArgs ( ast ) . map ( ( arg ) => arg . assignResultToVariable ( ) ) ;
474485 code . append ( ...args ) ;
475486 const fnName = ast . value . toUpperCase ( ) ;
476- return code . return ( `ctx['${ fnName } '](${ args . map ( ( arg ) => arg . returnExpression ) } )` ) ;
487+ if ( ! Object . hasOwn ( functions , fnName ) ) {
488+ throw new Error ( `Unknown function: "${ fnName } "` ) ;
489+ }
490+ const jsFnName = dangerouslyCreateJsStr ( fnName ) ; // validated with known functions
491+ return code . return ( jsStr `ctx['${ jsFnName } '](${ args . map ( ( arg ) => arg . returnExpression ) } )` ) ;
477492 case "ARRAY" : {
478493 // a literal array is compiled into function calls
479494 const arrayFunctionCall : ASTFuncall = {
@@ -492,26 +507,32 @@ function compileTokensOrThrow(tokens: Token[]): ICompiledFormula {
492507 return compileAST ( arrayFunctionCall ) ;
493508 }
494509 case "UNARY_OPERATION" : {
495- const fnName = UNARY_OPERATOR_MAP [ ast . value ] ;
510+ if ( ! Object . hasOwn ( UNARY_OPERATOR_MAP , ast . value ) ) {
511+ throw new Error ( `Unknown operator: "${ ast . value } "` ) ;
512+ }
513+ const fnName = dangerouslyCreateJsStr ( UNARY_OPERATOR_MAP [ ast . value ] ) ; // validated with known operators
496514 const operand = compileAST ( ast . operand , ast . value === "#" ) . assignResultToVariable ( ) ; // hasRange is true to avoid vectorization of SPILLED.RANGE
497515 code . append ( operand ) ;
498- return code . return ( `ctx['${ fnName } '](${ operand . returnExpression } )` ) ;
516+ return code . return ( jsStr `ctx['${ fnName } '](${ operand . returnExpression } )` ) ;
499517 }
500518 case "BIN_OPERATION" : {
501- const fnName = OPERATOR_MAP [ ast . value ] ;
519+ if ( ! Object . hasOwn ( OPERATOR_MAP , ast . value ) ) {
520+ throw new Error ( `Unknown operator: "${ ast . value } "` ) ;
521+ }
522+ const fnName = dangerouslyCreateJsStr ( OPERATOR_MAP [ ast . value ] ) ; // validated with known operators
502523 const left = compileAST ( ast . left , false ) . assignResultToVariable ( ) ;
503524 const right = compileAST ( ast . right , false ) . assignResultToVariable ( ) ;
504525 code . append ( left ) ;
505526 code . append ( right ) ;
506527 return code . return (
507- `ctx['${ fnName } '](${ left . returnExpression } , ${ right . returnExpression } )`
528+ jsStr `ctx['${ fnName } '](${ left . returnExpression } , ${ right . returnExpression } )`
508529 ) ;
509530 }
510531 case "SYMBOL" :
511532 const symbolIndex = symbols . indexOf ( ast . value ) ;
512- return code . return ( `getSymbolValue(this.symbols[${ symbolIndex } ], ${ hasRange } )` ) ;
533+ return code . return ( jsStr `getSymbolValue(this.symbols[${ symbolIndex } ], ${ hasRange } )` ) ;
513534 case "EMPTY" :
514- return code . return ( " undefined" ) ;
535+ return code . return ( jsStr ` undefined` ) ;
515536 }
516537 }
517538 }
0 commit comments