@mojir/dvala 0.0.7 → 0.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/cli.js +1553 -1599
- package/dist/cli/reference/examples.d.ts +1 -1
- package/dist/cli/src/AutoCompleter/AutoCompleter.d.ts +4 -2
- package/dist/cli/src/{Dvala/Cache.d.ts → Cache.d.ts} +1 -1
- package/dist/cli/src/builtin/specialExpressions/functions.d.ts +1 -1
- package/dist/cli/src/createDvala.d.ts +47 -0
- package/dist/cli/src/evaluator/ContextStack.d.ts +10 -2
- package/dist/cli/src/evaluator/effectTypes.d.ts +5 -5
- package/dist/cli/src/evaluator/trampoline.d.ts +10 -1
- package/dist/cli/src/parser/subParsers/parseDo.d.ts +1 -1
- package/dist/cli/src/tokenizer/token.d.ts +2 -4
- package/dist/cli/src/tokenizer/tokenize.d.ts +1 -2
- package/dist/cli/src/tokenizer/tokenizers.d.ts +2 -3
- package/dist/cli/src/tooling.d.ts +51 -0
- package/dist/debug.esm.js +1 -1
- package/dist/debug.esm.js.map +1 -1
- package/dist/debug.js +1 -1
- package/dist/debug.js.map +1 -1
- package/dist/dvala.iife.js +1 -1
- package/dist/dvala.iife.js.map +1 -1
- package/dist/full.esm.js +1 -1
- package/dist/full.esm.js.map +1 -1
- package/dist/full.js +1 -1
- package/dist/full.js.map +1 -1
- package/dist/index.esm.js +1 -1
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp-server/common/utils.d.ts +2 -0
- package/dist/mcp-server/mcp-server/src/server.d.ts +1 -0
- package/dist/mcp-server/reference/api.d.ts +73 -0
- package/dist/mcp-server/reference/datatype.d.ts +3 -0
- package/dist/mcp-server/reference/examples.d.ts +11 -0
- package/dist/mcp-server/reference/index.d.ts +195 -0
- package/dist/mcp-server/reference/shorthand.d.ts +3 -0
- package/dist/mcp-server/server.js +36330 -0
- package/dist/mcp-server/src/AutoCompleter/AutoCompleter.d.ts +27 -0
- package/dist/{src/Dvala → mcp-server/src}/Cache.d.ts +1 -1
- package/dist/mcp-server/src/allModules.d.ts +2 -0
- package/dist/mcp-server/src/builtin/bindingNode.d.ts +11 -0
- package/dist/mcp-server/src/builtin/core/array.d.ts +2 -0
- package/dist/mcp-server/src/builtin/core/assertion.d.ts +2 -0
- package/dist/mcp-server/src/builtin/core/bitwise.d.ts +2 -0
- package/dist/mcp-server/src/builtin/core/collection.d.ts +2 -0
- package/dist/mcp-server/src/builtin/core/functional.d.ts +2 -0
- package/dist/mcp-server/src/builtin/core/math.d.ts +2 -0
- package/dist/mcp-server/src/builtin/core/meta.d.ts +3 -0
- package/dist/mcp-server/src/builtin/core/misc.d.ts +2 -0
- package/dist/mcp-server/src/builtin/core/object.d.ts +2 -0
- package/dist/mcp-server/src/builtin/core/predicates.d.ts +2 -0
- package/dist/mcp-server/src/builtin/core/regexp.d.ts +2 -0
- package/dist/mcp-server/src/builtin/core/sequence.d.ts +2 -0
- package/dist/mcp-server/src/builtin/core/string.d.ts +2 -0
- package/dist/mcp-server/src/builtin/core/vector.d.ts +2 -0
- package/dist/mcp-server/src/builtin/index.d.ts +13 -0
- package/dist/mcp-server/src/builtin/interface.d.ts +113 -0
- package/dist/mcp-server/src/builtin/modules/assertion/docs.d.ts +2 -0
- package/dist/mcp-server/src/builtin/modules/assertion/index.d.ts +2 -0
- package/dist/mcp-server/src/builtin/modules/bitwise/index.d.ts +2 -0
- package/dist/mcp-server/src/builtin/modules/collection/index.d.ts +2 -0
- package/dist/mcp-server/src/builtin/modules/convert/index.d.ts +2 -0
- package/dist/mcp-server/src/builtin/modules/functional/index.d.ts +2 -0
- package/dist/mcp-server/src/builtin/modules/grid/docs.d.ts +2 -0
- package/dist/mcp-server/src/builtin/modules/grid/fromArray.d.ts +8 -0
- package/dist/mcp-server/src/builtin/modules/grid/index.d.ts +2 -0
- package/dist/mcp-server/src/builtin/modules/grid/transpose.d.ts +2 -0
- package/dist/mcp-server/src/builtin/modules/interface.d.ts +28 -0
- package/dist/mcp-server/src/builtin/modules/linear-algebra/docs.d.ts +2 -0
- package/dist/mcp-server/src/builtin/modules/linear-algebra/helpers/calcFractionalRanks.d.ts +1 -0
- package/dist/mcp-server/src/builtin/modules/linear-algebra/helpers/collinear.d.ts +2 -0
- package/dist/mcp-server/src/builtin/modules/linear-algebra/helpers/corrleation.d.ts +8 -0
- package/dist/mcp-server/src/builtin/modules/linear-algebra/helpers/covariance.d.ts +4 -0
- package/dist/mcp-server/src/builtin/modules/linear-algebra/helpers/dot.d.ts +1 -0
- package/dist/mcp-server/src/builtin/modules/linear-algebra/helpers/gaussJordanElimination.d.ts +7 -0
- package/dist/mcp-server/src/builtin/modules/linear-algebra/helpers/getUnit.d.ts +2 -0
- package/dist/mcp-server/src/builtin/modules/linear-algebra/helpers/isZeroVector.d.ts +1 -0
- package/dist/mcp-server/src/builtin/modules/linear-algebra/helpers/kendallTau.d.ts +10 -0
- package/dist/mcp-server/src/builtin/modules/linear-algebra/helpers/length.d.ts +1 -0
- package/dist/mcp-server/src/builtin/modules/linear-algebra/helpers/pearsonCorr.d.ts +1 -0
- package/dist/mcp-server/src/builtin/modules/linear-algebra/helpers/scale.d.ts +1 -0
- package/dist/mcp-server/src/builtin/modules/linear-algebra/helpers/solve.d.ts +8 -0
- package/dist/mcp-server/src/builtin/modules/linear-algebra/helpers/subtract.d.ts +1 -0
- package/dist/mcp-server/src/builtin/modules/linear-algebra/index.d.ts +4 -0
- package/dist/mcp-server/src/builtin/modules/math/index.d.ts +2 -0
- package/dist/mcp-server/src/builtin/modules/matrix/docs.d.ts +2 -0
- package/dist/mcp-server/src/builtin/modules/matrix/helpers/adjugate.d.ts +1 -0
- package/dist/mcp-server/src/builtin/modules/matrix/helpers/band.d.ts +9 -0
- package/dist/mcp-server/src/builtin/modules/matrix/helpers/cofactor.d.ts +1 -0
- package/dist/mcp-server/src/builtin/modules/matrix/helpers/determinant.d.ts +6 -0
- package/dist/mcp-server/src/builtin/modules/matrix/helpers/inverse.d.ts +6 -0
- package/dist/mcp-server/src/builtin/modules/matrix/helpers/isBanded.d.ts +11 -0
- package/dist/mcp-server/src/builtin/modules/matrix/helpers/isDiagonal.d.ts +10 -0
- package/dist/mcp-server/src/builtin/modules/matrix/helpers/isIdentity.d.ts +1 -0
- package/dist/mcp-server/src/builtin/modules/matrix/helpers/isOrthogonal.d.ts +1 -0
- package/dist/mcp-server/src/builtin/modules/matrix/helpers/isSquare.d.ts +1 -0
- package/dist/mcp-server/src/builtin/modules/matrix/helpers/isSymetric.d.ts +8 -0
- package/dist/mcp-server/src/builtin/modules/matrix/helpers/isTriangular.d.ts +13 -0
- package/dist/mcp-server/src/builtin/modules/matrix/helpers/matrixMultiply.d.ts +7 -0
- package/dist/mcp-server/src/builtin/modules/matrix/helpers/minor.d.ts +1 -0
- package/dist/mcp-server/src/builtin/modules/matrix/helpers/norm1.d.ts +1 -0
- package/dist/mcp-server/src/builtin/modules/matrix/helpers/trace.d.ts +8 -0
- package/dist/mcp-server/src/builtin/modules/matrix/index.d.ts +4 -0
- package/dist/mcp-server/src/builtin/modules/number-theory/binomialCefficient.d.ts +1 -0
- package/dist/mcp-server/src/builtin/modules/number-theory/combinations.d.ts +2 -0
- package/dist/mcp-server/src/builtin/modules/number-theory/derangements.d.ts +2 -0
- package/dist/mcp-server/src/builtin/modules/number-theory/divisors.d.ts +4 -0
- package/dist/mcp-server/src/builtin/modules/number-theory/docs.d.ts +2 -0
- package/dist/mcp-server/src/builtin/modules/number-theory/factorial.d.ts +3 -0
- package/dist/mcp-server/src/builtin/modules/number-theory/index.d.ts +4 -0
- package/dist/mcp-server/src/builtin/modules/number-theory/partitions.d.ts +2 -0
- package/dist/mcp-server/src/builtin/modules/number-theory/permutations.d.ts +2 -0
- package/dist/mcp-server/src/builtin/modules/number-theory/powerSet.d.ts +2 -0
- package/dist/mcp-server/src/builtin/modules/number-theory/primeFactors.d.ts +11 -0
- package/dist/mcp-server/src/builtin/modules/number-theory/sequences/abundant.d.ts +2 -0
- package/dist/mcp-server/src/builtin/modules/number-theory/sequences/arithmetic.d.ts +2 -0
- package/dist/mcp-server/src/builtin/modules/number-theory/sequences/bell.d.ts +1 -0
- package/dist/mcp-server/src/builtin/modules/number-theory/sequences/bernoulli.d.ts +2 -0
- package/dist/mcp-server/src/builtin/modules/number-theory/sequences/catalan.d.ts +1 -0
- package/dist/mcp-server/src/builtin/modules/number-theory/sequences/collatz.d.ts +2 -0
- package/dist/mcp-server/src/builtin/modules/number-theory/sequences/composite.d.ts +3 -0
- package/dist/mcp-server/src/builtin/modules/number-theory/sequences/deficient.d.ts +2 -0
- package/dist/mcp-server/src/builtin/modules/number-theory/sequences/factorial.d.ts +1 -0
- package/dist/mcp-server/src/builtin/modules/number-theory/sequences/fibonacci.d.ts +1 -0
- package/dist/mcp-server/src/builtin/modules/number-theory/sequences/geometric.d.ts +2 -0
- package/dist/mcp-server/src/builtin/modules/number-theory/sequences/golomb.d.ts +2 -0
- package/dist/mcp-server/src/builtin/modules/number-theory/sequences/happy.d.ts +2 -0
- package/dist/mcp-server/src/builtin/modules/number-theory/sequences/index.d.ts +27 -0
- package/dist/mcp-server/src/builtin/modules/number-theory/sequences/juggler.d.ts +2 -0
- package/dist/mcp-server/src/builtin/modules/number-theory/sequences/lookAndSay.d.ts +2 -0
- package/dist/mcp-server/src/builtin/modules/number-theory/sequences/lucas.d.ts +1 -0
- package/dist/mcp-server/src/builtin/modules/number-theory/sequences/lucky.d.ts +2 -0
- package/dist/mcp-server/src/builtin/modules/number-theory/sequences/mersenne.d.ts +1 -0
- package/dist/mcp-server/src/builtin/modules/number-theory/sequences/padovan.d.ts +2 -0
- package/dist/mcp-server/src/builtin/modules/number-theory/sequences/partition.d.ts +1 -0
- package/dist/mcp-server/src/builtin/modules/number-theory/sequences/pell.d.ts +1 -0
- package/dist/mcp-server/src/builtin/modules/number-theory/sequences/perfect.d.ts +1 -0
- package/dist/mcp-server/src/builtin/modules/number-theory/sequences/perfectCube.d.ts +2 -0
- package/dist/mcp-server/src/builtin/modules/number-theory/sequences/perfectPower.d.ts +10 -0
- package/dist/mcp-server/src/builtin/modules/number-theory/sequences/perfectSquare.d.ts +2 -0
- package/dist/mcp-server/src/builtin/modules/number-theory/sequences/poligonal.d.ts +2 -0
- package/dist/mcp-server/src/builtin/modules/number-theory/sequences/prime.d.ts +3 -0
- package/dist/mcp-server/src/builtin/modules/number-theory/sequences/recaman.d.ts +9 -0
- package/dist/mcp-server/src/builtin/modules/number-theory/sequences/sylvester.d.ts +1 -0
- package/dist/mcp-server/src/builtin/modules/number-theory/sequences/thueMorse.d.ts +2 -0
- package/dist/mcp-server/src/builtin/modules/number-theory/sequences/tribonacci.d.ts +1 -0
- package/dist/mcp-server/src/builtin/modules/sequence/index.d.ts +2 -0
- package/dist/mcp-server/src/builtin/modules/string/index.d.ts +2 -0
- package/dist/mcp-server/src/builtin/modules/vector/bincount.d.ts +9 -0
- package/dist/mcp-server/src/builtin/modules/vector/calcMad.d.ts +1 -0
- package/dist/mcp-server/src/builtin/modules/vector/calcMean.d.ts +1 -0
- package/dist/mcp-server/src/builtin/modules/vector/calcMedad.d.ts +1 -0
- package/dist/mcp-server/src/builtin/modules/vector/calcMedian.d.ts +1 -0
- package/dist/mcp-server/src/builtin/modules/vector/calcStdDev.d.ts +2 -0
- package/dist/mcp-server/src/builtin/modules/vector/calcVariance.d.ts +2 -0
- package/dist/mcp-server/src/builtin/modules/vector/docs.d.ts +2 -0
- package/dist/mcp-server/src/builtin/modules/vector/entropy.d.ts +8 -0
- package/dist/mcp-server/src/builtin/modules/vector/histogram.d.ts +9 -0
- package/dist/mcp-server/src/builtin/modules/vector/index.d.ts +2 -0
- package/dist/mcp-server/src/builtin/modules/vector/mode.d.ts +6 -0
- package/dist/mcp-server/src/builtin/modules/vector/outliers.d.ts +7 -0
- package/dist/mcp-server/src/builtin/modules/vector/percentile.d.ts +7 -0
- package/dist/mcp-server/src/builtin/modules/vector/quartiles.d.ts +1 -0
- package/dist/mcp-server/src/builtin/modules/vector/reductionFunctions/entropy.d.ts +2 -0
- package/dist/mcp-server/src/builtin/modules/vector/reductionFunctions/giniCoefficient.d.ts +2 -0
- package/dist/mcp-server/src/builtin/modules/vector/reductionFunctions/index.d.ts +13 -0
- package/dist/mcp-server/src/builtin/modules/vector/reductionFunctions/iqr.d.ts +2 -0
- package/dist/mcp-server/src/builtin/modules/vector/reductionFunctions/kurtosis.d.ts +5 -0
- package/dist/mcp-server/src/builtin/modules/vector/reductionFunctions/mad.d.ts +2 -0
- package/dist/mcp-server/src/builtin/modules/vector/reductionFunctions/mean.d.ts +4 -0
- package/dist/mcp-server/src/builtin/modules/vector/reductionFunctions/medad.d.ts +2 -0
- package/dist/mcp-server/src/builtin/modules/vector/reductionFunctions/median.d.ts +2 -0
- package/dist/mcp-server/src/builtin/modules/vector/reductionFunctions/prod.d.ts +2 -0
- package/dist/mcp-server/src/builtin/modules/vector/reductionFunctions/rms.d.ts +2 -0
- package/dist/mcp-server/src/builtin/modules/vector/reductionFunctions/skewness.d.ts +3 -0
- package/dist/mcp-server/src/builtin/modules/vector/reductionFunctions/span.d.ts +2 -0
- package/dist/mcp-server/src/builtin/modules/vector/reductionFunctions/standardDeviation.d.ts +3 -0
- package/dist/mcp-server/src/builtin/modules/vector/reductionFunctions/sum.d.ts +2 -0
- package/dist/mcp-server/src/builtin/modules/vector/reductionFunctions/variance.d.ts +3 -0
- package/dist/mcp-server/src/builtin/normalExpressions/index.d.ts +9 -0
- package/dist/mcp-server/src/builtin/normalExpressions/initCoreDvala.d.ts +1 -0
- package/dist/mcp-server/src/builtin/specialExpressionTypes.d.ts +24 -0
- package/dist/mcp-server/src/builtin/specialExpressions/and.d.ts +6 -0
- package/dist/mcp-server/src/builtin/specialExpressions/array.d.ts +6 -0
- package/dist/mcp-server/src/builtin/specialExpressions/block.d.ts +7 -0
- package/dist/mcp-server/src/builtin/specialExpressions/cond.d.ts +6 -0
- package/dist/mcp-server/src/builtin/specialExpressions/defined.d.ts +5 -0
- package/dist/mcp-server/src/builtin/specialExpressions/effect.d.ts +5 -0
- package/dist/mcp-server/src/builtin/specialExpressions/functions.d.ts +6 -0
- package/dist/mcp-server/src/builtin/specialExpressions/if.d.ts +6 -0
- package/dist/mcp-server/src/builtin/specialExpressions/import.d.ts +6 -0
- package/dist/mcp-server/src/builtin/specialExpressions/let.d.ts +6 -0
- package/dist/mcp-server/src/builtin/specialExpressions/loop.d.ts +6 -0
- package/dist/mcp-server/src/builtin/specialExpressions/loops.d.ts +9 -0
- package/dist/mcp-server/src/builtin/specialExpressions/match.d.ts +7 -0
- package/dist/mcp-server/src/builtin/specialExpressions/object.d.ts +6 -0
- package/dist/mcp-server/src/builtin/specialExpressions/or.d.ts +6 -0
- package/dist/mcp-server/src/builtin/specialExpressions/parallel.d.ts +6 -0
- package/dist/mcp-server/src/builtin/specialExpressions/perform.d.ts +6 -0
- package/dist/mcp-server/src/builtin/specialExpressions/qq.d.ts +6 -0
- package/dist/mcp-server/src/builtin/specialExpressions/race.d.ts +6 -0
- package/dist/mcp-server/src/builtin/specialExpressions/recur.d.ts +5 -0
- package/dist/mcp-server/src/builtin/specialExpressions/unless.d.ts +6 -0
- package/dist/mcp-server/src/builtin/utils.d.ts +6 -0
- package/dist/mcp-server/src/bundler/interface.d.ts +15 -0
- package/dist/mcp-server/src/constants/constants.d.ts +19 -0
- package/dist/mcp-server/src/createDvala.d.ts +47 -0
- package/dist/mcp-server/src/errors.d.ts +24 -0
- package/dist/mcp-server/src/evaluator/ContextStack.d.ts +70 -0
- package/dist/mcp-server/src/evaluator/contentHash.d.ts +21 -0
- package/dist/mcp-server/src/evaluator/dedupSubTrees.d.ts +37 -0
- package/dist/mcp-server/src/evaluator/effectRef.d.ts +27 -0
- package/dist/mcp-server/src/evaluator/effectTypes.d.ts +181 -0
- package/dist/mcp-server/src/evaluator/frames.d.ts +513 -0
- package/dist/mcp-server/src/evaluator/interface.d.ts +14 -0
- package/dist/mcp-server/src/evaluator/standardEffects.d.ts +50 -0
- package/dist/mcp-server/src/evaluator/step.d.ts +175 -0
- package/dist/mcp-server/src/evaluator/suspension.d.ts +86 -0
- package/dist/mcp-server/src/evaluator/trampoline.d.ts +133 -0
- package/dist/mcp-server/src/getUndefinedSymbols/index.d.ts +7 -0
- package/dist/mcp-server/src/initReferenceData.d.ts +1 -0
- package/dist/mcp-server/src/interface.d.ts +7 -0
- package/dist/mcp-server/src/parser/ParserContext.d.ts +20 -0
- package/dist/mcp-server/src/parser/getPrecedence.d.ts +3 -0
- package/dist/mcp-server/src/parser/helpers.d.ts +19 -0
- package/dist/mcp-server/src/parser/index.d.ts +5 -0
- package/dist/mcp-server/src/parser/subParsers/parseArray.d.ts +3 -0
- package/dist/mcp-server/src/parser/subParsers/parseBindingTarget.d.ts +8 -0
- package/dist/mcp-server/src/parser/subParsers/parseCond.d.ts +4 -0
- package/dist/mcp-server/src/parser/subParsers/parseDo.d.ts +3 -0
- package/dist/mcp-server/src/parser/subParsers/parseExpression.d.ts +5 -0
- package/dist/mcp-server/src/parser/subParsers/parseForOrDoseq.d.ts +4 -0
- package/dist/mcp-server/src/parser/subParsers/parseFunction.d.ts +4 -0
- package/dist/mcp-server/src/parser/subParsers/parseFunctionCall.d.ts +3 -0
- package/dist/mcp-server/src/parser/subParsers/parseIfOrUnless.d.ts +5 -0
- package/dist/mcp-server/src/parser/subParsers/parseImplicitBlock.d.ts +5 -0
- package/dist/mcp-server/src/parser/subParsers/parseLet.d.ts +4 -0
- package/dist/mcp-server/src/parser/subParsers/parseLoop.d.ts +4 -0
- package/dist/mcp-server/src/parser/subParsers/parseMatch.d.ts +4 -0
- package/dist/mcp-server/src/parser/subParsers/parseNumber.d.ts +3 -0
- package/dist/mcp-server/src/parser/subParsers/parseObject.d.ts +3 -0
- package/dist/mcp-server/src/parser/subParsers/parseOperand.d.ts +3 -0
- package/dist/mcp-server/src/parser/subParsers/parseRegexpShorthand.d.ts +3 -0
- package/dist/mcp-server/src/parser/subParsers/parseReservedSymbol.d.ts +3 -0
- package/dist/mcp-server/src/parser/subParsers/parseString.d.ts +4 -0
- package/dist/mcp-server/src/parser/subParsers/parseSymbol.d.ts +3 -0
- package/dist/mcp-server/src/parser/types.d.ts +128 -0
- package/dist/mcp-server/src/tokenizer/minifyTokenStream.d.ts +4 -0
- package/dist/mcp-server/src/tokenizer/operators.d.ts +12 -0
- package/dist/mcp-server/src/tokenizer/reservedNames.d.ts +65 -0
- package/dist/mcp-server/src/tokenizer/token.d.ts +82 -0
- package/dist/mcp-server/src/tokenizer/tokenize.d.ts +7 -0
- package/dist/mcp-server/src/tokenizer/tokenizers.d.ts +13 -0
- package/dist/mcp-server/src/tooling.d.ts +51 -0
- package/dist/mcp-server/src/transformer/index.d.ts +2 -0
- package/dist/mcp-server/src/typeGuards/annotatedCollections.d.ts +16 -0
- package/dist/mcp-server/src/typeGuards/array.d.ts +9 -0
- package/dist/mcp-server/src/typeGuards/astNode.d.ts +19 -0
- package/dist/mcp-server/src/typeGuards/dvala.d.ts +26 -0
- package/dist/mcp-server/src/typeGuards/dvalaFunction.d.ts +9 -0
- package/dist/mcp-server/src/typeGuards/index.d.ts +7 -0
- package/dist/mcp-server/src/typeGuards/number.d.ts +66 -0
- package/dist/mcp-server/src/typeGuards/string.d.ts +15 -0
- package/dist/mcp-server/src/untokenizer/index.d.ts +2 -0
- package/dist/mcp-server/src/utils/arity.d.ts +10 -0
- package/dist/mcp-server/src/utils/debug/debugTools.d.ts +1 -0
- package/dist/mcp-server/src/utils/debug/getCodeMarker.d.ts +2 -0
- package/dist/mcp-server/src/utils/debug/getSourceCodeInfo.d.ts +2 -0
- package/dist/mcp-server/src/utils/docString/generateDocString.d.ts +4 -0
- package/dist/mcp-server/src/utils/getAssertionError.d.ts +3 -0
- package/dist/mcp-server/src/utils/index.d.ts +14 -0
- package/dist/mcp-server/src/utils/maybePromise.d.ts +54 -0
- package/dist/mcp-server/src/utils/symbols.d.ts +3 -0
- package/dist/modules/grid.esm.js +1 -1
- package/dist/modules/grid.esm.js.map +1 -1
- package/dist/modules/grid.js +1 -1
- package/dist/modules/grid.js.map +1 -1
- package/dist/modules/reference/index.d.ts +136 -136
- package/dist/modules/src/AutoCompleter/AutoCompleter.d.ts +4 -2
- package/dist/modules/src/{Dvala/Cache.d.ts → Cache.d.ts} +1 -1
- package/dist/modules/src/builtin/specialExpressions/functions.d.ts +1 -1
- package/dist/modules/src/createDvala.d.ts +47 -0
- package/dist/modules/src/evaluator/ContextStack.d.ts +10 -2
- package/dist/modules/src/evaluator/effectTypes.d.ts +5 -5
- package/dist/modules/src/evaluator/trampoline.d.ts +10 -1
- package/dist/modules/src/index.d.ts +8 -5
- package/dist/modules/src/parser/subParsers/parseDo.d.ts +1 -1
- package/dist/modules/src/resume.d.ts +41 -0
- package/dist/modules/src/tokenizer/token.d.ts +2 -4
- package/dist/modules/src/tokenizer/tokenize.d.ts +1 -2
- package/dist/modules/src/tokenizer/tokenizers.d.ts +2 -3
- package/dist/modules/src/tooling.d.ts +51 -0
- package/dist/reference/index.d.ts +136 -136
- package/dist/src/AutoCompleter/AutoCompleter.d.ts +4 -2
- package/dist/src/Cache.d.ts +16 -0
- package/dist/src/builtin/specialExpressions/functions.d.ts +1 -1
- package/dist/src/createDvala.d.ts +47 -0
- package/dist/src/evaluator/ContextStack.d.ts +10 -2
- package/dist/src/evaluator/effectTypes.d.ts +5 -5
- package/dist/src/evaluator/trampoline.d.ts +10 -1
- package/dist/src/index.d.ts +8 -5
- package/dist/src/parser/subParsers/parseDo.d.ts +1 -1
- package/dist/src/resume.d.ts +41 -0
- package/dist/src/tokenizer/token.d.ts +2 -4
- package/dist/src/tokenizer/tokenize.d.ts +1 -2
- package/dist/src/tokenizer/tokenizers.d.ts +2 -3
- package/dist/src/tooling.d.ts +51 -0
- package/dist/testFramework.esm.js +1 -1
- package/dist/testFramework.esm.js.map +1 -1
- package/dist/testFramework.js +1 -1
- package/dist/testFramework.js.map +1 -1
- package/package.json +17 -6
- package/dist/cli/src/Dvala/Dvala.d.ts +0 -63
- package/dist/modules/src/Dvala/Dvala.d.ts +0 -63
- package/dist/modules/src/effects.d.ts +0 -110
- package/dist/src/Dvala/Dvala.d.ts +0 -63
- package/dist/src/effects.d.ts +0 -110
package/dist/cli/cli.js
CHANGED
|
@@ -7,7 +7,7 @@ var readline = require('node:readline');
|
|
|
7
7
|
var os = require('node:os');
|
|
8
8
|
var process$1 = require('node:process');
|
|
9
9
|
|
|
10
|
-
var version = "0.0.
|
|
10
|
+
var version = "0.0.9";
|
|
11
11
|
|
|
12
12
|
function getCodeMarker(sourceCodeInfo) {
|
|
13
13
|
if (!sourceCodeInfo.position || !sourceCodeInfo.code)
|
|
@@ -82,31 +82,6 @@ class UndefinedSymbolError extends DvalaError {
|
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
const specialExpressionTypes = {
|
|
86
|
-
'??': 0,
|
|
87
|
-
'&&': 1,
|
|
88
|
-
'||': 2,
|
|
89
|
-
'array': 3,
|
|
90
|
-
'cond': 4,
|
|
91
|
-
'defined?': 5,
|
|
92
|
-
'block': 6,
|
|
93
|
-
'doseq': 7,
|
|
94
|
-
'0_lambda': 8,
|
|
95
|
-
'for': 9,
|
|
96
|
-
'if': 10,
|
|
97
|
-
'let': 11,
|
|
98
|
-
'loop': 12,
|
|
99
|
-
'object': 13,
|
|
100
|
-
'recur': 14,
|
|
101
|
-
'match': 15,
|
|
102
|
-
'unless': 16,
|
|
103
|
-
'import': 17,
|
|
104
|
-
'effect': 18,
|
|
105
|
-
'perform': 19,
|
|
106
|
-
'parallel': 20,
|
|
107
|
-
'race': 21,
|
|
108
|
-
};
|
|
109
|
-
|
|
110
85
|
const NodeTypes = {
|
|
111
86
|
Number: 1,
|
|
112
87
|
String: 2,
|
|
@@ -185,109 +160,6 @@ function getAssertionError(typeName, value, sourceCodeInfo) {
|
|
|
185
160
|
return new DvalaError(`Expected ${typeName}, got ${valueToString(value)}.`, getSourceCodeInfo(value, sourceCodeInfo));
|
|
186
161
|
}
|
|
187
162
|
|
|
188
|
-
function isSymbolNode(node) {
|
|
189
|
-
const nodeType = node[0];
|
|
190
|
-
return NodeTypes.UserDefinedSymbol === nodeType
|
|
191
|
-
|| NodeTypes.NormalBuiltinSymbol === nodeType
|
|
192
|
-
|| NodeTypes.SpecialBuiltinSymbol === nodeType;
|
|
193
|
-
}
|
|
194
|
-
function isUserDefinedSymbolNode(node) {
|
|
195
|
-
return NodeTypes.UserDefinedSymbol === node[0];
|
|
196
|
-
}
|
|
197
|
-
function asUserDefinedSymbolNode(node, sourceCodeInfo) {
|
|
198
|
-
assertUserDefinedSymbolNode(node, sourceCodeInfo);
|
|
199
|
-
return node;
|
|
200
|
-
}
|
|
201
|
-
function assertUserDefinedSymbolNode(node, sourceCodeInfo) {
|
|
202
|
-
if (!isUserDefinedSymbolNode(node))
|
|
203
|
-
throw getAssertionError('UserDefinedSymbolNode', node, sourceCodeInfo);
|
|
204
|
-
}
|
|
205
|
-
function isNormalBuiltinSymbolNode(node) {
|
|
206
|
-
return NodeTypes.NormalBuiltinSymbol === node[0];
|
|
207
|
-
}
|
|
208
|
-
function isSpecialBuiltinSymbolNode(node) {
|
|
209
|
-
return NodeTypes.SpecialBuiltinSymbol === node[0];
|
|
210
|
-
}
|
|
211
|
-
function isNormalExpressionNode(node) {
|
|
212
|
-
return node[0] === NodeTypes.NormalExpression;
|
|
213
|
-
}
|
|
214
|
-
function isNormalExpressionNodeWithName(node) {
|
|
215
|
-
if (!isNormalExpressionNode(node)) {
|
|
216
|
-
return false;
|
|
217
|
-
}
|
|
218
|
-
return isSymbolNode(node[1][0]);
|
|
219
|
-
}
|
|
220
|
-
function isSpreadNode(node) {
|
|
221
|
-
return node[0] === NodeTypes.Spread;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
const getUndefinedSymbols = (ast, contextStack, builtin, evaluateNode) => {
|
|
225
|
-
const nodes = Array.isArray(ast)
|
|
226
|
-
? ast
|
|
227
|
-
: [[NodeTypes.SpecialExpression, [specialExpressionTypes.block, ast.body, undefined]]];
|
|
228
|
-
const unresolvedSymbols = new Set();
|
|
229
|
-
for (const subNode of nodes) {
|
|
230
|
-
findUnresolvedSymbolsInNode(subNode, contextStack, builtin, evaluateNode)
|
|
231
|
-
?.forEach(symbol => unresolvedSymbols.add(symbol));
|
|
232
|
-
}
|
|
233
|
-
return unresolvedSymbols;
|
|
234
|
-
};
|
|
235
|
-
function findUnresolvedSymbolsInNode(node, contextStack, builtin, evaluateNode) {
|
|
236
|
-
const nodeType = node[0];
|
|
237
|
-
switch (nodeType) {
|
|
238
|
-
case NodeTypes.UserDefinedSymbol: {
|
|
239
|
-
const symbolNode = node;
|
|
240
|
-
const lookUpResult = contextStack.lookUp(symbolNode);
|
|
241
|
-
if (lookUpResult === null)
|
|
242
|
-
return new Set([symbolNode[1]]);
|
|
243
|
-
return null;
|
|
244
|
-
}
|
|
245
|
-
case NodeTypes.NormalBuiltinSymbol:
|
|
246
|
-
case NodeTypes.SpecialBuiltinSymbol:
|
|
247
|
-
case NodeTypes.String:
|
|
248
|
-
case NodeTypes.Number:
|
|
249
|
-
case NodeTypes.ReservedSymbol:
|
|
250
|
-
case NodeTypes.Binding:
|
|
251
|
-
return null;
|
|
252
|
-
case NodeTypes.NormalExpression: {
|
|
253
|
-
const normalExpressionNode = node;
|
|
254
|
-
const unresolvedSymbols = new Set();
|
|
255
|
-
if (isNormalExpressionNodeWithName(normalExpressionNode)) {
|
|
256
|
-
const [, [symbolNode]] = normalExpressionNode;
|
|
257
|
-
if (isUserDefinedSymbolNode(symbolNode)) {
|
|
258
|
-
const lookUpResult = contextStack.lookUp(symbolNode);
|
|
259
|
-
if (lookUpResult === null)
|
|
260
|
-
unresolvedSymbols.add(symbolNode[1]);
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
else {
|
|
264
|
-
const [, [expressionNode]] = normalExpressionNode;
|
|
265
|
-
findUnresolvedSymbolsInNode(expressionNode, contextStack, builtin, evaluateNode)?.forEach(symbol => unresolvedSymbols.add(symbol));
|
|
266
|
-
}
|
|
267
|
-
for (const subNode of normalExpressionNode[1][1]) {
|
|
268
|
-
findUnresolvedSymbolsInNode(subNode, contextStack, builtin, evaluateNode)?.forEach(symbol => unresolvedSymbols.add(symbol));
|
|
269
|
-
}
|
|
270
|
-
return unresolvedSymbols;
|
|
271
|
-
}
|
|
272
|
-
case NodeTypes.SpecialExpression: {
|
|
273
|
-
const specialExpressionNode = node;
|
|
274
|
-
const specialExpressionType = specialExpressionNode[1][0];
|
|
275
|
-
const specialExpression = builtin.specialExpressions[specialExpressionType];
|
|
276
|
-
const castedGetUndefinedSymbols = specialExpression.getUndefinedSymbols;
|
|
277
|
-
return castedGetUndefinedSymbols(specialExpressionNode, contextStack, {
|
|
278
|
-
getUndefinedSymbols,
|
|
279
|
-
builtin,
|
|
280
|
-
evaluateNode,
|
|
281
|
-
});
|
|
282
|
-
}
|
|
283
|
-
case NodeTypes.Spread:
|
|
284
|
-
return findUnresolvedSymbolsInNode(node[1], contextStack, builtin, evaluateNode);
|
|
285
|
-
/* v8 ignore next 2 */
|
|
286
|
-
default:
|
|
287
|
-
throw new DvalaError(`Unhandled node type: ${nodeType}`, node[2]);
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
|
|
291
163
|
function isNonUndefined(value) {
|
|
292
164
|
return value !== undefined;
|
|
293
165
|
}
|
|
@@ -4875,7 +4747,7 @@ function argStrings(reference) {
|
|
|
4875
4747
|
|
|
4876
4748
|
function getMetaNormalExpression(normalExpressionReference, effectReference) {
|
|
4877
4749
|
return {
|
|
4878
|
-
doc: {
|
|
4750
|
+
'doc': {
|
|
4879
4751
|
evaluate: ([value], sourceCodeInfo) => {
|
|
4880
4752
|
assertNonUndefined(normalExpressionReference);
|
|
4881
4753
|
// Handle effects
|
|
@@ -4905,28 +4777,45 @@ function getMetaNormalExpression(normalExpressionReference, effectReference) {
|
|
|
4905
4777
|
args: { value: { type: ['function', 'effect'] } },
|
|
4906
4778
|
variants: [{ argumentNames: ['value'] }],
|
|
4907
4779
|
description: 'Returns documentation string of the $value. Works on functions and effects.',
|
|
4908
|
-
seeAlso: ['arity'],
|
|
4780
|
+
seeAlso: ['arity', 'with-doc'],
|
|
4909
4781
|
examples: [
|
|
4910
4782
|
'doc(+)',
|
|
4911
4783
|
'doc(effect(dvala.io.println))',
|
|
4912
|
-
|
|
4913
|
-
|
|
4914
|
-
|
|
4915
|
-
|
|
4916
|
-
|
|
4917
|
-
|
|
4918
|
-
|
|
4919
|
-
|
|
4920
|
-
|
|
4921
|
-
|
|
4922
|
-
|
|
4923
|
-
|
|
4924
|
-
|
|
4925
|
-
|
|
4784
|
+
'let add = (x, y) -> x + y with-doc "Adds two numbers.";\ndoc(add)',
|
|
4785
|
+
],
|
|
4786
|
+
},
|
|
4787
|
+
},
|
|
4788
|
+
'with-doc': {
|
|
4789
|
+
evaluate: ([fn, docString], sourceCodeInfo) => {
|
|
4790
|
+
assertFunctionLike(fn, sourceCodeInfo);
|
|
4791
|
+
assertString(docString, sourceCodeInfo);
|
|
4792
|
+
if (!isDvalaFunction(fn) || fn.functionType !== 'UserDefined') {
|
|
4793
|
+
throw new Error('with-doc can only be used with user-defined functions');
|
|
4794
|
+
}
|
|
4795
|
+
return {
|
|
4796
|
+
...fn,
|
|
4797
|
+
[FUNCTION_SYMBOL]: true,
|
|
4798
|
+
docString,
|
|
4799
|
+
};
|
|
4800
|
+
},
|
|
4801
|
+
arity: toFixedArity(2),
|
|
4802
|
+
docs: {
|
|
4803
|
+
category: 'meta',
|
|
4804
|
+
returns: { type: 'function' },
|
|
4805
|
+
args: {
|
|
4806
|
+
a: { type: 'function' },
|
|
4807
|
+
b: { type: 'string' },
|
|
4808
|
+
},
|
|
4809
|
+
variants: [{ argumentNames: ['a', 'b'] }],
|
|
4810
|
+
description: 'Returns a new function with the documentation string $b attached. The original function is not modified.',
|
|
4811
|
+
seeAlso: ['doc'],
|
|
4812
|
+
examples: [
|
|
4813
|
+
'((x, y) -> x + y) with-doc "Adds two numbers."',
|
|
4814
|
+
'let add = (x, y) -> x + y;\nadd with-doc "Adds x and y."',
|
|
4926
4815
|
],
|
|
4927
4816
|
},
|
|
4928
4817
|
},
|
|
4929
|
-
arity: {
|
|
4818
|
+
'arity': {
|
|
4930
4819
|
evaluate: ([value], sourceCodeInfo) => {
|
|
4931
4820
|
// Handle effects
|
|
4932
4821
|
if (isEffect(value)) {
|
|
@@ -6293,6 +6182,31 @@ const raceSpecialExpression = {
|
|
|
6293
6182
|
},
|
|
6294
6183
|
};
|
|
6295
6184
|
|
|
6185
|
+
const specialExpressionTypes = {
|
|
6186
|
+
'??': 0,
|
|
6187
|
+
'&&': 1,
|
|
6188
|
+
'||': 2,
|
|
6189
|
+
'array': 3,
|
|
6190
|
+
'cond': 4,
|
|
6191
|
+
'defined?': 5,
|
|
6192
|
+
'block': 6,
|
|
6193
|
+
'doseq': 7,
|
|
6194
|
+
'0_lambda': 8,
|
|
6195
|
+
'for': 9,
|
|
6196
|
+
'if': 10,
|
|
6197
|
+
'let': 11,
|
|
6198
|
+
'loop': 12,
|
|
6199
|
+
'object': 13,
|
|
6200
|
+
'recur': 14,
|
|
6201
|
+
'match': 15,
|
|
6202
|
+
'unless': 16,
|
|
6203
|
+
'import': 17,
|
|
6204
|
+
'effect': 18,
|
|
6205
|
+
'perform': 19,
|
|
6206
|
+
'parallel': 20,
|
|
6207
|
+
'race': 21,
|
|
6208
|
+
};
|
|
6209
|
+
|
|
6296
6210
|
const specialExpressions = [
|
|
6297
6211
|
qqSpecialExpression,
|
|
6298
6212
|
andSpecialExpression,
|
|
@@ -6394,119 +6308,1000 @@ function isSymbolicOperator(operator) {
|
|
|
6394
6308
|
return symbolicOperatorSet.has(operator);
|
|
6395
6309
|
}
|
|
6396
6310
|
|
|
6397
|
-
|
|
6398
|
-
|
|
6399
|
-
|
|
6311
|
+
const nonNumberReservedSymbolRecord = {
|
|
6312
|
+
true: true,
|
|
6313
|
+
false: false,
|
|
6314
|
+
null: null,
|
|
6315
|
+
do: null,
|
|
6316
|
+
else: null,
|
|
6317
|
+
case: null,
|
|
6318
|
+
each: null,
|
|
6319
|
+
in: null,
|
|
6320
|
+
when: null,
|
|
6321
|
+
while: null,
|
|
6322
|
+
function: null,
|
|
6323
|
+
as: null,
|
|
6324
|
+
then: null,
|
|
6325
|
+
end: null,
|
|
6326
|
+
with: null,
|
|
6327
|
+
_: null,
|
|
6328
|
+
};
|
|
6329
|
+
const phi = (1 + Math.sqrt(5)) / 2;
|
|
6330
|
+
const numberReservedSymbolRecord = {
|
|
6331
|
+
'E': Math.E,
|
|
6332
|
+
'-E': -Math.E,
|
|
6333
|
+
'ε': Math.E,
|
|
6334
|
+
'-ε': -Math.E,
|
|
6335
|
+
'PI': Math.PI,
|
|
6336
|
+
'-PI': -Math.PI,
|
|
6337
|
+
'π': Math.PI,
|
|
6338
|
+
'-π': -Math.PI,
|
|
6339
|
+
'PHI': phi,
|
|
6340
|
+
'-PHI': -phi,
|
|
6341
|
+
'φ': phi,
|
|
6342
|
+
'-φ': -phi,
|
|
6343
|
+
'POSITIVE_INFINITY': Number.POSITIVE_INFINITY,
|
|
6344
|
+
'∞': Number.POSITIVE_INFINITY,
|
|
6345
|
+
'NEGATIVE_INFINITY': Number.NEGATIVE_INFINITY,
|
|
6346
|
+
'-∞': Number.NEGATIVE_INFINITY,
|
|
6347
|
+
'MAX_SAFE_INTEGER': Number.MAX_SAFE_INTEGER,
|
|
6348
|
+
'MIN_SAFE_INTEGER': Number.MIN_SAFE_INTEGER,
|
|
6349
|
+
'MAX_VALUE': Number.MAX_VALUE,
|
|
6350
|
+
'MIN_VALUE': Number.MIN_VALUE,
|
|
6351
|
+
'NaN': Number.NaN,
|
|
6352
|
+
};
|
|
6353
|
+
const reservedSymbolRecord = {
|
|
6354
|
+
...nonNumberReservedSymbolRecord,
|
|
6355
|
+
...numberReservedSymbolRecord,
|
|
6356
|
+
};
|
|
6357
|
+
function isNumberReservedSymbol(symbol) {
|
|
6358
|
+
return symbol in numberReservedSymbolRecord;
|
|
6359
|
+
}
|
|
6360
|
+
|
|
6361
|
+
const illegalSymbolCharacters = [
|
|
6362
|
+
'(',
|
|
6363
|
+
')',
|
|
6364
|
+
'[',
|
|
6365
|
+
']',
|
|
6366
|
+
'{',
|
|
6367
|
+
'}',
|
|
6368
|
+
'\'',
|
|
6369
|
+
'"',
|
|
6370
|
+
'`',
|
|
6371
|
+
',',
|
|
6372
|
+
'.',
|
|
6373
|
+
';',
|
|
6374
|
+
' ',
|
|
6375
|
+
'\n',
|
|
6376
|
+
'\r',
|
|
6377
|
+
'\t',
|
|
6378
|
+
];
|
|
6379
|
+
const illegalFirstSymbolCharacters = [
|
|
6380
|
+
'0',
|
|
6381
|
+
'1',
|
|
6382
|
+
'2',
|
|
6383
|
+
'3',
|
|
6384
|
+
'4',
|
|
6385
|
+
'5',
|
|
6386
|
+
'6',
|
|
6387
|
+
'7',
|
|
6388
|
+
'8',
|
|
6389
|
+
'9',
|
|
6390
|
+
...illegalSymbolCharacters,
|
|
6391
|
+
];
|
|
6392
|
+
const illegalSymbolCharacterSet = new Set(illegalSymbolCharacters);
|
|
6393
|
+
const illegalFirstSymbolCharacterSet = new Set(illegalFirstSymbolCharacters);
|
|
6394
|
+
const whitespaceRegExp = /\s/;
|
|
6395
|
+
const NO_MATCH = [0];
|
|
6396
|
+
const tokenizeLParen = (input, position) => tokenizeToken('LParen', '(', input, position);
|
|
6397
|
+
const tokenizeRParen = (input, position) => tokenizeToken('RParen', ')', input, position);
|
|
6398
|
+
const tokenizeLBracket = (input, position) => tokenizeToken('LBracket', '[', input, position);
|
|
6399
|
+
const tokenizeRBracket = (input, position) => tokenizeToken('RBracket', ']', input, position);
|
|
6400
|
+
const tokenizeLBrace = (input, position) => tokenizeToken('LBrace', '{', input, position);
|
|
6401
|
+
const tokenizeRBrace = (input, position) => tokenizeToken('RBrace', '}', input, position);
|
|
6402
|
+
const tokenizeString = (input, position) => {
|
|
6403
|
+
if (input[position] !== '"')
|
|
6404
|
+
return NO_MATCH;
|
|
6405
|
+
let value = '"';
|
|
6406
|
+
let length = 1;
|
|
6407
|
+
let char = input[position + length];
|
|
6408
|
+
let escaping = false;
|
|
6409
|
+
while (char && (char !== '"' || escaping)) {
|
|
6410
|
+
length += 1;
|
|
6411
|
+
if (escaping) {
|
|
6412
|
+
escaping = false;
|
|
6413
|
+
value += char;
|
|
6414
|
+
}
|
|
6415
|
+
else {
|
|
6416
|
+
if (char === '\\') {
|
|
6417
|
+
escaping = true;
|
|
6418
|
+
}
|
|
6419
|
+
value += char;
|
|
6420
|
+
}
|
|
6421
|
+
char = input[position + length];
|
|
6400
6422
|
}
|
|
6401
|
-
if (
|
|
6402
|
-
return
|
|
6423
|
+
if (!char) {
|
|
6424
|
+
return [length, ['Error', value, undefined, `Unclosed string at position ${position}`]];
|
|
6403
6425
|
}
|
|
6404
|
-
|
|
6405
|
-
|
|
6406
|
-
|
|
6407
|
-
|
|
6408
|
-
|
|
6426
|
+
value += '"'; // closing quote
|
|
6427
|
+
return [length + 1, ['string', value]];
|
|
6428
|
+
};
|
|
6429
|
+
const tokenizeRegexpShorthand = (input, position) => {
|
|
6430
|
+
if (input[position] !== '#')
|
|
6431
|
+
return NO_MATCH;
|
|
6432
|
+
const [stringLength, token] = tokenizeString(input, position + 1);
|
|
6433
|
+
if (!token)
|
|
6434
|
+
return NO_MATCH;
|
|
6435
|
+
if (token[0] === 'Error') {
|
|
6436
|
+
const errorToken = ['Error', `#${token[1]}`, undefined, `Unclosed regexp at position ${position}`];
|
|
6437
|
+
return [stringLength + 1, errorToken];
|
|
6409
6438
|
}
|
|
6439
|
+
position += stringLength + 1;
|
|
6440
|
+
let length = stringLength + 1;
|
|
6441
|
+
let options = '';
|
|
6442
|
+
while (input[position] === 'g' || input[position] === 'i') {
|
|
6443
|
+
options += input[position];
|
|
6444
|
+
length += 1;
|
|
6445
|
+
position += 1;
|
|
6446
|
+
if (options.includes(input[position])) {
|
|
6447
|
+
return [length, ['Error', `#${token[1]}${options}`, undefined, `Duplicated regexp option "${input[position]}"`]];
|
|
6448
|
+
}
|
|
6449
|
+
}
|
|
6450
|
+
return [length, ['RegexpShorthand', `#${token[1]}${options}`]];
|
|
6451
|
+
};
|
|
6452
|
+
function tokenizeToken(type, value, input, position) {
|
|
6453
|
+
if (value === input.slice(position, position + value.length))
|
|
6454
|
+
return [value.length, [type, value]];
|
|
6455
|
+
else
|
|
6456
|
+
return NO_MATCH;
|
|
6410
6457
|
}
|
|
6411
|
-
|
|
6412
|
-
|
|
6413
|
-
|
|
6414
|
-
|
|
6415
|
-
function isReservedSymbolToken(token, symbolName) {
|
|
6416
|
-
if (token?.[0] !== 'ReservedSymbol') {
|
|
6417
|
-
return false;
|
|
6458
|
+
const tokenizeWhitespace = (input, position) => {
|
|
6459
|
+
let char = input[position];
|
|
6460
|
+
if (!char || !whitespaceRegExp.test(char)) {
|
|
6461
|
+
return NO_MATCH;
|
|
6418
6462
|
}
|
|
6419
|
-
|
|
6420
|
-
|
|
6463
|
+
let value = char;
|
|
6464
|
+
position += 1;
|
|
6465
|
+
char = input[position];
|
|
6466
|
+
while (char && whitespaceRegExp.test(char)) {
|
|
6467
|
+
value += char;
|
|
6468
|
+
position += 1;
|
|
6469
|
+
char = input[position];
|
|
6421
6470
|
}
|
|
6422
|
-
return
|
|
6423
|
-
}
|
|
6424
|
-
|
|
6425
|
-
|
|
6426
|
-
|
|
6471
|
+
return [value.length, ['Whitespace', value]];
|
|
6472
|
+
};
|
|
6473
|
+
const decimalNumberRegExp = /\d/;
|
|
6474
|
+
const octalNumberRegExp = /[0-7]/;
|
|
6475
|
+
const hexNumberRegExp = /[0-9a-f]/i;
|
|
6476
|
+
const binaryNumberRegExp = /[01]/;
|
|
6477
|
+
const postNumberRegExp = /[\s)\]}(,;]/;
|
|
6478
|
+
const tokenizeNumber = (input, position) => {
|
|
6479
|
+
let i;
|
|
6480
|
+
const negate = input[position] === '-';
|
|
6481
|
+
const plusPrefix = input[position] === '+';
|
|
6482
|
+
const start = negate || plusPrefix ? position + 1 : position;
|
|
6483
|
+
let hasDecimalPoint = false;
|
|
6484
|
+
let hasExponent = false;
|
|
6485
|
+
for (i = start; i < input.length; i += 1) {
|
|
6486
|
+
const char = input[i];
|
|
6487
|
+
if (char === '_') {
|
|
6488
|
+
if (!decimalNumberRegExp.test(input[i - 1]) || !decimalNumberRegExp.test(input[i + 1])) {
|
|
6489
|
+
if (i === start) {
|
|
6490
|
+
return NO_MATCH;
|
|
6491
|
+
}
|
|
6492
|
+
return [i - position + 1, ['Error', input.substring(position, i + 1), undefined, `Invalid number format at position ${i + 1}`]];
|
|
6493
|
+
}
|
|
6494
|
+
}
|
|
6495
|
+
else if (char === '.') {
|
|
6496
|
+
if (i === start) {
|
|
6497
|
+
return NO_MATCH;
|
|
6498
|
+
}
|
|
6499
|
+
if (hasDecimalPoint || hasExponent) {
|
|
6500
|
+
return [i - position + 1, ['Error', input.substring(position, i + 1), undefined, `Invalid number format at position ${i + 1}`]];
|
|
6501
|
+
}
|
|
6502
|
+
hasDecimalPoint = true;
|
|
6503
|
+
}
|
|
6504
|
+
else if (char === 'e' || char === 'E') {
|
|
6505
|
+
if (i === start) {
|
|
6506
|
+
return NO_MATCH;
|
|
6507
|
+
}
|
|
6508
|
+
if (hasExponent) {
|
|
6509
|
+
return [i - position + 1, ['Error', input.substring(position, i + 1), undefined, `Invalid number format at position ${i + 1}`]];
|
|
6510
|
+
}
|
|
6511
|
+
if (input[i - 1] === '.' || input[i - 1] === '+' || input[i - 1] === '-') {
|
|
6512
|
+
return [i - position + 1, ['Error', input.substring(position, i + 1), undefined, `Invalid number format at position ${i + 1}`]];
|
|
6513
|
+
}
|
|
6514
|
+
if (input[i + 1] === '+' || input[i + 1] === '-') {
|
|
6515
|
+
i += 1;
|
|
6516
|
+
}
|
|
6517
|
+
hasExponent = true;
|
|
6518
|
+
}
|
|
6519
|
+
else if (!decimalNumberRegExp.test(char)) {
|
|
6520
|
+
break;
|
|
6521
|
+
}
|
|
6427
6522
|
}
|
|
6428
|
-
|
|
6429
|
-
|
|
6430
|
-
assertReservedSymbolToken(token, symbolName);
|
|
6431
|
-
return token;
|
|
6432
|
-
}
|
|
6433
|
-
function isShebangToken(token) {
|
|
6434
|
-
return token?.[0] === 'Shebang';
|
|
6435
|
-
}
|
|
6436
|
-
function isSingleLineCommentToken(token) {
|
|
6437
|
-
return token?.[0] === 'SingleLineComment';
|
|
6438
|
-
}
|
|
6439
|
-
function isMultiLineCommentToken(token) {
|
|
6440
|
-
return token?.[0] === 'MultiLineComment';
|
|
6441
|
-
}
|
|
6442
|
-
function isOperatorToken(token, operatorName) {
|
|
6443
|
-
if (token?.[0] !== 'Operator') {
|
|
6444
|
-
return false;
|
|
6523
|
+
if ((negate || plusPrefix) && i === start) {
|
|
6524
|
+
return NO_MATCH;
|
|
6445
6525
|
}
|
|
6446
|
-
|
|
6447
|
-
|
|
6526
|
+
const length = i - position;
|
|
6527
|
+
if (length === 0) {
|
|
6528
|
+
return NO_MATCH;
|
|
6448
6529
|
}
|
|
6449
|
-
|
|
6450
|
-
|
|
6451
|
-
|
|
6452
|
-
if (!isOperatorToken(token, operatorName)) {
|
|
6453
|
-
throwUnexpectedToken('Operator', operatorName, token);
|
|
6530
|
+
const nextChar = input[i];
|
|
6531
|
+
if (nextChar && nextChar !== ':' && !postNumberRegExp.test(nextChar)) {
|
|
6532
|
+
return [i - position + 1, ['Error', input.substring(position, i + 1), undefined, `Invalid number format at position ${i + 1}`]];
|
|
6454
6533
|
}
|
|
6455
|
-
|
|
6456
|
-
|
|
6457
|
-
|
|
6458
|
-
|
|
6459
|
-
|
|
6460
|
-
return token?.[0] === 'Number';
|
|
6461
|
-
}
|
|
6462
|
-
function isBasePrefixedNumberToken(token) {
|
|
6463
|
-
return token?.[0] === 'BasePrefixedNumber';
|
|
6464
|
-
}
|
|
6465
|
-
function isLParenToken(token) {
|
|
6466
|
-
return token?.[0] === 'LParen';
|
|
6467
|
-
}
|
|
6468
|
-
function assertLParenToken(token) {
|
|
6469
|
-
if (!isLParenToken(token)) {
|
|
6470
|
-
throwUnexpectedToken('LParen', undefined, token);
|
|
6534
|
+
return [length, ['Number', input.substring(position, i)]];
|
|
6535
|
+
};
|
|
6536
|
+
const tokenizeBasePrefixedNumber = (input, position) => {
|
|
6537
|
+
if (input[position] !== '0') {
|
|
6538
|
+
return NO_MATCH;
|
|
6471
6539
|
}
|
|
6472
|
-
|
|
6473
|
-
|
|
6474
|
-
|
|
6475
|
-
|
|
6476
|
-
|
|
6477
|
-
|
|
6478
|
-
|
|
6540
|
+
const baseChar = input[position + 1];
|
|
6541
|
+
const type = baseChar === 'b' || baseChar === 'B'
|
|
6542
|
+
? 'binary'
|
|
6543
|
+
: baseChar === 'o' || baseChar === 'O'
|
|
6544
|
+
? 'octal'
|
|
6545
|
+
: baseChar === 'x' || baseChar === 'X'
|
|
6546
|
+
? 'hex'
|
|
6547
|
+
: null;
|
|
6548
|
+
if (type === null) {
|
|
6549
|
+
return NO_MATCH;
|
|
6479
6550
|
}
|
|
6480
|
-
|
|
6481
|
-
|
|
6482
|
-
|
|
6483
|
-
|
|
6484
|
-
|
|
6485
|
-
|
|
6486
|
-
|
|
6551
|
+
let i;
|
|
6552
|
+
for (i = position + 2; i < input.length; i += 1) {
|
|
6553
|
+
const char = input[i];
|
|
6554
|
+
if (type === 'binary' && !binaryNumberRegExp.test(char)) {
|
|
6555
|
+
break;
|
|
6556
|
+
}
|
|
6557
|
+
if (type === 'octal' && !octalNumberRegExp.test(char)) {
|
|
6558
|
+
break;
|
|
6559
|
+
}
|
|
6560
|
+
if (type === 'hex' && !hexNumberRegExp.test(char)) {
|
|
6561
|
+
break;
|
|
6562
|
+
}
|
|
6487
6563
|
}
|
|
6488
|
-
|
|
6489
|
-
|
|
6490
|
-
|
|
6491
|
-
return token;
|
|
6492
|
-
}
|
|
6493
|
-
function isRBracketToken(token) {
|
|
6494
|
-
return token?.[0] === 'RBracket';
|
|
6495
|
-
}
|
|
6496
|
-
function assertRBracketToken(token) {
|
|
6497
|
-
if (!isRBracketToken(token)) {
|
|
6498
|
-
throwUnexpectedToken('RBracket', undefined, token);
|
|
6564
|
+
const length = i - position;
|
|
6565
|
+
if (length <= 2) {
|
|
6566
|
+
return NO_MATCH;
|
|
6499
6567
|
}
|
|
6500
|
-
|
|
6501
|
-
|
|
6502
|
-
|
|
6503
|
-
}
|
|
6504
|
-
function assertLBraceToken(token) {
|
|
6505
|
-
if (!isLBraceToken(token)) {
|
|
6506
|
-
throwUnexpectedToken('LBrace', undefined, token);
|
|
6568
|
+
const nextChar = input[i];
|
|
6569
|
+
if (nextChar && !postNumberRegExp.test(nextChar)) {
|
|
6570
|
+
return NO_MATCH;
|
|
6507
6571
|
}
|
|
6508
|
-
|
|
6509
|
-
|
|
6572
|
+
return [length, ['BasePrefixedNumber', input.substring(position, i)]];
|
|
6573
|
+
};
|
|
6574
|
+
const tokenizeSymbol = (input, position) => {
|
|
6575
|
+
let value = input[position];
|
|
6576
|
+
if (value === '\'') {
|
|
6577
|
+
let length = 1;
|
|
6578
|
+
let char = input[position + length];
|
|
6579
|
+
let escaping = false;
|
|
6580
|
+
while (char !== '\'' || escaping) {
|
|
6581
|
+
if (char === undefined)
|
|
6582
|
+
return [length, ['Error', value, undefined, `Unclosed quoted symbol at position ${position}`]];
|
|
6583
|
+
length += 1;
|
|
6584
|
+
if (escaping) {
|
|
6585
|
+
escaping = false;
|
|
6586
|
+
value += char;
|
|
6587
|
+
}
|
|
6588
|
+
else {
|
|
6589
|
+
if (char === '\\') {
|
|
6590
|
+
escaping = true;
|
|
6591
|
+
}
|
|
6592
|
+
value += char;
|
|
6593
|
+
}
|
|
6594
|
+
char = input[position + length];
|
|
6595
|
+
}
|
|
6596
|
+
value += '\''; // closing quote
|
|
6597
|
+
return [length + 1, ['Symbol', value]];
|
|
6598
|
+
}
|
|
6599
|
+
if (!illegalFirstSymbolCharacterSet.has(value)) {
|
|
6600
|
+
const initialPosition = position;
|
|
6601
|
+
position += 1;
|
|
6602
|
+
let char = input[position];
|
|
6603
|
+
while (char && !illegalSymbolCharacterSet.has(char)) {
|
|
6604
|
+
value += char;
|
|
6605
|
+
position += 1;
|
|
6606
|
+
char = input[position];
|
|
6607
|
+
}
|
|
6608
|
+
// : can be used as symbol character, but it must not be the last character
|
|
6609
|
+
return value.endsWith(':')
|
|
6610
|
+
? [position - initialPosition - 1, ['Symbol', value.slice(0, -1)]]
|
|
6611
|
+
: [position - initialPosition, ['Symbol', value]];
|
|
6612
|
+
}
|
|
6613
|
+
return NO_MATCH;
|
|
6614
|
+
};
|
|
6615
|
+
const tokenizeReservedSymbolToken = (input, position) => {
|
|
6616
|
+
const symbolMeta = tokenizeSymbol(input, position);
|
|
6617
|
+
if (symbolMeta[0] === 0 || !symbolMeta[1]) {
|
|
6618
|
+
return NO_MATCH;
|
|
6619
|
+
}
|
|
6620
|
+
let symbolName = symbolMeta[1][1];
|
|
6621
|
+
symbolName = symbolName.startsWith('\'') ? symbolName.slice(1, symbolName.length - 1) : symbolName;
|
|
6622
|
+
const info = reservedSymbolRecord[symbolName];
|
|
6623
|
+
if (info === undefined) {
|
|
6624
|
+
return NO_MATCH;
|
|
6625
|
+
}
|
|
6626
|
+
return [symbolMeta[0], ['ReservedSymbol', symbolName]];
|
|
6627
|
+
};
|
|
6628
|
+
const tokenizeOperator = (input, position) => {
|
|
6629
|
+
const threeChars = input.slice(position, position + 3);
|
|
6630
|
+
if (position + 2 < input.length && isSymbolicOperator(threeChars)) {
|
|
6631
|
+
return [3, ['Operator', threeChars]];
|
|
6632
|
+
}
|
|
6633
|
+
const twoChars = input.slice(position, position + 2);
|
|
6634
|
+
if (position + 1 < input.length && isSymbolicOperator(twoChars)) {
|
|
6635
|
+
return [2, ['Operator', twoChars]];
|
|
6636
|
+
}
|
|
6637
|
+
const oneChar = input[position] ?? '';
|
|
6638
|
+
if (isSymbolicOperator(oneChar)) {
|
|
6639
|
+
return [1, ['Operator', oneChar]];
|
|
6640
|
+
}
|
|
6641
|
+
return NO_MATCH;
|
|
6642
|
+
};
|
|
6643
|
+
const tokenizeMultiLineComment = (input, position) => {
|
|
6644
|
+
if (input[position] === '/' && input[position + 1] === '*') {
|
|
6645
|
+
let length = 2;
|
|
6646
|
+
let value = '/*';
|
|
6647
|
+
while ((input[position + length] !== '*' || input[position + length + 1] !== '/') && position + length + 1 < input.length) {
|
|
6648
|
+
value += input[position + length];
|
|
6649
|
+
length += 1;
|
|
6650
|
+
}
|
|
6651
|
+
if (position + length + 1 >= input.length) {
|
|
6652
|
+
return [length, ['Error', value, undefined, `Unclosed multi-line comment at position ${position}`]];
|
|
6653
|
+
}
|
|
6654
|
+
value += '*/';
|
|
6655
|
+
length += 2;
|
|
6656
|
+
return [length, ['MultiLineComment', value]];
|
|
6657
|
+
}
|
|
6658
|
+
return NO_MATCH;
|
|
6659
|
+
};
|
|
6660
|
+
const tokenizeShebang = (input, position) => {
|
|
6661
|
+
if (input[position] === '#' && input[position + 1] === '!') {
|
|
6662
|
+
let length = 2;
|
|
6663
|
+
let value = '#!';
|
|
6664
|
+
while (input[position + length] !== '\n' && position + length < input.length) {
|
|
6665
|
+
value += input[position + length];
|
|
6666
|
+
length += 1;
|
|
6667
|
+
}
|
|
6668
|
+
return [length, ['SingleLineComment', value]];
|
|
6669
|
+
}
|
|
6670
|
+
return NO_MATCH;
|
|
6671
|
+
};
|
|
6672
|
+
const tokenizeSingleLineComment = (input, position) => {
|
|
6673
|
+
if (input[position] === '/' && input[position + 1] === '/') {
|
|
6674
|
+
let length = 2;
|
|
6675
|
+
let value = '//';
|
|
6676
|
+
while (input[position + length] !== '\n' && position + length < input.length) {
|
|
6677
|
+
value += input[position + length];
|
|
6678
|
+
length += 1;
|
|
6679
|
+
}
|
|
6680
|
+
return [length, ['SingleLineComment', value]];
|
|
6681
|
+
}
|
|
6682
|
+
return NO_MATCH;
|
|
6683
|
+
};
|
|
6684
|
+
// All tokenizers, order matters!
|
|
6685
|
+
const tokenizers = [
|
|
6686
|
+
tokenizeWhitespace,
|
|
6687
|
+
tokenizeMultiLineComment,
|
|
6688
|
+
tokenizeSingleLineComment,
|
|
6689
|
+
tokenizeReservedSymbolToken,
|
|
6690
|
+
tokenizeLParen,
|
|
6691
|
+
tokenizeRParen,
|
|
6692
|
+
tokenizeLBracket,
|
|
6693
|
+
tokenizeRBracket,
|
|
6694
|
+
tokenizeLBrace,
|
|
6695
|
+
tokenizeRBrace,
|
|
6696
|
+
tokenizeString,
|
|
6697
|
+
tokenizeRegexpShorthand,
|
|
6698
|
+
tokenizeBasePrefixedNumber,
|
|
6699
|
+
tokenizeNumber,
|
|
6700
|
+
tokenizeOperator,
|
|
6701
|
+
tokenizeSymbol,
|
|
6702
|
+
];
|
|
6703
|
+
|
|
6704
|
+
function tokenize(input, debug, filePath) {
|
|
6705
|
+
let position = 0;
|
|
6706
|
+
const tokenStream = {
|
|
6707
|
+
tokens: [],
|
|
6708
|
+
filePath,
|
|
6709
|
+
hasDebugData: debug,
|
|
6710
|
+
};
|
|
6711
|
+
while (position < input.length) {
|
|
6712
|
+
const sourceCodeInfo = debug
|
|
6713
|
+
? createSourceCodeInfo(input, position, filePath)
|
|
6714
|
+
: undefined;
|
|
6715
|
+
const tokenDescriptor = getCurrentToken(input, position);
|
|
6716
|
+
const [count, token] = tokenDescriptor;
|
|
6717
|
+
position += count;
|
|
6718
|
+
if (token) {
|
|
6719
|
+
if (sourceCodeInfo) {
|
|
6720
|
+
token[2] = sourceCodeInfo;
|
|
6721
|
+
}
|
|
6722
|
+
tokenStream.tokens.push(token);
|
|
6723
|
+
}
|
|
6724
|
+
}
|
|
6725
|
+
return tokenStream;
|
|
6726
|
+
}
|
|
6727
|
+
function getSourceCodeLine(input, lineNbr) {
|
|
6728
|
+
return input.split(/\r\n|\r|\n/)[lineNbr];
|
|
6729
|
+
}
|
|
6730
|
+
function createSourceCodeInfo(input, position, filePath) {
|
|
6731
|
+
const lines = input.substring(0, position + 1).split(/\r\n|\r|\n/);
|
|
6732
|
+
const lastLine = lines[lines.length - 1];
|
|
6733
|
+
const code = getSourceCodeLine(input, lines.length - 1);
|
|
6734
|
+
const line = lines.length;
|
|
6735
|
+
const column = lastLine.length;
|
|
6736
|
+
return {
|
|
6737
|
+
code,
|
|
6738
|
+
position: {
|
|
6739
|
+
line,
|
|
6740
|
+
column,
|
|
6741
|
+
},
|
|
6742
|
+
filePath,
|
|
6743
|
+
};
|
|
6744
|
+
}
|
|
6745
|
+
function getCurrentToken(input, position) {
|
|
6746
|
+
const initialPosition = position;
|
|
6747
|
+
if (position === 0) {
|
|
6748
|
+
const [nbrOfCharacters, token] = tokenizeShebang(input, position);
|
|
6749
|
+
position += nbrOfCharacters;
|
|
6750
|
+
if (nbrOfCharacters > 0) {
|
|
6751
|
+
return [position - initialPosition, token];
|
|
6752
|
+
}
|
|
6753
|
+
}
|
|
6754
|
+
for (const tokenizer of tokenizers) {
|
|
6755
|
+
const [nbrOfCharacters, token] = tokenizer(input, position);
|
|
6756
|
+
position += nbrOfCharacters;
|
|
6757
|
+
if (nbrOfCharacters === 0) {
|
|
6758
|
+
continue;
|
|
6759
|
+
}
|
|
6760
|
+
return [position - initialPosition, token];
|
|
6761
|
+
}
|
|
6762
|
+
return [1, ['Error', input[initialPosition], undefined, 'Unrecognized character']];
|
|
6763
|
+
}
|
|
6764
|
+
|
|
6765
|
+
const dvalaCommands = new Set([...normalExpressionKeys, ...specialExpressionKeys, ...Object.keys(reservedSymbolRecord)]);
|
|
6766
|
+
// TODO: replace with get suggestions function
|
|
6767
|
+
class AutoCompleter {
|
|
6768
|
+
originalProgram;
|
|
6769
|
+
originalPosition;
|
|
6770
|
+
prefixProgram = '';
|
|
6771
|
+
suffixProgram = '';
|
|
6772
|
+
searchString = '';
|
|
6773
|
+
suggestions = [];
|
|
6774
|
+
suggestionIndex = null;
|
|
6775
|
+
constructor(originalProgram, originalPosition, params = {}) {
|
|
6776
|
+
this.originalProgram = originalProgram;
|
|
6777
|
+
this.originalPosition = originalPosition;
|
|
6778
|
+
const partialProgram = this.originalProgram.slice(0, this.originalPosition);
|
|
6779
|
+
const tokenStream = tokenize(partialProgram, false, undefined);
|
|
6780
|
+
const lastToken = tokenStream.tokens.at(-1);
|
|
6781
|
+
if (!lastToken) {
|
|
6782
|
+
return;
|
|
6783
|
+
}
|
|
6784
|
+
if (lastToken[0] === 'Error') {
|
|
6785
|
+
return;
|
|
6786
|
+
}
|
|
6787
|
+
this.searchString = lastToken[1];
|
|
6788
|
+
this.prefixProgram = this.originalProgram.slice(0, this.originalPosition - this.searchString.length);
|
|
6789
|
+
this.suffixProgram = this.originalProgram.slice(this.prefixProgram.length + this.searchString.length);
|
|
6790
|
+
this.originalProgram.slice(this.prefixProgram.length + this.searchString.length);
|
|
6791
|
+
this.suggestions = this.generateSuggestions(params);
|
|
6792
|
+
}
|
|
6793
|
+
getNextSuggestion() {
|
|
6794
|
+
return this.getAutoCompleteSuggestionResult(this.getNextSuggestionSymbol());
|
|
6795
|
+
}
|
|
6796
|
+
getPreviousSuggestion() {
|
|
6797
|
+
return this.getAutoCompleteSuggestionResult(this.getPreviousSuggestionSymbol());
|
|
6798
|
+
}
|
|
6799
|
+
getAutoCompleteSuggestionResult(suggestion) {
|
|
6800
|
+
if (suggestion === null) {
|
|
6801
|
+
return null;
|
|
6802
|
+
}
|
|
6803
|
+
return {
|
|
6804
|
+
program: this.prefixProgram + suggestion + this.suffixProgram,
|
|
6805
|
+
position: this.prefixProgram.length + suggestion.length,
|
|
6806
|
+
};
|
|
6807
|
+
}
|
|
6808
|
+
getNextSuggestionSymbol() {
|
|
6809
|
+
if (this.suggestions.length === 0) {
|
|
6810
|
+
return null;
|
|
6811
|
+
}
|
|
6812
|
+
if (this.suggestionIndex === null) {
|
|
6813
|
+
this.suggestionIndex = 0;
|
|
6814
|
+
}
|
|
6815
|
+
else {
|
|
6816
|
+
this.suggestionIndex += 1;
|
|
6817
|
+
if (this.suggestionIndex >= this.suggestions.length) {
|
|
6818
|
+
this.suggestionIndex = 0;
|
|
6819
|
+
}
|
|
6820
|
+
}
|
|
6821
|
+
return this.suggestions[this.suggestionIndex];
|
|
6822
|
+
}
|
|
6823
|
+
getPreviousSuggestionSymbol() {
|
|
6824
|
+
if (this.suggestions.length === 0) {
|
|
6825
|
+
return null;
|
|
6826
|
+
}
|
|
6827
|
+
if (this.suggestionIndex === null) {
|
|
6828
|
+
this.suggestionIndex = this.suggestions.length - 1;
|
|
6829
|
+
}
|
|
6830
|
+
else {
|
|
6831
|
+
this.suggestionIndex -= 1;
|
|
6832
|
+
if (this.suggestionIndex < 0) {
|
|
6833
|
+
this.suggestionIndex = this.suggestions.length - 1;
|
|
6834
|
+
}
|
|
6835
|
+
}
|
|
6836
|
+
return this.suggestions[this.suggestionIndex];
|
|
6837
|
+
}
|
|
6838
|
+
getSuggestions() {
|
|
6839
|
+
return [...this.suggestions];
|
|
6840
|
+
}
|
|
6841
|
+
getSearchString() {
|
|
6842
|
+
return this.searchString;
|
|
6843
|
+
}
|
|
6844
|
+
generateSuggestions(params) {
|
|
6845
|
+
const blacklist = new Set(['0_defn', '0_lambda']);
|
|
6846
|
+
const startsWithCaseSensitive = this.generateWithPredicate(params, suggestion => !blacklist.has(suggestion) && suggestion.startsWith(this.searchString));
|
|
6847
|
+
startsWithCaseSensitive.forEach(suggestion => blacklist.add(suggestion));
|
|
6848
|
+
const startsWithCaseInsensitive = this.generateWithPredicate(params, suggestion => !blacklist.has(suggestion) && suggestion.toLowerCase().startsWith(this.searchString.toLowerCase()));
|
|
6849
|
+
startsWithCaseInsensitive.forEach(suggestion => blacklist.add(suggestion));
|
|
6850
|
+
const includesCaseSensitive = this.generateWithPredicate(params, suggestion => !blacklist.has(suggestion) && suggestion.includes(this.searchString));
|
|
6851
|
+
includesCaseSensitive.forEach(suggestion => blacklist.add(suggestion));
|
|
6852
|
+
const includesCaseInsensitive = this.generateWithPredicate(params, suggestion => !blacklist.has(suggestion) && suggestion.includes(this.searchString.toLowerCase()));
|
|
6853
|
+
includesCaseInsensitive.forEach(suggestion => blacklist.add(suggestion));
|
|
6854
|
+
return [...startsWithCaseSensitive, ...startsWithCaseInsensitive, ...includesCaseSensitive, ...includesCaseInsensitive];
|
|
6855
|
+
}
|
|
6856
|
+
generateWithPredicate(params, shouldInclude) {
|
|
6857
|
+
const suggestions = new Set();
|
|
6858
|
+
dvalaCommands.forEach((suggestion) => {
|
|
6859
|
+
if (shouldInclude(suggestion)) {
|
|
6860
|
+
suggestions.add(suggestion);
|
|
6861
|
+
}
|
|
6862
|
+
});
|
|
6863
|
+
Object.keys(params.bindings ?? {})
|
|
6864
|
+
.filter(shouldInclude)
|
|
6865
|
+
.forEach(suggestion => suggestions.add(suggestion));
|
|
6866
|
+
return [...suggestions].sort((a, b) => a.localeCompare(b));
|
|
6867
|
+
}
|
|
6868
|
+
}
|
|
6869
|
+
|
|
6870
|
+
function isSymbolNode(node) {
|
|
6871
|
+
const nodeType = node[0];
|
|
6872
|
+
return NodeTypes.UserDefinedSymbol === nodeType
|
|
6873
|
+
|| NodeTypes.NormalBuiltinSymbol === nodeType
|
|
6874
|
+
|| NodeTypes.SpecialBuiltinSymbol === nodeType;
|
|
6875
|
+
}
|
|
6876
|
+
function isUserDefinedSymbolNode(node) {
|
|
6877
|
+
return NodeTypes.UserDefinedSymbol === node[0];
|
|
6878
|
+
}
|
|
6879
|
+
function asUserDefinedSymbolNode(node, sourceCodeInfo) {
|
|
6880
|
+
assertUserDefinedSymbolNode(node, sourceCodeInfo);
|
|
6881
|
+
return node;
|
|
6882
|
+
}
|
|
6883
|
+
function assertUserDefinedSymbolNode(node, sourceCodeInfo) {
|
|
6884
|
+
if (!isUserDefinedSymbolNode(node))
|
|
6885
|
+
throw getAssertionError('UserDefinedSymbolNode', node, sourceCodeInfo);
|
|
6886
|
+
}
|
|
6887
|
+
function isNormalBuiltinSymbolNode(node) {
|
|
6888
|
+
return NodeTypes.NormalBuiltinSymbol === node[0];
|
|
6889
|
+
}
|
|
6890
|
+
function isSpecialBuiltinSymbolNode(node) {
|
|
6891
|
+
return NodeTypes.SpecialBuiltinSymbol === node[0];
|
|
6892
|
+
}
|
|
6893
|
+
function isNormalExpressionNode(node) {
|
|
6894
|
+
return node[0] === NodeTypes.NormalExpression;
|
|
6895
|
+
}
|
|
6896
|
+
function isNormalExpressionNodeWithName(node) {
|
|
6897
|
+
if (!isNormalExpressionNode(node)) {
|
|
6898
|
+
return false;
|
|
6899
|
+
}
|
|
6900
|
+
return isSymbolNode(node[1][0]);
|
|
6901
|
+
}
|
|
6902
|
+
function isSpreadNode(node) {
|
|
6903
|
+
return node[0] === NodeTypes.Spread;
|
|
6904
|
+
}
|
|
6905
|
+
|
|
6906
|
+
function isContextEntry(value) {
|
|
6907
|
+
return isUnknownRecord(value) && value.value !== undefined;
|
|
6908
|
+
}
|
|
6909
|
+
|
|
6910
|
+
class ContextStackImpl {
|
|
6911
|
+
_contexts;
|
|
6912
|
+
globalContext;
|
|
6913
|
+
values;
|
|
6914
|
+
modules;
|
|
6915
|
+
valueModules;
|
|
6916
|
+
pure;
|
|
6917
|
+
constructor({ contexts, values: hostValues, modules, valueModules, pure, }) {
|
|
6918
|
+
this.globalContext = asNonUndefined(contexts[0]);
|
|
6919
|
+
this._contexts = contexts;
|
|
6920
|
+
this.values = hostValues;
|
|
6921
|
+
this.modules = modules ?? new Map();
|
|
6922
|
+
this.valueModules = valueModules ?? new Map();
|
|
6923
|
+
this.pure = pure ?? false;
|
|
6924
|
+
}
|
|
6925
|
+
// -- Serialization support (Phase 4) --
|
|
6926
|
+
/** Get the raw context chain for serialization. */
|
|
6927
|
+
getContextsRaw() {
|
|
6928
|
+
return this._contexts;
|
|
6929
|
+
}
|
|
6930
|
+
/** Get host values (plain bindings passed at creation). */
|
|
6931
|
+
getHostValues() {
|
|
6932
|
+
return this.values;
|
|
6933
|
+
}
|
|
6934
|
+
/** Get the top-level module scope as plain key→value bindings. */
|
|
6935
|
+
getModuleScopeBindings() {
|
|
6936
|
+
const scope = this._contexts[0];
|
|
6937
|
+
const result = {};
|
|
6938
|
+
for (const [k, v] of Object.entries(scope))
|
|
6939
|
+
result[k] = v.value;
|
|
6940
|
+
return result;
|
|
6941
|
+
}
|
|
6942
|
+
/**
|
|
6943
|
+
* Find the index of globalContext in the _contexts array.
|
|
6944
|
+
* Returns -1 if not found (should not happen in valid state).
|
|
6945
|
+
*/
|
|
6946
|
+
getGlobalContextIndex() {
|
|
6947
|
+
return this._contexts.indexOf(this.globalContext);
|
|
6948
|
+
}
|
|
6949
|
+
/**
|
|
6950
|
+
* Create a ContextStack from deserialized data.
|
|
6951
|
+
* `contexts` is the restored context chain (already resolved).
|
|
6952
|
+
* `globalContextIndex` identifies which element is the globalContext.
|
|
6953
|
+
* Host bindings (`values`, `modules`) come from resume options.
|
|
6954
|
+
*/
|
|
6955
|
+
static fromDeserialized(params) {
|
|
6956
|
+
const cs = new ContextStackImpl({
|
|
6957
|
+
contexts: params.contexts,
|
|
6958
|
+
values: params.values,
|
|
6959
|
+
modules: params.modules,
|
|
6960
|
+
pure: params.pure,
|
|
6961
|
+
});
|
|
6962
|
+
if (params.globalContextIndex >= 0 && params.globalContextIndex < params.contexts.length) {
|
|
6963
|
+
cs.globalContext = params.contexts[params.globalContextIndex];
|
|
6964
|
+
}
|
|
6965
|
+
return cs;
|
|
6966
|
+
}
|
|
6967
|
+
/**
|
|
6968
|
+
* Replace the contexts array and globalContext. Used during deserialization
|
|
6969
|
+
* to fill in resolved context data after circular references are handled.
|
|
6970
|
+
*/
|
|
6971
|
+
setContextsFromDeserialized(contexts, globalContextIndex) {
|
|
6972
|
+
this._contexts = contexts;
|
|
6973
|
+
if (globalContextIndex >= 0 && globalContextIndex < contexts.length) {
|
|
6974
|
+
this.globalContext = contexts[globalContextIndex];
|
|
6975
|
+
}
|
|
6976
|
+
}
|
|
6977
|
+
getModule(name) {
|
|
6978
|
+
return this.modules.get(name);
|
|
6979
|
+
}
|
|
6980
|
+
getValueModule(name) {
|
|
6981
|
+
if (this.valueModules.has(name)) {
|
|
6982
|
+
return { value: this.valueModules.get(name), found: true };
|
|
6983
|
+
}
|
|
6984
|
+
return { value: undefined, found: false };
|
|
6985
|
+
}
|
|
6986
|
+
registerValueModule(name, value) {
|
|
6987
|
+
this.valueModules.set(name, value);
|
|
6988
|
+
}
|
|
6989
|
+
create(context) {
|
|
6990
|
+
const globalContext = this.globalContext;
|
|
6991
|
+
const contextStack = new ContextStackImpl({
|
|
6992
|
+
contexts: [context, ...this._contexts],
|
|
6993
|
+
values: this.values,
|
|
6994
|
+
modules: this.modules,
|
|
6995
|
+
valueModules: this.valueModules,
|
|
6996
|
+
pure: this.pure,
|
|
6997
|
+
});
|
|
6998
|
+
contextStack.globalContext = globalContext;
|
|
6999
|
+
return contextStack;
|
|
7000
|
+
}
|
|
7001
|
+
new(context) {
|
|
7002
|
+
const contexts = [{}, context];
|
|
7003
|
+
return new ContextStackImpl({ contexts, modules: this.modules, valueModules: this.valueModules, pure: this.pure });
|
|
7004
|
+
}
|
|
7005
|
+
addValues(values, sourceCodeInfo) {
|
|
7006
|
+
const currentContext = this._contexts[0];
|
|
7007
|
+
for (const [name, value] of Object.entries(values)) {
|
|
7008
|
+
if (currentContext[name]) {
|
|
7009
|
+
throw new DvalaError(`Cannot redefine value "${name}"`, sourceCodeInfo);
|
|
7010
|
+
}
|
|
7011
|
+
const shadowedName = getShadowedBuiltinName(name);
|
|
7012
|
+
if (shadowedName) {
|
|
7013
|
+
throw new DvalaError(`Cannot shadow ${shadowedName}`, sourceCodeInfo);
|
|
7014
|
+
}
|
|
7015
|
+
currentContext[name] = { value: toAny(value) };
|
|
7016
|
+
}
|
|
7017
|
+
}
|
|
7018
|
+
getValue(name) {
|
|
7019
|
+
for (const context of this._contexts) {
|
|
7020
|
+
const contextEntry = context[name];
|
|
7021
|
+
if (contextEntry)
|
|
7022
|
+
return contextEntry.value;
|
|
7023
|
+
}
|
|
7024
|
+
return this.values?.[name];
|
|
7025
|
+
}
|
|
7026
|
+
lookUp(node) {
|
|
7027
|
+
const value = node[1];
|
|
7028
|
+
for (const context of this._contexts) {
|
|
7029
|
+
const contextEntry = context[value];
|
|
7030
|
+
if (contextEntry)
|
|
7031
|
+
return contextEntry;
|
|
7032
|
+
}
|
|
7033
|
+
const hostValue = this.values?.[value];
|
|
7034
|
+
if (hostValue !== undefined) {
|
|
7035
|
+
return {
|
|
7036
|
+
value: toAny(hostValue),
|
|
7037
|
+
};
|
|
7038
|
+
}
|
|
7039
|
+
return null;
|
|
7040
|
+
}
|
|
7041
|
+
evaluateSymbol(node) {
|
|
7042
|
+
if (isSpecialBuiltinSymbolNode(node)) {
|
|
7043
|
+
const functionType = node[1];
|
|
7044
|
+
switch (functionType) {
|
|
7045
|
+
case specialExpressionTypes['&&']:
|
|
7046
|
+
case specialExpressionTypes['||']:
|
|
7047
|
+
case specialExpressionTypes.array:
|
|
7048
|
+
case specialExpressionTypes.object:
|
|
7049
|
+
case specialExpressionTypes['defined?']:
|
|
7050
|
+
case specialExpressionTypes.recur:
|
|
7051
|
+
case specialExpressionTypes['??']: {
|
|
7052
|
+
const specialExpression = asNonUndefined(builtin.specialExpressions[functionType], node[2]);
|
|
7053
|
+
return {
|
|
7054
|
+
[FUNCTION_SYMBOL]: true,
|
|
7055
|
+
functionType: 'SpecialBuiltin',
|
|
7056
|
+
specialBuiltinSymbolType: functionType,
|
|
7057
|
+
sourceCodeInfo: node[2],
|
|
7058
|
+
arity: specialExpression.arity,
|
|
7059
|
+
};
|
|
7060
|
+
}
|
|
7061
|
+
default:
|
|
7062
|
+
throw new DvalaError(`Unknown special builtin symbol type: ${functionType}`, node[2]);
|
|
7063
|
+
}
|
|
7064
|
+
}
|
|
7065
|
+
if (isNormalBuiltinSymbolNode(node)) {
|
|
7066
|
+
const type = node[1];
|
|
7067
|
+
const normalExpression = allNormalExpressions[type];
|
|
7068
|
+
const name = normalExpression.name;
|
|
7069
|
+
return {
|
|
7070
|
+
[FUNCTION_SYMBOL]: true,
|
|
7071
|
+
functionType: 'Builtin',
|
|
7072
|
+
normalBuiltinSymbolType: type,
|
|
7073
|
+
sourceCodeInfo: node[2],
|
|
7074
|
+
arity: normalExpression.arity,
|
|
7075
|
+
name,
|
|
7076
|
+
};
|
|
7077
|
+
}
|
|
7078
|
+
const lookUpResult = this.lookUp(node);
|
|
7079
|
+
if (isContextEntry(lookUpResult))
|
|
7080
|
+
return lookUpResult.value;
|
|
7081
|
+
throw new UndefinedSymbolError(node[1], node[2]);
|
|
7082
|
+
}
|
|
7083
|
+
}
|
|
7084
|
+
function getShadowedBuiltinName(name) {
|
|
7085
|
+
if (specialExpressionKeys.includes(name))
|
|
7086
|
+
return `special expression "${name}"`;
|
|
7087
|
+
if (normalExpressionKeys.includes(name))
|
|
7088
|
+
return `builtin function "${name}"`;
|
|
7089
|
+
if (name === 'self')
|
|
7090
|
+
return `builtin value "${name}"`;
|
|
7091
|
+
return null;
|
|
7092
|
+
}
|
|
7093
|
+
function assertNotShadowingBuiltin(name) {
|
|
7094
|
+
const shadowedName = getShadowedBuiltinName(name);
|
|
7095
|
+
if (shadowedName) {
|
|
7096
|
+
throw new DvalaError(`Cannot shadow ${shadowedName}`, undefined);
|
|
7097
|
+
}
|
|
7098
|
+
}
|
|
7099
|
+
function createContextStack(params = {}, modules, pure) {
|
|
7100
|
+
const globalContext = params.globalContext ?? {};
|
|
7101
|
+
// Contexts are checked from left to right
|
|
7102
|
+
const contexts = params.contexts ? [globalContext, ...params.contexts] : [globalContext];
|
|
7103
|
+
let hostValues;
|
|
7104
|
+
if (params.bindings) {
|
|
7105
|
+
for (const [identifier, entry] of Object.entries(params.bindings)) {
|
|
7106
|
+
if (identifier.includes('.')) {
|
|
7107
|
+
throw new DvalaError(`Dots are not allowed in binding keys: "${identifier}"`, undefined);
|
|
7108
|
+
}
|
|
7109
|
+
assertNotShadowingBuiltin(identifier);
|
|
7110
|
+
if (!hostValues) {
|
|
7111
|
+
hostValues = {};
|
|
7112
|
+
}
|
|
7113
|
+
hostValues[identifier] = entry;
|
|
7114
|
+
}
|
|
7115
|
+
}
|
|
7116
|
+
const contextStack = new ContextStackImpl({
|
|
7117
|
+
contexts,
|
|
7118
|
+
values: hostValues,
|
|
7119
|
+
modules,
|
|
7120
|
+
pure,
|
|
7121
|
+
});
|
|
7122
|
+
return params.globalModuleScope ? contextStack : contextStack.create({});
|
|
7123
|
+
}
|
|
7124
|
+
|
|
7125
|
+
const getUndefinedSymbols$1 = (ast, contextStack, builtin, evaluateNode) => {
|
|
7126
|
+
const nodes = Array.isArray(ast)
|
|
7127
|
+
? ast
|
|
7128
|
+
: [[NodeTypes.SpecialExpression, [specialExpressionTypes.block, ast.body, undefined]]];
|
|
7129
|
+
const unresolvedSymbols = new Set();
|
|
7130
|
+
for (const subNode of nodes) {
|
|
7131
|
+
findUnresolvedSymbolsInNode(subNode, contextStack, builtin, evaluateNode)
|
|
7132
|
+
?.forEach(symbol => unresolvedSymbols.add(symbol));
|
|
7133
|
+
}
|
|
7134
|
+
return unresolvedSymbols;
|
|
7135
|
+
};
|
|
7136
|
+
function findUnresolvedSymbolsInNode(node, contextStack, builtin, evaluateNode) {
|
|
7137
|
+
const nodeType = node[0];
|
|
7138
|
+
switch (nodeType) {
|
|
7139
|
+
case NodeTypes.UserDefinedSymbol: {
|
|
7140
|
+
const symbolNode = node;
|
|
7141
|
+
const lookUpResult = contextStack.lookUp(symbolNode);
|
|
7142
|
+
if (lookUpResult === null)
|
|
7143
|
+
return new Set([symbolNode[1]]);
|
|
7144
|
+
return null;
|
|
7145
|
+
}
|
|
7146
|
+
case NodeTypes.NormalBuiltinSymbol:
|
|
7147
|
+
case NodeTypes.SpecialBuiltinSymbol:
|
|
7148
|
+
case NodeTypes.String:
|
|
7149
|
+
case NodeTypes.Number:
|
|
7150
|
+
case NodeTypes.ReservedSymbol:
|
|
7151
|
+
case NodeTypes.Binding:
|
|
7152
|
+
return null;
|
|
7153
|
+
case NodeTypes.NormalExpression: {
|
|
7154
|
+
const normalExpressionNode = node;
|
|
7155
|
+
const unresolvedSymbols = new Set();
|
|
7156
|
+
if (isNormalExpressionNodeWithName(normalExpressionNode)) {
|
|
7157
|
+
const [, [symbolNode]] = normalExpressionNode;
|
|
7158
|
+
if (isUserDefinedSymbolNode(symbolNode)) {
|
|
7159
|
+
const lookUpResult = contextStack.lookUp(symbolNode);
|
|
7160
|
+
if (lookUpResult === null)
|
|
7161
|
+
unresolvedSymbols.add(symbolNode[1]);
|
|
7162
|
+
}
|
|
7163
|
+
}
|
|
7164
|
+
else {
|
|
7165
|
+
const [, [expressionNode]] = normalExpressionNode;
|
|
7166
|
+
findUnresolvedSymbolsInNode(expressionNode, contextStack, builtin, evaluateNode)?.forEach(symbol => unresolvedSymbols.add(symbol));
|
|
7167
|
+
}
|
|
7168
|
+
for (const subNode of normalExpressionNode[1][1]) {
|
|
7169
|
+
findUnresolvedSymbolsInNode(subNode, contextStack, builtin, evaluateNode)?.forEach(symbol => unresolvedSymbols.add(symbol));
|
|
7170
|
+
}
|
|
7171
|
+
return unresolvedSymbols;
|
|
7172
|
+
}
|
|
7173
|
+
case NodeTypes.SpecialExpression: {
|
|
7174
|
+
const specialExpressionNode = node;
|
|
7175
|
+
const specialExpressionType = specialExpressionNode[1][0];
|
|
7176
|
+
const specialExpression = builtin.specialExpressions[specialExpressionType];
|
|
7177
|
+
const castedGetUndefinedSymbols = specialExpression.getUndefinedSymbols;
|
|
7178
|
+
return castedGetUndefinedSymbols(specialExpressionNode, contextStack, {
|
|
7179
|
+
getUndefinedSymbols: getUndefinedSymbols$1,
|
|
7180
|
+
builtin,
|
|
7181
|
+
evaluateNode,
|
|
7182
|
+
});
|
|
7183
|
+
}
|
|
7184
|
+
case NodeTypes.Spread:
|
|
7185
|
+
return findUnresolvedSymbolsInNode(node[1], contextStack, builtin, evaluateNode);
|
|
7186
|
+
/* v8 ignore next 2 */
|
|
7187
|
+
default:
|
|
7188
|
+
throw new DvalaError(`Unhandled node type: ${nodeType}`, node[2]);
|
|
7189
|
+
}
|
|
7190
|
+
}
|
|
7191
|
+
|
|
7192
|
+
function isSymbolToken(token, symbolName) {
|
|
7193
|
+
if (token?.[0] !== 'Symbol') {
|
|
7194
|
+
return false;
|
|
7195
|
+
}
|
|
7196
|
+
if (symbolName && token[1] !== symbolName) {
|
|
7197
|
+
return false;
|
|
7198
|
+
}
|
|
7199
|
+
return true;
|
|
7200
|
+
}
|
|
7201
|
+
function assertSymbolToken(token, symbolName) {
|
|
7202
|
+
if (!isSymbolToken(token, symbolName)) {
|
|
7203
|
+
throwUnexpectedToken('Symbol', undefined, token);
|
|
7204
|
+
}
|
|
7205
|
+
}
|
|
7206
|
+
function asSymbolToken(token, symbolName) {
|
|
7207
|
+
assertSymbolToken(token, symbolName);
|
|
7208
|
+
return token;
|
|
7209
|
+
}
|
|
7210
|
+
function isReservedSymbolToken(token, symbolName) {
|
|
7211
|
+
if (token?.[0] !== 'ReservedSymbol') {
|
|
7212
|
+
return false;
|
|
7213
|
+
}
|
|
7214
|
+
if (symbolName && token[1] !== symbolName) {
|
|
7215
|
+
return false;
|
|
7216
|
+
}
|
|
7217
|
+
return true;
|
|
7218
|
+
}
|
|
7219
|
+
function assertReservedSymbolToken(token, symbolName) {
|
|
7220
|
+
if (!isReservedSymbolToken(token, symbolName)) {
|
|
7221
|
+
throwUnexpectedToken('ReservedSymbol', symbolName, token);
|
|
7222
|
+
}
|
|
7223
|
+
}
|
|
7224
|
+
function asReservedSymbolToken(token, symbolName) {
|
|
7225
|
+
assertReservedSymbolToken(token, symbolName);
|
|
7226
|
+
return token;
|
|
7227
|
+
}
|
|
7228
|
+
function isShebangToken(token) {
|
|
7229
|
+
return token?.[0] === 'Shebang';
|
|
7230
|
+
}
|
|
7231
|
+
function isSingleLineCommentToken(token) {
|
|
7232
|
+
return token?.[0] === 'SingleLineComment';
|
|
7233
|
+
}
|
|
7234
|
+
function isMultiLineCommentToken(token) {
|
|
7235
|
+
return token?.[0] === 'MultiLineComment';
|
|
7236
|
+
}
|
|
7237
|
+
function isOperatorToken(token, operatorName) {
|
|
7238
|
+
if (token?.[0] !== 'Operator') {
|
|
7239
|
+
return false;
|
|
7240
|
+
}
|
|
7241
|
+
if (operatorName && token[1] !== operatorName) {
|
|
7242
|
+
return false;
|
|
7243
|
+
}
|
|
7244
|
+
return true;
|
|
7245
|
+
}
|
|
7246
|
+
function assertOperatorToken(token, operatorName) {
|
|
7247
|
+
if (!isOperatorToken(token, operatorName)) {
|
|
7248
|
+
throwUnexpectedToken('Operator', operatorName, token);
|
|
7249
|
+
}
|
|
7250
|
+
}
|
|
7251
|
+
function isWhitespaceToken(token) {
|
|
7252
|
+
return token?.[0] === 'Whitespace';
|
|
7253
|
+
}
|
|
7254
|
+
function isNumberToken(token) {
|
|
7255
|
+
return token?.[0] === 'Number';
|
|
7256
|
+
}
|
|
7257
|
+
function isBasePrefixedNumberToken(token) {
|
|
7258
|
+
return token?.[0] === 'BasePrefixedNumber';
|
|
7259
|
+
}
|
|
7260
|
+
function isLParenToken(token) {
|
|
7261
|
+
return token?.[0] === 'LParen';
|
|
7262
|
+
}
|
|
7263
|
+
function assertLParenToken(token) {
|
|
7264
|
+
if (!isLParenToken(token)) {
|
|
7265
|
+
throwUnexpectedToken('LParen', undefined, token);
|
|
7266
|
+
}
|
|
7267
|
+
}
|
|
7268
|
+
function isRParenToken(token) {
|
|
7269
|
+
return token?.[0] === 'RParen';
|
|
7270
|
+
}
|
|
7271
|
+
function assertRParenToken(token) {
|
|
7272
|
+
if (!isRParenToken(token)) {
|
|
7273
|
+
throwUnexpectedToken('RParen', undefined, token);
|
|
7274
|
+
}
|
|
7275
|
+
}
|
|
7276
|
+
function isLBracketToken(token) {
|
|
7277
|
+
return token?.[0] === 'LBracket';
|
|
7278
|
+
}
|
|
7279
|
+
function assertLBracketToken(token) {
|
|
7280
|
+
if (!isLBracketToken(token)) {
|
|
7281
|
+
throwUnexpectedToken('LBracket', undefined, token);
|
|
7282
|
+
}
|
|
7283
|
+
}
|
|
7284
|
+
function asLBracketToken(token) {
|
|
7285
|
+
assertLBracketToken(token);
|
|
7286
|
+
return token;
|
|
7287
|
+
}
|
|
7288
|
+
function isRBracketToken(token) {
|
|
7289
|
+
return token?.[0] === 'RBracket';
|
|
7290
|
+
}
|
|
7291
|
+
function assertRBracketToken(token) {
|
|
7292
|
+
if (!isRBracketToken(token)) {
|
|
7293
|
+
throwUnexpectedToken('RBracket', undefined, token);
|
|
7294
|
+
}
|
|
7295
|
+
}
|
|
7296
|
+
function isLBraceToken(token) {
|
|
7297
|
+
return token?.[0] === 'LBrace';
|
|
7298
|
+
}
|
|
7299
|
+
function assertLBraceToken(token) {
|
|
7300
|
+
if (!isLBraceToken(token)) {
|
|
7301
|
+
throwUnexpectedToken('LBrace', undefined, token);
|
|
7302
|
+
}
|
|
7303
|
+
}
|
|
7304
|
+
function asLBraceToken(token) {
|
|
6510
7305
|
assertLBraceToken(token);
|
|
6511
7306
|
return token;
|
|
6512
7307
|
}
|
|
@@ -6521,9 +7316,6 @@ function assertRBraceToken(token) {
|
|
|
6521
7316
|
function isStringToken(token) {
|
|
6522
7317
|
return token?.[0] === 'string';
|
|
6523
7318
|
}
|
|
6524
|
-
function isDocStringToken(token) {
|
|
6525
|
-
return token?.[0] === 'DocString';
|
|
6526
|
-
}
|
|
6527
7319
|
function isA_BinaryOperatorToken(token) {
|
|
6528
7320
|
return token?.[0] === 'Operator' && isBinaryOperator(token[1]);
|
|
6529
7321
|
}
|
|
@@ -6799,49 +7591,9 @@ function parseCond(ctx, token) {
|
|
|
6799
7591
|
return withSourceCodeInfo([NodeTypes.SpecialExpression, [specialExpressionTypes.cond, params]], token[2]);
|
|
6800
7592
|
}
|
|
6801
7593
|
|
|
6802
|
-
function
|
|
6803
|
-
ctx.advance();
|
|
6804
|
-
const value = token[1].substring(1, token[1].length - 1)
|
|
6805
|
-
.replace(/(\\{2})|(\\")|(\\n)|(\\t)|(\\r)|(\\b)|(\\f)|\\(.)/g, (_, backslash, doubleQuote, newline, tab, carriageReturn, backspace, formFeed, normalChar) => {
|
|
6806
|
-
// If it's a double escape (\\x), return \x
|
|
6807
|
-
if (backslash) {
|
|
6808
|
-
return '\\';
|
|
6809
|
-
}
|
|
6810
|
-
// If it's a special character (\n, \t, \r, \b, \f), return the special character
|
|
6811
|
-
else if (newline) {
|
|
6812
|
-
return '\n';
|
|
6813
|
-
}
|
|
6814
|
-
else if (tab) {
|
|
6815
|
-
return '\t';
|
|
6816
|
-
}
|
|
6817
|
-
else if (carriageReturn) {
|
|
6818
|
-
return '\r';
|
|
6819
|
-
}
|
|
6820
|
-
else if (backspace) {
|
|
6821
|
-
return '\b';
|
|
6822
|
-
}
|
|
6823
|
-
else if (formFeed) {
|
|
6824
|
-
return '\f';
|
|
6825
|
-
}
|
|
6826
|
-
else if (doubleQuote) {
|
|
6827
|
-
return '"';
|
|
6828
|
-
}
|
|
6829
|
-
return normalChar;
|
|
6830
|
-
});
|
|
6831
|
-
return withSourceCodeInfo([NodeTypes.String, value], token[2]);
|
|
6832
|
-
}
|
|
6833
|
-
|
|
6834
|
-
function parseDo(ctx, allowDocString = false) {
|
|
7594
|
+
function parseDo(ctx) {
|
|
6835
7595
|
const token = asReservedSymbolToken(ctx.tryPeek(), 'do');
|
|
6836
7596
|
ctx.advance();
|
|
6837
|
-
let docString = '';
|
|
6838
|
-
if (allowDocString && isDocStringToken(ctx.tryPeek())) {
|
|
6839
|
-
docString = parseDocString(ctx);
|
|
6840
|
-
if (!ctx.isAtEnd() && !isReservedSymbolToken(ctx.tryPeek(), 'end') && !isReservedSymbolToken(ctx.tryPeek(), 'with')) {
|
|
6841
|
-
assertOperatorToken(ctx.tryPeek(), ';');
|
|
6842
|
-
ctx.advance();
|
|
6843
|
-
}
|
|
6844
|
-
}
|
|
6845
7597
|
const expressions = [];
|
|
6846
7598
|
while (!ctx.isAtEnd() && !isReservedSymbolToken(ctx.tryPeek(), 'end') && !isReservedSymbolToken(ctx.tryPeek(), 'with')) {
|
|
6847
7599
|
expressions.push(ctx.parseExpression());
|
|
@@ -6869,16 +7621,7 @@ function parseDo(ctx, allowDocString = false) {
|
|
|
6869
7621
|
}
|
|
6870
7622
|
assertReservedSymbolToken(ctx.tryPeek(), 'end');
|
|
6871
7623
|
ctx.advance();
|
|
6872
|
-
return [
|
|
6873
|
-
withSourceCodeInfo([NodeTypes.SpecialExpression, [specialExpressionTypes.block, expressions, withHandlers]], token[2]),
|
|
6874
|
-
docString,
|
|
6875
|
-
];
|
|
6876
|
-
}
|
|
6877
|
-
function parseDocString(ctx) {
|
|
6878
|
-
const token = ctx.peek();
|
|
6879
|
-
const stringToken = token[2] ? ['string', token[1].slice(2, -2), token[2]] : ['string', token[1].slice(2, -2)];
|
|
6880
|
-
const stringNode = parseString(ctx, stringToken);
|
|
6881
|
-
return smartTrim(stringNode[1]); // Extract the string value from the StringNode
|
|
7624
|
+
return withSourceCodeInfo([NodeTypes.SpecialExpression, [specialExpressionTypes.block, expressions, withHandlers]], token[2]);
|
|
6882
7625
|
}
|
|
6883
7626
|
|
|
6884
7627
|
function parseSymbol(ctx) {
|
|
@@ -6895,6 +7638,38 @@ function parseSymbol(ctx) {
|
|
|
6895
7638
|
}
|
|
6896
7639
|
}
|
|
6897
7640
|
|
|
7641
|
+
function parseString(ctx, token) {
|
|
7642
|
+
ctx.advance();
|
|
7643
|
+
const value = token[1].substring(1, token[1].length - 1)
|
|
7644
|
+
.replace(/(\\{2})|(\\")|(\\n)|(\\t)|(\\r)|(\\b)|(\\f)|\\(.)/g, (_, backslash, doubleQuote, newline, tab, carriageReturn, backspace, formFeed, normalChar) => {
|
|
7645
|
+
// If it's a double escape (\\x), return \x
|
|
7646
|
+
if (backslash) {
|
|
7647
|
+
return '\\';
|
|
7648
|
+
}
|
|
7649
|
+
// If it's a special character (\n, \t, \r, \b, \f), return the special character
|
|
7650
|
+
else if (newline) {
|
|
7651
|
+
return '\n';
|
|
7652
|
+
}
|
|
7653
|
+
else if (tab) {
|
|
7654
|
+
return '\t';
|
|
7655
|
+
}
|
|
7656
|
+
else if (carriageReturn) {
|
|
7657
|
+
return '\r';
|
|
7658
|
+
}
|
|
7659
|
+
else if (backspace) {
|
|
7660
|
+
return '\b';
|
|
7661
|
+
}
|
|
7662
|
+
else if (formFeed) {
|
|
7663
|
+
return '\f';
|
|
7664
|
+
}
|
|
7665
|
+
else if (doubleQuote) {
|
|
7666
|
+
return '"';
|
|
7667
|
+
}
|
|
7668
|
+
return normalChar;
|
|
7669
|
+
});
|
|
7670
|
+
return withSourceCodeInfo([NodeTypes.String, value], token[2]);
|
|
7671
|
+
}
|
|
7672
|
+
|
|
6898
7673
|
function parseNumber(ctx) {
|
|
6899
7674
|
const token = ctx.peek();
|
|
6900
7675
|
ctx.advance();
|
|
@@ -7268,56 +8043,6 @@ function parseRegexpShorthand(ctx) {
|
|
|
7268
8043
|
return node;
|
|
7269
8044
|
}
|
|
7270
8045
|
|
|
7271
|
-
const nonNumberReservedSymbolRecord = {
|
|
7272
|
-
true: true,
|
|
7273
|
-
false: false,
|
|
7274
|
-
null: null,
|
|
7275
|
-
do: null,
|
|
7276
|
-
else: null,
|
|
7277
|
-
case: null,
|
|
7278
|
-
each: null,
|
|
7279
|
-
in: null,
|
|
7280
|
-
when: null,
|
|
7281
|
-
while: null,
|
|
7282
|
-
function: null,
|
|
7283
|
-
as: null,
|
|
7284
|
-
then: null,
|
|
7285
|
-
end: null,
|
|
7286
|
-
with: null,
|
|
7287
|
-
_: null,
|
|
7288
|
-
};
|
|
7289
|
-
const phi = (1 + Math.sqrt(5)) / 2;
|
|
7290
|
-
const numberReservedSymbolRecord = {
|
|
7291
|
-
'E': Math.E,
|
|
7292
|
-
'-E': -Math.E,
|
|
7293
|
-
'ε': Math.E,
|
|
7294
|
-
'-ε': -Math.E,
|
|
7295
|
-
'PI': Math.PI,
|
|
7296
|
-
'-PI': -Math.PI,
|
|
7297
|
-
'π': Math.PI,
|
|
7298
|
-
'-π': -Math.PI,
|
|
7299
|
-
'PHI': phi,
|
|
7300
|
-
'-PHI': -phi,
|
|
7301
|
-
'φ': phi,
|
|
7302
|
-
'-φ': -phi,
|
|
7303
|
-
'POSITIVE_INFINITY': Number.POSITIVE_INFINITY,
|
|
7304
|
-
'∞': Number.POSITIVE_INFINITY,
|
|
7305
|
-
'NEGATIVE_INFINITY': Number.NEGATIVE_INFINITY,
|
|
7306
|
-
'-∞': Number.NEGATIVE_INFINITY,
|
|
7307
|
-
'MAX_SAFE_INTEGER': Number.MAX_SAFE_INTEGER,
|
|
7308
|
-
'MIN_SAFE_INTEGER': Number.MIN_SAFE_INTEGER,
|
|
7309
|
-
'MAX_VALUE': Number.MAX_VALUE,
|
|
7310
|
-
'MIN_VALUE': Number.MIN_VALUE,
|
|
7311
|
-
'NaN': Number.NaN,
|
|
7312
|
-
};
|
|
7313
|
-
const reservedSymbolRecord = {
|
|
7314
|
-
...nonNumberReservedSymbolRecord,
|
|
7315
|
-
...numberReservedSymbolRecord,
|
|
7316
|
-
};
|
|
7317
|
-
function isNumberReservedSymbol(symbol) {
|
|
7318
|
-
return symbol in numberReservedSymbolRecord;
|
|
7319
|
-
}
|
|
7320
|
-
|
|
7321
8046
|
function parseReservedSymbol(ctx) {
|
|
7322
8047
|
const token = asReservedSymbolToken(ctx.tryPeek());
|
|
7323
8048
|
ctx.advance();
|
|
@@ -7369,11 +8094,8 @@ function parseLambdaFunction(ctx) {
|
|
|
7369
8094
|
}
|
|
7370
8095
|
ctx.advance();
|
|
7371
8096
|
let nodes;
|
|
7372
|
-
let docString = '';
|
|
7373
8097
|
if (isReservedSymbolToken(ctx.peek(), 'do')) {
|
|
7374
|
-
const
|
|
7375
|
-
docString = parsedDo[1];
|
|
7376
|
-
const doNode = parsedDo[0];
|
|
8098
|
+
const doNode = parseDo(ctx);
|
|
7377
8099
|
const withHandlers = doNode[1][2];
|
|
7378
8100
|
if (withHandlers && withHandlers.length > 0) {
|
|
7379
8101
|
// do...with...end: preserve the full DoNode as a single expression so
|
|
@@ -7396,7 +8118,6 @@ function parseLambdaFunction(ctx) {
|
|
|
7396
8118
|
functionArguments,
|
|
7397
8119
|
nodes,
|
|
7398
8120
|
],
|
|
7399
|
-
docString,
|
|
7400
8121
|
],
|
|
7401
8122
|
], firstToken[2]);
|
|
7402
8123
|
}
|
|
@@ -7448,11 +8169,8 @@ function parseShorthandLambdaFunction(ctx) {
|
|
|
7448
8169
|
// TODO, do not like this...
|
|
7449
8170
|
const startPos = ctx.getPosition();
|
|
7450
8171
|
let nodes;
|
|
7451
|
-
let docString = '';
|
|
7452
8172
|
if (isReservedSymbolToken(ctx.peek(), 'do')) {
|
|
7453
|
-
const
|
|
7454
|
-
docString = parsedDo[1];
|
|
7455
|
-
const doNode = parsedDo[0];
|
|
8173
|
+
const doNode = parseDo(ctx);
|
|
7456
8174
|
const withHandlers = doNode[1][2];
|
|
7457
8175
|
if (withHandlers && withHandlers.length > 0) {
|
|
7458
8176
|
// do...with...end: preserve the full DoNode so the with-handlers are not lost.
|
|
@@ -7499,7 +8217,7 @@ function parseShorthandLambdaFunction(ctx) {
|
|
|
7499
8217
|
const node = withSourceCodeInfo([NodeTypes.SpecialExpression, [specialExpressionTypes['0_lambda'], [
|
|
7500
8218
|
functionArguments,
|
|
7501
8219
|
nodes,
|
|
7502
|
-
]
|
|
8220
|
+
]]], firstToken[2]);
|
|
7503
8221
|
return node;
|
|
7504
8222
|
}
|
|
7505
8223
|
|
|
@@ -7780,575 +8498,141 @@ function parseMatch(ctx, token) {
|
|
|
7780
8498
|
ctx.advance();
|
|
7781
8499
|
guard = ctx.parseExpression();
|
|
7782
8500
|
}
|
|
7783
|
-
assertReservedSymbolToken(ctx.tryPeek(), 'then');
|
|
7784
|
-
ctx.advance();
|
|
7785
|
-
const thenExpression = parseImplicitBlock(ctx, ['case', 'end']);
|
|
7786
|
-
params.push([pattern, thenExpression, guard]);
|
|
7787
|
-
if (isReservedSymbolToken(ctx.tryPeek(), 'end')) {
|
|
7788
|
-
break;
|
|
7789
|
-
}
|
|
7790
|
-
}
|
|
7791
|
-
assertReservedSymbolToken(ctx.tryPeek(), 'end');
|
|
7792
|
-
ctx.advance();
|
|
7793
|
-
return withSourceCodeInfo([NodeTypes.SpecialExpression, [specialExpressionTypes.match, valueExpression, params]], token[2]);
|
|
7794
|
-
}
|
|
7795
|
-
|
|
7796
|
-
function createParserContext(tokenStream) {
|
|
7797
|
-
const ctx = new ParserContext(tokenStream);
|
|
7798
|
-
ctx.parseExpression = (precedence = 0) => parseExpression(ctx, precedence);
|
|
7799
|
-
return ctx;
|
|
7800
|
-
}
|
|
7801
|
-
function parseExpression(ctx, precedence = 0) {
|
|
7802
|
-
const token = ctx.tryPeek();
|
|
7803
|
-
let left;
|
|
7804
|
-
if (isSymbolToken(token)) {
|
|
7805
|
-
switch (token[1]) {
|
|
7806
|
-
case 'let':
|
|
7807
|
-
return parseLet(ctx, token);
|
|
7808
|
-
case 'if':
|
|
7809
|
-
case 'unless':
|
|
7810
|
-
left = parseIfOrUnless(ctx, token);
|
|
7811
|
-
break;
|
|
7812
|
-
case 'cond':
|
|
7813
|
-
left = parseCond(ctx, token);
|
|
7814
|
-
break;
|
|
7815
|
-
case 'match':
|
|
7816
|
-
left = parseMatch(ctx, token);
|
|
7817
|
-
break;
|
|
7818
|
-
case 'for':
|
|
7819
|
-
case 'doseq':
|
|
7820
|
-
left = parseForOrDoseq(ctx, token);
|
|
7821
|
-
break;
|
|
7822
|
-
case 'loop':
|
|
7823
|
-
left = parseLoop(ctx, token);
|
|
7824
|
-
break;
|
|
7825
|
-
}
|
|
7826
|
-
}
|
|
7827
|
-
else if (isReservedSymbolToken(token, 'do')) {
|
|
7828
|
-
left = parseDo(ctx)[0];
|
|
7829
|
-
}
|
|
7830
|
-
left ||= parseOperand(ctx);
|
|
7831
|
-
let operator = ctx.tryPeek();
|
|
7832
|
-
while (!isAtExpressionEnd(ctx)) {
|
|
7833
|
-
if (isA_BinaryOperatorToken(operator)) {
|
|
7834
|
-
const name = operator[1];
|
|
7835
|
-
const newPrecedece = getPrecedence(name, operator[2]);
|
|
7836
|
-
if (newPrecedece <= precedence
|
|
7837
|
-
// ^ (exponentiation) is right associative
|
|
7838
|
-
&& !(newPrecedece === exponentiationPrecedence && precedence === exponentiationPrecedence)) {
|
|
7839
|
-
break;
|
|
7840
|
-
}
|
|
7841
|
-
const symbol = specialExpressionTypes[name]
|
|
7842
|
-
? withSourceCodeInfo([NodeTypes.SpecialBuiltinSymbol, specialExpressionTypes[name]], operator[2])
|
|
7843
|
-
: withSourceCodeInfo([NodeTypes.NormalBuiltinSymbol, normalExpressionTypes[name]], operator[2]);
|
|
7844
|
-
ctx.advance();
|
|
7845
|
-
const right = parseExpression(ctx, newPrecedece);
|
|
7846
|
-
left = fromBinaryOperatorToNode(operator, symbol, left, right, operator[2]);
|
|
7847
|
-
}
|
|
7848
|
-
else if (isSymbolToken(operator)) {
|
|
7849
|
-
if (!isFunctionOperator(operator[1])) {
|
|
7850
|
-
break;
|
|
7851
|
-
}
|
|
7852
|
-
const newPrecedence = binaryFunctionalOperatorPrecedence;
|
|
7853
|
-
if (newPrecedence <= precedence) {
|
|
7854
|
-
break;
|
|
7855
|
-
}
|
|
7856
|
-
const operatorSymbol = parseSymbol(ctx);
|
|
7857
|
-
const right = parseExpression(ctx, newPrecedence);
|
|
7858
|
-
if (isSpecialBuiltinSymbolNode(operatorSymbol)) {
|
|
7859
|
-
throw new DvalaError('Special expressions are not allowed in binary functional operators', operatorSymbol[2]);
|
|
7860
|
-
}
|
|
7861
|
-
left = createNamedNormalExpressionNode(operatorSymbol, [left, right], operator[2]);
|
|
7862
|
-
}
|
|
7863
|
-
else if (operator?.[1] === '?') {
|
|
7864
|
-
if (conditionalOperatorPrecedence <= precedence) {
|
|
7865
|
-
break;
|
|
7866
|
-
}
|
|
7867
|
-
ctx.advance();
|
|
7868
|
-
const trueNode = parseExpression(ctx);
|
|
7869
|
-
if (!isOperatorToken(ctx.tryPeek(), ':')) {
|
|
7870
|
-
throw new DvalaError('Expected :', ctx.peekSourceCodeInfo());
|
|
7871
|
-
}
|
|
7872
|
-
ctx.advance();
|
|
7873
|
-
const falseNode = parseExpression(ctx);
|
|
7874
|
-
left = withSourceCodeInfo([NodeTypes.SpecialExpression, [specialExpressionTypes.if, [left, trueNode, falseNode]]], left[2]);
|
|
7875
|
-
}
|
|
7876
|
-
else {
|
|
7877
|
-
break;
|
|
7878
|
-
}
|
|
7879
|
-
operator = ctx.tryPeek();
|
|
7880
|
-
}
|
|
7881
|
-
return left;
|
|
7882
|
-
}
|
|
7883
|
-
|
|
7884
|
-
function parse(tokenStream) {
|
|
7885
|
-
tokenStream.tokens.forEach((token) => {
|
|
7886
|
-
if (token[0] === 'Error') {
|
|
7887
|
-
throw new DvalaError(token[3], token[2]);
|
|
7888
|
-
}
|
|
7889
|
-
});
|
|
7890
|
-
const nodes = [];
|
|
7891
|
-
const ctx = createParserContext(tokenStream);
|
|
7892
|
-
while (!ctx.isAtEnd()) {
|
|
7893
|
-
nodes.push(parseExpression(ctx, 0));
|
|
7894
|
-
if (isOperatorToken(ctx.tryPeek(), ';')) {
|
|
7895
|
-
ctx.advance();
|
|
7896
|
-
}
|
|
7897
|
-
else {
|
|
7898
|
-
if (!ctx.isAtEnd()) {
|
|
7899
|
-
throw new DvalaError('Expected ;', ctx.peekSourceCodeInfo());
|
|
7900
|
-
}
|
|
7901
|
-
}
|
|
7902
|
-
}
|
|
7903
|
-
return nodes;
|
|
7904
|
-
}
|
|
7905
|
-
|
|
7906
|
-
function minifyTokenStream(tokenStream, { removeWhiteSpace }) {
|
|
7907
|
-
const tokens = tokenStream.tokens
|
|
7908
|
-
.filter((token) => {
|
|
7909
|
-
if (isSingleLineCommentToken(token)
|
|
7910
|
-
|| isMultiLineCommentToken(token)
|
|
7911
|
-
|| isShebangToken(token)
|
|
7912
|
-
|| (removeWhiteSpace && isWhitespaceToken(token))) {
|
|
7913
|
-
return false;
|
|
7914
|
-
}
|
|
7915
|
-
return true;
|
|
7916
|
-
});
|
|
7917
|
-
return { ...tokenStream, tokens };
|
|
7918
|
-
}
|
|
7919
|
-
|
|
7920
|
-
const illegalSymbolCharacters = [
|
|
7921
|
-
'(',
|
|
7922
|
-
')',
|
|
7923
|
-
'[',
|
|
7924
|
-
']',
|
|
7925
|
-
'{',
|
|
7926
|
-
'}',
|
|
7927
|
-
'\'',
|
|
7928
|
-
'"',
|
|
7929
|
-
'`',
|
|
7930
|
-
',',
|
|
7931
|
-
'.',
|
|
7932
|
-
';',
|
|
7933
|
-
' ',
|
|
7934
|
-
'\n',
|
|
7935
|
-
'\r',
|
|
7936
|
-
'\t',
|
|
7937
|
-
];
|
|
7938
|
-
const illegalFirstSymbolCharacters = [
|
|
7939
|
-
'0',
|
|
7940
|
-
'1',
|
|
7941
|
-
'2',
|
|
7942
|
-
'3',
|
|
7943
|
-
'4',
|
|
7944
|
-
'5',
|
|
7945
|
-
'6',
|
|
7946
|
-
'7',
|
|
7947
|
-
'8',
|
|
7948
|
-
'9',
|
|
7949
|
-
...illegalSymbolCharacters,
|
|
7950
|
-
];
|
|
7951
|
-
const illegalSymbolCharacterSet = new Set(illegalSymbolCharacters);
|
|
7952
|
-
const illegalFirstSymbolCharacterSet = new Set(illegalFirstSymbolCharacters);
|
|
7953
|
-
const whitespaceRegExp = /\s/;
|
|
7954
|
-
const NO_MATCH = [0];
|
|
7955
|
-
const tokenizeLParen = (input, position) => tokenizeToken('LParen', '(', input, position);
|
|
7956
|
-
const tokenizeRParen = (input, position) => tokenizeToken('RParen', ')', input, position);
|
|
7957
|
-
const tokenizeLBracket = (input, position) => tokenizeToken('LBracket', '[', input, position);
|
|
7958
|
-
const tokenizeRBracket = (input, position) => tokenizeToken('RBracket', ']', input, position);
|
|
7959
|
-
const tokenizeLBrace = (input, position) => tokenizeToken('LBrace', '{', input, position);
|
|
7960
|
-
const tokenizeRBrace = (input, position) => tokenizeToken('RBrace', '}', input, position);
|
|
7961
|
-
const tokenizeDocString = (input, position) => {
|
|
7962
|
-
if (input[position] !== '"' || input[position + 1] !== '"' || input[position + 2] !== '"')
|
|
7963
|
-
return NO_MATCH;
|
|
7964
|
-
let value = '"""';
|
|
7965
|
-
let length = 3;
|
|
7966
|
-
let char = input[position + length];
|
|
7967
|
-
let nextThreeChars = input.slice(position + length, position + length + 3);
|
|
7968
|
-
let escaping = false;
|
|
7969
|
-
while (char && (nextThreeChars !== '"""' || escaping)) {
|
|
7970
|
-
length += 1;
|
|
7971
|
-
if (escaping) {
|
|
7972
|
-
escaping = false;
|
|
7973
|
-
value += char;
|
|
7974
|
-
}
|
|
7975
|
-
else {
|
|
7976
|
-
if (char === '\\') {
|
|
7977
|
-
escaping = true;
|
|
7978
|
-
}
|
|
7979
|
-
value += char;
|
|
7980
|
-
}
|
|
7981
|
-
char = input[position + length];
|
|
7982
|
-
nextThreeChars = input.slice(position + length, position + length + 3);
|
|
7983
|
-
}
|
|
7984
|
-
if (!char) {
|
|
7985
|
-
return [length, ['Error', value, undefined, `Unclosed doc string at position ${position}`]];
|
|
7986
|
-
}
|
|
7987
|
-
value += '"""'; // closing quote
|
|
7988
|
-
return [length + 3, ['DocString', value]];
|
|
7989
|
-
};
|
|
7990
|
-
const tokenizeString = (input, position) => {
|
|
7991
|
-
if (input[position] !== '"')
|
|
7992
|
-
return NO_MATCH;
|
|
7993
|
-
let value = '"';
|
|
7994
|
-
let length = 1;
|
|
7995
|
-
let char = input[position + length];
|
|
7996
|
-
let escaping = false;
|
|
7997
|
-
while (char && (char !== '"' || escaping)) {
|
|
7998
|
-
length += 1;
|
|
7999
|
-
if (escaping) {
|
|
8000
|
-
escaping = false;
|
|
8001
|
-
value += char;
|
|
8002
|
-
}
|
|
8003
|
-
else {
|
|
8004
|
-
if (char === '\\') {
|
|
8005
|
-
escaping = true;
|
|
8006
|
-
}
|
|
8007
|
-
value += char;
|
|
8008
|
-
}
|
|
8009
|
-
char = input[position + length];
|
|
8010
|
-
}
|
|
8011
|
-
if (!char) {
|
|
8012
|
-
return [length, ['Error', value, undefined, `Unclosed string at position ${position}`]];
|
|
8013
|
-
}
|
|
8014
|
-
value += '"'; // closing quote
|
|
8015
|
-
return [length + 1, ['string', value]];
|
|
8016
|
-
};
|
|
8017
|
-
const tokenizeRegexpShorthand = (input, position) => {
|
|
8018
|
-
if (input[position] !== '#')
|
|
8019
|
-
return NO_MATCH;
|
|
8020
|
-
const [stringLength, token] = tokenizeString(input, position + 1);
|
|
8021
|
-
if (!token)
|
|
8022
|
-
return NO_MATCH;
|
|
8023
|
-
if (token[0] === 'Error') {
|
|
8024
|
-
const errorToken = ['Error', `#${token[1]}`, undefined, `Unclosed regexp at position ${position}`];
|
|
8025
|
-
return [stringLength + 1, errorToken];
|
|
8026
|
-
}
|
|
8027
|
-
position += stringLength + 1;
|
|
8028
|
-
let length = stringLength + 1;
|
|
8029
|
-
let options = '';
|
|
8030
|
-
while (input[position] === 'g' || input[position] === 'i') {
|
|
8031
|
-
options += input[position];
|
|
8032
|
-
length += 1;
|
|
8033
|
-
position += 1;
|
|
8034
|
-
if (options.includes(input[position])) {
|
|
8035
|
-
return [length, ['Error', `#${token[1]}${options}`, undefined, `Duplicated regexp option "${input[position]}"`]];
|
|
8036
|
-
}
|
|
8037
|
-
}
|
|
8038
|
-
return [length, ['RegexpShorthand', `#${token[1]}${options}`]];
|
|
8039
|
-
};
|
|
8040
|
-
function tokenizeToken(type, value, input, position) {
|
|
8041
|
-
if (value === input.slice(position, position + value.length))
|
|
8042
|
-
return [value.length, [type, value]];
|
|
8043
|
-
else
|
|
8044
|
-
return NO_MATCH;
|
|
8045
|
-
}
|
|
8046
|
-
const tokenizeWhitespace = (input, position) => {
|
|
8047
|
-
let char = input[position];
|
|
8048
|
-
if (!char || !whitespaceRegExp.test(char)) {
|
|
8049
|
-
return NO_MATCH;
|
|
8050
|
-
}
|
|
8051
|
-
let value = char;
|
|
8052
|
-
position += 1;
|
|
8053
|
-
char = input[position];
|
|
8054
|
-
while (char && whitespaceRegExp.test(char)) {
|
|
8055
|
-
value += char;
|
|
8056
|
-
position += 1;
|
|
8057
|
-
char = input[position];
|
|
8058
|
-
}
|
|
8059
|
-
return [value.length, ['Whitespace', value]];
|
|
8060
|
-
};
|
|
8061
|
-
const decimalNumberRegExp = /\d/;
|
|
8062
|
-
const octalNumberRegExp = /[0-7]/;
|
|
8063
|
-
const hexNumberRegExp = /[0-9a-f]/i;
|
|
8064
|
-
const binaryNumberRegExp = /[01]/;
|
|
8065
|
-
const postNumberRegExp = /[\s)\]}(,;]/;
|
|
8066
|
-
const tokenizeNumber = (input, position) => {
|
|
8067
|
-
let i;
|
|
8068
|
-
const negate = input[position] === '-';
|
|
8069
|
-
const plusPrefix = input[position] === '+';
|
|
8070
|
-
const start = negate || plusPrefix ? position + 1 : position;
|
|
8071
|
-
let hasDecimalPoint = false;
|
|
8072
|
-
let hasExponent = false;
|
|
8073
|
-
for (i = start; i < input.length; i += 1) {
|
|
8074
|
-
const char = input[i];
|
|
8075
|
-
if (char === '_') {
|
|
8076
|
-
if (!decimalNumberRegExp.test(input[i - 1]) || !decimalNumberRegExp.test(input[i + 1])) {
|
|
8077
|
-
if (i === start) {
|
|
8078
|
-
return NO_MATCH;
|
|
8079
|
-
}
|
|
8080
|
-
return [i - position + 1, ['Error', input.substring(position, i + 1), undefined, `Invalid number format at position ${i + 1}`]];
|
|
8081
|
-
}
|
|
8082
|
-
}
|
|
8083
|
-
else if (char === '.') {
|
|
8084
|
-
if (i === start) {
|
|
8085
|
-
return NO_MATCH;
|
|
8086
|
-
}
|
|
8087
|
-
if (hasDecimalPoint || hasExponent) {
|
|
8088
|
-
return [i - position + 1, ['Error', input.substring(position, i + 1), undefined, `Invalid number format at position ${i + 1}`]];
|
|
8089
|
-
}
|
|
8090
|
-
hasDecimalPoint = true;
|
|
8091
|
-
}
|
|
8092
|
-
else if (char === 'e' || char === 'E') {
|
|
8093
|
-
if (i === start) {
|
|
8094
|
-
return NO_MATCH;
|
|
8095
|
-
}
|
|
8096
|
-
if (hasExponent) {
|
|
8097
|
-
return [i - position + 1, ['Error', input.substring(position, i + 1), undefined, `Invalid number format at position ${i + 1}`]];
|
|
8098
|
-
}
|
|
8099
|
-
if (input[i - 1] === '.' || input[i - 1] === '+' || input[i - 1] === '-') {
|
|
8100
|
-
return [i - position + 1, ['Error', input.substring(position, i + 1), undefined, `Invalid number format at position ${i + 1}`]];
|
|
8101
|
-
}
|
|
8102
|
-
if (input[i + 1] === '+' || input[i + 1] === '-') {
|
|
8103
|
-
i += 1;
|
|
8104
|
-
}
|
|
8105
|
-
hasExponent = true;
|
|
8106
|
-
}
|
|
8107
|
-
else if (!decimalNumberRegExp.test(char)) {
|
|
8108
|
-
break;
|
|
8109
|
-
}
|
|
8110
|
-
}
|
|
8111
|
-
if ((negate || plusPrefix) && i === start) {
|
|
8112
|
-
return NO_MATCH;
|
|
8113
|
-
}
|
|
8114
|
-
const length = i - position;
|
|
8115
|
-
if (length === 0) {
|
|
8116
|
-
return NO_MATCH;
|
|
8117
|
-
}
|
|
8118
|
-
const nextChar = input[i];
|
|
8119
|
-
if (nextChar && nextChar !== ':' && !postNumberRegExp.test(nextChar)) {
|
|
8120
|
-
return [i - position + 1, ['Error', input.substring(position, i + 1), undefined, `Invalid number format at position ${i + 1}`]];
|
|
8121
|
-
}
|
|
8122
|
-
return [length, ['Number', input.substring(position, i)]];
|
|
8123
|
-
};
|
|
8124
|
-
const tokenizeBasePrefixedNumber = (input, position) => {
|
|
8125
|
-
if (input[position] !== '0') {
|
|
8126
|
-
return NO_MATCH;
|
|
8127
|
-
}
|
|
8128
|
-
const baseChar = input[position + 1];
|
|
8129
|
-
const type = baseChar === 'b' || baseChar === 'B'
|
|
8130
|
-
? 'binary'
|
|
8131
|
-
: baseChar === 'o' || baseChar === 'O'
|
|
8132
|
-
? 'octal'
|
|
8133
|
-
: baseChar === 'x' || baseChar === 'X'
|
|
8134
|
-
? 'hex'
|
|
8135
|
-
: null;
|
|
8136
|
-
if (type === null) {
|
|
8137
|
-
return NO_MATCH;
|
|
8138
|
-
}
|
|
8139
|
-
let i;
|
|
8140
|
-
for (i = position + 2; i < input.length; i += 1) {
|
|
8141
|
-
const char = input[i];
|
|
8142
|
-
if (type === 'binary' && !binaryNumberRegExp.test(char)) {
|
|
8143
|
-
break;
|
|
8144
|
-
}
|
|
8145
|
-
if (type === 'octal' && !octalNumberRegExp.test(char)) {
|
|
8146
|
-
break;
|
|
8147
|
-
}
|
|
8148
|
-
if (type === 'hex' && !hexNumberRegExp.test(char)) {
|
|
8501
|
+
assertReservedSymbolToken(ctx.tryPeek(), 'then');
|
|
8502
|
+
ctx.advance();
|
|
8503
|
+
const thenExpression = parseImplicitBlock(ctx, ['case', 'end']);
|
|
8504
|
+
params.push([pattern, thenExpression, guard]);
|
|
8505
|
+
if (isReservedSymbolToken(ctx.tryPeek(), 'end')) {
|
|
8149
8506
|
break;
|
|
8150
8507
|
}
|
|
8151
8508
|
}
|
|
8152
|
-
|
|
8153
|
-
|
|
8154
|
-
|
|
8509
|
+
assertReservedSymbolToken(ctx.tryPeek(), 'end');
|
|
8510
|
+
ctx.advance();
|
|
8511
|
+
return withSourceCodeInfo([NodeTypes.SpecialExpression, [specialExpressionTypes.match, valueExpression, params]], token[2]);
|
|
8512
|
+
}
|
|
8513
|
+
|
|
8514
|
+
function createParserContext(tokenStream) {
|
|
8515
|
+
const ctx = new ParserContext(tokenStream);
|
|
8516
|
+
ctx.parseExpression = (precedence = 0) => parseExpression(ctx, precedence);
|
|
8517
|
+
return ctx;
|
|
8518
|
+
}
|
|
8519
|
+
function parseExpression(ctx, precedence = 0) {
|
|
8520
|
+
const token = ctx.tryPeek();
|
|
8521
|
+
let left;
|
|
8522
|
+
if (isSymbolToken(token)) {
|
|
8523
|
+
switch (token[1]) {
|
|
8524
|
+
case 'let':
|
|
8525
|
+
return parseLet(ctx, token);
|
|
8526
|
+
case 'if':
|
|
8527
|
+
case 'unless':
|
|
8528
|
+
left = parseIfOrUnless(ctx, token);
|
|
8529
|
+
break;
|
|
8530
|
+
case 'cond':
|
|
8531
|
+
left = parseCond(ctx, token);
|
|
8532
|
+
break;
|
|
8533
|
+
case 'match':
|
|
8534
|
+
left = parseMatch(ctx, token);
|
|
8535
|
+
break;
|
|
8536
|
+
case 'for':
|
|
8537
|
+
case 'doseq':
|
|
8538
|
+
left = parseForOrDoseq(ctx, token);
|
|
8539
|
+
break;
|
|
8540
|
+
case 'loop':
|
|
8541
|
+
left = parseLoop(ctx, token);
|
|
8542
|
+
break;
|
|
8543
|
+
}
|
|
8155
8544
|
}
|
|
8156
|
-
|
|
8157
|
-
|
|
8158
|
-
return NO_MATCH;
|
|
8545
|
+
else if (isReservedSymbolToken(token, 'do')) {
|
|
8546
|
+
left = parseDo(ctx);
|
|
8159
8547
|
}
|
|
8160
|
-
|
|
8161
|
-
|
|
8162
|
-
|
|
8163
|
-
|
|
8164
|
-
|
|
8165
|
-
|
|
8166
|
-
|
|
8167
|
-
|
|
8168
|
-
|
|
8169
|
-
|
|
8170
|
-
return [length, ['Error', value, undefined, `Unclosed quoted symbol at position ${position}`]];
|
|
8171
|
-
length += 1;
|
|
8172
|
-
if (escaping) {
|
|
8173
|
-
escaping = false;
|
|
8174
|
-
value += char;
|
|
8175
|
-
}
|
|
8176
|
-
else {
|
|
8177
|
-
if (char === '\\') {
|
|
8178
|
-
escaping = true;
|
|
8179
|
-
}
|
|
8180
|
-
value += char;
|
|
8548
|
+
left ||= parseOperand(ctx);
|
|
8549
|
+
let operator = ctx.tryPeek();
|
|
8550
|
+
while (!isAtExpressionEnd(ctx)) {
|
|
8551
|
+
if (isA_BinaryOperatorToken(operator)) {
|
|
8552
|
+
const name = operator[1];
|
|
8553
|
+
const newPrecedece = getPrecedence(name, operator[2]);
|
|
8554
|
+
if (newPrecedece <= precedence
|
|
8555
|
+
// ^ (exponentiation) is right associative
|
|
8556
|
+
&& !(newPrecedece === exponentiationPrecedence && precedence === exponentiationPrecedence)) {
|
|
8557
|
+
break;
|
|
8181
8558
|
}
|
|
8182
|
-
|
|
8559
|
+
const symbol = specialExpressionTypes[name]
|
|
8560
|
+
? withSourceCodeInfo([NodeTypes.SpecialBuiltinSymbol, specialExpressionTypes[name]], operator[2])
|
|
8561
|
+
: withSourceCodeInfo([NodeTypes.NormalBuiltinSymbol, normalExpressionTypes[name]], operator[2]);
|
|
8562
|
+
ctx.advance();
|
|
8563
|
+
const right = parseExpression(ctx, newPrecedece);
|
|
8564
|
+
left = fromBinaryOperatorToNode(operator, symbol, left, right, operator[2]);
|
|
8183
8565
|
}
|
|
8184
|
-
|
|
8185
|
-
|
|
8186
|
-
|
|
8187
|
-
|
|
8188
|
-
|
|
8189
|
-
|
|
8190
|
-
|
|
8191
|
-
|
|
8192
|
-
|
|
8193
|
-
|
|
8194
|
-
|
|
8566
|
+
else if (isSymbolToken(operator)) {
|
|
8567
|
+
if (!isFunctionOperator(operator[1])) {
|
|
8568
|
+
break;
|
|
8569
|
+
}
|
|
8570
|
+
const newPrecedence = binaryFunctionalOperatorPrecedence;
|
|
8571
|
+
if (newPrecedence <= precedence) {
|
|
8572
|
+
break;
|
|
8573
|
+
}
|
|
8574
|
+
const operatorSymbol = parseSymbol(ctx);
|
|
8575
|
+
const right = parseExpression(ctx, newPrecedence);
|
|
8576
|
+
if (isSpecialBuiltinSymbolNode(operatorSymbol)) {
|
|
8577
|
+
throw new DvalaError('Special expressions are not allowed in binary functional operators', operatorSymbol[2]);
|
|
8578
|
+
}
|
|
8579
|
+
left = createNamedNormalExpressionNode(operatorSymbol, [left, right], operator[2]);
|
|
8195
8580
|
}
|
|
8196
|
-
|
|
8197
|
-
|
|
8198
|
-
|
|
8199
|
-
|
|
8200
|
-
|
|
8201
|
-
|
|
8202
|
-
|
|
8203
|
-
|
|
8204
|
-
|
|
8205
|
-
|
|
8206
|
-
|
|
8207
|
-
|
|
8208
|
-
let symbolName = symbolMeta[1][1];
|
|
8209
|
-
symbolName = symbolName.startsWith('\'') ? symbolName.slice(1, symbolName.length - 1) : symbolName;
|
|
8210
|
-
const info = reservedSymbolRecord[symbolName];
|
|
8211
|
-
if (info === undefined) {
|
|
8212
|
-
return NO_MATCH;
|
|
8213
|
-
}
|
|
8214
|
-
return [symbolMeta[0], ['ReservedSymbol', symbolName]];
|
|
8215
|
-
};
|
|
8216
|
-
const tokenizeOperator = (input, position) => {
|
|
8217
|
-
const threeChars = input.slice(position, position + 3);
|
|
8218
|
-
if (position + 2 < input.length && isSymbolicOperator(threeChars)) {
|
|
8219
|
-
return [3, ['Operator', threeChars]];
|
|
8220
|
-
}
|
|
8221
|
-
const twoChars = input.slice(position, position + 2);
|
|
8222
|
-
if (position + 1 < input.length && isSymbolicOperator(twoChars)) {
|
|
8223
|
-
return [2, ['Operator', twoChars]];
|
|
8224
|
-
}
|
|
8225
|
-
const oneChar = input[position] ?? '';
|
|
8226
|
-
if (isSymbolicOperator(oneChar)) {
|
|
8227
|
-
return [1, ['Operator', oneChar]];
|
|
8228
|
-
}
|
|
8229
|
-
return NO_MATCH;
|
|
8230
|
-
};
|
|
8231
|
-
const tokenizeMultiLineComment = (input, position) => {
|
|
8232
|
-
if (input[position] === '/' && input[position + 1] === '*') {
|
|
8233
|
-
let length = 2;
|
|
8234
|
-
let value = '/*';
|
|
8235
|
-
while ((input[position + length] !== '*' || input[position + length + 1] !== '/') && position + length + 1 < input.length) {
|
|
8236
|
-
value += input[position + length];
|
|
8237
|
-
length += 1;
|
|
8581
|
+
else if (operator?.[1] === '?') {
|
|
8582
|
+
if (conditionalOperatorPrecedence <= precedence) {
|
|
8583
|
+
break;
|
|
8584
|
+
}
|
|
8585
|
+
ctx.advance();
|
|
8586
|
+
const trueNode = parseExpression(ctx);
|
|
8587
|
+
if (!isOperatorToken(ctx.tryPeek(), ':')) {
|
|
8588
|
+
throw new DvalaError('Expected :', ctx.peekSourceCodeInfo());
|
|
8589
|
+
}
|
|
8590
|
+
ctx.advance();
|
|
8591
|
+
const falseNode = parseExpression(ctx);
|
|
8592
|
+
left = withSourceCodeInfo([NodeTypes.SpecialExpression, [specialExpressionTypes.if, [left, trueNode, falseNode]]], left[2]);
|
|
8238
8593
|
}
|
|
8239
|
-
|
|
8240
|
-
|
|
8594
|
+
else {
|
|
8595
|
+
break;
|
|
8241
8596
|
}
|
|
8242
|
-
|
|
8243
|
-
length += 2;
|
|
8244
|
-
return [length, ['MultiLineComment', value]];
|
|
8597
|
+
operator = ctx.tryPeek();
|
|
8245
8598
|
}
|
|
8246
|
-
return
|
|
8247
|
-
}
|
|
8248
|
-
|
|
8249
|
-
|
|
8250
|
-
|
|
8251
|
-
|
|
8252
|
-
|
|
8253
|
-
value += input[position + length];
|
|
8254
|
-
length += 1;
|
|
8599
|
+
return left;
|
|
8600
|
+
}
|
|
8601
|
+
|
|
8602
|
+
function parse(tokenStream) {
|
|
8603
|
+
tokenStream.tokens.forEach((token) => {
|
|
8604
|
+
if (token[0] === 'Error') {
|
|
8605
|
+
throw new DvalaError(token[3], token[2]);
|
|
8255
8606
|
}
|
|
8256
|
-
|
|
8257
|
-
|
|
8258
|
-
|
|
8259
|
-
|
|
8260
|
-
|
|
8261
|
-
|
|
8262
|
-
|
|
8263
|
-
let value = '//';
|
|
8264
|
-
while (input[position + length] !== '\n' && position + length < input.length) {
|
|
8265
|
-
value += input[position + length];
|
|
8266
|
-
length += 1;
|
|
8607
|
+
});
|
|
8608
|
+
const nodes = [];
|
|
8609
|
+
const ctx = createParserContext(tokenStream);
|
|
8610
|
+
while (!ctx.isAtEnd()) {
|
|
8611
|
+
nodes.push(parseExpression(ctx, 0));
|
|
8612
|
+
if (isOperatorToken(ctx.tryPeek(), ';')) {
|
|
8613
|
+
ctx.advance();
|
|
8267
8614
|
}
|
|
8268
|
-
|
|
8269
|
-
|
|
8270
|
-
|
|
8271
|
-
};
|
|
8272
|
-
// All tokenizers, order matters!
|
|
8273
|
-
const tokenizers = [
|
|
8274
|
-
tokenizeWhitespace,
|
|
8275
|
-
tokenizeMultiLineComment,
|
|
8276
|
-
tokenizeSingleLineComment,
|
|
8277
|
-
tokenizeReservedSymbolToken,
|
|
8278
|
-
tokenizeLParen,
|
|
8279
|
-
tokenizeRParen,
|
|
8280
|
-
tokenizeLBracket,
|
|
8281
|
-
tokenizeRBracket,
|
|
8282
|
-
tokenizeLBrace,
|
|
8283
|
-
tokenizeRBrace,
|
|
8284
|
-
tokenizeDocString,
|
|
8285
|
-
tokenizeString,
|
|
8286
|
-
tokenizeRegexpShorthand,
|
|
8287
|
-
tokenizeBasePrefixedNumber,
|
|
8288
|
-
tokenizeNumber,
|
|
8289
|
-
tokenizeOperator,
|
|
8290
|
-
tokenizeSymbol,
|
|
8291
|
-
];
|
|
8292
|
-
|
|
8293
|
-
function tokenize(input, debug, filePath) {
|
|
8294
|
-
let position = 0;
|
|
8295
|
-
const tokenStream = {
|
|
8296
|
-
tokens: [],
|
|
8297
|
-
filePath,
|
|
8298
|
-
hasDebugData: debug,
|
|
8299
|
-
};
|
|
8300
|
-
while (position < input.length) {
|
|
8301
|
-
const sourceCodeInfo = debug
|
|
8302
|
-
? createSourceCodeInfo(input, position, filePath)
|
|
8303
|
-
: undefined;
|
|
8304
|
-
const tokenDescriptor = getCurrentToken(input, position);
|
|
8305
|
-
const [count, token] = tokenDescriptor;
|
|
8306
|
-
position += count;
|
|
8307
|
-
if (token) {
|
|
8308
|
-
if (sourceCodeInfo) {
|
|
8309
|
-
token[2] = sourceCodeInfo;
|
|
8615
|
+
else {
|
|
8616
|
+
if (!ctx.isAtEnd()) {
|
|
8617
|
+
throw new DvalaError('Expected ;', ctx.peekSourceCodeInfo());
|
|
8310
8618
|
}
|
|
8311
|
-
tokenStream.tokens.push(token);
|
|
8312
8619
|
}
|
|
8313
8620
|
}
|
|
8314
|
-
return
|
|
8315
|
-
}
|
|
8316
|
-
function getSourceCodeLine(input, lineNbr) {
|
|
8317
|
-
return input.split(/\r\n|\r|\n/)[lineNbr];
|
|
8318
|
-
}
|
|
8319
|
-
function createSourceCodeInfo(input, position, filePath) {
|
|
8320
|
-
const lines = input.substring(0, position + 1).split(/\r\n|\r|\n/);
|
|
8321
|
-
const lastLine = lines[lines.length - 1];
|
|
8322
|
-
const code = getSourceCodeLine(input, lines.length - 1);
|
|
8323
|
-
const line = lines.length;
|
|
8324
|
-
const column = lastLine.length;
|
|
8325
|
-
return {
|
|
8326
|
-
code,
|
|
8327
|
-
position: {
|
|
8328
|
-
line,
|
|
8329
|
-
column,
|
|
8330
|
-
},
|
|
8331
|
-
filePath,
|
|
8332
|
-
};
|
|
8621
|
+
return nodes;
|
|
8333
8622
|
}
|
|
8334
|
-
|
|
8335
|
-
|
|
8336
|
-
|
|
8337
|
-
|
|
8338
|
-
|
|
8339
|
-
|
|
8340
|
-
|
|
8341
|
-
|
|
8342
|
-
|
|
8343
|
-
for (const tokenizer of tokenizers) {
|
|
8344
|
-
const [nbrOfCharacters, token] = tokenizer(input, position);
|
|
8345
|
-
position += nbrOfCharacters;
|
|
8346
|
-
if (nbrOfCharacters === 0) {
|
|
8347
|
-
continue;
|
|
8623
|
+
|
|
8624
|
+
function minifyTokenStream(tokenStream, { removeWhiteSpace }) {
|
|
8625
|
+
const tokens = tokenStream.tokens
|
|
8626
|
+
.filter((token) => {
|
|
8627
|
+
if (isSingleLineCommentToken(token)
|
|
8628
|
+
|| isMultiLineCommentToken(token)
|
|
8629
|
+
|| isShebangToken(token)
|
|
8630
|
+
|| (removeWhiteSpace && isWhitespaceToken(token))) {
|
|
8631
|
+
return false;
|
|
8348
8632
|
}
|
|
8349
|
-
return
|
|
8350
|
-
}
|
|
8351
|
-
return
|
|
8633
|
+
return true;
|
|
8634
|
+
});
|
|
8635
|
+
return { ...tokenStream, tokens };
|
|
8352
8636
|
}
|
|
8353
8637
|
|
|
8354
8638
|
/**
|
|
@@ -8397,9 +8681,8 @@ function effectNameMatchesPattern(effectName, pattern) {
|
|
|
8397
8681
|
return effectName === pattern;
|
|
8398
8682
|
}
|
|
8399
8683
|
/**
|
|
8400
|
-
* Find all matching handlers for an effect name, in registration order.
|
|
8401
|
-
* Returns an array of `[pattern, handler]` pairs
|
|
8402
|
-
* the "most specific" by registration order, not by pattern specificity.
|
|
8684
|
+
* Find all matching async handlers for an effect name, in registration order.
|
|
8685
|
+
* Returns an array of `[pattern, handler]` pairs.
|
|
8403
8686
|
*/
|
|
8404
8687
|
function findMatchingHandlers(effectName, handlers) {
|
|
8405
8688
|
if (!handlers) {
|
|
@@ -8508,217 +8791,6 @@ function getEffectRef(name) {
|
|
|
8508
8791
|
return ref;
|
|
8509
8792
|
}
|
|
8510
8793
|
|
|
8511
|
-
function isContextEntry(value) {
|
|
8512
|
-
return isUnknownRecord(value) && value.value !== undefined;
|
|
8513
|
-
}
|
|
8514
|
-
|
|
8515
|
-
class ContextStackImpl {
|
|
8516
|
-
_contexts;
|
|
8517
|
-
globalContext;
|
|
8518
|
-
values;
|
|
8519
|
-
modules;
|
|
8520
|
-
valueModules;
|
|
8521
|
-
pure;
|
|
8522
|
-
constructor({ contexts, values: hostValues, modules, valueModules, pure, }) {
|
|
8523
|
-
this.globalContext = asNonUndefined(contexts[0]);
|
|
8524
|
-
this._contexts = contexts;
|
|
8525
|
-
this.values = hostValues;
|
|
8526
|
-
this.modules = modules ?? new Map();
|
|
8527
|
-
this.valueModules = valueModules ?? new Map();
|
|
8528
|
-
this.pure = pure ?? false;
|
|
8529
|
-
}
|
|
8530
|
-
// -- Serialization support (Phase 4) --
|
|
8531
|
-
/** Get the raw context chain for serialization. */
|
|
8532
|
-
getContextsRaw() {
|
|
8533
|
-
return this._contexts;
|
|
8534
|
-
}
|
|
8535
|
-
/** Get host values (plain bindings passed at creation). */
|
|
8536
|
-
getHostValues() {
|
|
8537
|
-
return this.values;
|
|
8538
|
-
}
|
|
8539
|
-
/**
|
|
8540
|
-
* Find the index of globalContext in the _contexts array.
|
|
8541
|
-
* Returns -1 if not found (should not happen in valid state).
|
|
8542
|
-
*/
|
|
8543
|
-
getGlobalContextIndex() {
|
|
8544
|
-
return this._contexts.indexOf(this.globalContext);
|
|
8545
|
-
}
|
|
8546
|
-
/**
|
|
8547
|
-
* Create a ContextStack from deserialized data.
|
|
8548
|
-
* `contexts` is the restored context chain (already resolved).
|
|
8549
|
-
* `globalContextIndex` identifies which element is the globalContext.
|
|
8550
|
-
* Host bindings (`values`, `modules`) come from resume options.
|
|
8551
|
-
*/
|
|
8552
|
-
static fromDeserialized(params) {
|
|
8553
|
-
const cs = new ContextStackImpl({
|
|
8554
|
-
contexts: params.contexts,
|
|
8555
|
-
values: params.values,
|
|
8556
|
-
modules: params.modules,
|
|
8557
|
-
pure: params.pure,
|
|
8558
|
-
});
|
|
8559
|
-
if (params.globalContextIndex >= 0 && params.globalContextIndex < params.contexts.length) {
|
|
8560
|
-
cs.globalContext = params.contexts[params.globalContextIndex];
|
|
8561
|
-
}
|
|
8562
|
-
return cs;
|
|
8563
|
-
}
|
|
8564
|
-
/**
|
|
8565
|
-
* Replace the contexts array and globalContext. Used during deserialization
|
|
8566
|
-
* to fill in resolved context data after circular references are handled.
|
|
8567
|
-
*/
|
|
8568
|
-
setContextsFromDeserialized(contexts, globalContextIndex) {
|
|
8569
|
-
this._contexts = contexts;
|
|
8570
|
-
if (globalContextIndex >= 0 && globalContextIndex < contexts.length) {
|
|
8571
|
-
this.globalContext = contexts[globalContextIndex];
|
|
8572
|
-
}
|
|
8573
|
-
}
|
|
8574
|
-
getModule(name) {
|
|
8575
|
-
return this.modules.get(name);
|
|
8576
|
-
}
|
|
8577
|
-
getValueModule(name) {
|
|
8578
|
-
if (this.valueModules.has(name)) {
|
|
8579
|
-
return { value: this.valueModules.get(name), found: true };
|
|
8580
|
-
}
|
|
8581
|
-
return { value: undefined, found: false };
|
|
8582
|
-
}
|
|
8583
|
-
registerValueModule(name, value) {
|
|
8584
|
-
this.valueModules.set(name, value);
|
|
8585
|
-
}
|
|
8586
|
-
create(context) {
|
|
8587
|
-
const globalContext = this.globalContext;
|
|
8588
|
-
const contextStack = new ContextStackImpl({
|
|
8589
|
-
contexts: [context, ...this._contexts],
|
|
8590
|
-
values: this.values,
|
|
8591
|
-
modules: this.modules,
|
|
8592
|
-
valueModules: this.valueModules,
|
|
8593
|
-
pure: this.pure,
|
|
8594
|
-
});
|
|
8595
|
-
contextStack.globalContext = globalContext;
|
|
8596
|
-
return contextStack;
|
|
8597
|
-
}
|
|
8598
|
-
new(context) {
|
|
8599
|
-
const contexts = [{}, context];
|
|
8600
|
-
return new ContextStackImpl({ contexts, modules: this.modules, valueModules: this.valueModules, pure: this.pure });
|
|
8601
|
-
}
|
|
8602
|
-
addValues(values, sourceCodeInfo) {
|
|
8603
|
-
const currentContext = this._contexts[0];
|
|
8604
|
-
for (const [name, value] of Object.entries(values)) {
|
|
8605
|
-
if (currentContext[name]) {
|
|
8606
|
-
throw new DvalaError(`Cannot redefine value "${name}"`, sourceCodeInfo);
|
|
8607
|
-
}
|
|
8608
|
-
const shadowedName = getShadowedBuiltinName(name);
|
|
8609
|
-
if (shadowedName) {
|
|
8610
|
-
throw new DvalaError(`Cannot shadow ${shadowedName}`, sourceCodeInfo);
|
|
8611
|
-
}
|
|
8612
|
-
currentContext[name] = { value: toAny(value) };
|
|
8613
|
-
}
|
|
8614
|
-
}
|
|
8615
|
-
getValue(name) {
|
|
8616
|
-
for (const context of this._contexts) {
|
|
8617
|
-
const contextEntry = context[name];
|
|
8618
|
-
if (contextEntry)
|
|
8619
|
-
return contextEntry.value;
|
|
8620
|
-
}
|
|
8621
|
-
return this.values?.[name];
|
|
8622
|
-
}
|
|
8623
|
-
lookUp(node) {
|
|
8624
|
-
const value = node[1];
|
|
8625
|
-
for (const context of this._contexts) {
|
|
8626
|
-
const contextEntry = context[value];
|
|
8627
|
-
if (contextEntry)
|
|
8628
|
-
return contextEntry;
|
|
8629
|
-
}
|
|
8630
|
-
const hostValue = this.values?.[value];
|
|
8631
|
-
if (hostValue !== undefined) {
|
|
8632
|
-
return {
|
|
8633
|
-
value: toAny(hostValue),
|
|
8634
|
-
};
|
|
8635
|
-
}
|
|
8636
|
-
return null;
|
|
8637
|
-
}
|
|
8638
|
-
evaluateSymbol(node) {
|
|
8639
|
-
if (isSpecialBuiltinSymbolNode(node)) {
|
|
8640
|
-
const functionType = node[1];
|
|
8641
|
-
switch (functionType) {
|
|
8642
|
-
case specialExpressionTypes['&&']:
|
|
8643
|
-
case specialExpressionTypes['||']:
|
|
8644
|
-
case specialExpressionTypes.array:
|
|
8645
|
-
case specialExpressionTypes.object:
|
|
8646
|
-
case specialExpressionTypes['defined?']:
|
|
8647
|
-
case specialExpressionTypes.recur:
|
|
8648
|
-
case specialExpressionTypes['??']: {
|
|
8649
|
-
const specialExpression = asNonUndefined(builtin.specialExpressions[functionType], node[2]);
|
|
8650
|
-
return {
|
|
8651
|
-
[FUNCTION_SYMBOL]: true,
|
|
8652
|
-
functionType: 'SpecialBuiltin',
|
|
8653
|
-
specialBuiltinSymbolType: functionType,
|
|
8654
|
-
sourceCodeInfo: node[2],
|
|
8655
|
-
arity: specialExpression.arity,
|
|
8656
|
-
};
|
|
8657
|
-
}
|
|
8658
|
-
default:
|
|
8659
|
-
throw new DvalaError(`Unknown special builtin symbol type: ${functionType}`, node[2]);
|
|
8660
|
-
}
|
|
8661
|
-
}
|
|
8662
|
-
if (isNormalBuiltinSymbolNode(node)) {
|
|
8663
|
-
const type = node[1];
|
|
8664
|
-
const normalExpression = allNormalExpressions[type];
|
|
8665
|
-
const name = normalExpression.name;
|
|
8666
|
-
return {
|
|
8667
|
-
[FUNCTION_SYMBOL]: true,
|
|
8668
|
-
functionType: 'Builtin',
|
|
8669
|
-
normalBuiltinSymbolType: type,
|
|
8670
|
-
sourceCodeInfo: node[2],
|
|
8671
|
-
arity: normalExpression.arity,
|
|
8672
|
-
name,
|
|
8673
|
-
};
|
|
8674
|
-
}
|
|
8675
|
-
const lookUpResult = this.lookUp(node);
|
|
8676
|
-
if (isContextEntry(lookUpResult))
|
|
8677
|
-
return lookUpResult.value;
|
|
8678
|
-
throw new UndefinedSymbolError(node[1], node[2]);
|
|
8679
|
-
}
|
|
8680
|
-
}
|
|
8681
|
-
function getShadowedBuiltinName(name) {
|
|
8682
|
-
if (specialExpressionKeys.includes(name))
|
|
8683
|
-
return `special expression "${name}"`;
|
|
8684
|
-
if (normalExpressionKeys.includes(name))
|
|
8685
|
-
return `builtin function "${name}"`;
|
|
8686
|
-
if (name === 'self')
|
|
8687
|
-
return `builtin value "${name}"`;
|
|
8688
|
-
return null;
|
|
8689
|
-
}
|
|
8690
|
-
function assertNotShadowingBuiltin(name) {
|
|
8691
|
-
const shadowedName = getShadowedBuiltinName(name);
|
|
8692
|
-
if (shadowedName) {
|
|
8693
|
-
throw new DvalaError(`Cannot shadow ${shadowedName}`, undefined);
|
|
8694
|
-
}
|
|
8695
|
-
}
|
|
8696
|
-
function createContextStack(params = {}, modules, pure) {
|
|
8697
|
-
const globalContext = params.globalContext ?? {};
|
|
8698
|
-
// Contexts are checked from left to right
|
|
8699
|
-
const contexts = params.contexts ? [globalContext, ...params.contexts] : [globalContext];
|
|
8700
|
-
let hostValues;
|
|
8701
|
-
if (params.bindings) {
|
|
8702
|
-
for (const [identifier, entry] of Object.entries(params.bindings)) {
|
|
8703
|
-
if (identifier.includes('.')) {
|
|
8704
|
-
throw new DvalaError(`Dots are not allowed in binding keys: "${identifier}"`, undefined);
|
|
8705
|
-
}
|
|
8706
|
-
assertNotShadowingBuiltin(identifier);
|
|
8707
|
-
if (!hostValues) {
|
|
8708
|
-
hostValues = {};
|
|
8709
|
-
}
|
|
8710
|
-
hostValues[identifier] = entry;
|
|
8711
|
-
}
|
|
8712
|
-
}
|
|
8713
|
-
const contextStack = new ContextStackImpl({
|
|
8714
|
-
contexts,
|
|
8715
|
-
values: hostValues,
|
|
8716
|
-
modules,
|
|
8717
|
-
pure,
|
|
8718
|
-
});
|
|
8719
|
-
return params.globalModuleScope ? contextStack : contextStack.create({});
|
|
8720
|
-
}
|
|
8721
|
-
|
|
8722
8794
|
/**
|
|
8723
8795
|
* Content-addressable hashing for JSON-compatible value trees.
|
|
8724
8796
|
*
|
|
@@ -10239,7 +10311,7 @@ function evaluateFunction(fn, contextStack) {
|
|
|
10239
10311
|
});
|
|
10240
10312
|
return ctx;
|
|
10241
10313
|
}, {});
|
|
10242
|
-
const undefinedSymbols = getUndefinedSymbols(fn[1], contextStack.new(context), builtin, evaluateNodeRecursive);
|
|
10314
|
+
const undefinedSymbols = getUndefinedSymbols$1(fn[1], contextStack.new(context), builtin, evaluateNodeRecursive);
|
|
10243
10315
|
undefinedSymbols.forEach((name) => {
|
|
10244
10316
|
const value = contextStack.getValue(name);
|
|
10245
10317
|
if (isAny(value)) {
|
|
@@ -10642,7 +10714,6 @@ function stepSpecialExpression(node, env, k) {
|
|
|
10642
10714
|
// --- lambda (fn / ->) ---
|
|
10643
10715
|
case specialExpressionTypes['0_lambda']: {
|
|
10644
10716
|
const fn = node[1][1];
|
|
10645
|
-
const docString = (node[1][2] ?? '');
|
|
10646
10717
|
const evaluatedFunc = evaluateFunction(fn, env);
|
|
10647
10718
|
const min = evaluatedFunc[0].filter(arg => arg[0] !== bindingTargetTypes.rest && arg[1][1] === undefined).length;
|
|
10648
10719
|
const max = evaluatedFunc[0].some(arg => arg[0] === bindingTargetTypes.rest) ? undefined : evaluatedFunc[0].length;
|
|
@@ -10654,7 +10725,7 @@ function stepSpecialExpression(node, env, k) {
|
|
|
10654
10725
|
name: undefined,
|
|
10655
10726
|
evaluatedfunction: evaluatedFunc,
|
|
10656
10727
|
arity,
|
|
10657
|
-
docString,
|
|
10728
|
+
docString: '',
|
|
10658
10729
|
};
|
|
10659
10730
|
return { type: 'Value', value: dvalaFunction, k };
|
|
10660
10731
|
}
|
|
@@ -11812,129 +11883,144 @@ function dispatchPerform(effect, args, k, sourceCodeInfo, handlers, signal, snap
|
|
|
11812
11883
|
* shape. If no more handlers remain after `next()`, the effect is unhandled.
|
|
11813
11884
|
*
|
|
11814
11885
|
* Each handler must call exactly one of `resume`, `suspend`, `fail`, or
|
|
11815
|
-
* `next` before its promise resolves.
|
|
11886
|
+
* `next` before its promise resolves (async) or before returning (sync).
|
|
11816
11887
|
*
|
|
11817
11888
|
* - `resume(value)` — resolves with a `ValueStep` that continues evaluation.
|
|
11818
|
-
* - `suspend(meta?)` —
|
|
11889
|
+
* - `suspend(meta?)` — throws a `SuspensionSignal`.
|
|
11819
11890
|
* - `fail(msg?)` — produces an `ErrorStep` routed through `dvala.error`.
|
|
11820
11891
|
* - `next()` — pass to the next matching handler in the chain.
|
|
11892
|
+
*
|
|
11893
|
+
* Handlers may return `void` (synchronous) or `Promise<void>` (async).
|
|
11894
|
+
* When all handlers in a chain are synchronous, this function returns
|
|
11895
|
+
* a `Step` synchronously, allowing use from the sync trampoline.
|
|
11821
11896
|
*/
|
|
11822
11897
|
function dispatchHostHandler(effectName, matchingHandlers, args, k, signal, sourceCodeInfo, snapshotState) {
|
|
11823
11898
|
const effectSignal = signal ?? new AbortController().signal;
|
|
11824
11899
|
const argsArray = Array.from(args);
|
|
11900
|
+
function resolveOutcome(o, nextIndex) {
|
|
11901
|
+
switch (o.kind) {
|
|
11902
|
+
case 'step': return o.step;
|
|
11903
|
+
case 'asyncResume': return o.promise.then((v) => ({ type: 'Value', value: v, k }), (e) => ({ type: 'Error', error: e instanceof DvalaError ? e : new DvalaError(e instanceof Error ? e : `${e}`, sourceCodeInfo), k }));
|
|
11904
|
+
case 'throw': throw o.error;
|
|
11905
|
+
case 'next': return tryHandler(nextIndex);
|
|
11906
|
+
}
|
|
11907
|
+
}
|
|
11825
11908
|
// Recursive helper: try handler at `index`, with `next()` advancing to `index + 1`.
|
|
11826
11909
|
function tryHandler(index) {
|
|
11827
11910
|
if (index >= matchingHandlers.length) {
|
|
11828
|
-
// No more handlers — effect is unhandled.
|
|
11829
|
-
// Return rejected Promises (not synchronous throws) so that
|
|
11830
|
-
// next() can propagate via .then(resolve, reject).
|
|
11831
11911
|
if (effectName === 'dvala.error') {
|
|
11832
11912
|
const message = typeof argsArray[0] === 'string' ? argsArray[0] : String(argsArray[0] ?? 'Unknown error');
|
|
11833
|
-
|
|
11913
|
+
throw new UserDefinedError(message, sourceCodeInfo);
|
|
11834
11914
|
}
|
|
11835
|
-
|
|
11915
|
+
throw new DvalaError(`Unhandled effect: '${effectName}'`, sourceCodeInfo);
|
|
11836
11916
|
}
|
|
11837
11917
|
const [, handler] = matchingHandlers[index];
|
|
11838
|
-
|
|
11839
|
-
|
|
11840
|
-
|
|
11841
|
-
|
|
11842
|
-
|
|
11918
|
+
let outcome;
|
|
11919
|
+
let settled = false;
|
|
11920
|
+
function assertNotSettled(operation) {
|
|
11921
|
+
if (settled) {
|
|
11922
|
+
throw new DvalaError(`Effect handler called ${operation}() after already calling another operation`, sourceCodeInfo);
|
|
11923
|
+
}
|
|
11924
|
+
settled = true;
|
|
11925
|
+
}
|
|
11926
|
+
const ctx = {
|
|
11927
|
+
effectName,
|
|
11928
|
+
args: argsArray,
|
|
11929
|
+
signal: effectSignal,
|
|
11930
|
+
resume: (value) => {
|
|
11931
|
+
assertNotSettled('resume');
|
|
11932
|
+
if (value instanceof Promise) {
|
|
11933
|
+
outcome = { kind: 'asyncResume', promise: value };
|
|
11843
11934
|
}
|
|
11844
|
-
|
|
11845
|
-
|
|
11846
|
-
|
|
11847
|
-
|
|
11848
|
-
|
|
11849
|
-
|
|
11850
|
-
|
|
11851
|
-
|
|
11852
|
-
|
|
11853
|
-
|
|
11854
|
-
|
|
11855
|
-
|
|
11856
|
-
|
|
11857
|
-
|
|
11858
|
-
|
|
11859
|
-
|
|
11860
|
-
|
|
11861
|
-
|
|
11862
|
-
|
|
11863
|
-
|
|
11864
|
-
|
|
11865
|
-
|
|
11866
|
-
|
|
11867
|
-
|
|
11868
|
-
|
|
11869
|
-
|
|
11870
|
-
|
|
11871
|
-
|
|
11872
|
-
|
|
11873
|
-
|
|
11874
|
-
|
|
11875
|
-
|
|
11876
|
-
|
|
11877
|
-
|
|
11878
|
-
|
|
11879
|
-
|
|
11880
|
-
|
|
11881
|
-
|
|
11882
|
-
|
|
11883
|
-
|
|
11884
|
-
},
|
|
11885
|
-
get snapshots() { return snapshotState ? [...snapshotState.snapshots] : []; },
|
|
11886
|
-
checkpoint: (meta) => {
|
|
11887
|
-
if (!snapshotState) {
|
|
11888
|
-
throw new DvalaError('checkpoint is not available outside effect-enabled execution', sourceCodeInfo);
|
|
11889
|
-
}
|
|
11890
|
-
const continuation = serializeToObject(k);
|
|
11891
|
-
const snapshot = {
|
|
11892
|
-
continuation,
|
|
11893
|
-
timestamp: Date.now(),
|
|
11894
|
-
index: snapshotState.nextSnapshotIndex++,
|
|
11895
|
-
runId: snapshotState.runId,
|
|
11896
|
-
...(meta !== undefined ? { meta } : {}),
|
|
11897
|
-
};
|
|
11898
|
-
snapshotState.snapshots.push(snapshot);
|
|
11899
|
-
if (snapshotState.maxSnapshots !== undefined && snapshotState.snapshots.length > snapshotState.maxSnapshots) {
|
|
11900
|
-
snapshotState.snapshots.shift();
|
|
11901
|
-
}
|
|
11902
|
-
return snapshot;
|
|
11903
|
-
},
|
|
11904
|
-
resumeFrom: (snapshot, value) => {
|
|
11905
|
-
if (settled) {
|
|
11906
|
-
throw new DvalaError('Effect handler called resumeFrom() after already calling another operation', sourceCodeInfo);
|
|
11907
|
-
}
|
|
11908
|
-
if (!snapshotState) {
|
|
11909
|
-
throw new DvalaError('resumeFrom is not available outside effect-enabled execution', sourceCodeInfo);
|
|
11910
|
-
}
|
|
11911
|
-
const found = snapshotState.snapshots.find(s => s.index === snapshot.index && s.runId === snapshot.runId);
|
|
11912
|
-
if (!found) {
|
|
11913
|
-
throw new DvalaError(`Invalid snapshot: no snapshot with index ${snapshot.index} found in current run`, sourceCodeInfo);
|
|
11914
|
-
}
|
|
11915
|
-
settled = true;
|
|
11916
|
-
reject(new ResumeFromSignal(found.continuation, value, found.index));
|
|
11917
|
-
},
|
|
11918
|
-
};
|
|
11919
|
-
handler(ctx).catch((e) => {
|
|
11935
|
+
else {
|
|
11936
|
+
outcome = { kind: 'step', step: { type: 'Value', value, k } };
|
|
11937
|
+
}
|
|
11938
|
+
},
|
|
11939
|
+
fail: (msg) => {
|
|
11940
|
+
assertNotSettled('fail');
|
|
11941
|
+
const errorMsg = msg ?? `Effect handler failed for '${effectName}'`;
|
|
11942
|
+
outcome = { kind: 'step', step: { type: 'Error', error: new DvalaError(errorMsg, sourceCodeInfo), k } };
|
|
11943
|
+
},
|
|
11944
|
+
suspend: (meta) => {
|
|
11945
|
+
assertNotSettled('suspend');
|
|
11946
|
+
outcome = {
|
|
11947
|
+
kind: 'throw',
|
|
11948
|
+
error: new SuspensionSignal(k, snapshotState ? snapshotState.snapshots : [], snapshotState ? snapshotState.nextSnapshotIndex : 0, meta),
|
|
11949
|
+
};
|
|
11950
|
+
},
|
|
11951
|
+
next: () => {
|
|
11952
|
+
assertNotSettled('next');
|
|
11953
|
+
outcome = { kind: 'next' };
|
|
11954
|
+
},
|
|
11955
|
+
get snapshots() { return snapshotState ? [...snapshotState.snapshots] : []; },
|
|
11956
|
+
checkpoint: (meta) => {
|
|
11957
|
+
if (!snapshotState) {
|
|
11958
|
+
throw new DvalaError('checkpoint is not available outside effect-enabled execution', sourceCodeInfo);
|
|
11959
|
+
}
|
|
11960
|
+
const continuation = serializeToObject(k);
|
|
11961
|
+
const snapshot = {
|
|
11962
|
+
continuation,
|
|
11963
|
+
timestamp: Date.now(),
|
|
11964
|
+
index: snapshotState.nextSnapshotIndex++,
|
|
11965
|
+
runId: snapshotState.runId,
|
|
11966
|
+
...(meta !== undefined ? { meta } : {}),
|
|
11967
|
+
};
|
|
11968
|
+
snapshotState.snapshots.push(snapshot);
|
|
11969
|
+
if (snapshotState.maxSnapshots !== undefined && snapshotState.snapshots.length > snapshotState.maxSnapshots) {
|
|
11970
|
+
snapshotState.snapshots.shift();
|
|
11971
|
+
}
|
|
11972
|
+
return snapshot;
|
|
11973
|
+
},
|
|
11974
|
+
resumeFrom: (snapshot, value) => {
|
|
11920
11975
|
if (settled) {
|
|
11921
|
-
|
|
11922
|
-
return;
|
|
11976
|
+
throw new DvalaError('Effect handler called resumeFrom() after already calling another operation', sourceCodeInfo);
|
|
11923
11977
|
}
|
|
11924
|
-
|
|
11925
|
-
|
|
11926
|
-
reject(e);
|
|
11978
|
+
if (!snapshotState) {
|
|
11979
|
+
throw new DvalaError('resumeFrom is not available outside effect-enabled execution', sourceCodeInfo);
|
|
11927
11980
|
}
|
|
11928
|
-
|
|
11929
|
-
|
|
11930
|
-
|
|
11931
|
-
resolve({
|
|
11932
|
-
type: 'Error',
|
|
11933
|
-
error: e instanceof DvalaError ? e : new DvalaError(e instanceof Error ? e : `${e}`, sourceCodeInfo),
|
|
11934
|
-
k,
|
|
11935
|
-
});
|
|
11981
|
+
const found = snapshotState.snapshots.find(s => s.index === snapshot.index && s.runId === snapshot.runId);
|
|
11982
|
+
if (!found) {
|
|
11983
|
+
throw new DvalaError(`Invalid snapshot: no snapshot with index ${snapshot.index} found in current run`, sourceCodeInfo);
|
|
11936
11984
|
}
|
|
11937
|
-
|
|
11985
|
+
settled = true;
|
|
11986
|
+
outcome = { kind: 'throw', error: new ResumeFromSignal(found.continuation, value, found.index) };
|
|
11987
|
+
},
|
|
11988
|
+
};
|
|
11989
|
+
const handlerResult = handler(ctx);
|
|
11990
|
+
if (!(handlerResult instanceof Promise)) {
|
|
11991
|
+
// Synchronous handler — outcome must already be set
|
|
11992
|
+
if (!outcome) {
|
|
11993
|
+
throw new DvalaError(`Effect handler for '${effectName}' did not call resume(), fail(), suspend(), or next()`, sourceCodeInfo);
|
|
11994
|
+
}
|
|
11995
|
+
return resolveOutcome(outcome, index + 1);
|
|
11996
|
+
}
|
|
11997
|
+
// Async handler
|
|
11998
|
+
if (outcome) {
|
|
11999
|
+
// Handler settled synchronously before the async part
|
|
12000
|
+
handlerResult.catch(() => { }); // suppress unhandled rejection
|
|
12001
|
+
return resolveOutcome(outcome, index + 1);
|
|
12002
|
+
}
|
|
12003
|
+
// Not yet settled — wait for the handler's promise
|
|
12004
|
+
return handlerResult.then(() => {
|
|
12005
|
+
if (!outcome) {
|
|
12006
|
+
throw new DvalaError(`Effect handler for '${effectName}' did not call resume(), fail(), suspend(), or next()`, sourceCodeInfo);
|
|
12007
|
+
}
|
|
12008
|
+
return resolveOutcome(outcome, index + 1);
|
|
12009
|
+
}, (e) => {
|
|
12010
|
+
if (outcome) {
|
|
12011
|
+
// Already settled — return that result, ignore the rejection
|
|
12012
|
+
return resolveOutcome(outcome, index + 1);
|
|
12013
|
+
}
|
|
12014
|
+
if (isSuspensionSignal(e) || isResumeFromSignal(e)) {
|
|
12015
|
+
// eslint-disable-next-line ts/no-throw-literal -- SuspensionSignal/ResumeFromSignal is a signaling mechanism
|
|
12016
|
+
throw e;
|
|
12017
|
+
}
|
|
12018
|
+
const errorStep = {
|
|
12019
|
+
type: 'Error',
|
|
12020
|
+
error: e instanceof DvalaError ? e : new DvalaError(e instanceof Error ? e : `${e}`, sourceCodeInfo),
|
|
12021
|
+
k,
|
|
12022
|
+
};
|
|
12023
|
+
return errorStep;
|
|
11938
12024
|
});
|
|
11939
12025
|
}
|
|
11940
12026
|
return tryHandler(0);
|
|
@@ -12441,7 +12527,7 @@ function tick(step, handlers, signal, snapshotState) {
|
|
|
12441
12527
|
* Throws if any step produces a Promise (i.e., an async operation was
|
|
12442
12528
|
* encountered in a synchronous context).
|
|
12443
12529
|
*/
|
|
12444
|
-
function runSyncTrampoline(initial) {
|
|
12530
|
+
function runSyncTrampoline(initial, effectHandlers) {
|
|
12445
12531
|
let step = initial;
|
|
12446
12532
|
for (;;) {
|
|
12447
12533
|
if (step instanceof Promise) {
|
|
@@ -12450,7 +12536,7 @@ function runSyncTrampoline(initial) {
|
|
|
12450
12536
|
if (step.type === 'Value' && step.k.length === 0) {
|
|
12451
12537
|
return step.value;
|
|
12452
12538
|
}
|
|
12453
|
-
step = tick(step);
|
|
12539
|
+
step = tick(step, effectHandlers);
|
|
12454
12540
|
}
|
|
12455
12541
|
}
|
|
12456
12542
|
/**
|
|
@@ -12512,16 +12598,6 @@ function evaluate(ast, contextStack) {
|
|
|
12512
12598
|
throw error;
|
|
12513
12599
|
}
|
|
12514
12600
|
}
|
|
12515
|
-
/**
|
|
12516
|
-
* Evaluate an AST using the async trampoline directly.
|
|
12517
|
-
* Use this when the caller knows that async operations may be involved
|
|
12518
|
-
* (e.g., from Dvala.async.run) to avoid the sync-first-then-retry pattern
|
|
12519
|
-
* which can cause side effects to be executed twice.
|
|
12520
|
-
*/
|
|
12521
|
-
function evaluateAsync(ast, contextStack) {
|
|
12522
|
-
const initial = buildInitialStep(ast.body, contextStack);
|
|
12523
|
-
return runAsyncTrampoline(initial);
|
|
12524
|
-
}
|
|
12525
12601
|
/**
|
|
12526
12602
|
* Evaluate a single AST node using the trampoline.
|
|
12527
12603
|
* Used as the `evaluateNode` callback passed to `getUndefinedSymbols`
|
|
@@ -12563,6 +12639,27 @@ async function evaluateWithEffects(ast, contextStack, handlers, maxSnapshots, de
|
|
|
12563
12639
|
const initial = buildInitialStep(ast.body, contextStack);
|
|
12564
12640
|
return runEffectLoop(initial, handlers, signal, undefined, maxSnapshots, deserializeOptions);
|
|
12565
12641
|
}
|
|
12642
|
+
/**
|
|
12643
|
+
* Evaluate an AST synchronously with effect handler support.
|
|
12644
|
+
*
|
|
12645
|
+
* Uses the sync trampoline with `effectHandlers` threaded through `tick`.
|
|
12646
|
+
* Throws if an async operation is encountered (e.g., an async handler
|
|
12647
|
+
* is used). Handlers may call `resume(value)`, `fail(msg?)`, or `next()`.
|
|
12648
|
+
* Calling `suspend()` will throw a runtime error.
|
|
12649
|
+
*/
|
|
12650
|
+
function evaluateWithSyncEffects(ast, contextStack, effectHandlers) {
|
|
12651
|
+
const initial = buildInitialStep(ast.body, contextStack);
|
|
12652
|
+
try {
|
|
12653
|
+
return runSyncTrampoline(initial, effectHandlers);
|
|
12654
|
+
}
|
|
12655
|
+
catch (error) {
|
|
12656
|
+
if (error instanceof DvalaError && error.message.includes('Unexpected async operation')) {
|
|
12657
|
+
const freshInitial = buildInitialStep(ast.body, contextStack);
|
|
12658
|
+
return runSyncTrampoline(freshInitial, effectHandlers);
|
|
12659
|
+
}
|
|
12660
|
+
throw error;
|
|
12661
|
+
}
|
|
12662
|
+
}
|
|
12566
12663
|
/**
|
|
12567
12664
|
* Shared effect trampoline loop used by both `evaluateWithEffects` and
|
|
12568
12665
|
* `resumeWithEffects`. Runs the trampoline to completion, suspension, or error.
|
|
@@ -12580,7 +12677,7 @@ async function runEffectLoop(initial, handlers, signal, initialSnapshotState, ma
|
|
|
12580
12677
|
snapshots: [],
|
|
12581
12678
|
nextSnapshotIndex: 0,
|
|
12582
12679
|
runId: generateRunId(),
|
|
12583
|
-
...({}),
|
|
12680
|
+
...(maxSnapshots !== undefined ? { maxSnapshots } : {}),
|
|
12584
12681
|
};
|
|
12585
12682
|
let step = initial;
|
|
12586
12683
|
for (;;) {
|
|
@@ -12639,141 +12736,6 @@ async function runEffectLoop(initial, handlers, signal, initialSnapshotState, ma
|
|
|
12639
12736
|
}
|
|
12640
12737
|
}
|
|
12641
12738
|
|
|
12642
|
-
function transformSymbolTokens(tokenStram, transformer) {
|
|
12643
|
-
return {
|
|
12644
|
-
...tokenStram,
|
|
12645
|
-
tokens: tokenStram.tokens.map(token => isSymbolToken(token)
|
|
12646
|
-
? [token[0], transformer(token[1])]
|
|
12647
|
-
: token),
|
|
12648
|
-
};
|
|
12649
|
-
}
|
|
12650
|
-
|
|
12651
|
-
function untokenize(tokenStream) {
|
|
12652
|
-
return tokenStream.tokens.reduce((acc, token) => {
|
|
12653
|
-
return `${acc}${token[1]}`;
|
|
12654
|
-
}, '');
|
|
12655
|
-
}
|
|
12656
|
-
|
|
12657
|
-
const dvalaCommands = new Set([...normalExpressionKeys, ...specialExpressionKeys, ...Object.keys(reservedSymbolRecord)]);
|
|
12658
|
-
// TODO: replace with get suggestions function
|
|
12659
|
-
class AutoCompleter {
|
|
12660
|
-
originalProgram;
|
|
12661
|
-
originalPosition;
|
|
12662
|
-
prefixProgram = '';
|
|
12663
|
-
suffixProgram = '';
|
|
12664
|
-
searchString = '';
|
|
12665
|
-
suggestions = [];
|
|
12666
|
-
suggestionIndex = null;
|
|
12667
|
-
constructor(originalProgram, originalPosition, dvala, params) {
|
|
12668
|
-
this.originalProgram = originalProgram;
|
|
12669
|
-
this.originalPosition = originalPosition;
|
|
12670
|
-
const partialProgram = this.originalProgram.slice(0, this.originalPosition);
|
|
12671
|
-
const tokenStream = dvala.tokenize(partialProgram);
|
|
12672
|
-
const lastToken = tokenStream.tokens.at(-1);
|
|
12673
|
-
if (!lastToken) {
|
|
12674
|
-
return;
|
|
12675
|
-
}
|
|
12676
|
-
if (lastToken[0] === 'Error') {
|
|
12677
|
-
return;
|
|
12678
|
-
}
|
|
12679
|
-
this.searchString = lastToken[1];
|
|
12680
|
-
this.prefixProgram = this.originalProgram.slice(0, this.originalPosition - this.searchString.length);
|
|
12681
|
-
this.suffixProgram = this.originalProgram.slice(this.prefixProgram.length + this.searchString.length);
|
|
12682
|
-
this.originalProgram.slice(this.prefixProgram.length + this.searchString.length);
|
|
12683
|
-
this.suggestions = this.generateSuggestions(params);
|
|
12684
|
-
}
|
|
12685
|
-
getNextSuggestion() {
|
|
12686
|
-
return this.getAutoCompleteSuggestionResult(this.getNextSuggestionSymbol());
|
|
12687
|
-
}
|
|
12688
|
-
getPreviousSuggestion() {
|
|
12689
|
-
return this.getAutoCompleteSuggestionResult(this.getPreviousSuggestionSymbol());
|
|
12690
|
-
}
|
|
12691
|
-
getAutoCompleteSuggestionResult(suggestion) {
|
|
12692
|
-
if (suggestion === null) {
|
|
12693
|
-
return null;
|
|
12694
|
-
}
|
|
12695
|
-
return {
|
|
12696
|
-
program: this.prefixProgram + suggestion + this.suffixProgram,
|
|
12697
|
-
position: this.prefixProgram.length + suggestion.length,
|
|
12698
|
-
};
|
|
12699
|
-
}
|
|
12700
|
-
getNextSuggestionSymbol() {
|
|
12701
|
-
if (this.suggestions.length === 0) {
|
|
12702
|
-
return null;
|
|
12703
|
-
}
|
|
12704
|
-
if (this.suggestionIndex === null) {
|
|
12705
|
-
this.suggestionIndex = 0;
|
|
12706
|
-
}
|
|
12707
|
-
else {
|
|
12708
|
-
this.suggestionIndex += 1;
|
|
12709
|
-
if (this.suggestionIndex >= this.suggestions.length) {
|
|
12710
|
-
this.suggestionIndex = 0;
|
|
12711
|
-
}
|
|
12712
|
-
}
|
|
12713
|
-
return this.suggestions[this.suggestionIndex];
|
|
12714
|
-
}
|
|
12715
|
-
getPreviousSuggestionSymbol() {
|
|
12716
|
-
if (this.suggestions.length === 0) {
|
|
12717
|
-
return null;
|
|
12718
|
-
}
|
|
12719
|
-
if (this.suggestionIndex === null) {
|
|
12720
|
-
this.suggestionIndex = this.suggestions.length - 1;
|
|
12721
|
-
}
|
|
12722
|
-
else {
|
|
12723
|
-
this.suggestionIndex -= 1;
|
|
12724
|
-
if (this.suggestionIndex < 0) {
|
|
12725
|
-
this.suggestionIndex = this.suggestions.length - 1;
|
|
12726
|
-
}
|
|
12727
|
-
}
|
|
12728
|
-
return this.suggestions[this.suggestionIndex];
|
|
12729
|
-
}
|
|
12730
|
-
getSuggestions() {
|
|
12731
|
-
return [...this.suggestions];
|
|
12732
|
-
}
|
|
12733
|
-
getSearchString() {
|
|
12734
|
-
return this.searchString;
|
|
12735
|
-
}
|
|
12736
|
-
generateSuggestions(params) {
|
|
12737
|
-
const blacklist = new Set(['0_defn', '0_lambda']);
|
|
12738
|
-
const startsWithCaseSensitive = this.generateWithPredicate(params, suggestion => !blacklist.has(suggestion) && suggestion.startsWith(this.searchString));
|
|
12739
|
-
startsWithCaseSensitive.forEach(suggestion => blacklist.add(suggestion));
|
|
12740
|
-
const startsWithCaseInsensitive = this.generateWithPredicate(params, suggestion => !blacklist.has(suggestion) && suggestion.toLowerCase().startsWith(this.searchString.toLowerCase()));
|
|
12741
|
-
startsWithCaseInsensitive.forEach(suggestion => blacklist.add(suggestion));
|
|
12742
|
-
const includesCaseSensitive = this.generateWithPredicate(params, suggestion => !blacklist.has(suggestion) && suggestion.includes(this.searchString));
|
|
12743
|
-
includesCaseSensitive.forEach(suggestion => blacklist.add(suggestion));
|
|
12744
|
-
const includesCaseInsensitive = this.generateWithPredicate(params, suggestion => !blacklist.has(suggestion) && suggestion.includes(this.searchString.toLowerCase()));
|
|
12745
|
-
includesCaseInsensitive.forEach(suggestion => blacklist.add(suggestion));
|
|
12746
|
-
return [...startsWithCaseSensitive, ...startsWithCaseInsensitive, ...includesCaseSensitive, ...includesCaseInsensitive];
|
|
12747
|
-
}
|
|
12748
|
-
generateWithPredicate(params, shouldInclude) {
|
|
12749
|
-
const suggestions = new Set();
|
|
12750
|
-
dvalaCommands.forEach((suggestion) => {
|
|
12751
|
-
if (shouldInclude(suggestion)) {
|
|
12752
|
-
suggestions.add(suggestion);
|
|
12753
|
-
}
|
|
12754
|
-
});
|
|
12755
|
-
Object.keys(params.globalContext ?? {})
|
|
12756
|
-
.filter(shouldInclude)
|
|
12757
|
-
.forEach(suggestion => suggestions.add(suggestion));
|
|
12758
|
-
params.contexts?.forEach((context) => {
|
|
12759
|
-
Object.keys(context)
|
|
12760
|
-
.filter(shouldInclude)
|
|
12761
|
-
.forEach(suggestion => suggestions.add(suggestion));
|
|
12762
|
-
});
|
|
12763
|
-
Object.keys(params.bindings ?? {})
|
|
12764
|
-
.filter(shouldInclude)
|
|
12765
|
-
.forEach(suggestion => suggestions.add(suggestion));
|
|
12766
|
-
return [...suggestions].sort((a, b) => a.localeCompare(b));
|
|
12767
|
-
}
|
|
12768
|
-
}
|
|
12769
|
-
|
|
12770
|
-
function isDvalaBundle(value) {
|
|
12771
|
-
return (typeof value === 'object'
|
|
12772
|
-
&& value !== null
|
|
12773
|
-
&& typeof value.program === 'string'
|
|
12774
|
-
&& Array.isArray(value.fileModules));
|
|
12775
|
-
}
|
|
12776
|
-
|
|
12777
12739
|
var collectionSource = "{\n map: (first-coll, ...args) -> do\n let fn = last(args);\n let other-colls = slice(args, 0, count(args) - 1);\n let all-colls = [first-coll, ...other-colls];\n\n cond\n case object?(first-coll) then do\n let expected-keys = keys(first-coll) |> sort;\n doseq (obj in other-colls) -> do\n if not(object?(obj)) then\n perform(effect(dvala.error), \"Expected object\")\n end;\n let obj-keys = keys(obj) |> sort;\n if not(obj-keys == expected-keys) then\n perform(effect(dvala.error), ++(\n \"All objects must have the same keys. Expected: \",\n join(expected-keys, \", \"),\n \". Found: \",\n join(obj-keys, \", \")\n ))\n end\n end;\n reduce(keys(first-coll), (acc, k) -> do\n let a = for (coll in all-colls) -> coll(k);\n assoc(acc, k, apply(fn, a))\n end, {})\n end\n\n case string?(first-coll) then do\n doseq (s in other-colls) -> do\n if not(string?(s)) then\n perform(effect(dvala.error), \"Expected string\")\n end\n end;\n let len = reduce(other-colls, (m, s) -> min(m, count(s)), count(first-coll));\n let mapped = for (i in range(len)) -> do\n let a = for (coll in all-colls) -> nth(coll, i);\n apply(fn, a)\n end;\n reduce(mapped, (acc, ch) -> do\n if not(string?(ch)) then\n perform(effect(dvala.error), \"Expected string\")\n end;\n ++(acc, ch)\n end, \"\")\n end\n\n case true then do\n doseq (x in other-colls) -> do\n if not(array?(x)) then\n perform(effect(dvala.error), \"Expected array\")\n end\n end;\n let len = reduce(other-colls, (m, x) -> min(m, count(x)), count(first-coll));\n for (i in range(len)) -> do\n let a = for (coll in all-colls) -> nth(coll, i);\n apply(fn, a)\n end\n end\n end\n end,\n\n filter: (coll, fn) -> do\n cond\n case array?(coll) then\n reduce(coll, (acc, elem) -> if fn(elem) then [...acc, elem] else acc end, [])\n\n case string?(coll) then\n reduce(coll, (acc, ch) -> if fn(ch) then ++(acc, ch) else acc end, \"\")\n\n case object?(coll) then\n reduce(keys(coll), (acc, k) -> do\n if fn(coll(k)) then\n assoc(acc, k, coll(k))\n else\n acc\n end\n end, {})\n\n case true then\n perform(effect(dvala.error), \"Expected collection\")\n end\n end,\n\n reduce: (coll, fn, initial) -> do\n cond\n case string?(coll) then\n loop (acc = initial, i = 0) -> do\n if i >= count(coll) then\n acc\n else\n recur(fn(acc, nth(coll, i)), i + 1)\n end\n end\n\n case array?(coll) then\n loop (acc = initial, i = 0) -> do\n if i >= count(coll) then\n acc\n else\n recur(fn(acc, nth(coll, i)), i + 1)\n end\n end\n\n case object?(coll) then do\n let values = vals(coll);\n loop (acc = initial, i = 0) -> do\n if i >= count(values) then\n acc\n else\n recur(fn(acc, nth(values, i)), i + 1)\n end\n end\n end\n\n case true then\n perform(effect(dvala.error), \"Expected collection\")\n end\n end\n}";
|
|
12778
12740
|
|
|
12779
12741
|
var sequenceSource = "{\n some: (seq, fn) -> do\n if null?(seq) then null\n else do\n loop (i = 0) -> do\n if i >= count(seq) then\n null\n else do\n let elem = nth(seq, i);\n if fn(elem) then elem\n else recur(i + 1)\n end\n end\n end\n end\n end\n end\n end,\n\n take-while: (seq, fn) -> do\n let is-str = string?(seq);\n let len = count(seq);\n let idx = loop (i = 0) -> do\n if i >= len then\n len\n else if fn(nth(seq, i)) then\n recur(i + 1)\n else\n i\n end\n end\n end;\n slice(seq, 0, idx)\n end,\n\n drop-while: (seq, fn) -> do\n let is-str = string?(seq);\n let len = count(seq);\n let idx = loop (i = 0) -> do\n if i >= len then\n len\n else if fn(nth(seq, i)) then\n recur(i + 1)\n else\n i\n end\n end\n end;\n slice(seq, idx)\n end,\n\n sort: (seq, ...args) -> do\n let cmp = if count(args) == 0 then compare else first(args) end;\n let is-str = string?(seq);\n let arr = if is-str then split(seq, \"\") else seq end;\n let len = count(arr);\n\n // merge two sorted arrays\n let merge-arrays = (left, right) -> do\n let left-len = count(left);\n let right-len = count(right);\n loop (result = [], li = 0, ri = 0) -> do\n if li >= left-len then\n ++(result, slice(right, ri))\n else if ri >= right-len then\n ++(result, slice(left, li))\n else do\n let l = nth(left, li);\n let r = nth(right, ri);\n if cmp(l, r) <= 0 then\n recur(push(result, l), li + 1, ri)\n else\n recur(push(result, r), li, ri + 1)\n end\n end\n end\n end\n end\n end;\n\n // recursive merge-sort\n let merge-sort = (a) -> do\n let n = count(a);\n if n <= 1 then a\n else do\n let mid = floor(n / 2);\n let left = merge-sort(slice(a, 0, mid));\n let right = merge-sort(slice(a, mid));\n merge-arrays(left, right)\n end\n end\n end;\n\n let sorted = merge-sort(arr);\n if is-str then join(sorted, \"\") else sorted end\n end\n}\n";
|
|
@@ -12873,202 +12835,202 @@ class Cache {
|
|
|
12873
12835
|
}
|
|
12874
12836
|
}
|
|
12875
12837
|
|
|
12876
|
-
|
|
12877
|
-
|
|
12878
|
-
|
|
12879
|
-
|
|
12880
|
-
|
|
12881
|
-
constructor(config = {}) {
|
|
12882
|
-
initCoreDvalaSources();
|
|
12883
|
-
this.debug = config.debug ?? false;
|
|
12884
|
-
this.astCacheSize = config.astCacheSize ?? null;
|
|
12885
|
-
if (this.astCacheSize) {
|
|
12886
|
-
this.astCache = new Cache(this.astCacheSize);
|
|
12887
|
-
const initialCache = config.initialCache ?? {};
|
|
12888
|
-
for (const cacheEntry of Object.keys(initialCache))
|
|
12889
|
-
this.astCache.set(cacheEntry, initialCache[cacheEntry]);
|
|
12890
|
-
}
|
|
12891
|
-
else {
|
|
12892
|
-
this.astCache = null;
|
|
12893
|
-
}
|
|
12894
|
-
const nsList = config.modules ?? [];
|
|
12895
|
-
this.modules = new Map(nsList.map(ns => [ns.name, ns]));
|
|
12896
|
-
}
|
|
12897
|
-
getRuntimeInfo() {
|
|
12898
|
-
return {
|
|
12899
|
-
astCacheSize: this.astCacheSize,
|
|
12900
|
-
astCache: this.astCache,
|
|
12901
|
-
debug: this.debug,
|
|
12902
|
-
};
|
|
12903
|
-
}
|
|
12904
|
-
async = {
|
|
12905
|
-
run: async (programOrBundle, params = {}) => {
|
|
12906
|
-
assertSerializableBindings(params.bindings);
|
|
12907
|
-
if (isDvalaBundle(programOrBundle)) {
|
|
12908
|
-
return this.runBundle(programOrBundle, params);
|
|
12909
|
-
}
|
|
12910
|
-
const ast = this.generateAst(programOrBundle, params);
|
|
12911
|
-
if (params.handlers) {
|
|
12912
|
-
const contextStack = createContextStack(params, this.modules, params.pure);
|
|
12913
|
-
const result = await evaluateWithEffects(ast, contextStack, params.handlers);
|
|
12914
|
-
if (result.type === 'completed')
|
|
12915
|
-
return result.value;
|
|
12916
|
-
if (result.type === 'error')
|
|
12917
|
-
throw result.error;
|
|
12918
|
-
throw new TypeError('Unexpected suspension in Dvala.async.run(). Use the standalone effects API for suspend/resume.');
|
|
12919
|
-
}
|
|
12920
|
-
return this.evaluateAsync(ast, params);
|
|
12921
|
-
},
|
|
12922
|
-
apply: async (fn, fnParams, params = {}) => {
|
|
12923
|
-
return this.apply(fn, fnParams, params);
|
|
12924
|
-
},
|
|
12925
|
-
};
|
|
12926
|
-
run(programOrBundle, params = {}) {
|
|
12927
|
-
assertSerializableBindings(params.bindings);
|
|
12928
|
-
if (isDvalaBundle(programOrBundle)) {
|
|
12929
|
-
return this.runBundle(programOrBundle, params);
|
|
12930
|
-
}
|
|
12931
|
-
const ast = this.generateAst(programOrBundle, params);
|
|
12932
|
-
const result = this.evaluate(ast, params);
|
|
12933
|
-
if (result instanceof Promise) {
|
|
12934
|
-
throw new TypeError('Unexpected async result in synchronous run(). Use dvala.async.run() for async operations.');
|
|
12935
|
-
}
|
|
12936
|
-
return result;
|
|
12937
|
-
}
|
|
12938
|
-
runBundle(bundle, params = {}) {
|
|
12939
|
-
const contextStack = createContextStack(params, this.modules, params.pure);
|
|
12940
|
-
// Evaluate file modules in dependency order and register as value modules.
|
|
12941
|
-
// Each file module is evaluated in its own scope so local bindings don't leak.
|
|
12942
|
-
// File modules are always evaluated in pure mode to ensure deterministic,
|
|
12943
|
-
// side-effect-free initialization regardless of the caller's pure setting.
|
|
12944
|
-
const savedPure = contextStack.pure;
|
|
12945
|
-
contextStack.pure = true;
|
|
12946
|
-
for (const [name, source] of bundle.fileModules) {
|
|
12947
|
-
const ast = this.generateAst(source, params);
|
|
12948
|
-
const moduleContextStack = contextStack.create({});
|
|
12949
|
-
const result = evaluate(ast, moduleContextStack);
|
|
12950
|
-
// TODO: When async functions in file modules are able to mark themselves as pure and
|
|
12951
|
-
// are returning a Promise, uncomment the following check, and make sure a test is verifying the behaviour.
|
|
12952
|
-
// if (result instanceof Promise) {
|
|
12953
|
-
// throw new TypeError('Unexpected async result in synchronous runBundle(). Use dvala.async.run() for async operations.')
|
|
12954
|
-
// }
|
|
12955
|
-
contextStack.registerValueModule(name, result);
|
|
12956
|
-
}
|
|
12957
|
-
contextStack.pure = savedPure;
|
|
12958
|
-
// Parse and evaluate the main program
|
|
12959
|
-
const ast = this.generateAst(bundle.program, params);
|
|
12960
|
-
const result = evaluate(ast, contextStack);
|
|
12961
|
-
if (result instanceof Promise) {
|
|
12962
|
-
throw new TypeError('Unexpected async result in synchronous runBundle(). Use dvala.async.run() for async operations.');
|
|
12963
|
-
}
|
|
12964
|
-
return result;
|
|
12965
|
-
}
|
|
12966
|
-
getUndefinedSymbols(programOrAst, params = {}) {
|
|
12967
|
-
const ast = typeof programOrAst === 'string' ? this.generateAst(programOrAst, params) : programOrAst;
|
|
12968
|
-
const contextStack = createContextStack(params, this.modules);
|
|
12969
|
-
return getUndefinedSymbols(ast, contextStack, builtin, evaluateNode);
|
|
12970
|
-
}
|
|
12971
|
-
tokenize(program, tokenizeParams = {}) {
|
|
12972
|
-
const tokenStream = tokenize(program, this.debug, tokenizeParams.filePath);
|
|
12973
|
-
return tokenizeParams.minify ? minifyTokenStream(tokenStream, { removeWhiteSpace: false }) : tokenStream;
|
|
12974
|
-
}
|
|
12975
|
-
parse(tokenStream) {
|
|
12976
|
-
tokenStream = minifyTokenStream(tokenStream, { removeWhiteSpace: true });
|
|
12977
|
-
const ast = {
|
|
12978
|
-
body: [],
|
|
12979
|
-
hasDebugData: tokenStream.hasDebugData,
|
|
12980
|
-
};
|
|
12981
|
-
ast.body = parse(tokenStream);
|
|
12982
|
-
return ast;
|
|
12983
|
-
}
|
|
12984
|
-
evaluate(ast, params) {
|
|
12985
|
-
const contextStack = createContextStack(params, this.modules, params.pure);
|
|
12986
|
-
return evaluate(ast, contextStack);
|
|
12987
|
-
}
|
|
12988
|
-
evaluateAsync(ast, params) {
|
|
12989
|
-
const contextStack = createContextStack(params, this.modules, params.pure);
|
|
12990
|
-
return evaluateAsync(ast, contextStack);
|
|
12991
|
-
}
|
|
12992
|
-
transformSymbols(tokenStream, transformer) {
|
|
12993
|
-
return transformSymbolTokens(tokenStream, transformer);
|
|
12994
|
-
}
|
|
12995
|
-
untokenize(tokenStream) {
|
|
12996
|
-
return untokenize(tokenStream);
|
|
12997
|
-
}
|
|
12998
|
-
apply(fn, fnParams, params = {}) {
|
|
12999
|
-
const fnName = 'FN_2eb7b316_471c_5bfa_90cb_d3dfd9164a59';
|
|
13000
|
-
const program = this.generateApplyFunctionCall(fnName, fnParams);
|
|
13001
|
-
const ast = this.generateAst(program, params);
|
|
13002
|
-
const hostValues = fnParams.reduce((result, param, index) => {
|
|
13003
|
-
result[`${fnName}_${index}`] = param;
|
|
13004
|
-
return result;
|
|
13005
|
-
}, { [fnName]: fn });
|
|
13006
|
-
params.bindings = { ...params.bindings, ...hostValues };
|
|
13007
|
-
return this.evaluate(ast, params);
|
|
13008
|
-
}
|
|
13009
|
-
generateApplyFunctionCall(fnName, fnParams) {
|
|
13010
|
-
const paramsString = fnParams
|
|
13011
|
-
.map((_, index) => {
|
|
13012
|
-
return `${fnName}_${index}`;
|
|
13013
|
-
})
|
|
13014
|
-
.join(', ');
|
|
13015
|
-
return `${fnName}(${paramsString})`;
|
|
13016
|
-
}
|
|
13017
|
-
generateAst(program, params) {
|
|
13018
|
-
if (this.astCache) {
|
|
13019
|
-
const cachedAst = this.astCache.get(program);
|
|
13020
|
-
if (cachedAst)
|
|
13021
|
-
return cachedAst;
|
|
13022
|
-
}
|
|
13023
|
-
const tokenStream = this.tokenize(program, {
|
|
13024
|
-
filePath: params.filePath,
|
|
13025
|
-
});
|
|
13026
|
-
const ast = this.parse(tokenStream);
|
|
13027
|
-
this.astCache?.set(program, ast);
|
|
13028
|
-
return ast;
|
|
13029
|
-
}
|
|
13030
|
-
getAutoCompleter(program, position, params = {}) {
|
|
13031
|
-
return new AutoCompleter(program, position, this, params);
|
|
13032
|
-
}
|
|
12838
|
+
function isDvalaBundle(value) {
|
|
12839
|
+
return (typeof value === 'object'
|
|
12840
|
+
&& value !== null
|
|
12841
|
+
&& typeof value.program === 'string'
|
|
12842
|
+
&& Array.isArray(value.fileModules));
|
|
13033
12843
|
}
|
|
12844
|
+
|
|
12845
|
+
/**
|
|
12846
|
+
* Standalone tooling functions for tokenizing, parsing, and analysis.
|
|
12847
|
+
*
|
|
12848
|
+
* These are thin wrappers around internal utilities that do not require
|
|
12849
|
+
* a Dvala instance.
|
|
12850
|
+
*/
|
|
12851
|
+
/**
|
|
12852
|
+
* Get all undefined symbols in a Dvala program.
|
|
12853
|
+
*
|
|
12854
|
+
* @param source - Dvala source code
|
|
12855
|
+
* @param options - optional context to treat as defined
|
|
12856
|
+
* @param options.bindings - host bindings to treat as defined
|
|
12857
|
+
* @param options.modules - modules to treat as available
|
|
12858
|
+
*/
|
|
12859
|
+
function getUndefinedSymbols(source, options) {
|
|
12860
|
+
const modulesMap = options?.modules
|
|
12861
|
+
? new Map(options.modules.map(m => [m.name, m]))
|
|
12862
|
+
: undefined;
|
|
12863
|
+
const contextStack = createContextStack({ bindings: options?.bindings }, modulesMap);
|
|
12864
|
+
const tokenStream = tokenize(source, false, undefined);
|
|
12865
|
+
const minified = minifyTokenStream(tokenStream, { removeWhiteSpace: true });
|
|
12866
|
+
const ast = { body: parse(minified), hasDebugData: false };
|
|
12867
|
+
return getUndefinedSymbols$1(ast, contextStack, builtin, evaluateNode);
|
|
12868
|
+
}
|
|
12869
|
+
|
|
13034
12870
|
function assertSerializableBindings(bindings) {
|
|
13035
12871
|
if (!bindings)
|
|
13036
12872
|
return;
|
|
13037
|
-
for (const [key,
|
|
13038
|
-
assertSerializable(
|
|
13039
|
-
}
|
|
12873
|
+
for (const [key, val] of Object.entries(bindings))
|
|
12874
|
+
assertSerializable(val, `bindings["${key}"]`);
|
|
13040
12875
|
}
|
|
13041
|
-
function assertSerializable(
|
|
13042
|
-
if (
|
|
12876
|
+
function assertSerializable(val, path) {
|
|
12877
|
+
if (val === null || val === undefined)
|
|
13043
12878
|
return;
|
|
13044
|
-
if (typeof
|
|
12879
|
+
if (typeof val === 'boolean' || typeof val === 'string')
|
|
13045
12880
|
return;
|
|
13046
|
-
if (typeof
|
|
13047
|
-
if (!Number.isFinite(
|
|
13048
|
-
throw new TypeError(`${path} is not serializable (${
|
|
12881
|
+
if (typeof val === 'number') {
|
|
12882
|
+
if (!Number.isFinite(val))
|
|
12883
|
+
throw new TypeError(`${path} is not serializable (${val})`);
|
|
13049
12884
|
return;
|
|
13050
12885
|
}
|
|
13051
|
-
if (typeof
|
|
12886
|
+
if (typeof val === 'function')
|
|
13052
12887
|
throw new TypeError(`${path} is not serializable (function)`);
|
|
13053
|
-
if (typeof
|
|
13054
|
-
|
|
13055
|
-
if (FUNCTION_SYMBOL in value) {
|
|
13056
|
-
return;
|
|
13057
|
-
}
|
|
13058
|
-
if (REGEXP_SYMBOL in value || EFFECT_SYMBOL in value)
|
|
12888
|
+
if (typeof val === 'object') {
|
|
12889
|
+
if (FUNCTION_SYMBOL in val || REGEXP_SYMBOL in val || EFFECT_SYMBOL in val)
|
|
13059
12890
|
return;
|
|
13060
|
-
if (Array.isArray(
|
|
13061
|
-
|
|
12891
|
+
if (Array.isArray(val)) {
|
|
12892
|
+
val.forEach((item, i) => assertSerializable(item, `${path}[${i}]`));
|
|
13062
12893
|
return;
|
|
13063
12894
|
}
|
|
13064
|
-
if (Object.getPrototypeOf(
|
|
12895
|
+
if (Object.getPrototypeOf(val) !== Object.prototype)
|
|
13065
12896
|
throw new TypeError(`${path} is not serializable (not a plain object)`);
|
|
13066
|
-
for (const [k, v] of Object.entries(
|
|
12897
|
+
for (const [k, v] of Object.entries(val))
|
|
13067
12898
|
assertSerializable(v, `${path}.${k}`);
|
|
13068
12899
|
return;
|
|
13069
12900
|
}
|
|
13070
12901
|
throw new TypeError(`${path} is not serializable`);
|
|
13071
12902
|
}
|
|
12903
|
+
function createDvala(options) {
|
|
12904
|
+
initCoreDvalaSources();
|
|
12905
|
+
const modules = options?.modules
|
|
12906
|
+
? new Map(options.modules.map(m => [m.name, m]))
|
|
12907
|
+
: undefined;
|
|
12908
|
+
const factoryBindings = options?.bindings;
|
|
12909
|
+
const factoryEffectHandlers = options?.effectHandlers;
|
|
12910
|
+
const debug = options?.debug ?? false;
|
|
12911
|
+
const cache = options?.cache ? new Cache(options.cache) : null;
|
|
12912
|
+
function buildAst(source, filePath) {
|
|
12913
|
+
if (!filePath && cache) {
|
|
12914
|
+
const cached = cache.get(source);
|
|
12915
|
+
if (cached)
|
|
12916
|
+
return cached;
|
|
12917
|
+
}
|
|
12918
|
+
const tokenStream = tokenize(source, debug, filePath);
|
|
12919
|
+
const minified = minifyTokenStream(tokenStream, { removeWhiteSpace: true });
|
|
12920
|
+
const ast = { body: parse(minified), hasDebugData: debug };
|
|
12921
|
+
if (!filePath)
|
|
12922
|
+
cache?.set(source, ast);
|
|
12923
|
+
return ast;
|
|
12924
|
+
}
|
|
12925
|
+
function mergeBindings(runBindings) {
|
|
12926
|
+
if (!factoryBindings && !runBindings)
|
|
12927
|
+
return undefined;
|
|
12928
|
+
return { ...factoryBindings, ...runBindings };
|
|
12929
|
+
}
|
|
12930
|
+
function mergeEffectHandlers(runEffectHandlers) {
|
|
12931
|
+
if (!factoryEffectHandlers && !runEffectHandlers)
|
|
12932
|
+
return undefined;
|
|
12933
|
+
// Run handlers first (checked first), factory handlers fill in the rest.
|
|
12934
|
+
// For same key, run overrides factory.
|
|
12935
|
+
const result = { ...runEffectHandlers };
|
|
12936
|
+
if (factoryEffectHandlers) {
|
|
12937
|
+
for (const [k, v] of Object.entries(factoryEffectHandlers)) {
|
|
12938
|
+
if (!(k in result))
|
|
12939
|
+
result[k] = v;
|
|
12940
|
+
}
|
|
12941
|
+
}
|
|
12942
|
+
return result;
|
|
12943
|
+
}
|
|
12944
|
+
function assertNotPureWithHandlers(pure, effectHandlers) {
|
|
12945
|
+
if (!pure)
|
|
12946
|
+
return;
|
|
12947
|
+
const hasEffectHandlers = effectHandlers && Object.keys(effectHandlers).length > 0;
|
|
12948
|
+
if (hasEffectHandlers) {
|
|
12949
|
+
throw new TypeError('Cannot use pure mode with effect handlers');
|
|
12950
|
+
}
|
|
12951
|
+
}
|
|
12952
|
+
return {
|
|
12953
|
+
run(source, runOptions) {
|
|
12954
|
+
assertSerializableBindings(runOptions?.bindings);
|
|
12955
|
+
const bindings = mergeBindings(runOptions?.bindings);
|
|
12956
|
+
const effectHandlers = mergeEffectHandlers(runOptions?.effectHandlers);
|
|
12957
|
+
const pure = runOptions?.pure ?? false;
|
|
12958
|
+
assertNotPureWithHandlers(pure, effectHandlers);
|
|
12959
|
+
const contextStack = createContextStack({ bindings }, modules, pure);
|
|
12960
|
+
if (isDvalaBundle(source)) {
|
|
12961
|
+
const savedPure = contextStack.pure;
|
|
12962
|
+
contextStack.pure = true;
|
|
12963
|
+
for (const [name, fileSource] of source.fileModules) {
|
|
12964
|
+
const fileAst = buildAst(fileSource);
|
|
12965
|
+
const moduleContextStack = contextStack.create({});
|
|
12966
|
+
contextStack.registerValueModule(name, evaluate(fileAst, moduleContextStack));
|
|
12967
|
+
}
|
|
12968
|
+
contextStack.pure = savedPure;
|
|
12969
|
+
const ast = buildAst(source.program);
|
|
12970
|
+
const result = evaluate(ast, contextStack);
|
|
12971
|
+
if (result instanceof Promise)
|
|
12972
|
+
throw new TypeError('Unexpected async result in run(). Use runAsync() for async operations.');
|
|
12973
|
+
return result;
|
|
12974
|
+
}
|
|
12975
|
+
const ast = buildAst(source, runOptions?.filePath);
|
|
12976
|
+
if (effectHandlers) {
|
|
12977
|
+
return evaluateWithSyncEffects(ast, contextStack, effectHandlers);
|
|
12978
|
+
}
|
|
12979
|
+
const result = evaluate(ast, contextStack);
|
|
12980
|
+
if (result instanceof Promise) {
|
|
12981
|
+
throw new TypeError('Unexpected async result in run(). Use runAsync() for async operations.');
|
|
12982
|
+
}
|
|
12983
|
+
return result;
|
|
12984
|
+
},
|
|
12985
|
+
async runAsync(source, runOptions) {
|
|
12986
|
+
assertSerializableBindings(runOptions?.bindings);
|
|
12987
|
+
const bindings = mergeBindings(runOptions?.bindings);
|
|
12988
|
+
const effectHandlers = mergeEffectHandlers(runOptions?.effectHandlers);
|
|
12989
|
+
const pure = runOptions?.pure ?? false;
|
|
12990
|
+
assertNotPureWithHandlers(pure, effectHandlers);
|
|
12991
|
+
try {
|
|
12992
|
+
const contextStack = createContextStack({ bindings }, modules, pure);
|
|
12993
|
+
if (isDvalaBundle(source)) {
|
|
12994
|
+
const savedPure = contextStack.pure;
|
|
12995
|
+
contextStack.pure = true;
|
|
12996
|
+
for (const [name, fileSource] of source.fileModules) {
|
|
12997
|
+
const fileAst = buildAst(fileSource);
|
|
12998
|
+
const moduleContextStack = contextStack.create({});
|
|
12999
|
+
contextStack.registerValueModule(name, evaluate(fileAst, moduleContextStack));
|
|
13000
|
+
}
|
|
13001
|
+
contextStack.pure = savedPure;
|
|
13002
|
+
}
|
|
13003
|
+
const programSource = isDvalaBundle(source) ? source.program : source;
|
|
13004
|
+
const ast = buildAst(programSource);
|
|
13005
|
+
const result = await evaluateWithEffects(ast, contextStack, effectHandlers, runOptions?.maxSnapshots, {
|
|
13006
|
+
values: bindings,
|
|
13007
|
+
modules,
|
|
13008
|
+
});
|
|
13009
|
+
if (result.type === 'completed') {
|
|
13010
|
+
return { ...result, definedBindings: contextStack.getModuleScopeBindings() };
|
|
13011
|
+
}
|
|
13012
|
+
return result;
|
|
13013
|
+
}
|
|
13014
|
+
catch (error) {
|
|
13015
|
+
if (error instanceof DvalaError) {
|
|
13016
|
+
return { type: 'error', error };
|
|
13017
|
+
}
|
|
13018
|
+
if (error instanceof TypeError) {
|
|
13019
|
+
throw error;
|
|
13020
|
+
}
|
|
13021
|
+
return { type: 'error', error: new DvalaError(`${error}`, undefined) };
|
|
13022
|
+
}
|
|
13023
|
+
},
|
|
13024
|
+
getUndefinedSymbols(source) {
|
|
13025
|
+
const modulesList = modules ? [...modules.values()] : undefined;
|
|
13026
|
+
return getUndefinedSymbols(source, { bindings: factoryBindings, modules: modulesList });
|
|
13027
|
+
},
|
|
13028
|
+
getAutoCompleter(program, position) {
|
|
13029
|
+
const params = { bindings: factoryBindings };
|
|
13030
|
+
return new AutoCompleter(program, position, params);
|
|
13031
|
+
},
|
|
13032
|
+
};
|
|
13033
|
+
}
|
|
13072
13034
|
|
|
13073
13035
|
var assertionModuleSource = "{}";
|
|
13074
13036
|
|
|
@@ -14448,7 +14410,7 @@ const assertModule = {
|
|
|
14448
14410
|
docs: moduleDocs$5,
|
|
14449
14411
|
};
|
|
14450
14412
|
|
|
14451
|
-
var gridModuleSource = "do\nlet _transpose = (g) ->\n map(range(count(first(g))), (i) ->\n map(range(count(g)), (j) -> nth(nth(g, j), i))\n );\n{\n \"cell-every?\": (grid, predicate) -> do\n let cells = flatten(grid, 1);\n loop(i = 0) ->\n cond\n case i >= count(cells) then true\n case not(predicate(nth(cells, i))) then false\n case true then recur(i + 1)\n end\n end,\n
|
|
14413
|
+
var gridModuleSource = "do\nlet _transpose = (g) ->\n map(range(count(first(g))), (i) ->\n map(range(count(g)), (j) -> nth(nth(g, j), i))\n );\n{\n \"cell-every?\": (grid, predicate) -> do\n let cells = flatten(grid, 1);\n loop(i = 0) ->\n cond\n case i >= count(cells) then true\n case not(predicate(nth(cells, i))) then false\n case true then recur(i + 1)\n end\n end,\n \"some?\": (grid, predicate) -> do\n let cells = flatten(grid, 1);\n loop(i = 0) ->\n cond\n case i >= count(cells) then false\n case predicate(nth(cells, i)) then true\n case true then recur(i + 1)\n end\n end,\n\n \"every-row?\": (grid, predicate) ->\n loop(i = 0) ->\n cond\n case i >= count(grid) then true\n case not(predicate(nth(grid, i))) then false\n case true then recur(i + 1)\n end,\n\n \"some-row?\": (grid, predicate) ->\n loop(i = 0) ->\n cond\n case i >= count(grid) then false\n case predicate(nth(grid, i)) then true\n case true then recur(i + 1)\n end,\n\n \"every-col?\": (grid, predicate) -> do\n let cols = _transpose(grid);\n loop(i = 0) ->\n cond\n case i >= count(cols) then true\n case not(predicate(nth(cols, i))) then false\n case true then recur(i + 1)\n end\n end,\n\n \"some-col?\": (grid, predicate) -> do\n let cols = _transpose(grid);\n loop(i = 0) ->\n cond\n case i >= count(cols) then false\n case predicate(nth(cols, i)) then true\n case true then recur(i + 1)\n end\n end,\n\n \"generate\": (rows, cols, generator) ->\n map(range(rows), (i) -> map(range(cols), (j) -> generator(i, j))),\n\n \"cell-map\": (...params) -> do\n let fn = last(params);\n let grids = drop-last(params, 1);\n let rows = count(first(grids));\n let cols = count(first(first(grids)));\n map(range(rows), (i) ->\n map(range(cols), (j) ->\n apply(fn, map(grids, (g) -> nth(nth(g, i), j)))\n )\n )\n end,\n\n \"cell-mapi\": (grid, fn) -> do\n let rows = count(grid);\n let cols = count(first(grid));\n map(range(rows), (i) ->\n map(range(cols), (j) ->\n fn(nth(nth(grid, i), j), i, j)\n )\n )\n end,\n\n \"cell-reduce\": (grid, fn, initial-value) ->\n reduce(flatten(grid, 1), fn, initial-value),\n\n \"cell-reducei\": (grid, fn, initial-value) -> do\n let rows = count(grid);\n let cols = count(first(grid));\n loop(acc = initial-value, i = 0, j = 0) ->\n cond\n case i >= rows then acc\n case j >= cols then recur(acc, i + 1, 0)\n case true then recur(fn(acc, nth(nth(grid, i), j), i, j), i, j + 1)\n end\n end\n}\nend;";
|
|
14452
14414
|
|
|
14453
14415
|
const moduleDocs$4 = {
|
|
14454
14416
|
'cell-every?': {
|
|
@@ -34681,7 +34643,7 @@ function runTest({ testPath: filePath, testNamePattern }) {
|
|
|
34681
34643
|
}
|
|
34682
34644
|
else {
|
|
34683
34645
|
try {
|
|
34684
|
-
const dvala =
|
|
34646
|
+
const dvala = createDvala({ debug: true, modules: allBuiltinModules });
|
|
34685
34647
|
const bindings = getBindings(includedFilePaths, dvala);
|
|
34686
34648
|
dvala.run(testChunkProgram.program, {
|
|
34687
34649
|
bindings,
|
|
@@ -37064,7 +37026,7 @@ function getArgumentInfo(fmt, reference) {
|
|
|
37064
37026
|
}
|
|
37065
37027
|
|
|
37066
37028
|
/* eslint-disable no-console */
|
|
37067
|
-
const dvala =
|
|
37029
|
+
const dvala = createDvala({ debug: false });
|
|
37068
37030
|
function getCliFunctionExamples(fmt, reference) {
|
|
37069
37031
|
const { examples } = reference;
|
|
37070
37032
|
return examples
|
|
@@ -37671,19 +37633,15 @@ const helpRegExp = new RegExp(`^\`help\\s+(${polishSymbolFirstCharacterClass}${p
|
|
|
37671
37633
|
const expressions = [...normalExpressionKeys, ...specialExpressionKeys];
|
|
37672
37634
|
const config = processArguments(process.argv.slice(2));
|
|
37673
37635
|
const cliModules = getCliModules();
|
|
37674
|
-
function
|
|
37675
|
-
const
|
|
37636
|
+
function makeDvala(bindings, pure) {
|
|
37637
|
+
const runner = createDvala({ debug: true, modules: [...allBuiltinModules, ...cliModules], bindings });
|
|
37676
37638
|
return {
|
|
37677
|
-
run: (program) =>
|
|
37678
|
-
globalContext: context,
|
|
37679
|
-
globalModuleScope: true,
|
|
37680
|
-
pure,
|
|
37681
|
-
}),
|
|
37639
|
+
run: (program) => runner.run(program, { pure }),
|
|
37682
37640
|
};
|
|
37683
37641
|
}
|
|
37684
37642
|
switch (config.subcommand) {
|
|
37685
37643
|
case 'run': {
|
|
37686
|
-
const dvala =
|
|
37644
|
+
const dvala = makeDvala(config.context, config.pure);
|
|
37687
37645
|
try {
|
|
37688
37646
|
const content = fs.readFileSync(config.filename, { encoding: 'utf-8' });
|
|
37689
37647
|
const result = dvala.run(content);
|
|
@@ -37699,7 +37657,7 @@ switch (config.subcommand) {
|
|
|
37699
37657
|
break;
|
|
37700
37658
|
}
|
|
37701
37659
|
case 'run-bundle': {
|
|
37702
|
-
const dvala =
|
|
37660
|
+
const dvala = makeDvala(config.context, config.pure);
|
|
37703
37661
|
try {
|
|
37704
37662
|
const content = fs.readFileSync(config.filename, { encoding: 'utf-8' });
|
|
37705
37663
|
let parsed;
|
|
@@ -37727,7 +37685,7 @@ switch (config.subcommand) {
|
|
|
37727
37685
|
break;
|
|
37728
37686
|
}
|
|
37729
37687
|
case 'eval': {
|
|
37730
|
-
const dvala =
|
|
37688
|
+
const dvala = makeDvala(config.context, config.pure);
|
|
37731
37689
|
try {
|
|
37732
37690
|
const result = dvala.run(config.expression);
|
|
37733
37691
|
if (config.printResult) {
|
|
@@ -37767,12 +37725,12 @@ switch (config.subcommand) {
|
|
|
37767
37725
|
}
|
|
37768
37726
|
case 'repl': {
|
|
37769
37727
|
if (config.loadFilename) {
|
|
37770
|
-
const dvala =
|
|
37728
|
+
const dvala = makeDvala(config.context, false);
|
|
37771
37729
|
const content = fs.readFileSync(config.loadFilename, { encoding: 'utf-8' });
|
|
37772
37730
|
const result = dvala.run(content);
|
|
37773
37731
|
if (result !== null && typeof result === 'object' && !Array.isArray(result)) {
|
|
37774
37732
|
for (const [key, value] of Object.entries(result)) {
|
|
37775
|
-
config.context[key] =
|
|
37733
|
+
config.context[key] = value;
|
|
37776
37734
|
}
|
|
37777
37735
|
}
|
|
37778
37736
|
}
|
|
@@ -37803,13 +37761,12 @@ function runDvalaTest(testPath, testNamePattern) {
|
|
|
37803
37761
|
if (!success)
|
|
37804
37762
|
process.exit(1);
|
|
37805
37763
|
}
|
|
37806
|
-
async function execute(expression,
|
|
37807
|
-
const _dvala =
|
|
37764
|
+
async function execute(expression, bindings, readLine) {
|
|
37765
|
+
const _dvala = createDvala({ debug: true, modules: [...allBuiltinModules, ...cliModules] });
|
|
37808
37766
|
try {
|
|
37809
|
-
const
|
|
37810
|
-
|
|
37811
|
-
|
|
37812
|
-
handlers: {
|
|
37767
|
+
const runResult = await _dvala.runAsync(expression, {
|
|
37768
|
+
bindings,
|
|
37769
|
+
effectHandlers: {
|
|
37813
37770
|
'dvala.io.read-line': async ({ args, resume }) => {
|
|
37814
37771
|
const message = typeof args[0] === 'string' ? args[0] : '';
|
|
37815
37772
|
const answer = await readLine(message);
|
|
@@ -37817,18 +37774,21 @@ async function execute(expression, context, readLine) {
|
|
|
37817
37774
|
},
|
|
37818
37775
|
},
|
|
37819
37776
|
});
|
|
37777
|
+
if (runResult.type === 'error')
|
|
37778
|
+
throw runResult.error;
|
|
37779
|
+
const result = runResult.type === 'completed' ? runResult.value : null;
|
|
37820
37780
|
historyResults.unshift(result);
|
|
37821
37781
|
if (historyResults.length > 9) {
|
|
37822
37782
|
historyResults.length = 9;
|
|
37823
37783
|
}
|
|
37824
|
-
|
|
37784
|
+
const newBindings = { ...bindings, ...(runResult.type === 'completed' ? runResult.definedBindings : {}) };
|
|
37785
|
+
setReplHistoryVariables(newBindings);
|
|
37825
37786
|
console.log(stringifyValue(result, false));
|
|
37826
|
-
return
|
|
37787
|
+
return newBindings;
|
|
37827
37788
|
}
|
|
37828
37789
|
catch (error) {
|
|
37829
37790
|
printErrorMessage(`${error}`);
|
|
37830
|
-
|
|
37831
|
-
return false;
|
|
37791
|
+
return { ...bindings, '*e*': getErrorMessage(error) };
|
|
37832
37792
|
}
|
|
37833
37793
|
}
|
|
37834
37794
|
function getErrorMessage(error) {
|
|
@@ -37836,18 +37796,11 @@ function getErrorMessage(error) {
|
|
|
37836
37796
|
return error.message;
|
|
37837
37797
|
return 'Unknown error';
|
|
37838
37798
|
}
|
|
37839
|
-
function setReplHistoryVariables(
|
|
37840
|
-
|
|
37841
|
-
|
|
37842
|
-
delete context['*3*'];
|
|
37843
|
-
delete context['*4*'];
|
|
37844
|
-
delete context['*5*'];
|
|
37845
|
-
delete context['*6*'];
|
|
37846
|
-
delete context['*7*'];
|
|
37847
|
-
delete context['*8*'];
|
|
37848
|
-
delete context['*9*'];
|
|
37799
|
+
function setReplHistoryVariables(bindings) {
|
|
37800
|
+
for (let i = 1; i <= 9; i++)
|
|
37801
|
+
delete bindings[`*${i}*`];
|
|
37849
37802
|
historyResults.forEach((value, i) => {
|
|
37850
|
-
|
|
37803
|
+
bindings[`*${i + 1}*`] = value;
|
|
37851
37804
|
});
|
|
37852
37805
|
}
|
|
37853
37806
|
function parseOption(args, i) {
|
|
@@ -37890,7 +37843,7 @@ function parseContextOptions(args, startIndex) {
|
|
|
37890
37843
|
}
|
|
37891
37844
|
try {
|
|
37892
37845
|
Object.entries(JSON.parse(parsed.argument)).forEach(([key, value]) => {
|
|
37893
|
-
options.context[key] =
|
|
37846
|
+
options.context[key] = value;
|
|
37894
37847
|
});
|
|
37895
37848
|
}
|
|
37896
37849
|
catch (e) {
|
|
@@ -37908,7 +37861,7 @@ function parseContextOptions(args, startIndex) {
|
|
|
37908
37861
|
try {
|
|
37909
37862
|
const contextString = fs.readFileSync(parsed.argument, { encoding: 'utf-8' });
|
|
37910
37863
|
Object.entries(JSON.parse(contextString)).forEach(([key, value]) => {
|
|
37911
|
-
options.context[key] =
|
|
37864
|
+
options.context[key] = value;
|
|
37912
37865
|
});
|
|
37913
37866
|
}
|
|
37914
37867
|
catch (e) {
|
|
@@ -38140,9 +38093,10 @@ function processArguments(args) {
|
|
|
38140
38093
|
}
|
|
38141
38094
|
}
|
|
38142
38095
|
}
|
|
38143
|
-
function runREPL(
|
|
38096
|
+
function runREPL(initialBindings) {
|
|
38144
38097
|
console.log(`Welcome to Dvala v${version}.
|
|
38145
38098
|
Type ${fmt.italic('`help')} for more information.`);
|
|
38099
|
+
let bindings = initialBindings;
|
|
38146
38100
|
const rl = createReadlineInterface({
|
|
38147
38101
|
completer,
|
|
38148
38102
|
historySize: HIST_SIZE,
|
|
@@ -38169,7 +38123,7 @@ Type ${fmt.italic('`help')} for more information.`);
|
|
|
38169
38123
|
printHelp();
|
|
38170
38124
|
break;
|
|
38171
38125
|
case '`context':
|
|
38172
|
-
printContext(
|
|
38126
|
+
printContext(bindings);
|
|
38173
38127
|
break;
|
|
38174
38128
|
case '`quit':
|
|
38175
38129
|
rl.close();
|
|
@@ -38179,7 +38133,7 @@ Type ${fmt.italic('`help')} for more information.`);
|
|
|
38179
38133
|
}
|
|
38180
38134
|
}
|
|
38181
38135
|
else if (line) {
|
|
38182
|
-
await execute(line,
|
|
38136
|
+
bindings = await execute(line, bindings, readLine);
|
|
38183
38137
|
}
|
|
38184
38138
|
rl.prompt();
|
|
38185
38139
|
}).on('close', () => {
|
|
@@ -38248,14 +38202,14 @@ Global options:
|
|
|
38248
38202
|
With no subcommand, starts an interactive REPL.
|
|
38249
38203
|
`.trim());
|
|
38250
38204
|
}
|
|
38251
|
-
function printContext(
|
|
38252
|
-
const keys = Object.keys(
|
|
38205
|
+
function printContext(bindings) {
|
|
38206
|
+
const keys = Object.keys(bindings);
|
|
38253
38207
|
if (keys.length === 0) {
|
|
38254
38208
|
console.log('[empty]\n');
|
|
38255
38209
|
}
|
|
38256
38210
|
else {
|
|
38257
38211
|
keys.sort().forEach((x) => {
|
|
38258
|
-
console.log(`${x} = ${formatValue(stringifyValue(
|
|
38212
|
+
console.log(`${x} = ${formatValue(stringifyValue(bindings[x]))}`);
|
|
38259
38213
|
});
|
|
38260
38214
|
console.log();
|
|
38261
38215
|
}
|
|
@@ -38270,8 +38224,8 @@ function completer(line) {
|
|
|
38270
38224
|
if (expressionMatch)
|
|
38271
38225
|
return [expressions.filter(c => c.startsWith(expressionMatch[2])).map(c => `${expressionMatch[1]}${c} `), line];
|
|
38272
38226
|
// TODO, add reserved names
|
|
38273
|
-
const
|
|
38274
|
-
const names = Array.from(new Set([...Object.keys(
|
|
38227
|
+
const replBindings = config.context ?? {};
|
|
38228
|
+
const names = Array.from(new Set([...Object.keys(replBindings)]));
|
|
38275
38229
|
const nameMatch = nameRegExp.exec(line);
|
|
38276
38230
|
if (nameMatch)
|
|
38277
38231
|
return [names.filter(c => c.startsWith(nameMatch[2])).map(c => `${nameMatch[1]}${c} `), line];
|