@thomasfosterau/effect-parse 0.2.0 → 0.3.0

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.
@@ -1 +1 @@
1
- {"version":3,"file":"ParserSchema.js","names":[],"sources":["../src/ParserSchema.ts"],"sourcesContent":["/**\n * Building Effect `Schema`s from parsers.\n *\n * A parser over strings becomes a schema that decodes a `string` into the\n * parser's output. Parse errors become schema issues carrying the rendered\n * `ParseError` message. Encoding needs a printer, supplied as `encode`;\n * without one, encoding is forbidden.\n *\n * @example\n * ```ts\n * import { Schema } from \"effect\"\n * import { Ascii, Parser, ParserSchema, Token } from \"@thomasfosterau/effect-parse\"\n *\n * const Version = ParserSchema.make(\n * Parser.struct({\n * major: Ascii.decUint,\n * minor: Parser.preceded(Token.literal(\".\"), Ascii.decUint)\n * }),\n * { encode: ({ major, minor }) => `${major}.${minor}` }\n * )\n *\n * Schema.decodeUnknownSync(Version)(\"1.2\") // { major: 1, minor: 2 }\n * Schema.encodeSync(Version)({ major: 3, minor: 4 }) // \"3.4\"\n * ```\n *\n * @since 0.1.0\n */\nimport * as Effect from \"effect/Effect\"\nimport * as Result from \"effect/Result\"\nimport * as Schema from \"effect/Schema\"\nimport * as SchemaIssue from \"effect/SchemaIssue\"\nimport * as SchemaTransformation from \"effect/SchemaTransformation\"\nimport type { Parser } from \"./Parser.js\"\nimport * as P from \"./Parser.js\"\n\n/**\n * Options for {@link make}.\n *\n * @since 0.1.0\n * @category models\n */\nexport interface Options<A> {\n /** Prints a value back to a string. Without it, encoding fails. */\n readonly encode?: ((value: A) => string) | undefined\n /** A description of the decoded type, used by schema tooling. */\n readonly description?: string | undefined\n}\n\n/**\n * A schema decoding strings with a parser.\n *\n * @since 0.1.0\n * @category models\n */\nexport interface ParserSchema<A> extends Schema.decodeTo<Schema.declare<A>, Schema.String> {}\n\n/**\n * Creates a schema that decodes a string with `parser`, which must consume\n * the whole string.\n *\n * @since 0.1.0\n * @category constructors\n */\nexport const make = <A, E>(parser: Parser<A, E, never, string>, options?: Options<A>): ParserSchema<A> => {\n const target = Schema.declare<A>(\n (_u): _u is A => true,\n options?.description !== undefined ? { description: options.description } : undefined\n )\n const encode = options?.encode\n return Schema.String.pipe(\n Schema.decodeTo(\n target,\n SchemaTransformation.transformEffect<A, string>({\n decode: (input, parseOptions) => {\n const result = P.parse(parser, input)\n return Result.isSuccess(result)\n ? Effect.succeed(result.success)\n : Effect.fail(new SchemaIssue.InvalidValue({ message: result.failure.message }, input, parseOptions))\n },\n encode: (value, parseOptions) =>\n encode !== undefined\n ? Effect.succeed(encode(value))\n : Effect.fail(new SchemaIssue.Forbidden({ message: \"Encoding is not supported\" }, value, parseOptions))\n })\n )\n )\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+DA,MAAa,QAAc,QAAqC,YAA0C;CACxG,MAAM,SAAS,OAAO,SACnB,OAAgB,MACjB,SAAS,gBAAgB,KAAA,IAAY,EAAE,aAAa,QAAQ,YAAY,IAAI,KAAA,CAC9E;CACA,MAAM,SAAS,SAAS;CACxB,OAAO,OAAO,OAAO,KACnB,OAAO,SACL,QACA,qBAAqB,gBAA2B;EAC9C,SAAS,OAAO,iBAAiB;GAC/B,MAAM,SAAS,EAAE,MAAM,QAAQ,KAAK;GACpC,OAAO,OAAO,UAAU,MAAM,IAC1B,OAAO,QAAQ,OAAO,OAAO,IAC7B,OAAO,KAAK,IAAI,YAAY,aAAa,EAAE,SAAS,OAAO,QAAQ,QAAQ,GAAG,OAAO,YAAY,CAAC;EACxG;EACA,SAAS,OAAO,iBACd,WAAW,KAAA,IACP,OAAO,QAAQ,OAAO,KAAK,CAAC,IAC5B,OAAO,KAAK,IAAI,YAAY,UAAU,EAAE,SAAS,4BAA4B,GAAG,OAAO,YAAY,CAAC;CAC5G,CAAC,CACH,CACF;AACF"}
1
+ {"version":3,"file":"ParserSchema.js","names":[],"sources":["../src/ParserSchema.ts"],"sourcesContent":["/**\n * Effect `Schema`s and parsers, in both directions.\n *\n * {@link make} turns a parser over strings into a schema that decodes a\n * `string` into the parser's output. Parse errors become schema issues\n * carrying the rendered `ParseError` message. Encoding needs a printer,\n * supplied as `encode`; without one, encoding is forbidden.\n *\n * {@link toParser} goes the other way: it derives a parser from a schema,\n * guided by annotations ({@link annotate}) that say how each part is\n * written. {@link toPrinter} derives the printer that writes that text, and\n * {@link fromSchema} wraps both as a schema.\n *\n * @example\n * ```ts\n * import { Schema } from \"effect\"\n * import { Ascii, Parser, ParserSchema, Token } from \"@thomasfosterau/effect-parse\"\n *\n * const Version = ParserSchema.make(\n * Parser.struct({\n * major: Ascii.decUint,\n * minor: Parser.preceded(Token.literal(\".\"), Ascii.decUint)\n * }),\n * { encode: ({ major, minor }) => `${major}.${minor}` }\n * )\n *\n * Schema.decodeUnknownSync(Version)(\"1.2\") // { major: 1, minor: 2 }\n * Schema.encodeSync(Version)({ major: 3, minor: 4 }) // \"3.4\"\n * ```\n *\n * @since 0.1.0\n */\nimport * as Arr from \"effect/Array\"\nimport * as Effect from \"effect/Effect\"\nimport { dual } from \"effect/Function\"\nimport * as Match from \"effect/Match\"\nimport * as MutableHashMap from \"effect/MutableHashMap\"\nimport * as Option from \"effect/Option\"\nimport * as Order from \"effect/Order\"\nimport * as Predicate from \"effect/Predicate\"\nimport * as Record from \"effect/Record\"\nimport * as Result from \"effect/Result\"\nimport * as Schema from \"effect/Schema\"\nimport * as SchemaAST from \"effect/SchemaAST\"\nimport * as SchemaIssue from \"effect/SchemaIssue\"\nimport * as SchemaTransformation from \"effect/SchemaTransformation\"\nimport * as Ascii from \"./Ascii.js\"\nimport type { Parser } from \"./Parser.js\"\nimport * as P from \"./Parser.js\"\nimport * as Token from \"./Token.js\"\nimport { describeLiteral } from \"./internal/tokens.js\"\n\n/**\n * The key of the annotation that says how a schema is written as text\n * ({@link Annotation}), namespaced to this package so it cannot collide with\n * another library's. {@link annotate} sets it.\n *\n * @since 0.3.0\n * @category annotations\n */\nexport const annotationKey = \"@thomasfosterau/effect-parse/ParserSchema\" as const\n\ndeclare module \"effect/Schema\" {\n namespace Annotations {\n interface Annotations {\n /**\n * How the schema is written as text, read by `ParserSchema.toParser`\n * and `ParserSchema.toPrinter`: a parser for the schema's type, or a\n * `ParserSchema.Grammar`.\n */\n readonly [annotationKey]?: Annotation<any> | undefined\n }\n }\n}\n\n/**\n * Options for {@link make}.\n *\n * @since 0.1.0\n * @category models\n */\nexport interface Options<A> {\n /** Prints a value back to a string. Without it, encoding fails. */\n readonly encode?: ((value: A) => string) | undefined\n /** A description of the decoded type, used by schema tooling. */\n readonly description?: string | undefined\n}\n\n/**\n * A schema decoding strings with a parser.\n *\n * @since 0.1.0\n * @category models\n */\nexport interface ParserSchema<A> extends Schema.decodeTo<Schema.declare<A>, Schema.String> {}\n\ntype Encode<A> = (value: A) => Result.Result<string, SchemaIssue.Issue>\n\nconst encodeWith =\n <A>(encode: (value: A) => string): Encode<A> =>\n (value) =>\n Result.succeed(encode(value))\n\nconst decodeWith = <T extends Schema.Top>(\n target: T,\n parser: Parser<T[\"Encoded\"], unknown, never, string>,\n encode: Encode<T[\"Encoded\"]> | undefined\n) =>\n Schema.String.pipe(\n Schema.decodeTo(\n target,\n SchemaTransformation.transformEffect<T[\"Encoded\"], string>({\n decode: (input, parseOptions) => {\n const result = P.parse(parser, input)\n return Result.isSuccess(result)\n ? Effect.succeed(result.success)\n : Effect.fail(new SchemaIssue.InvalidValue({ message: result.failure.message }, input, parseOptions))\n },\n encode: (value, parseOptions) => {\n if (encode === undefined) {\n return Effect.fail(new SchemaIssue.Forbidden({ message: \"Encoding is not supported\" }, value, parseOptions))\n }\n const result = encode(value)\n return Result.isSuccess(result) ? Effect.succeed(result.success) : Effect.fail(result.failure)\n }\n })\n )\n )\n\n/**\n * Creates a schema that decodes a string with `parser`, which must consume\n * the whole string.\n *\n * @since 0.1.0\n * @category constructors\n */\nexport const make = <A, E>(parser: Parser<A, E, never, string>, options?: Options<A>): ParserSchema<A> =>\n decodeWith(\n Schema.declare<A>(\n (_u): _u is A => true,\n options?.description !== undefined ? { description: options.description } : undefined\n ),\n parser,\n options?.encode === undefined ? undefined : encodeWith(options.encode)\n )\n\n// -----------------------------------------------------------------------------\n// Deriving parsers and printers from schemas\n// -----------------------------------------------------------------------------\n\n/**\n * How a schema is written as text, given in its annotation (see\n * {@link annotate}) and read by {@link toParser} and {@link toPrinter}.\n * Every field is optional; a schema without one is written as described on\n * {@link toParser}.\n *\n * @since 0.3.0\n * @category models\n */\nexport interface Grammar<A = unknown> {\n /**\n * Parses the schema's type outright, replacing what {@link toParser} would\n * derive. Its output is still validated against the schema's type and\n * checks, and its failures' causes become `SchemaError`s with their message.\n * Give a {@link Grammar.print} with it, or the schema cannot be printed.\n */\n readonly parser?: Parser<A, unknown, never, string> | undefined\n /** Writes a value as the text {@link Grammar.parser} reads, replacing what {@link toPrinter} would derive. */\n readonly print?: ((value: A) => string) | undefined\n /** Text written before the value. */\n readonly prefix?: string | undefined\n /** Text written after the value. */\n readonly suffix?: string | undefined\n /** Text written between the fields of a struct, the elements of a tuple or array, or the entries of a record. */\n readonly separator?: string | undefined\n /**\n * Text written between a key and its value. On a struct, it writes each\n * field as `key`, separator, value, in any order; records always need one.\n */\n readonly keySeparator?: string | undefined\n /**\n * Whether whitespace may surround the text this schema writes (its prefix,\n * suffix and separators), and whitespace around unannotated strings is\n * trimmed. Inherited by the schemas inside it. Printers write no\n * whitespace.\n */\n readonly whitespace?: boolean | undefined\n}\n\n/**\n * The value of the annotation under {@link annotationKey}: a\n * {@link Grammar}, or a parser for the schema's type (short for\n * `{ parser }`, which cannot be printed).\n *\n * @since 0.3.0\n * @category models\n */\nexport type Annotation<A = unknown> = Grammar<A> | Parser<A, unknown, never, string>\n\n/**\n * Annotates a schema with how it is written as text, for {@link toParser}\n * and {@link toPrinter}. The same as\n * `schema.annotate({ [ParserSchema.annotationKey]: annotation })`, except\n * that the parser's output must have the schema's type.\n *\n * @example\n * ```ts\n * import { Schema } from \"effect\"\n * import { ParserSchema } from \"@thomasfosterau/effect-parse\"\n *\n * const Point = Schema.Struct({ x: Schema.Int, y: Schema.Int }).pipe(\n * ParserSchema.annotate({ prefix: \"(\", separator: \",\", suffix: \")\" })\n * )\n * ```\n *\n * @since 0.3.0\n * @category annotations\n */\nexport const annotate: {\n // A grammar without a parser constrains nothing\n <A = never>(\n annotation: Annotation<A>\n ): <S extends Schema.Top>(self: S & ([A] extends [S[\"Type\"]] ? unknown : never)) => S[\"Rebuild\"]\n <S extends Schema.Top>(self: S, annotation: Annotation<S[\"Type\"]>): S[\"Rebuild\"]\n} = /*#__PURE__*/ dual(2, <S extends Schema.Top>(self: S, annotation: Annotation<S[\"Type\"]>): S[\"Rebuild\"] =>\n self.annotate({ [annotationKey]: annotation })\n)\n\n/**\n * Derives a parser from a schema. The parser reads the text the schema's\n * annotations ({@link Grammar}) describe and returns a value of the schema's\n * type, which the schema's checks and transformations have already\n * validated; their failures become parse errors whose `cause` is the\n * `SchemaError`.\n *\n * Without an annotation, a schema is parsed as follows:\n *\n * - `String`: one or more characters up to the next separator, key\n * separator, suffix or literal around it (to the end of the input at the\n * top level).\n * - `Number`: a decimal number (`Ascii.float`), or a decimal integer when\n * the schema checks `isInt` (as `Schema.Int` does). `BigInt`: a decimal\n * integer. `Boolean`: `true` or `false`. `Null`: `null`. `Undefined` and\n * `Void`: nothing.\n * - `Literal`, `Enum` and `TemplateLiteral`: their text.\n * - `Struct` and `Tuple`: their fields or elements in order, between\n * separators; an optional one may be left out along with its separator.\n * `Array`: elements between separators.\n * - `Record`, and `Struct` with a `keySeparator`: `key`, key separator,\n * value entries in any order, between separators.\n * - `Union`: the first member that parses, in order (literals longest\n * first). `suspend`: recursion.\n * - A transformation (a `Class`, `NumberFromString`, ...): its encoded side,\n * decoded by the schema. A grammar on it with a separator applies to the\n * encoded side.\n *\n * A parser that fails where the schema starts reports the schema's\n * `identifier` annotation (or its `expected` annotation, unless that belongs\n * to a check) as what it expected. Other declarations, `Unknown`, `Any`,\n * symbols and `object` need a parser in their annotation; without one,\n * `toParser` throws. Transformations must decode synchronously.\n *\n * @example\n * ```ts\n * import { Schema } from \"effect\"\n * import { Parser, ParserSchema } from \"@thomasfosterau/effect-parse\"\n *\n * const Version = Schema.Struct({ major: Schema.Int, minor: Schema.Int }).pipe(\n * ParserSchema.annotate({ separator: \".\" })\n * )\n *\n * Parser.parse(ParserSchema.toParser(Version), \"1.2\") // Result.succeed({ major: 1, minor: 2 })\n * ```\n *\n * @since 0.3.0\n * @category derivation\n */\nexport const toParser = <S extends Schema.ConstraintDecoder<unknown>>(\n schema: S\n): Parser<S[\"Type\"], Schema.SchemaError, never, string> => {\n const ast = schema.ast\n const parser = derive(ast, initial<AnyParser>())\n return grammarOf(ast).whitespace === true ? P.delimited(Ascii.multispace0, parser, Ascii.multispace0) : parser\n}\n\n/**\n * Derives a printer from a schema: it writes a value of the schema's type as\n * the text {@link toParser} reads, following the same annotations, with no\n * optional whitespace. Transformations encode the value first, and a\n * {@link Grammar.print} replaces the derived printer.\n *\n * The printer fails with a `SchemaError` when the value is not of the\n * schema's type, or cannot be written so that it reads back: a string that\n * is empty or contains a character that would end it (a separator, a\n * suffix), or a part annotated with a parser but no `print`. Where the\n * grammar is ambiguous (an optional field followed by a field of the same\n * type), the text can still read back as a different value;\n * {@link fromSchema} checks that it doesn't.\n *\n * @example\n * ```ts\n * import { Schema } from \"effect\"\n * import { ParserSchema } from \"@thomasfosterau/effect-parse\"\n *\n * const Version = Schema.Struct({ major: Schema.Int, minor: Schema.Int }).pipe(\n * ParserSchema.annotate({ separator: \".\" })\n * )\n *\n * ParserSchema.toPrinter(Version)({ major: 1, minor: 2 }) // Result.succeed(\"1.2\")\n * ```\n *\n * @since 0.3.0\n * @category derivation\n */\nexport const toPrinter = <S extends Schema.ConstraintCodec<unknown, unknown, unknown, never>>(\n schema: S\n): ((value: S[\"Type\"]) => Result.Result<string, Schema.SchemaError>) => {\n const validate = typeDecoder(schema.ast)\n const print = printerOf(schema.ast, initial<Printer>())\n return (value) => {\n const valid = validate(value)\n if (Result.isFailure(valid)) return Result.fail(valid.failure)\n const out: Array<string> = []\n const issue = print(valid.success, out)\n return issue === undefined ? Result.succeed(out.join(\"\")) : Result.fail(schemaError(issue))\n }\n}\n\n/**\n * Creates a schema that decodes a string with the parser {@link toParser}\n * derives from `schema`, into `schema`'s type, and encodes with the printer\n * {@link toPrinter} derives, or with `encode` when given. A derived printer's\n * text is parsed back, and encoding fails unless it gives a value equivalent\n * to the one encoded, so decoding what was encoded always gives it back.\n *\n * @example\n * ```ts\n * import { Schema } from \"effect\"\n * import { ParserSchema } from \"@thomasfosterau/effect-parse\"\n *\n * const Pair = ParserSchema.fromSchema(\n * Schema.Tuple([Schema.String, Schema.Number]).pipe(ParserSchema.annotate({ separator: \"=\" }))\n * )\n *\n * Schema.decodeUnknownSync(Pair)(\"width=10\") // [\"width\", 10]\n * Schema.encodeSync(Pair)([\"height\", 2]) // \"height=2\"\n * ```\n *\n * @since 0.3.0\n * @category constructors\n */\nexport const fromSchema = <S extends Schema.ConstraintCodec<unknown, unknown, never, never> & Schema.Top>(\n schema: S,\n options?: { readonly encode?: ((value: S[\"Type\"]) => string) | undefined }\n): Schema.decodeTo<Schema.toType<S>, Schema.String> => {\n const parser = toParser(schema)\n const encode = options?.encode\n return decodeWith<Schema.toType<S>>(\n Schema.toType(schema),\n parser,\n encode === undefined ? roundTrip(schema, parser) : encodeWith(encode)\n )\n}\n\n/** Prints with the derived printer, then checks that the text reads back as the value. */\nconst roundTrip = <S extends Schema.ConstraintCodec<unknown, unknown, never, never> & Schema.Top>(\n schema: S,\n parser: Parser<S[\"Type\"], Schema.SchemaError, never, string>\n): Encode<S[\"Type\"]> => {\n const print = toPrinter(schema)\n const equivalent = Schema.toEquivalence(Schema.toType(schema))\n return (value) =>\n Result.flatMap(\n Result.mapError(print(value), (error) => error.issue),\n (text) => {\n const back = P.parse(parser, text)\n return Result.isSuccess(back) && equivalent(back.success, value)\n ? Result.succeed(text)\n : Result.fail(\n new SchemaIssue.InvalidValue({\n message: `The value is written ${describeLiteral(text)}, which does not read back as the value`\n })\n )\n }\n )\n}\n\n// -----------------------------------------------------------------------------\n// The walk shared by parsers and printers\n// -----------------------------------------------------------------------------\n\ninterface Context<T> {\n /** Characters ending an unannotated string, sorted. */\n readonly stop: string\n readonly whitespace: boolean\n /** Grammar passed from a transformation to its encoded side. */\n readonly inherit: Grammar | undefined\n readonly path: ReadonlyArray<PropertyKey>\n /** What was derived for the recursive schemas met so far, by context. */\n readonly recursions: Array<Recursion<T>>\n}\n\ninterface Recursion<T> {\n readonly ast: SchemaAST.Suspend\n readonly key: string\n readonly derived: T\n}\n\nconst initial = <T>(): Context<T> => ({ stop: \"\", whitespace: false, inherit: undefined, path: [], recursions: [] })\n\n/** The annotation `key` on `ast`, from its last check back to the node, as `Schema.resolveAnnotations` resolves it. */\nconst lookup = (ast: SchemaAST.AST, key: string): unknown => {\n const checks = ast.checks\n if (checks !== undefined) {\n for (let i = checks.length - 1; i >= 0; i--) {\n const value = checks[i].annotations?.[key]\n if (value !== undefined) return value\n }\n }\n return ast.annotations?.[key]\n}\n\nconst grammarOf = (ast: SchemaAST.AST): Grammar => {\n const value = lookup(ast, annotationKey)\n if (value === undefined) return {}\n // SAFETY: the annotation is typed `Annotation`, a parser or a grammar\n return P.isParser(value) ? { parser: value as ForeignParser } : (value as Grammar)\n}\n\nconst isAnnotated = (ast: SchemaAST.AST): boolean => lookup(ast, annotationKey) !== undefined\n\nconst withStop = <T>(ctx: Context<T>, text: string | undefined): Context<T> => {\n if (text === undefined || text === \"\" || ctx.stop.includes(text[0])) return ctx\n return { ...ctx, stop: Arr.sort([...ctx.stop, text[0]], Order.String).join(\"\") }\n}\n\nconst at = <T>(ctx: Context<T>, key: PropertyKey): Context<T> => ({\n ...ctx,\n inherit: undefined,\n path: [...ctx.path, key]\n})\n\nconst where = <T>(ctx: Context<T>): string => `[${ctx.path.map(String).join(\", \")}]`\n\nconst unsupported = <T>(ast: SchemaAST.AST, ctx: Context<T>, what: string): never => {\n throw new TypeError(`ParserSchema: cannot derive a ${what} for ${ast._tag} at ${where(ctx)}; annotate it`)\n}\n\ninterface Resolved<T> {\n readonly grammar: Grammar\n readonly whitespace: boolean\n /** The context of what the node contains. */\n readonly inner: Context<T>\n}\n\n/** The node's grammar, with what its transformation passed down, and the context inside it. */\nconst resolve = <T>(ast: SchemaAST.AST, ctx: Context<T>): Resolved<T> => {\n const own = grammarOf(ast)\n const inherit = ctx.inherit\n const grammar: Grammar =\n inherit === undefined\n ? own\n : {\n ...own,\n separator: own.separator ?? inherit.separator,\n keySeparator: own.keySeparator ?? inherit.keySeparator\n }\n const whitespace = grammar.whitespace ?? ctx.whitespace\n return { grammar, whitespace, inner: { ...withStop(ctx, grammar.suffix), whitespace, inherit: undefined } }\n}\n\n/** The context of a transformation's encoded side, which the transformation's separators apply to. */\nconst encodedContext = <T>(grammar: Grammar, ctx: Context<T>): Context<T> => ({\n ...ctx,\n inherit: { separator: grammar.separator, keySeparator: grammar.keySeparator }\n})\n\n/**\n * The node with its chain of links ending at the type of its encoded side,\n * which is what the encoded side is parsed into and printed from.\n */\nconst linkTarget = (ast: SchemaAST.AST, links: SchemaAST.Encoding): SchemaAST.AST => {\n const last = links[links.length - 1]\n let target = SchemaAST.toType(ast)\n for (const link of links) {\n const source = link === last ? SchemaAST.toType(last.to) : link.to\n // SAFETY: `decodeTo` appends the link as it is, middleware included, as the schema's own links are\n target = SchemaAST.decodeTo(source, target, link.transformation as SchemaTransformation.Transformation<any, any>)\n }\n return target\n}\n\n/**\n * What is derived for a recursive schema: deriving it again in the same\n * context gives the same result, so the derivation ends.\n */\nconst recursive = <T>(ast: SchemaAST.Suspend, ctx: Context<T>, make: () => T): T => {\n const key = `${ctx.whitespace ? 1 : 0}${ctx.stop}`\n const known = ctx.recursions.find((r) => r.ast === ast && r.key === key)\n if (known !== undefined) return known.derived\n const derived = make()\n ctx.recursions.push({ ast, key, derived })\n return derived\n}\n\n/** The context for the items of a sequence: unannotated strings also stop at the separator. */\nconst itemContext = <T>(grammar: Grammar, ctx: Context<T>): Context<T> => withStop(ctx, grammar.separator)\n\n/** The rest element of an array schema, if any; elements after it are not supported. */\nconst restOf = <T>(ast: SchemaAST.Arrays, ctx: Context<T>, what: string): SchemaAST.AST | undefined => {\n const [head, ...after] = ast.rest\n // Elements after the rest would need the rest to stop short\n return Arr.isReadonlyArrayNonEmpty(after) ? unsupported(ast, ctx, what) : head\n}\n\n/** The contexts of an array schema's elements and its rest. */\nconst elementContexts = <T>(\n ast: SchemaAST.Arrays,\n rest: SchemaAST.AST | undefined,\n grammar: Grammar,\n ctx: Context<T>\n): ReadonlyArray<Context<T>> => {\n const n = ast.elements.length\n return ast.elements.map((_, i) => at(i < n - 1 || rest !== undefined ? itemContext(grammar, ctx) : ctx, i))\n}\n\n/** The contexts of a struct's fields, written in order. */\nconst fieldContexts = <T>(ast: SchemaAST.Objects, grammar: Grammar, ctx: Context<T>): ReadonlyArray<Context<T>> => {\n const fields = ast.propertySignatures\n return fields.map((field, i) => at(i < fields.length - 1 ? itemContext(grammar, ctx) : ctx, field.name))\n}\n\nconst isKeyed = (ast: SchemaAST.Objects, grammar: Grammar): boolean =>\n grammar.keySeparator !== undefined || Arr.isReadonlyArrayNonEmpty(ast.indexSignatures)\n\nconst keySeparatorOf = <T>(grammar: Grammar, ctx: Context<T>): string => {\n if (grammar.keySeparator === undefined) {\n throw new TypeError(`ParserSchema: a record at ${where(ctx)} needs a keySeparator in its annotation`)\n }\n return grammar.keySeparator\n}\n\n/** The field name of a struct in keyed form: a string. */\nconst keyName = <T>(ast: SchemaAST.Objects, field: SchemaAST.PropertySignature, ctx: Context<T>, what: string) =>\n Predicate.isString(field.name) ? field.name : unsupported(ast, ctx, what)\n\nconst propertyName = (key: PropertyKey): string | symbol => (Predicate.isNumber(key) ? String(key) : key)\n\n/** Whether a check (as `Schema.Int` has) restricts numbers to integers. */\nconst isIntegral = (checks: SchemaAST.Checks | undefined): boolean =>\n checks !== undefined &&\n checks.some((check) =>\n check instanceof SchemaAST.FilterGroup\n ? isIntegral(check.checks)\n : check.annotations?.arbitraryConstraint?.[\"number\"] === \"integer\"\n )\n\ntype LiteralValue = SchemaAST.Literal[\"literal\"]\n\n/** Literals with the longest text first, so a literal is never cut short by one it starts with. */\nconst byLength = <A extends LiteralValue>(values: ReadonlyArray<A>): Array<A> =>\n Arr.sort(\n values,\n Order.mapInput(Order.Number, (value: A) => -String(value).length)\n )\n\nconst isPlainLiteral = (ast: SchemaAST.AST): ast is SchemaAST.Literal =>\n SchemaAST.isLiteral(ast) && ast.encoding === undefined && !isAnnotated(ast)\n\n/** The literals of a union of plain literals, longest first, or `undefined`. */\nconst plainLiterals = (ast: SchemaAST.Union): ReadonlyArray<LiteralValue> | undefined => {\n const literals = Arr.filter(ast.types, isPlainLiteral)\n return literals.length === ast.types.length ? byLength(literals.map((member) => member.literal)) : undefined\n}\n\nconst schemaError = (issue: SchemaIssue.Issue) => new Schema.SchemaError(issue)\n\nconst decoder = (schema: Schema.ConstraintDecoder<unknown>) => Schema.decodeUnknownResult(schema)\n\n/** Decodes into the type of `ast`, checks included. */\nconst typeDecoder = (ast: SchemaAST.AST) => decoder(Schema.make<Schema.Codec<unknown>>(SchemaAST.toType(ast)))\n\n// -----------------------------------------------------------------------------\n// Parsers\n// -----------------------------------------------------------------------------\n\ntype AnyParser = Parser<any, Schema.SchemaError, never, string>\n\ntype ForeignParser = Parser<unknown, unknown, never, string>\n\nconst messageOf = (cause: unknown): string =>\n Predicate.isString(cause)\n ? cause\n : Predicate.hasProperty(cause, \"message\") && Predicate.isString(cause.message)\n ? cause.message\n : String(cause)\n\n/** A parser whose failures' causes are `SchemaError`s, as {@link toParser}'s are. */\nconst asSchemaErrors = (parser: ForeignParser): AnyParser =>\n P.mapError(parser, (cause) =>\n cause instanceof Schema.SchemaError\n ? cause\n : schemaError(new SchemaIssue.InvalidValue({ message: messageOf(cause) }))\n )\n\n/** Literal text, with optional whitespace around it. */\nconst text = (s: string, ws: boolean): AnyParser =>\n ws ? P.delimited(Ascii.multispace0, Token.literal(s), Ascii.multispace0) : Token.literal(s)\n\nconst derive = (ast: SchemaAST.AST, ctx: Context<AnyParser>): AnyParser => {\n const { grammar, inner, whitespace } = resolve(ast, ctx)\n let parser: AnyParser\n if (grammar.parser !== undefined) parser = P.tryMap(asSchemaErrors(grammar.parser), typeDecoder(ast))\n else if (ast.encoding !== undefined) parser = decoded(ast, ast.encoding, grammar, inner)\n else parser = checked(ast, structural(ast, grammar, inner))\n if (grammar.prefix !== undefined) parser = P.preceded(text(grammar.prefix, whitespace), parser)\n if (grammar.suffix !== undefined) parser = P.terminated(parser, text(grammar.suffix, whitespace))\n // A check's own `expected` describes the check, not the text\n const label = lookup(ast, \"identifier\") ?? ast.annotations?.expected\n return Predicate.isString(label) ? P.expected(parser, label) : parser\n}\n\n/** Runs the checks on `ast` (its filters) on the parser's output. */\nconst checked = (ast: SchemaAST.AST, parser: AnyParser): AnyParser =>\n ast.checks === undefined ? parser : P.tryMap(parser, decoder(Schema.Unknown.check(...ast.checks)))\n\n/**\n * Parses the encoded side of a transformation and decodes it. The encoded\n * side is parsed into its own type, so the last link decodes from that type\n * rather than from the fully encoded form.\n */\nconst decoded = (\n ast: SchemaAST.AST,\n links: SchemaAST.Encoding,\n grammar: Grammar,\n ctx: Context<AnyParser>\n): AnyParser => {\n const from = derive(links[links.length - 1].to, encodedContext(grammar, ctx))\n return P.tryMap(from, decoder(Schema.make<Schema.Codec<unknown>>(linkTarget(ast, links))))\n}\n\nconst structural = (ast: SchemaAST.AST, grammar: Grammar, ctx: Context<AnyParser>): AnyParser =>\n Match.valueTags(ast, {\n String: () => unannotatedString(ctx, 1),\n Number: (number) => (isIntegral(number.checks) ? integer : Ascii.float),\n BigInt: () => Ascii.decBigInt,\n Boolean: () => P.alt(P.as(Token.literal(\"true\"), true), P.as(Token.literal(\"false\"), false)),\n Null: () => P.as(Token.literal(\"null\"), null),\n Undefined: () => P.succeed(undefined),\n Void: () => P.succeed(undefined),\n Never: () => P.reject,\n Literal: (lit) => literal(lit.literal),\n Enum: (e) => P.alt(...byLength(e.enums.map(([, value]) => value)).map(literal)),\n TemplateLiteral: (template) => templateLiteral(template, ctx),\n Arrays: (arrays) => sequenceOf(arrays, grammar, ctx),\n Objects: (objects) =>\n isKeyed(objects, grammar) ? keyed(objects, grammar, ctx) : positional(objects, grammar, ctx),\n Union: (union) => alternatives(union, ctx),\n Suspend: (suspend) => recursive(suspend, ctx, () => P.suspend(() => derive(suspend.thunk(), ctx))),\n Declaration: (other) => unsupported(other, ctx, \"parser\"),\n Unknown: (other) => unsupported(other, ctx, \"parser\"),\n Any: (other) => unsupported(other, ctx, \"parser\"),\n Symbol: (other) => unsupported(other, ctx, \"parser\"),\n UniqueSymbol: (other) => unsupported(other, ctx, \"parser\"),\n ObjectKeyword: (other) => unsupported(other, ctx, \"parser\")\n })\n\nconst unannotatedString = (ctx: Context<AnyParser>, min: number): AnyParser => {\n const s = Token.takeTill(ctx.stop, { min })\n // Leading whitespace is skipped first, so it doesn't count towards `min`\n return ctx.whitespace\n ? P.preceded(\n Ascii.multispace0,\n P.map(s, (value) => value.trimEnd())\n )\n : s\n}\n\nconst integer: AnyParser = /*#__PURE__*/ asSchemaErrors(Ascii.decInt)\n\nconst literal = (value: LiteralValue): AnyParser => P.as(Token.literal(String(value)), value)\n\nconst templateLiteral = (ast: SchemaAST.TemplateLiteral, ctx: Context<AnyParser>): AnyParser =>\n P.taken(\n P.seq(\n ...ast.parts.map((part, i) => {\n const next = ast.parts[i + 1]\n const partCtx = next !== undefined && SchemaAST.isLiteral(next) ? withStop(ctx, String(next.literal)) : ctx\n // An interpolated string may be empty\n return SchemaAST.isString(part) && !isAnnotated(part)\n ? unannotatedString(partCtx, 0)\n : derive(part, at(partCtx, i))\n })\n )\n )\n\nconst alternatives = (ast: SchemaAST.Union, ctx: Context<AnyParser>): AnyParser => {\n const literals = plainLiterals(ast)\n return literals !== undefined\n ? P.alt(...literals.map(literal))\n : P.alt(...ast.types.map((member) => derive(member, ctx)))\n}\n\ninterface Item {\n readonly parser: AnyParser\n readonly optional: boolean\n}\n\ntype Values = Parser<Array<unknown>, Schema.SchemaError, never, string>\n\n/**\n * Parses `items` in order, then any number of `rest`, with `separator`\n * between the ones present. The output has the value of item `i` at index\n * `i` (a hole when an optional item is missing), then the rest.\n */\nconst sequence = (\n items: ReadonlyArray<Item>,\n rest: AnyParser | undefined,\n separator: AnyParser | undefined\n): Values => {\n const n = items.length\n const tail = (needSeparator: boolean): Values => {\n if (rest === undefined) return P.sync(() => new Array(n))\n const values =\n separator === undefined\n ? P.repeat(rest)\n : needSeparator\n ? P.repeat(P.preceded(separator, rest))\n : P.separated(rest, separator)\n return P.map(values, (xs) => {\n const out = new Array(n)\n for (let j = 0; j < xs.length; j++) out[n + j] = xs[j]\n return out\n })\n }\n // One parser per position and whether a separator comes first, at index `2 * i + needSeparator`\n const memo: Array<Values | undefined> = []\n const from = (i: number, needSeparator: boolean): Values => {\n const key = i * 2 + (needSeparator ? 1 : 0)\n const known = memo[key]\n if (known !== undefined) return known\n let parser: Values\n if (i === n) parser = tail(needSeparator)\n else {\n const item = items[i]\n const head = needSeparator && separator !== undefined ? P.preceded(separator, item.parser) : item.parser\n const present = P.map(P.seq(head, from(i + 1, true)), ([value, out]) => {\n out[i] = value\n return out\n })\n parser = item.optional ? P.alt(present, from(i + 1, needSeparator)) : present\n }\n memo[key] = parser\n return parser\n }\n return from(0, false)\n}\n\nconst separatorOf = (grammar: Grammar, ctx: Context<AnyParser>): AnyParser | undefined =>\n grammar.separator === undefined ? undefined : text(grammar.separator, ctx.whitespace)\n\nconst sequenceOf = (ast: SchemaAST.Arrays, grammar: Grammar, ctx: Context<AnyParser>): AnyParser => {\n const head = restOf(ast, ctx, \"parser\")\n const contexts = elementContexts(ast, head, grammar, ctx)\n const items = ast.elements.map((element, i) => ({\n parser: derive(element, contexts[i]),\n optional: SchemaAST.isOptional(element)\n }))\n const rest = head === undefined ? undefined : derive(head, at(itemContext(grammar, ctx), items.length))\n // Optional elements come last, so the present values are the first ones\n return P.map(sequence(items, rest, separatorOf(grammar, ctx)), (out) => out.filter((_, i) => i in out))\n}\n\nconst positional = (ast: SchemaAST.Objects, grammar: Grammar, ctx: Context<AnyParser>): AnyParser => {\n const fields = ast.propertySignatures\n const contexts = fieldContexts(ast, grammar, ctx)\n const items = fields.map((field, i) => ({\n parser: derive(field.type, contexts[i]),\n optional: SchemaAST.isOptional(field.type)\n }))\n return P.map(sequence(items, undefined, separatorOf(grammar, ctx)), (out) =>\n Record.fromEntries(fields.flatMap((field, i) => (i in out ? [[propertyName(field.name), out[i]] as const] : [])))\n )\n}\n\ntype Entry = readonly [key: string | symbol, value: unknown, known: boolean]\n\nconst keyed = (ast: SchemaAST.Objects, grammar: Grammar, ctx: Context<AnyParser>): AnyParser => {\n const keySeparator = keySeparatorOf(grammar, ctx)\n const between = text(keySeparator, ctx.whitespace)\n const valueCtx = itemContext(grammar, ctx)\n const known = ast.propertySignatures.map((field): AnyParser => {\n const name = keyName(ast, field, ctx, \"parser\")\n const value = derive(field.type, at(valueCtx, name))\n return P.map(P.preceded(P.seq(Token.literal(name), between), value), (v): Entry => [name, v, true])\n })\n const indexed = ast.indexSignatures.map((signature): AnyParser => {\n const key = derive(signature.parameter, at(withStop(ctx, keySeparator), \"<key>\"))\n const value = derive(signature.type, at(valueCtx, \"<value>\"))\n return P.map(P.separatedPair(key, between, value), ([k, v]): Entry => [propertyName(k), v, false])\n })\n const entry = P.alt(...known, ...indexed)\n const separator = separatorOf(grammar, ctx)\n const entries = separator === undefined ? P.repeat(entry) : P.separated(entry, separator)\n // A missing field fails where its entry could have been, as a syntax error, so a\n // failure further in (the entry that ended the repetition early) is reported instead\n const missing = ast.propertySignatures.map((field) =>\n P.expected(P.reject, describeLiteral(`${String(field.name)}${keySeparator}`))\n )\n return P.flatMap(\n P.tryMap(entries, (es: ReadonlyArray<Entry>) => assemble(ast, es)),\n ([value, absent]) => (absent === undefined ? P.succeed(value) : missing[absent])\n )\n}\n\n/**\n * Builds the object from its entries, declared fields first, rejecting\n * duplicate keys. Also returns the index of the first required field\n * missing, if any.\n */\nconst assemble = (\n ast: SchemaAST.Objects,\n entries: ReadonlyArray<Entry>\n): Result.Result<readonly [object, number | undefined], Schema.SchemaError> => {\n const values = MutableHashMap.empty<string | symbol, unknown>()\n for (const [key, value] of entries) {\n if (MutableHashMap.has(values, key)) {\n return Result.fail(\n schemaError(new SchemaIssue.Pointer([key], new SchemaIssue.InvalidValue({ message: \"Duplicate key\" })))\n )\n }\n MutableHashMap.set(values, key, value)\n }\n const out: Array<readonly [string | symbol, unknown]> = []\n let absent: number | undefined\n ast.propertySignatures.forEach((field, i) => {\n const name = propertyName(field.name)\n const value = MutableHashMap.get(values, name)\n if (Option.isSome(value)) out.push([name, value.value])\n else if (absent === undefined && !SchemaAST.isOptional(field.type)) absent = i\n })\n for (const [key, value, isKnown] of entries) if (!isKnown) out.push([key, value])\n return Result.succeed([Record.fromEntries(out), absent])\n}\n\n// -----------------------------------------------------------------------------\n// Printers\n// -----------------------------------------------------------------------------\n\n/**\n * Writes the text of a value, already validated against the schema's type,\n * to `out`, or returns why it cannot be written.\n */\ntype Printer = (value: any, out: Array<string>) => SchemaIssue.Issue | undefined\n\n/** The issue for a value that cannot be written at the node `ctx` is at. */\nconst unwritable = <T>(ctx: Context<T>, message: string, value: unknown): SchemaIssue.Issue => {\n const issue = new SchemaIssue.InvalidValue({ message }, value, { reportInput: true })\n return Arr.isReadonlyArrayNonEmpty(ctx.path) ? new SchemaIssue.Pointer(ctx.path, issue) : issue\n}\n\nconst writing =\n (show: (value: any) => string): Printer =>\n (value, out) => {\n out.push(show(value))\n return undefined\n }\n\nconst nothing: Printer = (_, __) => undefined\n\nconst printerOf = (ast: SchemaAST.AST, ctx: Context<Printer>): Printer => {\n const { grammar, inner } = resolve(ast, ctx)\n let print: Printer\n if (grammar.print !== undefined) print = writing(grammar.print)\n else if (grammar.parser !== undefined) print = unprintable(ctx)\n else if (ast.encoding !== undefined) print = encoded(ast, ast.encoding, grammar, inner)\n else print = printerFor(ast, grammar, inner)\n const prefix = grammar.prefix\n const suffix = grammar.suffix\n if (prefix === undefined && suffix === undefined) return print\n const inside = print\n return (value, out) => {\n if (prefix !== undefined) out.push(prefix)\n const issue = inside(value, out)\n if (suffix !== undefined) out.push(suffix)\n return issue\n }\n}\n\nconst unprintable =\n (ctx: Context<Printer>): Printer =>\n (value) =>\n unwritable(ctx, \"This value has a parser in its annotation but no print, so it cannot be written\", value)\n\n/** Encodes a transformation's value and prints its encoded side. */\nconst encoded = (ast: SchemaAST.AST, links: SchemaAST.Encoding, grammar: Grammar, ctx: Context<Printer>): Printer => {\n const to = printerOf(links[links.length - 1].to, encodedContext(grammar, ctx))\n const encode = Schema.encodeUnknownResult(Schema.make<Schema.Codec<unknown, unknown>>(linkTarget(ast, links)))\n return (value, out) => {\n const result = encode(value)\n return Result.isSuccess(result) ? to(result.success, out) : result.failure.issue\n }\n}\n\nconst printerFor = (ast: SchemaAST.AST, grammar: Grammar, ctx: Context<Printer>): Printer =>\n Match.valueTags(ast, {\n String: () => stringPrinter(ctx),\n Number: () => writing(String),\n BigInt: () => writing(String),\n Boolean: () => writing(String),\n Null: () => writing(String),\n Undefined: () => nothing,\n Void: () => nothing,\n Never: () => nothing,\n Literal: () => writing(String),\n Enum: () => writing(String),\n TemplateLiteral: () => writing(String),\n Arrays: (arrays) => arraysPrinter(arrays, grammar, ctx),\n Objects: (objects) =>\n isKeyed(objects, grammar) ? keyedPrinter(objects, grammar, ctx) : positionalPrinter(objects, grammar, ctx),\n Union: (union) => unionPrinter(union, ctx),\n Suspend: (suspend) =>\n recursive(suspend, ctx, () => {\n let print: Printer | undefined\n return (value, out) => (print ??= printerOf(suspend.thunk(), ctx))(value, out)\n }),\n Declaration: (other) => unsupported(other, ctx, \"printer\"),\n Unknown: (other) => unsupported(other, ctx, \"printer\"),\n Any: (other) => unsupported(other, ctx, \"printer\"),\n Symbol: (other) => unsupported(other, ctx, \"printer\"),\n UniqueSymbol: (other) => unsupported(other, ctx, \"printer\"),\n ObjectKeyword: (other) => unsupported(other, ctx, \"printer\")\n })\n\n/**\n * Writes a string as an unannotated string is parsed: refusing one that\n * would not read back, being empty or holding a character that ends it.\n */\nconst stringPrinter =\n (ctx: Context<Printer>): Printer =>\n (value: string, out) => {\n if (value === \"\") return unwritable(ctx, \"An empty string cannot be written here\", value)\n const stop = Arr.findFirst(Array.from(ctx.stop), (c) => value.includes(c))\n if (Option.isSome(stop)) {\n return unwritable(ctx, `A string containing ${describeLiteral(stop.value)} cannot be written here`, value)\n }\n if (ctx.whitespace && value.trim() !== value) {\n return unwritable(ctx, \"A string with whitespace around it cannot be written here\", value)\n }\n out.push(value)\n return undefined\n }\n\n/** Writes values with a separator between them, stopping at the first that cannot be written. */\nconst writeAll = (\n writes: ReadonlyArray<(out: Array<string>) => SchemaIssue.Issue | undefined>,\n separator: string,\n out: Array<string>\n): SchemaIssue.Issue | undefined => {\n for (let i = 0; i < writes.length; i++) {\n if (i > 0) out.push(separator)\n const issue = writes[i](out)\n if (issue !== undefined) return issue\n }\n return undefined\n}\n\nconst arraysPrinter = (ast: SchemaAST.Arrays, grammar: Grammar, ctx: Context<Printer>): Printer => {\n const head = restOf(ast, ctx, \"printer\")\n const contexts = elementContexts(ast, head, grammar, ctx)\n const elements = ast.elements.map((element, i) => printerOf(element, contexts[i]))\n const rest = head === undefined ? nothing : printerOf(head, at(itemContext(grammar, ctx), elements.length))\n const separator = grammar.separator ?? \"\"\n return (value: ReadonlyArray<unknown>, out) =>\n writeAll(\n value.map((element, i) => (o: Array<string>) => (elements[i] ?? rest)(element, o)),\n separator,\n out\n )\n}\n\nconst positionalPrinter = (ast: SchemaAST.Objects, grammar: Grammar, ctx: Context<Printer>): Printer => {\n const contexts = fieldContexts(ast, grammar, ctx)\n const fields = ast.propertySignatures.map((field, i) => ({\n name: propertyName(field.name),\n print: printerOf(field.type, contexts[i])\n }))\n const separator = grammar.separator ?? \"\"\n return (value: Record.ReadonlyRecord<string | symbol, unknown>, out) =>\n writeAll(\n fields\n .filter((field) => Record.has(value, field.name))\n .map((field) => (o: Array<string>) => field.print(value[field.name], o)),\n separator,\n out\n )\n}\n\nconst keyedPrinter = (ast: SchemaAST.Objects, grammar: Grammar, ctx: Context<Printer>): Printer => {\n const keySeparator = keySeparatorOf(grammar, ctx)\n const valueCtx = itemContext(grammar, ctx)\n const fields = ast.propertySignatures.map((field) => {\n const name = keyName(ast, field, ctx, \"printer\")\n return { name, print: printerOf(field.type, at(valueCtx, name)) }\n })\n const names = fields.map((field) => field.name)\n const indexed = ast.indexSignatures.map((signature) => ({\n is: Schema.is(Schema.make<Schema.Top>(SchemaAST.toType(signature.parameter))),\n key: printerOf(signature.parameter, at(withStop(ctx, keySeparator), \"<key>\")),\n value: printerOf(signature.type, at(valueCtx, \"<value>\"))\n }))\n const entry =\n (key: Printer, print: Printer, k: unknown, v: unknown) =>\n (out: Array<string>): SchemaIssue.Issue | undefined =>\n key(k, out) ?? (out.push(keySeparator), print(v, out))\n return (value: Record.ReadonlyRecord<string, unknown>, out) => {\n const writes = fields\n .filter((field) => Record.has(value, field.name))\n .map((field) => entry(writing(String), field.print, field.name, value[field.name]))\n for (const key of Record.keys(value)) {\n const signature = names.includes(key) ? undefined : indexed.find((s) => s.is(key))\n if (signature !== undefined) writes.push(entry(signature.key, signature.value, key, value[key]))\n }\n return writeAll(writes, grammar.separator ?? \"\", out)\n }\n}\n\n/** Writes a union's value with the first member it belongs to that can write it. */\nconst unionPrinter = (ast: SchemaAST.Union, ctx: Context<Printer>): Printer => {\n if (plainLiterals(ast) !== undefined) return writing(String)\n const members = ast.types.map((member) => ({\n is: Schema.is(Schema.make<Schema.Top>(SchemaAST.toType(member))),\n print: printerOf(member, ctx)\n }))\n return (value, out) => {\n let issue: SchemaIssue.Issue | undefined\n for (const member of members) {\n if (!member.is(value)) continue\n const mark = out.length\n issue = member.print(value, out)\n if (issue === undefined) return undefined\n out.length = mark\n }\n return issue ?? unwritable(ctx, \"No member of the union can write this value\", value)\n }\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"stack.d.ts","names":[],"sources":["../../src/internal/stack.ts"],"mappings":";;;;;;;qBAmBa,kBAAmB;;;;;;qBASnB,MAAO,UAAU,YAAY,GAAG,OAAO,OAAO,MAAM,GAAG,OAAO,MAAI,IAAI"}
1
+ {"version":3,"file":"stack.d.ts","names":[],"sources":["../../src/internal/stack.ts"],"mappings":";;;;;;;qBAoBa,kBAAmB;;;;;;qBAanB,MAAO,UAAU,YAAY,GAAG,OAAO,OAAO,MAAM,GAAG,OAAO,MAAI,IAAI"}
@@ -1,4 +1,14 @@
1
+ import * as Predicate from "effect/Predicate";
1
2
  //#region src/internal/stack.ts
3
+ /**
4
+ * Call-stack overflows.
5
+ *
6
+ * The interpreter and the compiled backends recurse once (or more) per
7
+ * nesting level of a recursive grammar, so deeply nested input, such as
8
+ * thousands of `{`, can exhaust the call stack. The runners catch the
9
+ * engine's overflow error and report a `TooDeep` failure instead, keeping
10
+ * their `Result` contract on untrusted input.
11
+ */
2
12
  /** The message of a `TooDeep` failure. */
3
13
  const tooDeepMessage = "input is nested too deeply: parsing exhausted the call stack";
4
14
  /**
@@ -6,7 +16,7 @@ const tooDeepMessage = "input is nested too deeply: parsing exhausted the call s
6
16
  * and JavaScriptCore, an `InternalError` ("too much recursion") in
7
17
  * SpiderMonkey.
8
18
  */
9
- const isStackOverflow = (e) => e instanceof RangeError && /call stack/i.test(e.message) || e instanceof Error && e.name === "InternalError" && /recursion/i.test(e.message);
19
+ const isStackOverflow = (e) => e instanceof RangeError && /call stack/i.test(e.message) || Predicate.hasProperty(e, "name") && Predicate.hasProperty(e, "message") && e.name === "InternalError" && Predicate.isString(e.message) && /recursion/i.test(e.message);
10
20
  /**
11
21
  * Runs `step`, turning a call-stack overflow into an unrecoverable
12
22
  * `TooDeep` failure at the offset parsing had reached. Other exceptions
@@ -1 +1 @@
1
- {"version":3,"file":"stack.js","names":[],"sources":["../../src/internal/stack.ts"],"sourcesContent":["/**\n * Call-stack overflows.\n *\n * The interpreter and the compiled backends recurse once (or more) per\n * nesting level of a recursive grammar, so deeply nested input, such as\n * thousands of `{`, can exhaust the call stack. The runners catch the\n * engine's overflow error and report a `TooDeep` failure instead, keeping\n * their `Result` contract on untrusted input.\n */\nimport type { Fail, State } from \"../Input.js\"\n\n/** The message of a `TooDeep` failure. */\nconst tooDeepMessage = \"input is nested too deeply: parsing exhausted the call stack\"\n\n/**\n * Whether `e` is the engine's call-stack overflow: a `RangeError` in V8\n * and JavaScriptCore, an `InternalError` (\"too much recursion\") in\n * SpiderMonkey.\n */\nexport const isStackOverflow = (e: unknown): boolean =>\n (e instanceof RangeError && /call stack/i.test(e.message)) ||\n (e instanceof Error && e.name === \"InternalError\" && /recursion/i.test(e.message))\n\n/**\n * Runs `step`, turning a call-stack overflow into an unrecoverable\n * `TooDeep` failure at the offset parsing had reached. Other exceptions\n * propagate.\n */\nexport const run = <S extends State<any>, A>(step: (state: S) => A, state: S): A | Fail => {\n try {\n return step(state)\n } catch (e) {\n if (!isStackOverflow(e)) throw e\n return state.failMessage(\"Cut\", \"TooDeep\", tooDeepMessage)\n }\n}\n"],"mappings":";;AAYA,MAAM,iBAAiB;;;;;;AAOvB,MAAa,mBAAmB,MAC7B,aAAa,cAAc,cAAc,KAAK,EAAE,OAAO,KACvD,aAAa,SAAS,EAAE,SAAS,mBAAmB,aAAa,KAAK,EAAE,OAAO;;;;;;AAOlF,MAAa,OAAgC,MAAuB,UAAuB;CACzF,IAAI;EACF,OAAO,KAAK,KAAK;CACnB,SAAS,GAAG;EACV,IAAI,CAAC,gBAAgB,CAAC,GAAG,MAAM;EAC/B,OAAO,MAAM,YAAY,OAAO,WAAW,cAAc;CAC3D;AACF"}
1
+ {"version":3,"file":"stack.js","names":[],"sources":["../../src/internal/stack.ts"],"sourcesContent":["/**\n * Call-stack overflows.\n *\n * The interpreter and the compiled backends recurse once (or more) per\n * nesting level of a recursive grammar, so deeply nested input, such as\n * thousands of `{`, can exhaust the call stack. The runners catch the\n * engine's overflow error and report a `TooDeep` failure instead, keeping\n * their `Result` contract on untrusted input.\n */\nimport * as Predicate from \"effect/Predicate\"\nimport type { Fail, State } from \"../Input.js\"\n\n/** The message of a `TooDeep` failure. */\nconst tooDeepMessage = \"input is nested too deeply: parsing exhausted the call stack\"\n\n/**\n * Whether `e` is the engine's call-stack overflow: a `RangeError` in V8\n * and JavaScriptCore, an `InternalError` (\"too much recursion\") in\n * SpiderMonkey.\n */\nexport const isStackOverflow = (e: unknown): boolean =>\n (e instanceof RangeError && /call stack/i.test(e.message)) ||\n (Predicate.hasProperty(e, \"name\") &&\n Predicate.hasProperty(e, \"message\") &&\n e.name === \"InternalError\" &&\n Predicate.isString(e.message) &&\n /recursion/i.test(e.message))\n\n/**\n * Runs `step`, turning a call-stack overflow into an unrecoverable\n * `TooDeep` failure at the offset parsing had reached. Other exceptions\n * propagate.\n */\nexport const run = <S extends State<any>, A>(step: (state: S) => A, state: S): A | Fail => {\n try {\n return step(state)\n } catch (e) {\n if (!isStackOverflow(e)) throw e\n return state.failMessage(\"Cut\", \"TooDeep\", tooDeepMessage)\n }\n}\n"],"mappings":";;;;;;;;;;;;AAaA,MAAM,iBAAiB;;;;;;AAOvB,MAAa,mBAAmB,MAC7B,aAAa,cAAc,cAAc,KAAK,EAAE,OAAO,KACvD,UAAU,YAAY,GAAG,MAAM,KAC9B,UAAU,YAAY,GAAG,SAAS,KAClC,EAAE,SAAS,mBACX,UAAU,SAAS,EAAE,OAAO,KAC5B,aAAa,KAAK,EAAE,OAAO;;;;;;AAO/B,MAAa,OAAgC,MAAuB,UAAuB;CACzF,IAAI;EACF,OAAO,KAAK,KAAK;CACnB,SAAS,GAAG;EACV,IAAI,CAAC,gBAAgB,CAAC,GAAG,MAAM;EAC/B,OAAO,MAAM,YAAY,OAAO,WAAW,cAAc;CAC3D;AACF"}
@@ -118,6 +118,7 @@ export declare class SyntaxState<I extends Input = Input> extends State<I> imple
118
118
  readonly context?: Context.Context<never> | undefined;
119
119
  }, previous: Previous | undefined);
120
120
  failWith(mode: ErrMode, failure: Failure): Fail;
121
+ failTies(head: Failure, tie1: Failure, tie2: Failure | undefined): Fail;
121
122
  setHint(offset: number, expected: ReadonlyArray<string>): void;
122
123
  node(state: State<any>, step: (state: State<any>) => unknown, key: object, kind: string, named: boolean): unknown;
123
124
  read(end: number): void;
@@ -1 +1 @@
1
- {"version":3,"file":"syntax.d.ts","names":[],"sources":["../../src/internal/syntax.ts"],"mappings":";;;;;iBAmCiB;WACN,SAAS;WACT,MAAM;;;qBAIJ;WAEA;WACA;;WAEA;WACA;;WAEA;WACA,UAAU,cAAc;;WAExB,SAAS;;WAET,QAAQ;WACR;;WAEA,OAAO;;WAEP;;WAEA,aAAa;EAlBb,YAAA,cACA;;EAEA,yBACA;;EAEA,mBACA,UAAU,cAAc;;EAExB,SAAS;;EAET,QAAQ,+CACR;;EAEA,OAAO;;EAEP;;EAEA,aAAa;;;;;;;iBAST;;WAEN,SAAS;;WAET;;WAEA;WACA,cAAc;;;cAInB;WAEO,OAAO;WACP;WACA;EACF;EAHE,YAAA,OAAO,OACP,eACA,aACF;;qBAIE;;qBAMA,WAAY,GAAG,SAAS,kBAAgB;;;;;iBAuCpC;WACN;WACA;WACA;;;iBAIM;WACN,MAAM;WACN;WACA;WACA,UAAU,cAAc;WACxB,OAAO;;WAEP;WACA,UAAU;;;iBAIJ;EACf,KAAK,OAAO,YAAY,OAAO,OAAO,wBAAwB,aAAa,cAAc;EACzF,MAAM,OAAO,YAAY,OAAO,OAAO,wBAAwB;;EAE/D,QAAQ,eAAe,SAAS,SAAS,MAAM;;;;;EAK/C,KAAK;;;qBAIM,YAAY,UAAU,QAAQ,eAAe,MAAM,cAAc;EAGpE;;EAEA;;EAEA,OAAO,MAAM;EACb,UAAU;;EAEV;;EAEA,YAAY;EACZ;EAsBN,YAAA,QAAQ,IAAI,OAAO,IACnB;aACW,UAAU,QAAQ;KAE7B,UAAU;EAcH,SAAS,MAAM,SAAS,SAAS,UAAU;EAK3C,QAAQ,gBAAgB,UAAU;EAK3C,KAAK,OAAO,YAAY,OAAO,OAAO,wBAAwB,aAAa,cAAc;EA0DzF,KAAK;;UAMG;EAIR,MAAM,OAAO,YAAY,OAAO,OAAO,wBAAwB;EAQ/D,QAAQ,eAAe,SAAS,SAAS,MAAM;;;;;;EAiB/C,OAAO,cAAc,gBAAgB,OAAO,uBAAuB,qBAAqB;;;;;;;UAqBhF;;UAsCA"}
1
+ {"version":3,"file":"syntax.d.ts","names":[],"sources":["../../src/internal/syntax.ts"],"mappings":";;;;;iBAmCiB;WACN,SAAS;WACT,MAAM;;;qBAIJ;WAEA;WACA;;WAEA;WACA;;WAEA;WACA,UAAU,cAAc;;WAExB,SAAS;;WAET,QAAQ;WACR;;WAEA,OAAO;;WAEP;;WAEA,aAAa;EAlBb,YAAA,cACA;;EAEA,yBACA;;EAEA,mBACA,UAAU,cAAc;;EAExB,SAAS;;EAET,QAAQ,+CACR;;EAEA,OAAO;;EAEP;;EAEA,aAAa;;;;;;;iBAST;;WAEN,SAAS;;WAET;;WAEA;WACA,cAAc;;;cAInB;WAEO,OAAO;WACP;WACA;EACF;EAHE,YAAA,OAAO,OACP,eACA,aACF;;qBAIE;;qBAMA,WAAY,GAAG,SAAS,kBAAgB;;;;;iBAuCpC;WACN;WACA;WACA;;;iBAIM;WACN,MAAM;WACN;WACA;WACA,UAAU,cAAc;WACxB,OAAO;;WAEP;WACA,UAAU;;;iBAIJ;EACf,KAAK,OAAO,YAAY,OAAO,OAAO,wBAAwB,aAAa,cAAc;EACzF,MAAM,OAAO,YAAY,OAAO,OAAO,wBAAwB;;EAE/D,QAAQ,eAAe,SAAS,SAAS,MAAM;;;;;EAK/C,KAAK;;;qBAIM,YAAY,UAAU,QAAQ,eAAe,MAAM,cAAc;EAGpE;;EAEA;;EAEA,OAAO,MAAM;EACb,UAAU;;EAEV;;EAEA,YAAY;EACZ;EAsBN,YAAA,QAAQ,IAAI,OAAO,IACnB;aACW,UAAU,QAAQ;KAE7B,UAAU;EAcH,SAAS,MAAM,SAAS,SAAS,UAAU;EAK3C,SAAS,MAAM,SAAS,MAAM,SAAS,MAAM,sBAAsB;EAKnE,QAAQ,gBAAgB,UAAU;EAK3C,KAAK,OAAO,YAAY,OAAO,OAAO,wBAAwB,aAAa,cAAc;EA0DzF,KAAK;;UAMG;EAIR,MAAM,OAAO,YAAY,OAAO,OAAO,wBAAwB;EAQ/D,QAAQ,eAAe,SAAS,SAAS,MAAM;;;;;;EAiB/C,OAAO,cAAc,gBAAgB,OAAO,uBAAuB,qBAAqB;;;;;;;UAqBhF;;UAsCA"}
@@ -128,6 +128,10 @@ var SyntaxState = class extends State {
128
128
  if (failure.offset > this.highWater) this.highWater = failure.offset;
129
129
  return super.failWith(mode, failure);
130
130
  }
131
+ failTies(head, tie1, tie2) {
132
+ if (head.offset > this.highWater) this.highWater = head.offset;
133
+ return super.failTies(head, tie1, tie2);
134
+ }
131
135
  setHint(offset, expected) {
132
136
  if (offset > this.highWater) this.highWater = offset;
133
137
  super.setHint(offset, expected);
@@ -1 +1 @@
1
- {"version":3,"file":"syntax.js","names":[],"sources":["../../src/internal/syntax.ts"],"sourcesContent":["/**\n * The tree builder behind the `Syntax` module (see `docs/DESIGN.md`,\n * \"Syntax trees\").\n *\n * Trees are stored as *green* nodes, as in Roslyn and rust-analyzer: a green\n * node knows its kind, its width and its children's offsets relative to its\n * own start, but not where it is in the input or who its parent is. A subtree\n * that an edit doesn't touch can therefore be shared, unchanged, by the tree\n * before the edit and the tree after it. `Syntax.SyntaxNode` is the *red*\n * view: a green node, its absolute start and its parent, built lazily while\n * navigating.\n *\n * While parsing, completed nodes wait on a stack until the node around them\n * completes and adopts them. Nodes built by an attempt that is later\n * abandoned must not end up in the tree. Every combinator that abandons an\n * attempt moves the cursor back to (or before) where the attempt started,\n * and every node has a positive width, so the nodes of an abandoned attempt\n * are exactly those that end after the position the cursor moves back to:\n * the `pos` setter of {@link SyntaxState} drops them. This also covers\n * lookahead (`peek`, `not`) and custom parsers written with `Parser.make`.\n *\n * For incremental parsing, every node records how far its parse looked: the\n * furthest position the cursor reached and the furthest failure recorded\n * while it was being parsed (its *lookahead*). A node from the previous tree\n * is reused at a position when it was built by the same `Syntax.node`, and\n * the input it looked at, plus a margin for the tokens that read a little\n * past where they stop, is unchanged.\n */\nimport * as Predicate from \"effect/Predicate\"\nimport type * as Context from \"effect/Context\"\nimport type { Encoding } from \"../Encoding.js\"\nimport type { ErrMode, Input, Source } from \"../Input.js\"\nimport { Fail, Failure, State } from \"../Input.js\"\n\n/** What a failure inside an `ERROR` node was. Offsets are relative to the node. */\nexport interface ErrorInfo {\n readonly failure: Failure\n readonly mode: ErrMode\n}\n\n/** A position-independent syntax tree node. */\nexport class Green {\n constructor(\n readonly kind: string,\n readonly named: boolean,\n /** The `Syntax.node` that built it; `undefined` for roots and errors, which are never reused alone. */\n readonly key: object | undefined,\n readonly width: number,\n /** How far its parse looked, relative to its start (at least `width`). */\n readonly lookahead: number,\n readonly children: ReadonlyArray<Green>,\n /** The children's starts, relative to this node's start. */\n readonly offsets: ReadonlyArray<number>,\n /** The children's field names, when any child has one. */\n readonly fields: ReadonlyArray<string | undefined> | undefined,\n readonly value: unknown,\n /** Set on `ERROR` nodes. */\n readonly error: ErrorInfo | undefined,\n /** Whether this node or a descendant is an `ERROR` node. */\n readonly hasError: boolean,\n /** What its parse left behind for error reporting, replayed when it is reused. */\n readonly diagnostics: Diagnostics | undefined\n ) {}\n}\n\n/**\n * The error-reporting state a node's parse leaves behind (see\n * `State.deepest` and `State.setHint`). A reused node replays it, so that\n * a reparse reports the errors a fresh parse does.\n */\nexport interface Diagnostics {\n /** The furthest failure, at its offset in the parse that built the node... */\n readonly deepest: Failure | undefined\n /** ...which started the node at `base`. */\n readonly base: number\n /** Relative to the node's start. */\n readonly hintOffset: number\n readonly hintExpected: ReadonlyArray<string> | undefined\n}\n\n/** A completed node waiting for its parent, at an absolute position. */\nclass Child {\n constructor(\n readonly green: Green,\n readonly start: number,\n readonly end: number,\n public field: string | undefined\n ) {}\n}\n\nexport const errorKind = \"ERROR\"\n\nconst rebase = (f: Failure, start: number): Failure =>\n new Failure(f.offset - start, f.kind, f.expected, f.context, f.hasCause, f.cause, f.message, f.needed)\n\n/** Moves a failure stored relative to a node back to absolute offsets. */\nexport const absolute = (f: Failure, start: number): Failure => rebase(f, -start)\n\n/**\n * Builds a green node over `[start, end)` from the children waiting on the\n * stack.\n */\nconst build = (\n kind: string,\n named: boolean,\n key: object | undefined,\n start: number,\n end: number,\n lookahead: number,\n entries: ReadonlyArray<Child>,\n value: unknown,\n error: ErrorInfo | undefined,\n diagnostics?: Diagnostics\n): Green => {\n const n = entries.length\n const children = new Array<Green>(n)\n const offsets = new Array<number>(n)\n let fields: Array<string | undefined> | undefined\n let hasError = error !== undefined\n for (let i = 0; i < n; i++) {\n const e = entries[i]\n children[i] = e.green\n offsets[i] = e.start - start\n if (e.green.hasError) hasError = true\n if (e.field !== undefined) (fields ??= new Array(n).fill(undefined))[i] = e.field\n }\n const width = end - start\n const looked = Math.max(lookahead, end) - start\n return new Green(kind, named, key, width, looked, children, offsets, fields, value, error, hasError, diagnostics)\n}\n\n/**\n * A stretch of the new input copied unchanged from the previous one:\n * `[newStart, newStart + length)` is `[oldStart, oldStart + length)`.\n */\nexport interface Segment {\n readonly newStart: number\n readonly oldStart: number\n readonly length: number\n}\n\n/** What a reparse may reuse. */\nexport interface Previous {\n readonly root: Green\n readonly oldLength: number\n readonly newLength: number\n readonly segments: ReadonlyArray<Segment>\n readonly input: Input\n /** How far past its lookahead a parser may have read, besides a token at the lookahead. */\n readonly extra: number\n readonly encoding: Encoding<any> | undefined\n}\n\n/** The hooks that `Syntax` combinators and `Parser.resumeAfter`/`retryAfter` call. */\nexport interface Builder {\n node(state: State<any>, step: (state: State<any>) => unknown, key: object, kind: string, named: boolean): unknown\n field(state: State<any>, step: (state: State<any>) => unknown, name: string): unknown\n /** After error recovery: `[start, pos)` was skipped after `failure`. */\n skipped(start: number, failure: Failure, mode: ErrMode): void\n /**\n * Called by token parsers that read input up to `end` (exclusive) beyond\n * where they leave the cursor or record a failure.\n */\n read(end: number): void\n}\n\n/** The parse state of a `Syntax` parse. */\nexport class SyntaxState<I extends Input = Input> extends State<I> implements Builder {\n // Declared, not defined: `State`'s constructor sets `pos` through the\n // accessor below before these could be initialized\n declare cursor: number\n /** The furthest position the cursor reached, or failure recorded, since the innermost open node started. */\n declare highWater: number\n /** Completed nodes waiting for their parent, in input order. */\n declare stack: Array<Child>\n declare previous: Previous | undefined\n /** How many nodes were reused from the previous tree. */\n declare reused: number\n /** Where {@link find} found the last node it found. */\n declare lastParent: Green | undefined\n declare lastParentStart: number\n\n static {\n Object.defineProperty(this.prototype, \"pos\", {\n get(this: SyntaxState) {\n return this.cursor\n },\n set(this: SyntaxState, p: number) {\n if (p < this.cursor) {\n // An attempt was abandoned (or a lookahead finished): drop its nodes\n const stack = this.stack\n while (stack.length > 0 && stack[stack.length - 1].end > p) stack.pop()\n }\n if (p > this.highWater) this.highWater = p\n this.cursor = p\n },\n configurable: true,\n enumerable: true\n })\n }\n\n constructor(\n source: I | Source<I>,\n options: {\n readonly context?: Context.Context<never> | undefined\n },\n previous: Previous | undefined\n ) {\n super(source, { context: options.context })\n this.highWater = this.cursor\n this.stack = []\n this.previous = previous\n this.reused = 0\n this.lastParent = undefined\n this.lastParentStart = 0\n this.syntax = this\n // Error recovery is always on: like Tree-sitter, a syntax parse always produces a tree\n this.recovered = []\n }\n\n override failWith(mode: ErrMode, failure: Failure): Fail {\n if (failure.offset > this.highWater) this.highWater = failure.offset\n return super.failWith(mode, failure)\n }\n\n override setHint(offset: number, expected: ReadonlyArray<string>): void {\n if (offset > this.highWater) this.highWater = offset\n super.setHint(offset, expected)\n }\n\n node(state: State<any>, step: (state: State<any>) => unknown, key: object, kind: string, named: boolean): unknown {\n const start = this.cursor\n const stack = this.stack\n if (this.previous !== undefined) {\n const green = this.reusable(this.previous, key, start)\n if (green !== undefined) {\n this.reused++\n const end = start + green.width\n state.pos = end\n const looked = start + green.lookahead\n if (looked > this.highWater) this.highWater = looked\n const d = green.diagnostics\n if (d !== undefined) {\n if (d.deepest !== undefined) this.deepen(start === d.base ? d.deepest : rebase(d.deepest, d.base - start))\n if (d.hintExpected !== undefined) this.setHint(start + d.hintOffset, d.hintExpected)\n }\n stack.push(new Child(green, start, end, undefined))\n return green.value\n }\n }\n const mark = stack.length\n const outer = this.highWater\n const outerDeepest = this.deepest\n const hintOffset = this.hintOffset\n const hintExpected = this.hintExpected\n this.highWater = start\n // Collect the furthest failure of this node alone, then merge it as `failWith` would have\n this.deepest = undefined\n const a = step(state)\n const looked = this.highWater\n if (outer > looked) this.highWater = outer\n const deepest = this.deepest as Failure | undefined\n this.deepest = outerDeepest\n if (deepest !== undefined) this.deepen(deepest)\n if (a === Fail) {\n if (stack.length > mark) stack.length = mark\n return a\n }\n const end = this.cursor\n // Like Tree-sitter's rules, nodes are never empty: an empty match adds nothing to the tree\n if (end === start) return a\n const hinted = this.hintOffset !== hintOffset || this.hintExpected !== hintExpected\n const diagnostics: Diagnostics | undefined =\n deepest === undefined && !hinted\n ? undefined\n : {\n deepest,\n base: start,\n hintOffset: this.hintOffset - start,\n hintExpected: hinted ? this.hintExpected : undefined\n }\n const entries = stack.splice(mark)\n stack.push(\n new Child(build(kind, named, key, start, end, looked, entries, a, undefined, diagnostics), start, end, undefined)\n )\n return a\n }\n\n read(end: number): void {\n // `highWater` is the last position looked at, `end` is exclusive\n if (end - 1 > this.highWater) this.highWater = end - 1\n }\n\n /** Records `failure` as the furthest failure if it is, as `failWith` does. */\n private deepen(failure: Failure): void {\n if (this.deepest === undefined || failure.offset >= this.deepest.offset) this.deepest = failure\n }\n\n field(state: State<any>, step: (state: State<any>) => unknown, name: string): unknown {\n const stack = this.stack\n const mark = stack.length\n const a = step(state)\n if (a !== Fail) for (let i = mark; i < stack.length; i++) stack[i].field = name\n return a\n }\n\n skipped(start: number, failure: Failure, mode: ErrMode): void {\n const stack = this.stack\n let i = stack.length\n while (i > 0 && stack[i - 1].start >= start && stack[i - 1].end > start) i--\n const end = this.cursor\n const green = build(errorKind, true, undefined, start, end, this.highWater, stack.splice(i), undefined, {\n failure: rebase(failure, start),\n mode\n })\n stack.push(new Child(green, start, end, undefined))\n }\n\n /**\n * Builds the root over the whole input from the nodes left on the stack.\n * When the parse failed, or stopped before the end, the rest of the input\n * becomes an `ERROR` node.\n */\n finish(kind: string, value: unknown, fatal: ErrorInfo | undefined, errorStart: number): Green {\n const entries = this.stack.splice(0)\n const end = this.end\n if (fatal !== undefined) {\n const last = entries.length > 0 ? entries[entries.length - 1].end : 0\n const start = Math.max(Math.min(errorStart, end), last)\n const error = build(errorKind, true, undefined, start, end, end, [], undefined, {\n failure: rebase(fatal.failure, start),\n mode: fatal.mode\n })\n entries.push(new Child(error, start, end, undefined))\n }\n return build(kind, true, undefined, 0, end, Math.max(end, this.highWater), entries, value, undefined)\n }\n\n /**\n * The outermost node of the previous tree built by `key` that starts at\n * `offset`. Reused nodes are mostly siblings, found one after the other,\n * so the search starts from the parent of the last one found when\n * `offset` lies inside it: no ancestor of that parent can start there.\n */\n private find(root: Green, offset: number, key: object): Green | undefined {\n let node = root\n let start = 0\n const last = this.lastParent\n if (last !== undefined && offset > this.lastParentStart && offset < this.lastParentStart + last.width) {\n node = last\n start = this.lastParentStart\n }\n while (true) {\n const offsets = node.offsets\n // The last child starting at or before `offset`\n let lo = 0\n let hi = offsets.length - 1\n let found = -1\n while (lo <= hi) {\n const mid = (lo + hi) >> 1\n if (start + offsets[mid] <= offset) {\n found = mid\n lo = mid + 1\n } else {\n hi = mid - 1\n }\n }\n if (found < 0) return undefined\n const child = node.children[found]\n const childStart = start + offsets[found]\n if (offset >= childStart + child.width) return undefined\n if (childStart === offset && child.key === key) {\n this.lastParent = node\n this.lastParentStart = start\n return child\n }\n node = child\n start = childStart\n }\n }\n\n /** The node of the previous tree built by `key` at `pos` (in the new input), if it can be reused. */\n private reusable(previous: Previous, key: object, pos: number): Green | undefined {\n const segments = previous.segments\n // The segment containing `pos`\n let lo = 0\n let hi = segments.length - 1\n while (lo <= hi) {\n const mid = (lo + hi) >> 1\n const seg = segments[mid]\n if (pos < seg.newStart) hi = mid - 1\n else if (pos >= seg.newStart + seg.length) lo = mid + 1\n else {\n const old = seg.oldStart + (pos - seg.newStart)\n const green = this.find(previous.root, old, key)\n if (green === undefined) return undefined\n const segEnd = seg.oldStart + seg.length\n // The input it looked at must be unchanged; past the end of both inputs counts as unchanged\n if (old + green.lookahead + tokenWidth(previous.input, old + green.lookahead) + previous.extra <= segEnd) {\n return green\n }\n if (segEnd === previous.oldLength && seg.newStart + seg.length === previous.newLength) return green\n return undefined\n }\n }\n return undefined\n }\n}\n\n/**\n * How many units a token parser may read at `offset`, where a parse\n * stopped looking: one code point. Of a string, that is two units at a high\n * surrogate. Of bytes in an unknown encoding, up to four.\n */\nconst tokenWidth = (input: Input, offset: number): number => {\n if (Predicate.isString(input)) {\n const c = input.charCodeAt(offset)\n return c >= 0xd800 && c <= 0xdbff ? 2 : 1\n }\n return input instanceof Uint8Array ? 4 : 1\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"syntax.js","names":[],"sources":["../../src/internal/syntax.ts"],"sourcesContent":["/**\n * The tree builder behind the `Syntax` module (see `docs/DESIGN.md`,\n * \"Syntax trees\").\n *\n * Trees are stored as *green* nodes, as in Roslyn and rust-analyzer: a green\n * node knows its kind, its width and its children's offsets relative to its\n * own start, but not where it is in the input or who its parent is. A subtree\n * that an edit doesn't touch can therefore be shared, unchanged, by the tree\n * before the edit and the tree after it. `Syntax.SyntaxNode` is the *red*\n * view: a green node, its absolute start and its parent, built lazily while\n * navigating.\n *\n * While parsing, completed nodes wait on a stack until the node around them\n * completes and adopts them. Nodes built by an attempt that is later\n * abandoned must not end up in the tree. Every combinator that abandons an\n * attempt moves the cursor back to (or before) where the attempt started,\n * and every node has a positive width, so the nodes of an abandoned attempt\n * are exactly those that end after the position the cursor moves back to:\n * the `pos` setter of {@link SyntaxState} drops them. This also covers\n * lookahead (`peek`, `not`) and custom parsers written with `Parser.make`.\n *\n * For incremental parsing, every node records how far its parse looked: the\n * furthest position the cursor reached and the furthest failure recorded\n * while it was being parsed (its *lookahead*). A node from the previous tree\n * is reused at a position when it was built by the same `Syntax.node`, and\n * the input it looked at, plus a margin for the tokens that read a little\n * past where they stop, is unchanged.\n */\nimport * as Predicate from \"effect/Predicate\"\nimport type * as Context from \"effect/Context\"\nimport type { Encoding } from \"../Encoding.js\"\nimport type { ErrMode, Input, Source } from \"../Input.js\"\nimport { Fail, Failure, State } from \"../Input.js\"\n\n/** What a failure inside an `ERROR` node was. Offsets are relative to the node. */\nexport interface ErrorInfo {\n readonly failure: Failure\n readonly mode: ErrMode\n}\n\n/** A position-independent syntax tree node. */\nexport class Green {\n constructor(\n readonly kind: string,\n readonly named: boolean,\n /** The `Syntax.node` that built it; `undefined` for roots and errors, which are never reused alone. */\n readonly key: object | undefined,\n readonly width: number,\n /** How far its parse looked, relative to its start (at least `width`). */\n readonly lookahead: number,\n readonly children: ReadonlyArray<Green>,\n /** The children's starts, relative to this node's start. */\n readonly offsets: ReadonlyArray<number>,\n /** The children's field names, when any child has one. */\n readonly fields: ReadonlyArray<string | undefined> | undefined,\n readonly value: unknown,\n /** Set on `ERROR` nodes. */\n readonly error: ErrorInfo | undefined,\n /** Whether this node or a descendant is an `ERROR` node. */\n readonly hasError: boolean,\n /** What its parse left behind for error reporting, replayed when it is reused. */\n readonly diagnostics: Diagnostics | undefined\n ) {}\n}\n\n/**\n * The error-reporting state a node's parse leaves behind (see\n * `State.deepest` and `State.setHint`). A reused node replays it, so that\n * a reparse reports the errors a fresh parse does.\n */\nexport interface Diagnostics {\n /** The furthest failure, at its offset in the parse that built the node... */\n readonly deepest: Failure | undefined\n /** ...which started the node at `base`. */\n readonly base: number\n /** Relative to the node's start. */\n readonly hintOffset: number\n readonly hintExpected: ReadonlyArray<string> | undefined\n}\n\n/** A completed node waiting for its parent, at an absolute position. */\nclass Child {\n constructor(\n readonly green: Green,\n readonly start: number,\n readonly end: number,\n public field: string | undefined\n ) {}\n}\n\nexport const errorKind = \"ERROR\"\n\nconst rebase = (f: Failure, start: number): Failure =>\n new Failure(f.offset - start, f.kind, f.expected, f.context, f.hasCause, f.cause, f.message, f.needed)\n\n/** Moves a failure stored relative to a node back to absolute offsets. */\nexport const absolute = (f: Failure, start: number): Failure => rebase(f, -start)\n\n/**\n * Builds a green node over `[start, end)` from the children waiting on the\n * stack.\n */\nconst build = (\n kind: string,\n named: boolean,\n key: object | undefined,\n start: number,\n end: number,\n lookahead: number,\n entries: ReadonlyArray<Child>,\n value: unknown,\n error: ErrorInfo | undefined,\n diagnostics?: Diagnostics\n): Green => {\n const n = entries.length\n const children = new Array<Green>(n)\n const offsets = new Array<number>(n)\n let fields: Array<string | undefined> | undefined\n let hasError = error !== undefined\n for (let i = 0; i < n; i++) {\n const e = entries[i]\n children[i] = e.green\n offsets[i] = e.start - start\n if (e.green.hasError) hasError = true\n if (e.field !== undefined) (fields ??= new Array(n).fill(undefined))[i] = e.field\n }\n const width = end - start\n const looked = Math.max(lookahead, end) - start\n return new Green(kind, named, key, width, looked, children, offsets, fields, value, error, hasError, diagnostics)\n}\n\n/**\n * A stretch of the new input copied unchanged from the previous one:\n * `[newStart, newStart + length)` is `[oldStart, oldStart + length)`.\n */\nexport interface Segment {\n readonly newStart: number\n readonly oldStart: number\n readonly length: number\n}\n\n/** What a reparse may reuse. */\nexport interface Previous {\n readonly root: Green\n readonly oldLength: number\n readonly newLength: number\n readonly segments: ReadonlyArray<Segment>\n readonly input: Input\n /** How far past its lookahead a parser may have read, besides a token at the lookahead. */\n readonly extra: number\n readonly encoding: Encoding<any> | undefined\n}\n\n/** The hooks that `Syntax` combinators and `Parser.resumeAfter`/`retryAfter` call. */\nexport interface Builder {\n node(state: State<any>, step: (state: State<any>) => unknown, key: object, kind: string, named: boolean): unknown\n field(state: State<any>, step: (state: State<any>) => unknown, name: string): unknown\n /** After error recovery: `[start, pos)` was skipped after `failure`. */\n skipped(start: number, failure: Failure, mode: ErrMode): void\n /**\n * Called by token parsers that read input up to `end` (exclusive) beyond\n * where they leave the cursor or record a failure.\n */\n read(end: number): void\n}\n\n/** The parse state of a `Syntax` parse. */\nexport class SyntaxState<I extends Input = Input> extends State<I> implements Builder {\n // Declared, not defined: `State`'s constructor sets `pos` through the\n // accessor below before these could be initialized\n declare cursor: number\n /** The furthest position the cursor reached, or failure recorded, since the innermost open node started. */\n declare highWater: number\n /** Completed nodes waiting for their parent, in input order. */\n declare stack: Array<Child>\n declare previous: Previous | undefined\n /** How many nodes were reused from the previous tree. */\n declare reused: number\n /** Where {@link find} found the last node it found. */\n declare lastParent: Green | undefined\n declare lastParentStart: number\n\n static {\n Object.defineProperty(this.prototype, \"pos\", {\n get(this: SyntaxState) {\n return this.cursor\n },\n set(this: SyntaxState, p: number) {\n if (p < this.cursor) {\n // An attempt was abandoned (or a lookahead finished): drop its nodes\n const stack = this.stack\n while (stack.length > 0 && stack[stack.length - 1].end > p) stack.pop()\n }\n if (p > this.highWater) this.highWater = p\n this.cursor = p\n },\n configurable: true,\n enumerable: true\n })\n }\n\n constructor(\n source: I | Source<I>,\n options: {\n readonly context?: Context.Context<never> | undefined\n },\n previous: Previous | undefined\n ) {\n super(source, { context: options.context })\n this.highWater = this.cursor\n this.stack = []\n this.previous = previous\n this.reused = 0\n this.lastParent = undefined\n this.lastParentStart = 0\n this.syntax = this\n // Error recovery is always on: like Tree-sitter, a syntax parse always produces a tree\n this.recovered = []\n }\n\n override failWith(mode: ErrMode, failure: Failure): Fail {\n if (failure.offset > this.highWater) this.highWater = failure.offset\n return super.failWith(mode, failure)\n }\n\n override failTies(head: Failure, tie1: Failure, tie2: Failure | undefined): Fail {\n if (head.offset > this.highWater) this.highWater = head.offset\n return super.failTies(head, tie1, tie2)\n }\n\n override setHint(offset: number, expected: ReadonlyArray<string>): void {\n if (offset > this.highWater) this.highWater = offset\n super.setHint(offset, expected)\n }\n\n node(state: State<any>, step: (state: State<any>) => unknown, key: object, kind: string, named: boolean): unknown {\n const start = this.cursor\n const stack = this.stack\n if (this.previous !== undefined) {\n const green = this.reusable(this.previous, key, start)\n if (green !== undefined) {\n this.reused++\n const end = start + green.width\n state.pos = end\n const looked = start + green.lookahead\n if (looked > this.highWater) this.highWater = looked\n const d = green.diagnostics\n if (d !== undefined) {\n if (d.deepest !== undefined) this.deepen(start === d.base ? d.deepest : rebase(d.deepest, d.base - start))\n if (d.hintExpected !== undefined) this.setHint(start + d.hintOffset, d.hintExpected)\n }\n stack.push(new Child(green, start, end, undefined))\n return green.value\n }\n }\n const mark = stack.length\n const outer = this.highWater\n const outerDeepest = this.deepest\n const hintOffset = this.hintOffset\n const hintExpected = this.hintExpected\n this.highWater = start\n // Collect the furthest failure of this node alone, then merge it as `failWith` would have\n this.deepest = undefined\n const a = step(state)\n const looked = this.highWater\n if (outer > looked) this.highWater = outer\n const deepest = this.deepest as Failure | undefined\n this.deepest = outerDeepest\n if (deepest !== undefined) this.deepen(deepest)\n if (a === Fail) {\n if (stack.length > mark) stack.length = mark\n return a\n }\n const end = this.cursor\n // Like Tree-sitter's rules, nodes are never empty: an empty match adds nothing to the tree\n if (end === start) return a\n const hinted = this.hintOffset !== hintOffset || this.hintExpected !== hintExpected\n const diagnostics: Diagnostics | undefined =\n deepest === undefined && !hinted\n ? undefined\n : {\n deepest,\n base: start,\n hintOffset: this.hintOffset - start,\n hintExpected: hinted ? this.hintExpected : undefined\n }\n const entries = stack.splice(mark)\n stack.push(\n new Child(build(kind, named, key, start, end, looked, entries, a, undefined, diagnostics), start, end, undefined)\n )\n return a\n }\n\n read(end: number): void {\n // `highWater` is the last position looked at, `end` is exclusive\n if (end - 1 > this.highWater) this.highWater = end - 1\n }\n\n /** Records `failure` as the furthest failure if it is, as `failWith` does. */\n private deepen(failure: Failure): void {\n if (this.deepest === undefined || failure.offset >= this.deepest.offset) this.deepest = failure\n }\n\n field(state: State<any>, step: (state: State<any>) => unknown, name: string): unknown {\n const stack = this.stack\n const mark = stack.length\n const a = step(state)\n if (a !== Fail) for (let i = mark; i < stack.length; i++) stack[i].field = name\n return a\n }\n\n skipped(start: number, failure: Failure, mode: ErrMode): void {\n const stack = this.stack\n let i = stack.length\n while (i > 0 && stack[i - 1].start >= start && stack[i - 1].end > start) i--\n const end = this.cursor\n const green = build(errorKind, true, undefined, start, end, this.highWater, stack.splice(i), undefined, {\n failure: rebase(failure, start),\n mode\n })\n stack.push(new Child(green, start, end, undefined))\n }\n\n /**\n * Builds the root over the whole input from the nodes left on the stack.\n * When the parse failed, or stopped before the end, the rest of the input\n * becomes an `ERROR` node.\n */\n finish(kind: string, value: unknown, fatal: ErrorInfo | undefined, errorStart: number): Green {\n const entries = this.stack.splice(0)\n const end = this.end\n if (fatal !== undefined) {\n const last = entries.length > 0 ? entries[entries.length - 1].end : 0\n const start = Math.max(Math.min(errorStart, end), last)\n const error = build(errorKind, true, undefined, start, end, end, [], undefined, {\n failure: rebase(fatal.failure, start),\n mode: fatal.mode\n })\n entries.push(new Child(error, start, end, undefined))\n }\n return build(kind, true, undefined, 0, end, Math.max(end, this.highWater), entries, value, undefined)\n }\n\n /**\n * The outermost node of the previous tree built by `key` that starts at\n * `offset`. Reused nodes are mostly siblings, found one after the other,\n * so the search starts from the parent of the last one found when\n * `offset` lies inside it: no ancestor of that parent can start there.\n */\n private find(root: Green, offset: number, key: object): Green | undefined {\n let node = root\n let start = 0\n const last = this.lastParent\n if (last !== undefined && offset > this.lastParentStart && offset < this.lastParentStart + last.width) {\n node = last\n start = this.lastParentStart\n }\n while (true) {\n const offsets = node.offsets\n // The last child starting at or before `offset`\n let lo = 0\n let hi = offsets.length - 1\n let found = -1\n while (lo <= hi) {\n const mid = (lo + hi) >> 1\n if (start + offsets[mid] <= offset) {\n found = mid\n lo = mid + 1\n } else {\n hi = mid - 1\n }\n }\n if (found < 0) return undefined\n const child = node.children[found]\n const childStart = start + offsets[found]\n if (offset >= childStart + child.width) return undefined\n if (childStart === offset && child.key === key) {\n this.lastParent = node\n this.lastParentStart = start\n return child\n }\n node = child\n start = childStart\n }\n }\n\n /** The node of the previous tree built by `key` at `pos` (in the new input), if it can be reused. */\n private reusable(previous: Previous, key: object, pos: number): Green | undefined {\n const segments = previous.segments\n // The segment containing `pos`\n let lo = 0\n let hi = segments.length - 1\n while (lo <= hi) {\n const mid = (lo + hi) >> 1\n const seg = segments[mid]\n if (pos < seg.newStart) hi = mid - 1\n else if (pos >= seg.newStart + seg.length) lo = mid + 1\n else {\n const old = seg.oldStart + (pos - seg.newStart)\n const green = this.find(previous.root, old, key)\n if (green === undefined) return undefined\n const segEnd = seg.oldStart + seg.length\n // The input it looked at must be unchanged; past the end of both inputs counts as unchanged\n if (old + green.lookahead + tokenWidth(previous.input, old + green.lookahead) + previous.extra <= segEnd) {\n return green\n }\n if (segEnd === previous.oldLength && seg.newStart + seg.length === previous.newLength) return green\n return undefined\n }\n }\n return undefined\n }\n}\n\n/**\n * How many units a token parser may read at `offset`, where a parse\n * stopped looking: one code point. Of a string, that is two units at a high\n * surrogate. Of bytes in an unknown encoding, up to four.\n */\nconst tokenWidth = (input: Input, offset: number): number => {\n if (Predicate.isString(input)) {\n const c = input.charCodeAt(offset)\n return c >= 0xd800 && c <= 0xdbff ? 2 : 1\n }\n return input instanceof Uint8Array ? 4 : 1\n}\n"],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import { Fail, Failure, Input, State } from "../Input.js";
2
+ //#region src/internal/ties.d.ts
3
+ /** The failures of a round of attempts, folded lazily. */
4
+ export declare class TiedFailures {
5
+ /** The running failure, before the pending ties are merged into it. */
6
+ failure: Failure | undefined;
7
+ /** The oldest pending tie, at `failure`'s offset. */
8
+ tie1: Failure | undefined;
9
+ /** The newest pending tie, at `failure`'s offset. */
10
+ tie2: Failure | undefined;
11
+ /** Forgets every failure, for a new round. */
12
+ clear(): void;
13
+ /**
14
+ * Folds in the failure the latest attempt left on `state`, taking over
15
+ * its own unmerged ties when it is the furthest.
16
+ */
17
+ add<I extends Input>(state: State<I>): void;
18
+ /**
19
+ * Fails `state` with the folded failure (recoverably), or with its
20
+ * current failure when nothing was folded.
21
+ */
22
+ fail<I extends Input>(state: State<I>): Fail;
23
+ /**
24
+ * Records the folded expectations as a hint when the folded failure lies
25
+ * where `state` stopped (an attempt that fails without consuming input).
26
+ */
27
+ hint<I extends Input>(state: State<I>): void;
28
+ }
29
+ //#endregion
30
+ //# sourceMappingURL=ties.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ties.d.ts","names":[],"sources":["../../src/internal/ties.ts"],"mappings":";;;qBAkBa;;EAEX,SAAS;;EAET,MAAM;;EAEN,MAAM;;EAGN;;;;;EAUA,IAAI,UAAU,OAAO,OAAO,MAAM;;;;;EA0BlC,KAAK,UAAU,OAAO,OAAO,MAAM,KAAK;;;;;EAWxC,KAAK,UAAU,OAAO,OAAO,MAAM"}
@@ -0,0 +1,67 @@
1
+ import { mergeExpected, mergeTiedFailures } from "../Input.js";
2
+ //#region src/internal/ties.ts
3
+ /** The failures of a round of attempts, folded lazily. */
4
+ var TiedFailures = class {
5
+ /** The running failure, before the pending ties are merged into it. */
6
+ failure = void 0;
7
+ /** The oldest pending tie, at `failure`'s offset. */
8
+ tie1 = void 0;
9
+ /** The newest pending tie, at `failure`'s offset. */
10
+ tie2 = void 0;
11
+ /** Forgets every failure, for a new round. */
12
+ clear() {
13
+ this.failure = void 0;
14
+ this.tie1 = void 0;
15
+ this.tie2 = void 0;
16
+ }
17
+ /**
18
+ * Folds in the failure the latest attempt left on `state`, taking over
19
+ * its own unmerged ties when it is the furthest.
20
+ */
21
+ add(state) {
22
+ const head = state.failureHead;
23
+ const running = this.failure;
24
+ if (running === void 0 || head.offset > running.offset) {
25
+ this.failure = head;
26
+ this.tie1 = state.failureTie1;
27
+ this.tie2 = state.failureTie2;
28
+ return;
29
+ }
30
+ if (head.offset < running.offset) return;
31
+ const failure = state.failure;
32
+ const tie1 = this.tie1;
33
+ if (tie1 === void 0) this.tie1 = failure;
34
+ else if (this.tie2 === void 0) this.tie2 = failure;
35
+ else {
36
+ this.failure = mergeTiedFailures(running, tie1, mergeExpected(running.expected, tie1.expected));
37
+ this.tie1 = this.tie2;
38
+ this.tie2 = failure;
39
+ }
40
+ }
41
+ /**
42
+ * Fails `state` with the folded failure (recoverably), or with its
43
+ * current failure when nothing was folded.
44
+ */
45
+ fail(state) {
46
+ const failure = this.failure;
47
+ if (failure === void 0) return state.failWith("Backtrack", state.failure);
48
+ const tie1 = this.tie1;
49
+ return tie1 === void 0 ? state.failWith("Backtrack", failure) : state.failTies(failure, tie1, this.tie2);
50
+ }
51
+ /**
52
+ * Records the folded expectations as a hint when the folded failure lies
53
+ * where `state` stopped (an attempt that fails without consuming input).
54
+ */
55
+ hint(state) {
56
+ const failure = this.failure;
57
+ if (failure === void 0 || failure.offset !== state.pos) return;
58
+ let expected = failure.expected;
59
+ if (this.tie1 !== void 0) expected = mergeExpected(expected, this.tie1.expected);
60
+ if (this.tie2 !== void 0) expected = mergeExpected(expected, this.tie2.expected);
61
+ state.setHint(failure.offset, expected);
62
+ }
63
+ };
64
+ //#endregion
65
+ export { TiedFailures };
66
+
67
+ //# sourceMappingURL=ties.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ties.js","names":[],"sources":["../../src/internal/ties.ts"],"sourcesContent":["/**\n * Tied failures, merged only when read.\n *\n * A combinator that tries several parsers at the same position (an\n * alternation, a permutation round, an operator table) reports the merge\n * of their failures, left to right, as `mergeFailures` would. Most of the\n * time one of the later attempts succeeds and the merge is thrown away, so\n * {@link TiedFailures} keeps the last two failures tied with the running\n * one unmerged, and {@link TiedFailures.fail} hands them to the state with\n * `State.failTies`, which merges them on first read (#38, #44).\n *\n * `Parser.alt` does the same fold in locals, since it is the hottest\n * combinator and cannot afford an accumulator per call.\n */\nimport type { Failure, Fail, Input, State } from \"../Input.js\"\nimport { mergeExpected, mergeTiedFailures } from \"../Input.js\"\n\n/** The failures of a round of attempts, folded lazily. */\nexport class TiedFailures {\n /** The running failure, before the pending ties are merged into it. */\n failure: Failure | undefined = undefined\n /** The oldest pending tie, at `failure`'s offset. */\n tie1: Failure | undefined = undefined\n /** The newest pending tie, at `failure`'s offset. */\n tie2: Failure | undefined = undefined\n\n /** Forgets every failure, for a new round. */\n clear(): void {\n this.failure = undefined\n this.tie1 = undefined\n this.tie2 = undefined\n }\n\n /**\n * Folds in the failure the latest attempt left on `state`, taking over\n * its own unmerged ties when it is the furthest.\n */\n add<I extends Input>(state: State<I>): void {\n const head = state.failureHead\n const running = this.failure\n if (running === undefined || head.offset > running.offset) {\n this.failure = head\n this.tie1 = state.failureTie1\n this.tie2 = state.failureTie2\n return\n }\n if (head.offset < running.offset) return\n const failure = state.failure\n const tie1 = this.tie1\n if (tie1 === undefined) this.tie1 = failure\n else if (this.tie2 === undefined) this.tie2 = failure\n else {\n // A third tie: fold the oldest pending one in, keeping the order\n this.failure = mergeTiedFailures(running, tie1, mergeExpected(running.expected, tie1.expected))\n this.tie1 = this.tie2\n this.tie2 = failure\n }\n }\n\n /**\n * Fails `state` with the folded failure (recoverably), or with its\n * current failure when nothing was folded.\n */\n fail<I extends Input>(state: State<I>): Fail {\n const failure = this.failure\n if (failure === undefined) return state.failWith(\"Backtrack\", state.failure)\n const tie1 = this.tie1\n return tie1 === undefined ? state.failWith(\"Backtrack\", failure) : state.failTies(failure, tie1, this.tie2)\n }\n\n /**\n * Records the folded expectations as a hint when the folded failure lies\n * where `state` stopped (an attempt that fails without consuming input).\n */\n hint<I extends Input>(state: State<I>): void {\n const failure = this.failure\n if (failure === undefined || failure.offset !== state.pos) return\n let expected = failure.expected\n if (this.tie1 !== undefined) expected = mergeExpected(expected, this.tie1.expected)\n if (this.tie2 !== undefined) expected = mergeExpected(expected, this.tie2.expected)\n state.setHint(failure.offset, expected)\n }\n}\n"],"mappings":";;;AAkBA,IAAa,eAAb,MAA0B;;CAExB,UAA+B,KAAA;;CAE/B,OAA4B,KAAA;;CAE5B,OAA4B,KAAA;;CAG5B,QAAc;EACZ,KAAK,UAAU,KAAA;EACf,KAAK,OAAO,KAAA;EACZ,KAAK,OAAO,KAAA;CACd;;;;;CAMA,IAAqB,OAAuB;EAC1C,MAAM,OAAO,MAAM;EACnB,MAAM,UAAU,KAAK;EACrB,IAAI,YAAY,KAAA,KAAa,KAAK,SAAS,QAAQ,QAAQ;GACzD,KAAK,UAAU;GACf,KAAK,OAAO,MAAM;GAClB,KAAK,OAAO,MAAM;GAClB;EACF;EACA,IAAI,KAAK,SAAS,QAAQ,QAAQ;EAClC,MAAM,UAAU,MAAM;EACtB,MAAM,OAAO,KAAK;EAClB,IAAI,SAAS,KAAA,GAAW,KAAK,OAAO;OAC/B,IAAI,KAAK,SAAS,KAAA,GAAW,KAAK,OAAO;OACzC;GAEH,KAAK,UAAU,kBAAkB,SAAS,MAAM,cAAc,QAAQ,UAAU,KAAK,QAAQ,CAAC;GAC9F,KAAK,OAAO,KAAK;GACjB,KAAK,OAAO;EACd;CACF;;;;;CAMA,KAAsB,OAAuB;EAC3C,MAAM,UAAU,KAAK;EACrB,IAAI,YAAY,KAAA,GAAW,OAAO,MAAM,SAAS,aAAa,MAAM,OAAO;EAC3E,MAAM,OAAO,KAAK;EAClB,OAAO,SAAS,KAAA,IAAY,MAAM,SAAS,aAAa,OAAO,IAAI,MAAM,SAAS,SAAS,MAAM,KAAK,IAAI;CAC5G;;;;;CAMA,KAAsB,OAAuB;EAC3C,MAAM,UAAU,KAAK;EACrB,IAAI,YAAY,KAAA,KAAa,QAAQ,WAAW,MAAM,KAAK;EAC3D,IAAI,WAAW,QAAQ;EACvB,IAAI,KAAK,SAAS,KAAA,GAAW,WAAW,cAAc,UAAU,KAAK,KAAK,QAAQ;EAClF,IAAI,KAAK,SAAS,KAAA,GAAW,WAAW,cAAc,UAAU,KAAK,KAAK,QAAQ;EAClF,MAAM,QAAQ,QAAQ,QAAQ,QAAQ;CACxC;AACF"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://www.schemastore.org/package",
3
3
  "name": "@thomasfosterau/effect-parse",
4
- "version": "0.2.0",
4
+ "version": "0.3.0",
5
5
  "description": "Parser combinators for Effect, ported from Rust's nom and winnow: text, bytes, bits and token streams, streaming input, compiled parsers and Schema integration",
6
6
  "keywords": [
7
7
  "effect",
package/src/Expression.ts CHANGED
@@ -35,10 +35,10 @@
35
35
  * @since 0.1.0
36
36
  */
37
37
  import type { Input, State } from "./Input.js"
38
- import { Fail, mergeFailures } from "./Input.js"
39
- import type { Failure } from "./Input.js"
38
+ import { Fail } from "./Input.js"
40
39
  import type { Parser } from "./Parser.js"
41
40
  import { make as makeParser } from "./Parser.js"
41
+ import { TiedFailures } from "./internal/ties.js"
42
42
 
43
43
  /**
44
44
  * An operator in an expression grammar.
@@ -160,9 +160,11 @@ export const make = <A, E, R, I extends Input, const Ops extends ReadonlyArray<O
160
160
 
161
161
  // Attempts each operator in turn. Returns the index of the first match
162
162
  // (with its output in `matched`), -1 if none matched, or -2 on a fatal
163
- // failure. Expectations of failed attempts are accumulated in `failure`.
163
+ // failure. Failed attempts are folded into `failures`, merged only when
164
+ // read (#44): a round in which an operator matches discards them unmerged.
165
+ // Like `matched`, it is shared by nested expressions, which clear it.
164
166
  let matched: unknown
165
- let failure: Failure | undefined
167
+ const failures = new TiedFailures()
166
168
  const tryOps = (state: State<any>, ops: ReadonlyArray<OperatorBase<any, any, any>>, mustConsume: boolean): number => {
167
169
  const start = state.pos
168
170
  for (let i = 0; i < ops.length; i++) {
@@ -177,15 +179,15 @@ export const make = <A, E, R, I extends Input, const Ops extends ReadonlyArray<O
177
179
  return i
178
180
  }
179
181
  if (state.mode !== "Backtrack") return -2
180
- failure = failure === undefined ? state.failure : mergeFailures(failure, state.failure)
181
182
  state.pos = start
183
+ failures.add(state)
182
184
  }
183
185
  return -1
184
186
  }
185
187
 
186
188
  const expr = (state: State<any>, minPower: number): A | Fail => {
187
189
  let lhs: A | Fail
188
- failure = undefined
190
+ failures.clear()
189
191
  const p = tryOps(state, prefixes, true)
190
192
  if (p === -2) return Fail
191
193
  if (p >= 0) {
@@ -195,11 +197,18 @@ export const make = <A, E, R, I extends Input, const Ops extends ReadonlyArray<O
195
197
  if (operandValue === Fail) return Fail
196
198
  lhs = op.fold(opOut, operandValue)
197
199
  } else {
198
- const prefixFailure = failure
200
+ const prefixFailure = failures.failure
201
+ const prefixTie1 = failures.tie1
202
+ const prefixTie2 = failures.tie2
199
203
  lhs = operand(state)
200
204
  if (lhs === Fail) {
201
205
  if (prefixFailure !== undefined && state.mode === "Backtrack") {
202
- state.failWith("Backtrack", mergeFailures(prefixFailure, state.failure))
206
+ // The operand may have parsed nested expressions, which reuse `failures`
207
+ failures.failure = prefixFailure
208
+ failures.tie1 = prefixTie1
209
+ failures.tie2 = prefixTie2
210
+ failures.add(state)
211
+ failures.fail(state)
203
212
  }
204
213
  return Fail
205
214
  }
@@ -207,7 +216,7 @@ export const make = <A, E, R, I extends Input, const Ops extends ReadonlyArray<O
207
216
 
208
217
  while (true) {
209
218
  const start = state.pos
210
- failure = undefined
219
+ failures.clear()
211
220
  const q = tryOps(state, postfixes, true)
212
221
  if (q === -2) return Fail
213
222
  if (q >= 0) {
@@ -219,17 +228,11 @@ export const make = <A, E, R, I extends Input, const Ops extends ReadonlyArray<O
219
228
  lhs = op.fold(lhs, matched)
220
229
  continue
221
230
  }
222
- const postfixFailure = failure
231
+ // The infix attempts are folded on top of the postfix ones
223
232
  const i = tryOps(state, infixes, false)
224
233
  if (i === -2) return Fail
225
234
  if (i < 0) {
226
- const f =
227
- postfixFailure === undefined
228
- ? failure
229
- : failure === undefined
230
- ? postfixFailure
231
- : mergeFailures(postfixFailure, failure)
232
- if (f !== undefined && f.offset === state.pos) state.setHint(f.offset, f.expected)
235
+ failures.hint(state)
233
236
  break
234
237
  }
235
238
  const op = infixes[i]