From ff98c077a9541136600ea193e9c01ea6bb4dd85b Mon Sep 17 00:00:00 2001 From: Kaz Wesley Date: Wed, 30 Aug 2023 20:49:22 +0000 Subject: [PATCH 01/44] Parser TS bindings --- Cargo.lock | 20 +- Cargo.toml | 2 +- app/gui2/parser-codegen/.babelrc | 5 + app/gui2/parser-codegen/out/generated.ts | 900 ++++ app/gui2/parser-codegen/package-lock.json | 3917 +++++++++++++++++ app/gui2/parser-codegen/package.json | 22 + app/gui2/parser-codegen/src/codegen.ts | 556 +++ app/gui2/parser-codegen/src/prototype.ts | 124 + .../parser-codegen/support/serialization.ts | 140 + app/gui2/parser-codegen/tsconfig.json | 11 + app/gui2/parser-codegen/tslint.json | 9 + app/gui2/rust-ffi/src/lib.rs | 6 + lib/rust/metamodel/src/data_structures.rs | 8 + lib/rust/metamodel/src/java/from_meta.rs | 4 +- lib/rust/metamodel/src/java/implementation.rs | 2 +- lib/rust/metamodel/src/java/mod.rs | 24 +- lib/rust/metamodel/src/lib.rs | 2 + lib/rust/metamodel/src/meta/graphviz.rs | 3 +- lib/rust/metamodel/src/meta/mod.rs | 21 +- lib/rust/parser/Cargo.toml | 1 - lib/rust/parser/generate-ts/Cargo.toml | 19 + .../generate-ts/src/lazy_deserialization.rs | 0 lib/rust/parser/generate-ts/src/lib.rs | 27 + lib/rust/parser/generate-ts/src/main.rs | 248 ++ lib/rust/parser/generate-ts/src/proto.ts | 50 + .../parser/generate-ts/src/serialization.rs | 180 + lib/rust/parser/src/bin/serialize.rs | 24 + lib/rust/parser/src/format.rs | 512 +++ lib/rust/parser/src/lib.rs | 11 +- lib/rust/parser/src/syntax/tree.rs | 286 +- lib/rust/parser/src/syntax/tree/block.rs | 6 +- .../parser/src/syntax/tree/visitor/Cargo.toml | 22 - .../parser/src/syntax/tree/visitor/src/lib.rs | 181 - 33 files changed, 6820 insertions(+), 523 deletions(-) create mode 100644 app/gui2/parser-codegen/.babelrc create mode 100644 app/gui2/parser-codegen/out/generated.ts create mode 100644 app/gui2/parser-codegen/package-lock.json create mode 100644 app/gui2/parser-codegen/package.json create mode 100644 app/gui2/parser-codegen/src/codegen.ts create mode 100644 app/gui2/parser-codegen/src/prototype.ts create mode 100644 app/gui2/parser-codegen/support/serialization.ts create mode 100644 app/gui2/parser-codegen/tsconfig.json create mode 100644 app/gui2/parser-codegen/tslint.json create mode 100644 lib/rust/parser/generate-ts/Cargo.toml create mode 100644 lib/rust/parser/generate-ts/src/lazy_deserialization.rs create mode 100644 lib/rust/parser/generate-ts/src/lib.rs create mode 100644 lib/rust/parser/generate-ts/src/main.rs create mode 100644 lib/rust/parser/generate-ts/src/proto.ts create mode 100644 lib/rust/parser/generate-ts/src/serialization.rs create mode 100644 lib/rust/parser/src/bin/serialize.rs create mode 100644 lib/rust/parser/src/format.rs delete mode 100644 lib/rust/parser/src/syntax/tree/visitor/Cargo.toml delete mode 100644 lib/rust/parser/src/syntax/tree/visitor/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index e9cd34b1047b..9d3321006e1e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2353,7 +2353,6 @@ dependencies = [ "enso-data-structures", "enso-metamodel", "enso-metamodel-lexpr", - "enso-parser-syntax-tree-visitor", "enso-prelude", "enso-reflect", "enso-shapely-macros", @@ -2391,23 +2390,26 @@ dependencies = [ ] [[package]] -name = "enso-parser-jni" +name = "enso-parser-generate-ts" version = "0.1.0" dependencies = [ - "bincode 2.0.0-rc.2", + "derivative", + "enso-metamodel", "enso-parser", "enso-prelude", - "jni", + "enso-reflect", + "serde", + "serde_json", ] [[package]] -name = "enso-parser-syntax-tree-visitor" +name = "enso-parser-jni" version = "0.1.0" dependencies = [ - "enso-macro-utils", - "proc-macro2", - "quote", - "syn 1.0.107", + "bincode 2.0.0-rc.2", + "enso-parser", + "enso-prelude", + "jni", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 1f673f5807e2..d8a8734c8285 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,9 +20,9 @@ members = [ "build/shader-tools", "lib/rust/*", "lib/rust/parser/doc-parser", - "lib/rust/parser/src/syntax/tree/visitor", "lib/rust/parser/jni", "lib/rust/parser/generate-java", + "lib/rust/parser/generate-ts", "lib/rust/parser/debug", "lib/rust/ensogl/pack", "lib/rust/profiler/data", diff --git a/app/gui2/parser-codegen/.babelrc b/app/gui2/parser-codegen/.babelrc new file mode 100644 index 000000000000..a29ac9986c16 --- /dev/null +++ b/app/gui2/parser-codegen/.babelrc @@ -0,0 +1,5 @@ +{ + "presets": [ + "@babel/preset-env" + ] +} diff --git a/app/gui2/parser-codegen/out/generated.ts b/app/gui2/parser-codegen/out/generated.ts new file mode 100644 index 000000000000..f10e316daf5e --- /dev/null +++ b/app/gui2/parser-codegen/out/generated.ts @@ -0,0 +1,900 @@ +export class LazyObject { + protected readonly lazyObjectData: Cursor + + constructor(data: Cursor) { + this.lazyObjectData = data + } + + debug(): {} { + return {} + } +} + +export const builtin = { + Array: Array +} as const + +export class Cursor { + private readonly blob: Uint8Array + private readonly address: number + + constructor(blob: Uint8Array, address: number) { + this.blob = blob + this.address = address + } + + * readSequence( + readElement: (cursor: Cursor) => T, + elementSize: number + ): Iterable { + const data = this.readPointer() + let count = data.readU32() + let offset = 4 + while (count > 0) { + yield readElement(data.seek(offset)) + count-- + offset += elementSize + } + } + + readOption( + readElement: (cursor: Cursor) => T + ): T | null { + const discriminant = this.readU8() + switch (discriminant) { + case 0: + return null + case 1: + return readElement(this.seek(1).readPointer()) + default: + throw new Error(`Invalid Option discriminant: 0x${discriminant.toString(16)}.`) + } + } + + readResult( + readOk: (cursor: Cursor) => Ok, + readErr: (cursor: Cursor) => Err + ): Ok | Err { + const data = this.readPointer() + const discriminant = data.readU32() + switch (discriminant) { + case 0: + return readOk(data.seek(4)) + case 1: + return readErr(data.seek(4)) + default: + throw new Error(`Invalid Result discriminant: 0x${discriminant.toString(16)}.`) + } + } + + readPointer(): Cursor { + return new Cursor(this.blob, this.readU32()) + } + + readU8(): number { + return this.blob.at(this.address)! + } + + readU32(): number { + return this.readU8() + | (this.seek(1).readU8() << 8) + | (this.seek(2).readU8() << 16) + | (this.seek(3).readU8() << 24) + } + + readI32(): number { + const raw = this.readU32() + const value = raw & 0x7fff_ffff + if (value === raw) { + return value + } else { + return -value + } + } + + readU64(): number { + const lo = this.readU32() + const hi = this.seek(4).readU32() + //if (hi !== 0) { + // throw new RangeError() + //} + return lo + } + + readBool(): boolean { + const value = this.readU8() + switch (value) { + case 0: + return false + case 1: + return true + default: + throw new Error(`Invalid boolean: 0x${value.toString(16)} @ 0x${this.address.toString(16)}.`) + } + } + + readString(): string { + const data = this.readPointer() + const len = data.readU32() + const stringData = data.seek(4) + const bytes = stringData.blob.slice(stringData.address, stringData.address + len) + return new TextDecoder().decode(bytes) + } + + seek(offset: number): Cursor { + return new Cursor(this.blob, this.address + offset) + } +} + +export function debugHelper(value: any): object | null { + if (value === null) { + return null + } + if (typeof value["debug"] === "function") { + return value.debug() + } + if (typeof value[Symbol.iterator] === "function") { + return Array.from(value, debugHelper) + } + return value +} +export class DocComment extends LazyObject { + constructor(cursor: Cursor) { super(cursor); } + static read(cursor: Cursor): DocComment { return new DocComment(cursor); } + get open(): Token.TextStart { return Token.TextStart.read(this.lazyObjectData); } + get elements(): Iterable { return this.lazyObjectData.seek(40).readSequence((element: Cursor) => TextElement.read(element.readPointer()), 4); } + get newlines(): Iterable { return this.lazyObjectData.seek(44).readSequence((element: Cursor) => Token.Newline.read(element), 40); } + debug(): any { return { ...super.debug(), open: debugHelper(this.open), elements: debugHelper(this.elements), newlines: debugHelper(this.newlines) }; } +} +export module TextElement { + abstract class AbstractBase extends LazyObject { + constructor(cursor: Cursor) { super(cursor); } + debug(): any { return { ...super.debug() }; } + } + export const enum Type { + Section = 0, + Escape = 1, + Newline = 2, + Splice = 3 + } + export class Section extends AbstractBase { + readonly type: Type.Section; + constructor(cursor: Cursor) { super(cursor); this.type = Type.Section; } + static read(cursor: Cursor): Section { return new Section(cursor); } + get text(): Token.TextSection { return Token.TextSection.read(this.lazyObjectData); } + debug(): any { return { ...super.debug(), text: debugHelper(this.text) }; } + } + export class Escape extends AbstractBase { + readonly type: Type.Escape; + constructor(cursor: Cursor) { super(cursor); this.type = Type.Escape; } + static read(cursor: Cursor): Escape { return new Escape(cursor); } + get token(): Token.TextEscape { return Token.TextEscape.read(this.lazyObjectData); } + debug(): any { return { ...super.debug(), token: debugHelper(this.token) }; } + } + export class Newline extends AbstractBase { + readonly type: Type.Newline; + constructor(cursor: Cursor) { super(cursor); this.type = Type.Newline; } + static read(cursor: Cursor): Newline { return new Newline(cursor); } + get newline(): Token.Newline { return Token.Newline.read(this.lazyObjectData); } + debug(): any { return { ...super.debug(), newline: debugHelper(this.newline) }; } + } + export class Splice extends AbstractBase { + readonly type: Type.Splice; + constructor(cursor: Cursor) { super(cursor); this.type = Type.Splice; } + static read(cursor: Cursor): Splice { return new Splice(cursor); } + get open(): Token.OpenSymbol { return Token.OpenSymbol.read(this.lazyObjectData); } + get expression(): Tree | null { return this.lazyObjectData.seek(40).readOption((element: Cursor) => Tree.read(element.readPointer())); } + get close(): Token.CloseSymbol { return Token.CloseSymbol.read(this.lazyObjectData.seek(45)); } + debug(): any { return { ...super.debug(), open: debugHelper(this.open), expression: debugHelper(this.expression), close: debugHelper(this.close) }; } + } + export type TextElement = Section | Escape | Newline | Splice; + export function read(cursor: Cursor): TextElement { switch (cursor.readU32()) { + case 0: return new Section(cursor.seek(4)); + case 1: return new Escape(cursor.seek(4)); + case 2: return new Newline(cursor.seek(4)); + case 3: return new Splice(cursor.seek(4)); + default: throw new Error("Unexpected discriminant while deserializing."); + } } +} +export type TextElement = TextElement.TextElement; +export class OperatorDelimitedTree extends LazyObject { + constructor(cursor: Cursor) { super(cursor); } + static read(cursor: Cursor): OperatorDelimitedTree { return new OperatorDelimitedTree(cursor); } + get operator(): Token.Operator { return Token.Operator.read(this.lazyObjectData); } + get body(): Tree | null { return this.lazyObjectData.seek(40).readOption((element: Cursor) => Tree.read(element.readPointer())); } + debug(): any { return { ...super.debug(), operator: debugHelper(this.operator), body: debugHelper(this.body) }; } +} +export class ArgumentDefault extends LazyObject { + constructor(cursor: Cursor) { super(cursor); } + static read(cursor: Cursor): ArgumentDefault { return new ArgumentDefault(cursor); } + get equals(): Token.Operator { return Token.Operator.read(this.lazyObjectData); } + get expression(): Tree { return Tree.read(this.lazyObjectData.seek(40).readPointer()); } + debug(): any { return { ...super.debug(), equals: debugHelper(this.equals), expression: debugHelper(this.expression) }; } +} +export class ArgumentDefinition extends LazyObject { + constructor(cursor: Cursor) { super(cursor); } + static read(cursor: Cursor): ArgumentDefinition { return new ArgumentDefinition(cursor); } + get open(): Token.OpenSymbol | null { return this.lazyObjectData.readOption((element: Cursor) => Token.OpenSymbol.read(element)); } + get open2(): Token.OpenSymbol | null { return this.lazyObjectData.seek(5).readOption((element: Cursor) => Token.OpenSymbol.read(element)); } + get suspension(): Token.Operator | null { return this.lazyObjectData.seek(10).readOption((element: Cursor) => Token.Operator.read(element)); } + get pattern(): Tree { return Tree.read(this.lazyObjectData.seek(15).readPointer()); } + get typeNode(): ArgumentType | null { return this.lazyObjectData.seek(19).readOption((element: Cursor) => ArgumentType.read(element)); } + get close2(): Token.CloseSymbol | null { return this.lazyObjectData.seek(24).readOption((element: Cursor) => Token.CloseSymbol.read(element)); } + get default(): ArgumentDefault | null { return this.lazyObjectData.seek(29).readOption((element: Cursor) => ArgumentDefault.read(element)); } + get close(): Token.CloseSymbol | null { return this.lazyObjectData.seek(34).readOption((element: Cursor) => Token.CloseSymbol.read(element)); } + debug(): any { return { ...super.debug(), open: debugHelper(this.open), open2: debugHelper(this.open2), suspension: debugHelper(this.suspension), pattern: debugHelper(this.pattern), typeNode: debugHelper(this.typeNode), close2: debugHelper(this.close2), default: debugHelper(this.default), close: debugHelper(this.close) }; } +} +export module Base { + abstract class AbstractBase extends LazyObject { + constructor(cursor: Cursor) { super(cursor); } + debug(): any { return { ...super.debug() }; } + } + export const enum Type { + Binary = 0, + Octal = 1, + Hexadecimal = 2 + } + export class Binary extends AbstractBase { + readonly type: Type.Binary; + constructor(cursor: Cursor) { super(cursor); this.type = Type.Binary; } + static read(cursor: Cursor): Binary { return new Binary(cursor); } + debug(): any { return { ...super.debug() }; } + } + export class Octal extends AbstractBase { + readonly type: Type.Octal; + constructor(cursor: Cursor) { super(cursor); this.type = Type.Octal; } + static read(cursor: Cursor): Octal { return new Octal(cursor); } + debug(): any { return { ...super.debug() }; } + } + export class Hexadecimal extends AbstractBase { + readonly type: Type.Hexadecimal; + constructor(cursor: Cursor) { super(cursor); this.type = Type.Hexadecimal; } + static read(cursor: Cursor): Hexadecimal { return new Hexadecimal(cursor); } + debug(): any { return { ...super.debug() }; } + } + export type Base = Binary | Octal | Hexadecimal; + export function read(cursor: Cursor): Base { switch (cursor.readU32()) { + case 0: return new Binary(cursor.seek(4)); + case 1: return new Octal(cursor.seek(4)); + case 2: return new Hexadecimal(cursor.seek(4)); + default: throw new Error("Unexpected discriminant while deserializing."); + } } +} +export type Base = Base.Base; +export class OperatorLine extends LazyObject { + constructor(cursor: Cursor) { super(cursor); } + static read(cursor: Cursor): OperatorLine { return new OperatorLine(cursor); } + get newline(): Token.Newline { return Token.Newline.read(this.lazyObjectData); } + get expression(): OperatorBlockExpression | null { return this.lazyObjectData.seek(40).readOption((element: Cursor) => OperatorBlockExpression.read(element)); } + debug(): any { return { ...super.debug(), newline: debugHelper(this.newline), expression: debugHelper(this.expression) }; } +} +export class OperatorBlockExpression extends LazyObject { + constructor(cursor: Cursor) { super(cursor); } + static read(cursor: Cursor): OperatorBlockExpression { return new OperatorBlockExpression(cursor); } + get operator(): Token.Operator | MultipleOperatorError { return this.lazyObjectData.readResult((okData: Cursor) => Token.Operator.read(okData), (errData: Cursor) => MultipleOperatorError.read(errData)); } + get expression(): Tree { return Tree.read(this.lazyObjectData.seek(4).readPointer()); } + debug(): any { return { ...super.debug(), operator: debugHelper(this.operator), expression: debugHelper(this.expression) }; } +} +export class ArgumentDefinitionLine extends LazyObject { + constructor(cursor: Cursor) { super(cursor); } + static read(cursor: Cursor): ArgumentDefinitionLine { return new ArgumentDefinitionLine(cursor); } + get newline(): Token.Newline { return Token.Newline.read(this.lazyObjectData); } + get argument(): ArgumentDefinition | null { return this.lazyObjectData.seek(40).readOption((element: Cursor) => ArgumentDefinition.read(element)); } + debug(): any { return { ...super.debug(), newline: debugHelper(this.newline), argument: debugHelper(this.argument) }; } +} +export class Case extends LazyObject { + constructor(cursor: Cursor) { super(cursor); } + static read(cursor: Cursor): Case { return new Case(cursor); } + get documentation(): DocComment | null { return this.lazyObjectData.readOption((element: Cursor) => DocComment.read(element)); } + get pattern(): Tree | null { return this.lazyObjectData.seek(5).readOption((element: Cursor) => Tree.read(element.readPointer())); } + get arrow(): Token.Operator | null { return this.lazyObjectData.seek(10).readOption((element: Cursor) => Token.Operator.read(element)); } + get expression(): Tree | null { return this.lazyObjectData.seek(15).readOption((element: Cursor) => Tree.read(element.readPointer())); } + debug(): any { return { ...super.debug(), documentation: debugHelper(this.documentation), pattern: debugHelper(this.pattern), arrow: debugHelper(this.arrow), expression: debugHelper(this.expression) }; } +} +export module Token { + abstract class AbstractBase extends LazyObject { + constructor(cursor: Cursor) { super(cursor); } + get leftOffsetVisible(): number { return this.lazyObjectData.readU64(); } + get leftOffsetCodeReprBegin(): number { return this.lazyObjectData.seek(8).readU32(); } + get leftOffsetCodeReprLen(): number { return this.lazyObjectData.seek(12).readU32(); } + get leftOffsetCodeUtf16(): number { return this.lazyObjectData.seek(16).readU64(); } + get codeReprBegin(): number { return this.lazyObjectData.seek(24).readU32(); } + get codeReprLen(): number { return this.lazyObjectData.seek(28).readU32(); } + get codeUtf16(): number { return this.lazyObjectData.seek(32).readU64(); } + debug(): any { return { ...super.debug(), leftOffsetVisible: debugHelper(this.leftOffsetVisible), leftOffsetCodeReprBegin: debugHelper(this.leftOffsetCodeReprBegin), leftOffsetCodeReprLen: debugHelper(this.leftOffsetCodeReprLen), leftOffsetCodeUtf16: debugHelper(this.leftOffsetCodeUtf16), codeReprBegin: debugHelper(this.codeReprBegin), codeReprLen: debugHelper(this.codeReprLen), codeUtf16: debugHelper(this.codeUtf16) }; } + } + export const enum Type { + Newline = 0, + OpenSymbol = 1, + CloseSymbol = 2, + BlockStart = 3, + BlockEnd = 4, + Wildcard = 5, + AutoScope = 6, + Ident = 7, + Operator = 8, + Digits = 9, + NumberBase = 10, + TextStart = 11, + TextEnd = 12, + TextSection = 13, + TextEscape = 14, + TextInitialNewline = 15, + TextNewline = 16, + Invalid = 17 + } + export class Newline extends AbstractBase { + readonly type: Type.Newline; + constructor(cursor: Cursor) { super(cursor); this.type = Type.Newline; } + static read(cursor: Cursor): Newline { return new Newline(cursor); } + debug(): any { return { ...super.debug() }; } + } + export class OpenSymbol extends AbstractBase { + readonly type: Type.OpenSymbol; + constructor(cursor: Cursor) { super(cursor); this.type = Type.OpenSymbol; } + static read(cursor: Cursor): OpenSymbol { return new OpenSymbol(cursor); } + debug(): any { return { ...super.debug() }; } + } + export class CloseSymbol extends AbstractBase { + readonly type: Type.CloseSymbol; + constructor(cursor: Cursor) { super(cursor); this.type = Type.CloseSymbol; } + static read(cursor: Cursor): CloseSymbol { return new CloseSymbol(cursor); } + debug(): any { return { ...super.debug() }; } + } + export class BlockStart extends AbstractBase { + readonly type: Type.BlockStart; + constructor(cursor: Cursor) { super(cursor); this.type = Type.BlockStart; } + static read(cursor: Cursor): BlockStart { return new BlockStart(cursor); } + debug(): any { return { ...super.debug() }; } + } + export class BlockEnd extends AbstractBase { + readonly type: Type.BlockEnd; + constructor(cursor: Cursor) { super(cursor); this.type = Type.BlockEnd; } + static read(cursor: Cursor): BlockEnd { return new BlockEnd(cursor); } + debug(): any { return { ...super.debug() }; } + } + export class Wildcard extends AbstractBase { + readonly type: Type.Wildcard; + constructor(cursor: Cursor) { super(cursor); this.type = Type.Wildcard; } + static read(cursor: Cursor): Wildcard { return new Wildcard(cursor); } + get liftLevel(): number { return this.lazyObjectData.seek(40).readU64(); } + debug(): any { return { ...super.debug(), liftLevel: debugHelper(this.liftLevel) }; } + } + export class AutoScope extends AbstractBase { + readonly type: Type.AutoScope; + constructor(cursor: Cursor) { super(cursor); this.type = Type.AutoScope; } + static read(cursor: Cursor): AutoScope { return new AutoScope(cursor); } + debug(): any { return { ...super.debug() }; } + } + export class Ident extends AbstractBase { + readonly type: Type.Ident; + constructor(cursor: Cursor) { super(cursor); this.type = Type.Ident; } + static read(cursor: Cursor): Ident { return new Ident(cursor); } + get isFree(): boolean { return this.lazyObjectData.seek(40).readBool(); } + get liftLevel(): number { return this.lazyObjectData.seek(41).readU64(); } + get isTypeOrConstructor(): boolean { return this.lazyObjectData.seek(49).readBool(); } + get isOperatorLexically(): boolean { return this.lazyObjectData.seek(50).readBool(); } + debug(): any { return { ...super.debug(), isFree: debugHelper(this.isFree), liftLevel: debugHelper(this.liftLevel), isTypeOrConstructor: debugHelper(this.isTypeOrConstructor), isOperatorLexically: debugHelper(this.isOperatorLexically) }; } + } + export class Operator extends AbstractBase { + readonly type: Type.Operator; + constructor(cursor: Cursor) { super(cursor); this.type = Type.Operator; } + static read(cursor: Cursor): Operator { return new Operator(cursor); } + debug(): any { return { ...super.debug() }; } + } + export class Digits extends AbstractBase { + readonly type: Type.Digits; + constructor(cursor: Cursor) { super(cursor); this.type = Type.Digits; } + static read(cursor: Cursor): Digits { return new Digits(cursor); } + get base(): Base | null { return this.lazyObjectData.seek(40).readOption((element: Cursor) => Base.read(element.readPointer())); } + debug(): any { return { ...super.debug(), base: debugHelper(this.base) }; } + } + export class NumberBase extends AbstractBase { + readonly type: Type.NumberBase; + constructor(cursor: Cursor) { super(cursor); this.type = Type.NumberBase; } + static read(cursor: Cursor): NumberBase { return new NumberBase(cursor); } + debug(): any { return { ...super.debug() }; } + } + export class TextStart extends AbstractBase { + readonly type: Type.TextStart; + constructor(cursor: Cursor) { super(cursor); this.type = Type.TextStart; } + static read(cursor: Cursor): TextStart { return new TextStart(cursor); } + debug(): any { return { ...super.debug() }; } + } + export class TextEnd extends AbstractBase { + readonly type: Type.TextEnd; + constructor(cursor: Cursor) { super(cursor); this.type = Type.TextEnd; } + static read(cursor: Cursor): TextEnd { return new TextEnd(cursor); } + debug(): any { return { ...super.debug() }; } + } + export class TextSection extends AbstractBase { + readonly type: Type.TextSection; + constructor(cursor: Cursor) { super(cursor); this.type = Type.TextSection; } + static read(cursor: Cursor): TextSection { return new TextSection(cursor); } + debug(): any { return { ...super.debug() }; } + } + export class TextEscape extends AbstractBase { + readonly type: Type.TextEscape; + constructor(cursor: Cursor) { super(cursor); this.type = Type.TextEscape; } + static read(cursor: Cursor): TextEscape { return new TextEscape(cursor); } + get value(): number { return this.lazyObjectData.seek(40).readU32(); } + debug(): any { return { ...super.debug(), value: debugHelper(this.value) }; } + } + export class TextInitialNewline extends AbstractBase { + readonly type: Type.TextInitialNewline; + constructor(cursor: Cursor) { super(cursor); this.type = Type.TextInitialNewline; } + static read(cursor: Cursor): TextInitialNewline { return new TextInitialNewline(cursor); } + debug(): any { return { ...super.debug() }; } + } + export class TextNewline extends AbstractBase { + readonly type: Type.TextNewline; + constructor(cursor: Cursor) { super(cursor); this.type = Type.TextNewline; } + static read(cursor: Cursor): TextNewline { return new TextNewline(cursor); } + debug(): any { return { ...super.debug() }; } + } + export class Invalid extends AbstractBase { + readonly type: Type.Invalid; + constructor(cursor: Cursor) { super(cursor); this.type = Type.Invalid; } + static read(cursor: Cursor): Invalid { return new Invalid(cursor); } + debug(): any { return { ...super.debug() }; } + } + export type Token = Newline | OpenSymbol | CloseSymbol | BlockStart | BlockEnd | Wildcard | AutoScope | Ident | Operator | Digits | NumberBase | TextStart | TextEnd | TextSection | TextEscape | TextInitialNewline | TextNewline | Invalid; + export function read(cursor: Cursor): Token { switch (cursor.readU32()) { + case 0: return new Newline(cursor.seek(4)); + case 1: return new OpenSymbol(cursor.seek(4)); + case 2: return new CloseSymbol(cursor.seek(4)); + case 3: return new BlockStart(cursor.seek(4)); + case 4: return new BlockEnd(cursor.seek(4)); + case 5: return new Wildcard(cursor.seek(4)); + case 6: return new AutoScope(cursor.seek(4)); + case 7: return new Ident(cursor.seek(4)); + case 8: return new Operator(cursor.seek(4)); + case 9: return new Digits(cursor.seek(4)); + case 10: return new NumberBase(cursor.seek(4)); + case 11: return new TextStart(cursor.seek(4)); + case 12: return new TextEnd(cursor.seek(4)); + case 13: return new TextSection(cursor.seek(4)); + case 14: return new TextEscape(cursor.seek(4)); + case 15: return new TextInitialNewline(cursor.seek(4)); + case 16: return new TextNewline(cursor.seek(4)); + case 17: return new Invalid(cursor.seek(4)); + default: throw new Error("Unexpected discriminant while deserializing."); + } } +} +export type Token = Token.Token; +export class CaseLine extends LazyObject { + constructor(cursor: Cursor) { super(cursor); } + static read(cursor: Cursor): CaseLine { return new CaseLine(cursor); } + get newline(): Token.Newline | null { return this.lazyObjectData.readOption((element: Cursor) => Token.Newline.read(element)); } + get case(): Case | null { return this.lazyObjectData.seek(5).readOption((element: Cursor) => Case.read(element)); } + debug(): any { return { ...super.debug(), newline: debugHelper(this.newline), case: debugHelper(this.case) }; } +} +export class MultipleOperatorError extends LazyObject { + constructor(cursor: Cursor) { super(cursor); } + static read(cursor: Cursor): MultipleOperatorError { return new MultipleOperatorError(cursor); } + get operators(): Iterable { return this.lazyObjectData.readSequence((element: Cursor) => Token.Operator.read(element), 40); } + debug(): any { return { ...super.debug(), operators: debugHelper(this.operators) }; } +} +export module Tree { + abstract class AbstractBase extends LazyObject { + constructor(cursor: Cursor) { super(cursor); } + get spanLeftOffsetVisible(): number { return this.lazyObjectData.readU64(); } + get spanLeftOffsetCodeReprBegin(): number { return this.lazyObjectData.seek(8).readU32(); } + get spanLeftOffsetCodeReprLen(): number { return this.lazyObjectData.seek(12).readU32(); } + get spanLeftOffsetCodeUtf16(): number { return this.lazyObjectData.seek(16).readU64(); } + get spanCodeLengthUtf8(): number { return this.lazyObjectData.seek(24).readU64(); } + get spanCodeLengthUtf16(): number { return this.lazyObjectData.seek(32).readU64(); } + debug(): any { return { ...super.debug(), spanLeftOffsetVisible: debugHelper(this.spanLeftOffsetVisible), spanLeftOffsetCodeReprBegin: debugHelper(this.spanLeftOffsetCodeReprBegin), spanLeftOffsetCodeReprLen: debugHelper(this.spanLeftOffsetCodeReprLen), spanLeftOffsetCodeUtf16: debugHelper(this.spanLeftOffsetCodeUtf16), spanCodeLengthUtf8: debugHelper(this.spanCodeLengthUtf8), spanCodeLengthUtf16: debugHelper(this.spanCodeLengthUtf16) }; } + } + export const enum Type { + Invalid = 0, + BodyBlock = 1, + ArgumentBlockApplication = 2, + OperatorBlockApplication = 3, + Ident = 4, + Number = 5, + Wildcard = 6, + AutoScope = 7, + TextLiteral = 8, + App = 9, + NamedApp = 10, + DefaultApp = 11, + OprApp = 12, + UnaryOprApp = 13, + OprSectionBoundary = 14, + TemplateFunction = 15, + MultiSegmentApp = 16, + TypeDef = 17, + Assignment = 18, + Function = 19, + ForeignFunction = 20, + Import = 21, + Export = 22, + Group = 23, + TypeSignature = 24, + TypeAnnotated = 25, + CaseOf = 26, + Lambda = 27, + Array = 28, + Tuple = 29, + Annotated = 30, + AnnotatedBuiltin = 31, + Documented = 32, + ConstructorDefinition = 33 + } + export class Invalid extends AbstractBase { + readonly type: Type.Invalid; + constructor(cursor: Cursor) { super(cursor); this.type = Type.Invalid; } + static read(cursor: Cursor): Invalid { return new Invalid(cursor); } + get error(): string { return this.lazyObjectData.seek(40).readString(); } + get ast(): Tree { return Tree.read(this.lazyObjectData.seek(44).readPointer()); } + debug(): any { return { ...super.debug(), error: debugHelper(this.error), ast: debugHelper(this.ast) }; } + } + export class BodyBlock extends AbstractBase { + readonly type: Type.BodyBlock; + constructor(cursor: Cursor) { super(cursor); this.type = Type.BodyBlock; } + static read(cursor: Cursor): BodyBlock { return new BodyBlock(cursor); } + get statements(): Iterable { return this.lazyObjectData.seek(40).readSequence((element: Cursor) => Line.read(element), 45); } + debug(): any { return { ...super.debug(), statements: debugHelper(this.statements) }; } + } + export class ArgumentBlockApplication extends AbstractBase { + readonly type: Type.ArgumentBlockApplication; + constructor(cursor: Cursor) { super(cursor); this.type = Type.ArgumentBlockApplication; } + static read(cursor: Cursor): ArgumentBlockApplication { return new ArgumentBlockApplication(cursor); } + get lhs(): Tree | null { return this.lazyObjectData.seek(40).readOption((element: Cursor) => Tree.read(element.readPointer())); } + get arguments(): Iterable { return this.lazyObjectData.seek(45).readSequence((element: Cursor) => Line.read(element), 45); } + debug(): any { return { ...super.debug(), lhs: debugHelper(this.lhs), arguments: debugHelper(this.arguments) }; } + } + export class OperatorBlockApplication extends AbstractBase { + readonly type: Type.OperatorBlockApplication; + constructor(cursor: Cursor) { super(cursor); this.type = Type.OperatorBlockApplication; } + static read(cursor: Cursor): OperatorBlockApplication { return new OperatorBlockApplication(cursor); } + get lhs(): Tree | null { return this.lazyObjectData.seek(40).readOption((element: Cursor) => Tree.read(element.readPointer())); } + get expressions(): Iterable { return this.lazyObjectData.seek(45).readSequence((element: Cursor) => OperatorLine.read(element), 45); } + get excess(): Iterable { return this.lazyObjectData.seek(49).readSequence((element: Cursor) => Line.read(element), 45); } + debug(): any { return { ...super.debug(), lhs: debugHelper(this.lhs), expressions: debugHelper(this.expressions), excess: debugHelper(this.excess) }; } + } + export class Ident extends AbstractBase { + readonly type: Type.Ident; + constructor(cursor: Cursor) { super(cursor); this.type = Type.Ident; } + static read(cursor: Cursor): Ident { return new Ident(cursor); } + get token(): Token.Ident { return Token.Ident.read(this.lazyObjectData.seek(40)); } + debug(): any { return { ...super.debug(), token: debugHelper(this.token) }; } + } + export class Number extends AbstractBase { + readonly type: Type.Number; + constructor(cursor: Cursor) { super(cursor); this.type = Type.Number; } + static read(cursor: Cursor): Number { return new Number(cursor); } + get base(): Token.NumberBase | null { return this.lazyObjectData.seek(40).readOption((element: Cursor) => Token.NumberBase.read(element)); } + get integer(): Token.Digits | null { return this.lazyObjectData.seek(45).readOption((element: Cursor) => Token.Digits.read(element)); } + get fractionalDigits(): FractionalDigits | null { return this.lazyObjectData.seek(50).readOption((element: Cursor) => FractionalDigits.read(element)); } + debug(): any { return { ...super.debug(), base: debugHelper(this.base), integer: debugHelper(this.integer), fractionalDigits: debugHelper(this.fractionalDigits) }; } + } + export class Wildcard extends AbstractBase { + readonly type: Type.Wildcard; + constructor(cursor: Cursor) { super(cursor); this.type = Type.Wildcard; } + static read(cursor: Cursor): Wildcard { return new Wildcard(cursor); } + get token(): Token.Wildcard { return Token.Wildcard.read(this.lazyObjectData.seek(40)); } + get deBruijnIndex(): number { return this.lazyObjectData.seek(88).readI32(); } + debug(): any { return { ...super.debug(), token: debugHelper(this.token), deBruijnIndex: debugHelper(this.deBruijnIndex) }; } + } + export class AutoScope extends AbstractBase { + readonly type: Type.AutoScope; + constructor(cursor: Cursor) { super(cursor); this.type = Type.AutoScope; } + static read(cursor: Cursor): AutoScope { return new AutoScope(cursor); } + get token(): Token.AutoScope { return Token.AutoScope.read(this.lazyObjectData.seek(40)); } + debug(): any { return { ...super.debug(), token: debugHelper(this.token) }; } + } + export class TextLiteral extends AbstractBase { + readonly type: Type.TextLiteral; + constructor(cursor: Cursor) { super(cursor); this.type = Type.TextLiteral; } + static read(cursor: Cursor): TextLiteral { return new TextLiteral(cursor); } + get open(): Token.TextStart | null { return this.lazyObjectData.seek(40).readOption((element: Cursor) => Token.TextStart.read(element)); } + get newline(): Token.Newline | null { return this.lazyObjectData.seek(45).readOption((element: Cursor) => Token.Newline.read(element)); } + get elements(): Iterable { return this.lazyObjectData.seek(50).readSequence((element: Cursor) => TextElement.read(element.readPointer()), 4); } + get close(): Token.TextEnd | null { return this.lazyObjectData.seek(54).readOption((element: Cursor) => Token.TextEnd.read(element)); } + debug(): any { return { ...super.debug(), open: debugHelper(this.open), newline: debugHelper(this.newline), elements: debugHelper(this.elements), close: debugHelper(this.close) }; } + } + export class App extends AbstractBase { + readonly type: Type.App; + constructor(cursor: Cursor) { super(cursor); this.type = Type.App; } + static read(cursor: Cursor): App { return new App(cursor); } + get func(): Tree { return Tree.read(this.lazyObjectData.seek(40).readPointer()); } + get arg(): Tree { return Tree.read(this.lazyObjectData.seek(44).readPointer()); } + debug(): any { return { ...super.debug(), func: debugHelper(this.func), arg: debugHelper(this.arg) }; } + } + export class NamedApp extends AbstractBase { + readonly type: Type.NamedApp; + constructor(cursor: Cursor) { super(cursor); this.type = Type.NamedApp; } + static read(cursor: Cursor): NamedApp { return new NamedApp(cursor); } + get func(): Tree { return Tree.read(this.lazyObjectData.seek(40).readPointer()); } + get open(): Token.OpenSymbol | null { return this.lazyObjectData.seek(44).readOption((element: Cursor) => Token.OpenSymbol.read(element)); } + get name(): Token.Ident { return Token.Ident.read(this.lazyObjectData.seek(49)); } + get equals(): Token.Operator { return Token.Operator.read(this.lazyObjectData.seek(100)); } + get arg(): Tree { return Tree.read(this.lazyObjectData.seek(140).readPointer()); } + get close(): Token.CloseSymbol | null { return this.lazyObjectData.seek(144).readOption((element: Cursor) => Token.CloseSymbol.read(element)); } + debug(): any { return { ...super.debug(), func: debugHelper(this.func), open: debugHelper(this.open), name: debugHelper(this.name), equals: debugHelper(this.equals), arg: debugHelper(this.arg), close: debugHelper(this.close) }; } + } + export class DefaultApp extends AbstractBase { + readonly type: Type.DefaultApp; + constructor(cursor: Cursor) { super(cursor); this.type = Type.DefaultApp; } + static read(cursor: Cursor): DefaultApp { return new DefaultApp(cursor); } + get func(): Tree { return Tree.read(this.lazyObjectData.seek(40).readPointer()); } + get default(): Token.Ident { return Token.Ident.read(this.lazyObjectData.seek(44)); } + debug(): any { return { ...super.debug(), func: debugHelper(this.func), default: debugHelper(this.default) }; } + } + export class OprApp extends AbstractBase { + readonly type: Type.OprApp; + constructor(cursor: Cursor) { super(cursor); this.type = Type.OprApp; } + static read(cursor: Cursor): OprApp { return new OprApp(cursor); } + get lhs(): Tree | null { return this.lazyObjectData.seek(40).readOption((element: Cursor) => Tree.read(element.readPointer())); } + get opr(): Token.Operator | MultipleOperatorError { return this.lazyObjectData.seek(45).readResult((okData: Cursor) => Token.Operator.read(okData), (errData: Cursor) => MultipleOperatorError.read(errData)); } + get rhs(): Tree | null { return this.lazyObjectData.seek(49).readOption((element: Cursor) => Tree.read(element.readPointer())); } + debug(): any { return { ...super.debug(), lhs: debugHelper(this.lhs), opr: debugHelper(this.opr), rhs: debugHelper(this.rhs) }; } + } + export class UnaryOprApp extends AbstractBase { + readonly type: Type.UnaryOprApp; + constructor(cursor: Cursor) { super(cursor); this.type = Type.UnaryOprApp; } + static read(cursor: Cursor): UnaryOprApp { return new UnaryOprApp(cursor); } + get opr(): Token.Operator { return Token.Operator.read(this.lazyObjectData.seek(40)); } + get rhs(): Tree | null { return this.lazyObjectData.seek(80).readOption((element: Cursor) => Tree.read(element.readPointer())); } + debug(): any { return { ...super.debug(), opr: debugHelper(this.opr), rhs: debugHelper(this.rhs) }; } + } + export class OprSectionBoundary extends AbstractBase { + readonly type: Type.OprSectionBoundary; + constructor(cursor: Cursor) { super(cursor); this.type = Type.OprSectionBoundary; } + static read(cursor: Cursor): OprSectionBoundary { return new OprSectionBoundary(cursor); } + get arguments(): number { return this.lazyObjectData.seek(40).readU32(); } + get ast(): Tree { return Tree.read(this.lazyObjectData.seek(44).readPointer()); } + debug(): any { return { ...super.debug(), arguments: debugHelper(this.arguments), ast: debugHelper(this.ast) }; } + } + export class TemplateFunction extends AbstractBase { + readonly type: Type.TemplateFunction; + constructor(cursor: Cursor) { super(cursor); this.type = Type.TemplateFunction; } + static read(cursor: Cursor): TemplateFunction { return new TemplateFunction(cursor); } + get arguments(): number { return this.lazyObjectData.seek(40).readU32(); } + get ast(): Tree { return Tree.read(this.lazyObjectData.seek(44).readPointer()); } + debug(): any { return { ...super.debug(), arguments: debugHelper(this.arguments), ast: debugHelper(this.ast) }; } + } + export class MultiSegmentApp extends AbstractBase { + readonly type: Type.MultiSegmentApp; + constructor(cursor: Cursor) { super(cursor); this.type = Type.MultiSegmentApp; } + static read(cursor: Cursor): MultiSegmentApp { return new MultiSegmentApp(cursor); } + get segments(): Iterable { return this.lazyObjectData.seek(40).readSequence((element: Cursor) => MultiSegmentAppSegment.read(element), 9); } + debug(): any { return { ...super.debug(), segments: debugHelper(this.segments) }; } + } + export class TypeDef extends AbstractBase { + readonly type: Type.TypeDef; + constructor(cursor: Cursor) { super(cursor); this.type = Type.TypeDef; } + static read(cursor: Cursor): TypeDef { return new TypeDef(cursor); } + get keyword(): Token.Ident { return Token.Ident.read(this.lazyObjectData.seek(40)); } + get name(): Token.Ident { return Token.Ident.read(this.lazyObjectData.seek(91)); } + get params(): Iterable { return this.lazyObjectData.seek(142).readSequence((element: Cursor) => ArgumentDefinition.read(element), 39); } + get body(): Iterable { return this.lazyObjectData.seek(146).readSequence((element: Cursor) => Line.read(element), 45); } + debug(): any { return { ...super.debug(), keyword: debugHelper(this.keyword), name: debugHelper(this.name), params: debugHelper(this.params), body: debugHelper(this.body) }; } + } + export class Assignment extends AbstractBase { + readonly type: Type.Assignment; + constructor(cursor: Cursor) { super(cursor); this.type = Type.Assignment; } + static read(cursor: Cursor): Assignment { return new Assignment(cursor); } + get pattern(): Tree { return Tree.read(this.lazyObjectData.seek(40).readPointer()); } + get equals(): Token.Operator { return Token.Operator.read(this.lazyObjectData.seek(44)); } + get expr(): Tree { return Tree.read(this.lazyObjectData.seek(84).readPointer()); } + debug(): any { return { ...super.debug(), pattern: debugHelper(this.pattern), equals: debugHelper(this.equals), expr: debugHelper(this.expr) }; } + } + export class Function extends AbstractBase { + readonly type: Type.Function; + constructor(cursor: Cursor) { super(cursor); this.type = Type.Function; } + static read(cursor: Cursor): Function { return new Function(cursor); } + get name(): Tree { return Tree.read(this.lazyObjectData.seek(40).readPointer()); } + get args(): Iterable { return this.lazyObjectData.seek(44).readSequence((element: Cursor) => ArgumentDefinition.read(element), 39); } + get equals(): Token.Operator { return Token.Operator.read(this.lazyObjectData.seek(48)); } + get body(): Tree | null { return this.lazyObjectData.seek(88).readOption((element: Cursor) => Tree.read(element.readPointer())); } + debug(): any { return { ...super.debug(), name: debugHelper(this.name), args: debugHelper(this.args), equals: debugHelper(this.equals), body: debugHelper(this.body) }; } + } + export class ForeignFunction extends AbstractBase { + readonly type: Type.ForeignFunction; + constructor(cursor: Cursor) { super(cursor); this.type = Type.ForeignFunction; } + static read(cursor: Cursor): ForeignFunction { return new ForeignFunction(cursor); } + get foreign(): Token.Ident { return Token.Ident.read(this.lazyObjectData.seek(40)); } + get language(): Token.Ident { return Token.Ident.read(this.lazyObjectData.seek(91)); } + get name(): Token.Ident { return Token.Ident.read(this.lazyObjectData.seek(142)); } + get args(): Iterable { return this.lazyObjectData.seek(193).readSequence((element: Cursor) => ArgumentDefinition.read(element), 39); } + get equals(): Token.Operator { return Token.Operator.read(this.lazyObjectData.seek(197)); } + get body(): Tree { return Tree.read(this.lazyObjectData.seek(237).readPointer()); } + debug(): any { return { ...super.debug(), foreign: debugHelper(this.foreign), language: debugHelper(this.language), name: debugHelper(this.name), args: debugHelper(this.args), equals: debugHelper(this.equals), body: debugHelper(this.body) }; } + } + export class Import extends AbstractBase { + readonly type: Type.Import; + constructor(cursor: Cursor) { super(cursor); this.type = Type.Import; } + static read(cursor: Cursor): Import { return new Import(cursor); } + get polyglot(): MultiSegmentAppSegment | null { return this.lazyObjectData.seek(40).readOption((element: Cursor) => MultiSegmentAppSegment.read(element)); } + get from(): MultiSegmentAppSegment | null { return this.lazyObjectData.seek(45).readOption((element: Cursor) => MultiSegmentAppSegment.read(element)); } + get import(): MultiSegmentAppSegment { return MultiSegmentAppSegment.read(this.lazyObjectData.seek(50)); } + get all(): Token.Ident | null { return this.lazyObjectData.seek(59).readOption((element: Cursor) => Token.Ident.read(element)); } + get as(): MultiSegmentAppSegment | null { return this.lazyObjectData.seek(64).readOption((element: Cursor) => MultiSegmentAppSegment.read(element)); } + get hiding(): MultiSegmentAppSegment | null { return this.lazyObjectData.seek(69).readOption((element: Cursor) => MultiSegmentAppSegment.read(element)); } + debug(): any { return { ...super.debug(), polyglot: debugHelper(this.polyglot), from: debugHelper(this.from), import: debugHelper(this.import), all: debugHelper(this.all), as: debugHelper(this.as), hiding: debugHelper(this.hiding) }; } + } + export class Export extends AbstractBase { + readonly type: Type.Export; + constructor(cursor: Cursor) { super(cursor); this.type = Type.Export; } + static read(cursor: Cursor): Export { return new Export(cursor); } + get from(): MultiSegmentAppSegment | null { return this.lazyObjectData.seek(40).readOption((element: Cursor) => MultiSegmentAppSegment.read(element)); } + get export(): MultiSegmentAppSegment { return MultiSegmentAppSegment.read(this.lazyObjectData.seek(45)); } + get all(): Token.Ident | null { return this.lazyObjectData.seek(54).readOption((element: Cursor) => Token.Ident.read(element)); } + get as(): MultiSegmentAppSegment | null { return this.lazyObjectData.seek(59).readOption((element: Cursor) => MultiSegmentAppSegment.read(element)); } + get hiding(): MultiSegmentAppSegment | null { return this.lazyObjectData.seek(64).readOption((element: Cursor) => MultiSegmentAppSegment.read(element)); } + debug(): any { return { ...super.debug(), from: debugHelper(this.from), export: debugHelper(this.export), all: debugHelper(this.all), as: debugHelper(this.as), hiding: debugHelper(this.hiding) }; } + } + export class Group extends AbstractBase { + readonly type: Type.Group; + constructor(cursor: Cursor) { super(cursor); this.type = Type.Group; } + static read(cursor: Cursor): Group { return new Group(cursor); } + get open(): Token.OpenSymbol | null { return this.lazyObjectData.seek(40).readOption((element: Cursor) => Token.OpenSymbol.read(element)); } + get body(): Tree | null { return this.lazyObjectData.seek(45).readOption((element: Cursor) => Tree.read(element.readPointer())); } + get close(): Token.CloseSymbol | null { return this.lazyObjectData.seek(50).readOption((element: Cursor) => Token.CloseSymbol.read(element)); } + debug(): any { return { ...super.debug(), open: debugHelper(this.open), body: debugHelper(this.body), close: debugHelper(this.close) }; } + } + export class TypeSignature extends AbstractBase { + readonly type: Type.TypeSignature; + constructor(cursor: Cursor) { super(cursor); this.type = Type.TypeSignature; } + static read(cursor: Cursor): TypeSignature { return new TypeSignature(cursor); } + get variable(): Tree { return Tree.read(this.lazyObjectData.seek(40).readPointer()); } + get operator(): Token.Operator { return Token.Operator.read(this.lazyObjectData.seek(44)); } + get typeNode(): Tree { return Tree.read(this.lazyObjectData.seek(84).readPointer()); } + debug(): any { return { ...super.debug(), variable: debugHelper(this.variable), operator: debugHelper(this.operator), typeNode: debugHelper(this.typeNode) }; } + } + export class TypeAnnotated extends AbstractBase { + readonly type: Type.TypeAnnotated; + constructor(cursor: Cursor) { super(cursor); this.type = Type.TypeAnnotated; } + static read(cursor: Cursor): TypeAnnotated { return new TypeAnnotated(cursor); } + get expression(): Tree { return Tree.read(this.lazyObjectData.seek(40).readPointer()); } + get operator(): Token.Operator { return Token.Operator.read(this.lazyObjectData.seek(44)); } + get typeNode(): Tree { return Tree.read(this.lazyObjectData.seek(84).readPointer()); } + debug(): any { return { ...super.debug(), expression: debugHelper(this.expression), operator: debugHelper(this.operator), typeNode: debugHelper(this.typeNode) }; } + } + export class CaseOf extends AbstractBase { + readonly type: Type.CaseOf; + constructor(cursor: Cursor) { super(cursor); this.type = Type.CaseOf; } + static read(cursor: Cursor): CaseOf { return new CaseOf(cursor); } + get case(): Token.Ident { return Token.Ident.read(this.lazyObjectData.seek(40)); } + get expression(): Tree | null { return this.lazyObjectData.seek(91).readOption((element: Cursor) => Tree.read(element.readPointer())); } + get of(): Token.Ident { return Token.Ident.read(this.lazyObjectData.seek(96)); } + get cases(): Iterable { return this.lazyObjectData.seek(147).readSequence((element: Cursor) => CaseLine.read(element), 10); } + debug(): any { return { ...super.debug(), case: debugHelper(this.case), expression: debugHelper(this.expression), of: debugHelper(this.of), cases: debugHelper(this.cases) }; } + } + export class Lambda extends AbstractBase { + readonly type: Type.Lambda; + constructor(cursor: Cursor) { super(cursor); this.type = Type.Lambda; } + static read(cursor: Cursor): Lambda { return new Lambda(cursor); } + get operator(): Token.Operator { return Token.Operator.read(this.lazyObjectData.seek(40)); } + get arrow(): Tree | null { return this.lazyObjectData.seek(80).readOption((element: Cursor) => Tree.read(element.readPointer())); } + debug(): any { return { ...super.debug(), operator: debugHelper(this.operator), arrow: debugHelper(this.arrow) }; } + } + export class Array extends AbstractBase { + readonly type: Type.Array; + constructor(cursor: Cursor) { super(cursor); this.type = Type.Array; } + static read(cursor: Cursor): Array { return new Array(cursor); } + get left(): Token.OpenSymbol { return Token.OpenSymbol.read(this.lazyObjectData.seek(40)); } + get first(): Tree | null { return this.lazyObjectData.seek(80).readOption((element: Cursor) => Tree.read(element.readPointer())); } + get rest(): Iterable { return this.lazyObjectData.seek(85).readSequence((element: Cursor) => OperatorDelimitedTree.read(element), 45); } + get right(): Token.CloseSymbol { return Token.CloseSymbol.read(this.lazyObjectData.seek(89)); } + debug(): any { return { ...super.debug(), left: debugHelper(this.left), first: debugHelper(this.first), rest: debugHelper(this.rest), right: debugHelper(this.right) }; } + } + export class Tuple extends AbstractBase { + readonly type: Type.Tuple; + constructor(cursor: Cursor) { super(cursor); this.type = Type.Tuple; } + static read(cursor: Cursor): Tuple { return new Tuple(cursor); } + get left(): Token.OpenSymbol { return Token.OpenSymbol.read(this.lazyObjectData.seek(40)); } + get first(): Tree | null { return this.lazyObjectData.seek(80).readOption((element: Cursor) => Tree.read(element.readPointer())); } + get rest(): Iterable { return this.lazyObjectData.seek(85).readSequence((element: Cursor) => OperatorDelimitedTree.read(element), 45); } + get right(): Token.CloseSymbol { return Token.CloseSymbol.read(this.lazyObjectData.seek(89)); } + debug(): any { return { ...super.debug(), left: debugHelper(this.left), first: debugHelper(this.first), rest: debugHelper(this.rest), right: debugHelper(this.right) }; } + } + export class Annotated extends AbstractBase { + readonly type: Type.Annotated; + constructor(cursor: Cursor) { super(cursor); this.type = Type.Annotated; } + static read(cursor: Cursor): Annotated { return new Annotated(cursor); } + get token(): Token.Operator { return Token.Operator.read(this.lazyObjectData.seek(40)); } + get annotation(): Token.Ident { return Token.Ident.read(this.lazyObjectData.seek(80)); } + get argument(): Tree | null { return this.lazyObjectData.seek(131).readOption((element: Cursor) => Tree.read(element.readPointer())); } + get newlines(): Iterable { return this.lazyObjectData.seek(136).readSequence((element: Cursor) => Token.Newline.read(element), 40); } + get expression(): Tree | null { return this.lazyObjectData.seek(140).readOption((element: Cursor) => Tree.read(element.readPointer())); } + debug(): any { return { ...super.debug(), token: debugHelper(this.token), annotation: debugHelper(this.annotation), argument: debugHelper(this.argument), newlines: debugHelper(this.newlines), expression: debugHelper(this.expression) }; } + } + export class AnnotatedBuiltin extends AbstractBase { + readonly type: Type.AnnotatedBuiltin; + constructor(cursor: Cursor) { super(cursor); this.type = Type.AnnotatedBuiltin; } + static read(cursor: Cursor): AnnotatedBuiltin { return new AnnotatedBuiltin(cursor); } + get token(): Token.Operator { return Token.Operator.read(this.lazyObjectData.seek(40)); } + get annotation(): Token.Ident { return Token.Ident.read(this.lazyObjectData.seek(80)); } + get newlines(): Iterable { return this.lazyObjectData.seek(131).readSequence((element: Cursor) => Token.Newline.read(element), 40); } + get expression(): Tree | null { return this.lazyObjectData.seek(135).readOption((element: Cursor) => Tree.read(element.readPointer())); } + debug(): any { return { ...super.debug(), token: debugHelper(this.token), annotation: debugHelper(this.annotation), newlines: debugHelper(this.newlines), expression: debugHelper(this.expression) }; } + } + export class Documented extends AbstractBase { + readonly type: Type.Documented; + constructor(cursor: Cursor) { super(cursor); this.type = Type.Documented; } + static read(cursor: Cursor): Documented { return new Documented(cursor); } + get documentation(): DocComment { return DocComment.read(this.lazyObjectData.seek(40)); } + get expression(): Tree | null { return this.lazyObjectData.seek(88).readOption((element: Cursor) => Tree.read(element.readPointer())); } + debug(): any { return { ...super.debug(), documentation: debugHelper(this.documentation), expression: debugHelper(this.expression) }; } + } + export class ConstructorDefinition extends AbstractBase { + readonly type: Type.ConstructorDefinition; + constructor(cursor: Cursor) { super(cursor); this.type = Type.ConstructorDefinition; } + static read(cursor: Cursor): ConstructorDefinition { return new ConstructorDefinition(cursor); } + get ident(): Token.Ident { return Token.Ident.read(this.lazyObjectData.seek(40)); } + get arguments(): Iterable { return this.lazyObjectData.seek(91).readSequence((element: Cursor) => ArgumentDefinition.read(element), 39); } + get block(): Iterable { return this.lazyObjectData.seek(95).readSequence((element: Cursor) => ArgumentDefinitionLine.read(element), 45); } + debug(): any { return { ...super.debug(), ident: debugHelper(this.ident), arguments: debugHelper(this.arguments), block: debugHelper(this.block) }; } + } + export type Tree = Invalid | BodyBlock | ArgumentBlockApplication | OperatorBlockApplication | Ident | Number | Wildcard | AutoScope | TextLiteral | App | NamedApp | DefaultApp | OprApp | UnaryOprApp | OprSectionBoundary | TemplateFunction | MultiSegmentApp | TypeDef | Assignment | Function | ForeignFunction | Import | Export | Group | TypeSignature | TypeAnnotated | CaseOf | Lambda | Array | Tuple | Annotated | AnnotatedBuiltin | Documented | ConstructorDefinition; + export function read(cursor: Cursor): Tree { switch (cursor.readU32()) { + case 0: return new Invalid(cursor.seek(4)); + case 1: return new BodyBlock(cursor.seek(4)); + case 2: return new ArgumentBlockApplication(cursor.seek(4)); + case 3: return new OperatorBlockApplication(cursor.seek(4)); + case 4: return new Ident(cursor.seek(4)); + case 5: return new Number(cursor.seek(4)); + case 6: return new Wildcard(cursor.seek(4)); + case 7: return new AutoScope(cursor.seek(4)); + case 8: return new TextLiteral(cursor.seek(4)); + case 9: return new App(cursor.seek(4)); + case 10: return new NamedApp(cursor.seek(4)); + case 11: return new DefaultApp(cursor.seek(4)); + case 12: return new OprApp(cursor.seek(4)); + case 13: return new UnaryOprApp(cursor.seek(4)); + case 14: return new OprSectionBoundary(cursor.seek(4)); + case 15: return new TemplateFunction(cursor.seek(4)); + case 16: return new MultiSegmentApp(cursor.seek(4)); + case 17: return new TypeDef(cursor.seek(4)); + case 18: return new Assignment(cursor.seek(4)); + case 19: return new Function(cursor.seek(4)); + case 20: return new ForeignFunction(cursor.seek(4)); + case 21: return new Import(cursor.seek(4)); + case 22: return new Export(cursor.seek(4)); + case 23: return new Group(cursor.seek(4)); + case 24: return new TypeSignature(cursor.seek(4)); + case 25: return new TypeAnnotated(cursor.seek(4)); + case 26: return new CaseOf(cursor.seek(4)); + case 27: return new Lambda(cursor.seek(4)); + case 28: return new Array(cursor.seek(4)); + case 29: return new Tuple(cursor.seek(4)); + case 30: return new Annotated(cursor.seek(4)); + case 31: return new AnnotatedBuiltin(cursor.seek(4)); + case 32: return new Documented(cursor.seek(4)); + case 33: return new ConstructorDefinition(cursor.seek(4)); + default: throw new Error("Unexpected discriminant while deserializing."); + } } +} +export type Tree = Tree.Tree; +export class FractionalDigits extends LazyObject { + constructor(cursor: Cursor) { super(cursor); } + static read(cursor: Cursor): FractionalDigits { return new FractionalDigits(cursor); } + get dot(): Token.Operator { return Token.Operator.read(this.lazyObjectData); } + get digits(): Token.Digits { return Token.Digits.read(this.lazyObjectData.seek(40)); } + debug(): any { return { ...super.debug(), dot: debugHelper(this.dot), digits: debugHelper(this.digits) }; } +} +export class MultiSegmentAppSegment extends LazyObject { + constructor(cursor: Cursor) { super(cursor); } + static read(cursor: Cursor): MultiSegmentAppSegment { return new MultiSegmentAppSegment(cursor); } + get header(): Token { return Token.read(this.lazyObjectData.readPointer()); } + get body(): Tree | null { return this.lazyObjectData.seek(4).readOption((element: Cursor) => Tree.read(element.readPointer())); } + debug(): any { return { ...super.debug(), header: debugHelper(this.header), body: debugHelper(this.body) }; } +} +export class Line extends LazyObject { + constructor(cursor: Cursor) { super(cursor); } + static read(cursor: Cursor): Line { return new Line(cursor); } + get newline(): Token.Newline { return Token.Newline.read(this.lazyObjectData); } + get expression(): Tree | null { return this.lazyObjectData.seek(40).readOption((element: Cursor) => Tree.read(element.readPointer())); } + debug(): any { return { ...super.debug(), newline: debugHelper(this.newline), expression: debugHelper(this.expression) }; } +} +export class ArgumentType extends LazyObject { + constructor(cursor: Cursor) { super(cursor); } + static read(cursor: Cursor): ArgumentType { return new ArgumentType(cursor); } + get operator(): Token.Operator { return Token.Operator.read(this.lazyObjectData); } + get typeNode(): Tree { return Tree.read(this.lazyObjectData.seek(40).readPointer()); } + debug(): any { return { ...super.debug(), operator: debugHelper(this.operator), typeNode: debugHelper(this.typeNode) }; } +} diff --git a/app/gui2/parser-codegen/package-lock.json b/app/gui2/parser-codegen/package-lock.json new file mode 100644 index 000000000000..d1203d9214fb --- /dev/null +++ b/app/gui2/parser-codegen/package-lock.json @@ -0,0 +1,3917 @@ +{ + "name": "parser-codegen", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "parser-codegen", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "nodemon": "^3.0.1" + }, + "devDependencies": { + "@babel/cli": "^7.22.15", + "@babel/core": "^7.22.20", + "@babel/node": "^7.22.19", + "@babel/preset-env": "^7.22.20", + "typescript": "^5.2.2" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", + "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/cli": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.22.15.tgz", + "integrity": "sha512-prtg5f6zCERIaECeTZzd2fMtVjlfjhUcO+fBLQ6DXXdq5FljN+excVitJ2nogsusdf31LeqkjAfXZ7Xq+HmN8g==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.17", + "commander": "^4.0.1", + "convert-source-map": "^1.1.0", + "fs-readdir-recursive": "^1.1.0", + "glob": "^7.2.0", + "make-dir": "^2.1.0", + "slash": "^2.0.0" + }, + "bin": { + "babel": "bin/babel.js", + "babel-external-helpers": "bin/babel-external-helpers.js" + }, + "engines": { + "node": ">=6.9.0" + }, + "optionalDependencies": { + "@nicolo-ribaudo/chokidar-2": "2.1.8-no-fsevents.3", + "chokidar": "^3.4.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.20.tgz", + "integrity": "sha512-BQYjKbpXjoXwFW5jGqiizJQQT/aC7pFm9Ok1OWssonuguICi264lbgMzRp2ZMmRSlfkX6DsWDDcsrctK8Rwfiw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.20.tgz", + "integrity": "sha512-Y6jd1ahLubuYweD/zJH+vvOY141v4f9igNQAQ+MBgq9JlHS2iTsZKn1aMsb3vGccZsXI16VzTBw52Xx0DWmtnA==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.22.15", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-module-transforms": "^7.22.20", + "@babel/helpers": "^7.22.15", + "@babel/parser": "^7.22.16", + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.22.20", + "@babel/types": "^7.22.19", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.15.tgz", + "integrity": "sha512-Zu9oWARBqeVOW0dZOjXc3JObrzuqothQ3y/n1kUtrjCoCPLkXUwMvOo/F/TCfoHMbWIFlWwpZtkZVb9ga4U2pA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.15", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", + "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.15.tgz", + "integrity": "sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", + "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.22.9", + "@babel/helper-validator-option": "^7.22.15", + "browserslist": "^4.21.9", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.15.tgz", + "integrity": "sha512-jKkwA59IXcvSaiK2UN45kKwSC9o+KuoXsBDvHvU/7BecYIp8GQ2UwrVvFgJASUT+hBnwJx6MhvMCuMzwZZ7jlg==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-member-expression-to-functions": "^7.22.15", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.15.tgz", + "integrity": "sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "regexpu-core": "^5.3.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.2.tgz", + "integrity": "sha512-k0qnnOqHn5dK9pZpfD5XXZ9SojAITdCKRn2Lp6rnDGzIbaP0rHyMPk/4wsSxVBVz4RfN0q6VpXWP2pDGIoQ7hw==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", + "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", + "dev": true, + "dependencies": { + "@babel/template": "^7.22.5", + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.22.15.tgz", + "integrity": "sha512-qLNsZbgrNh0fDQBCPocSL8guki1hcPvltGDv/NxvUoABwFq7GkKSu1nRXeJkVZc+wJvne2E0RKQz+2SQrz6eAA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.20.tgz", + "integrity": "sha512-dLT7JVWIUUxKOs1UnJUBR3S70YK+pKX6AbJgB2vMIvEkZkrfJDbYDJesnPshtKV4LhDOR3Oc5YULeDizRek+5A==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz", + "integrity": "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.20.tgz", + "integrity": "sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-wrap-function": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.20.tgz", + "integrity": "sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-member-expression-to-functions": "^7.22.15", + "@babel/helper-optimise-call-expression": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz", + "integrity": "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz", + "integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.20.tgz", + "integrity": "sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw==", + "dev": true, + "dependencies": { + "@babel/helper-function-name": "^7.22.5", + "@babel/template": "^7.22.15", + "@babel/types": "^7.22.19" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.15.tgz", + "integrity": "sha512-7pAjK0aSdxOwR+CcYAqgWOGy5dcfvzsTIfFTb2odQqW47MDfv14UaJDY6eng8ylM2EaeKXdxaSWESbkmaQHTmw==", + "dev": true, + "dependencies": { + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.22.15", + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/node": { + "version": "7.22.19", + "resolved": "https://registry.npmjs.org/@babel/node/-/node-7.22.19.tgz", + "integrity": "sha512-VsKSO9aEHdO16NdtqkJfrXZ9Sxlna1BVnBbToWr1KGdI3cyIk6KqOoa8mWvpK280lJDOwJqxvnl994KmLhq1Yw==", + "dev": true, + "dependencies": { + "@babel/register": "^7.22.15", + "commander": "^4.0.1", + "core-js": "^3.30.2", + "node-environment-flags": "^1.0.5", + "regenerator-runtime": "^0.14.0", + "v8flags": "^3.1.1" + }, + "bin": { + "babel-node": "bin/babel-node.js" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/parser": { + "version": "7.22.16", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.16.tgz", + "integrity": "sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.22.15.tgz", + "integrity": "sha512-FB9iYlz7rURmRJyXRKEnalYPPdn87H5no108cyuQQyMwlpJ2SJtpIUBI27kdTin956pz+LPypkPVPUTlxOmrsg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.22.15.tgz", + "integrity": "sha512-Hyph9LseGvAeeXzikV88bczhsrLrIZqDPxO+sSmAunMPaGrBGhfMWzCPYTtiW9t+HzSE2wtV8e5cc5P6r1xMDQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-transform-optional-chaining": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.22.5.tgz", + "integrity": "sha512-rdV97N7KqsRzeNGoWUOK6yUsWarLjE5Su/Snk9IYPU9CwkWHs4t+rTGOvffTR8XGkJMTAdLfO0xVnXm8wugIJg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.22.5.tgz", + "integrity": "sha512-KwvoWDeNKPETmozyFE0P2rOLqh39EoQHNjqizrI5B8Vt0ZNS7M56s7dAiAqbYfiAYOuIzIh96z3iR2ktgu3tEg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.22.5.tgz", + "integrity": "sha512-26lTNXoVRdAnsaDXPpvCNUq+OVWEVC6bx7Vvz9rC53F2bagUWW4u4ii2+h8Fejfh7RYqPxn+libeFBBck9muEw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.22.15.tgz", + "integrity": "sha512-jBm1Es25Y+tVoTi5rfd5t1KLmL8ogLKpXszboWOTTtGFGz2RKnQe2yn7HbZ+kb/B8N0FVSGQo874NSlOU1T4+w==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.9", + "@babel/plugin-syntax-async-generators": "^7.8.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.22.5.tgz", + "integrity": "sha512-b1A8D8ZzE/VhNDoV1MSJTnpKkCG5bJo+19R4o4oy03zM7ws8yEMK755j61Dc3EyvdysbqH5BOOTquJ7ZX9C6vQ==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.22.5.tgz", + "integrity": "sha512-tdXZ2UdknEKQWKJP1KMNmuF5Lx3MymtMN/pvA+p/VEkhK8jVcQ1fzSy8KM9qRYhAf2/lV33hoMPKI/xaI9sADA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.22.15.tgz", + "integrity": "sha512-G1czpdJBZCtngoK1sJgloLiOHUnkb/bLZwqVZD8kXmq0ZnVfTTWUcs9OWtp0mBtYJ+4LQY1fllqBkOIPhXmFmw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.22.5.tgz", + "integrity": "sha512-nDkQ0NfkOhPTq8YCLiWNxp1+f9fCobEjCb0n8WdbNUBc4IB5V7P1QnX9IjpSoquKrXF5SKojHleVNs2vGeHCHQ==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.22.11.tgz", + "integrity": "sha512-GMM8gGmqI7guS/llMFk1bJDkKfn3v3C4KHK9Yg1ey5qcHcOlKb0QvcMrgzvxo+T03/4szNh5lghY+fEC98Kq9g==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.22.11", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.22.15.tgz", + "integrity": "sha512-VbbC3PGjBdE0wAWDdHM9G8Gm977pnYI0XpqMd6LrKISj8/DJXEsWqgRuTYaNE9Bv0JGhTZUzHDlMk18IpOuoqw==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.9", + "@babel/helper-split-export-declaration": "^7.22.6", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.22.5.tgz", + "integrity": "sha512-4GHWBgRf0krxPX+AaPtgBAlTgTeZmqDynokHOX7aqqAB4tHs3U2Y02zH6ETFdLZGcg9UQSD1WCmkVrE9ErHeOg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/template": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.22.15.tgz", + "integrity": "sha512-HzG8sFl1ZVGTme74Nw+X01XsUTqERVQ6/RLHo3XjGRzm7XD6QTtfS3NJotVgCGy8BzkDqRjRBD8dAyJn5TuvSQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.22.5.tgz", + "integrity": "sha512-5/Yk9QxCQCl+sOIB1WelKnVRxTJDSAIxtJLL2/pqL14ZVlbH0fUQUZa/T5/UnQtBNgghR7mfB8ERBKyKPCi7Vw==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.22.5.tgz", + "integrity": "sha512-dEnYD+9BBgld5VBXHnF/DbYGp3fqGMsyxKbtD1mDyIA7AkTSpKXFhCVuj/oQVOoALfBs77DudA0BE4d5mcpmqw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.22.11.tgz", + "integrity": "sha512-g/21plo58sfteWjaO0ZNVb+uEOkJNjAaHhbejrnBmu011l/eNDScmkbjCC3l4FKb10ViaGU4aOkFznSu2zRHgA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.22.5.tgz", + "integrity": "sha512-vIpJFNM/FjZ4rh1myqIya9jXwrwwgFRHPjT3DkUA9ZLHuzox8jiXkOLvwm1H+PQIP3CqfC++WPKeuDi0Sjdj1g==", + "dev": true, + "dependencies": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.22.11.tgz", + "integrity": "sha512-xa7aad7q7OiT8oNZ1mU7NrISjlSkVdMbNxn9IuLZyL9AJEhs1Apba3I+u5riX1dIkdptP5EKDG5XDPByWxtehw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.22.15.tgz", + "integrity": "sha512-me6VGeHsx30+xh9fbDLLPi0J1HzmeIIyenoOQHuw2D4m2SAU3NrspX5XxJLBpqn5yrLzrlw2Iy3RA//Bx27iOA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.22.5.tgz", + "integrity": "sha512-UIzQNMS0p0HHiQm3oelztj+ECwFnj+ZRV4KnguvlsD2of1whUeM6o7wGNj6oLwcDoAXQ8gEqfgC24D+VdIcevg==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.22.11.tgz", + "integrity": "sha512-CxT5tCqpA9/jXFlme9xIBCc5RPtdDq3JpkkhgHQqtDdiTnTI0jtZ0QzXhr5DILeYifDPp2wvY2ad+7+hLMW5Pw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-json-strings": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.22.5.tgz", + "integrity": "sha512-fTLj4D79M+mepcw3dgFBTIDYpbcB9Sm0bpm4ppXPaO+U+PKFFyV9MGRvS0gvGw62sd10kT5lRMKXAADb9pWy8g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.22.11.tgz", + "integrity": "sha512-qQwRTP4+6xFCDV5k7gZBF3C31K34ut0tbEcTKxlX/0KXxm9GLcO14p570aWxFvVzx6QAfPgq7gaeIHXJC8LswQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.22.5.tgz", + "integrity": "sha512-RZEdkNtzzYCFl9SE9ATaUMTj2hqMb4StarOJLrZRbqqU4HSBE7UlBw9WBWQiDzrJZJdUWiMTVDI6Gv/8DPvfew==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.22.5.tgz", + "integrity": "sha512-R+PTfLTcYEmb1+kK7FNkhQ1gP4KgjpSO6HfH9+f8/yfp2Nt3ggBjiVpRwmwTlfqZLafYKJACy36yDXlEmI9HjQ==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.22.15.tgz", + "integrity": "sha512-jWL4eh90w0HQOTKP2MoXXUpVxilxsB2Vl4ji69rSjS3EcZ/v4sBmn+A3NpepuJzBhOaEBbR7udonlHHn5DWidg==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-simple-access": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.22.11.tgz", + "integrity": "sha512-rIqHmHoMEOhI3VkVf5jQ15l539KrwhzqcBO6wdCNWPWc/JWt9ILNYNUssbRpeq0qWns8svuw8LnMNCvWBIJ8wA==", + "dev": true, + "dependencies": { + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-module-transforms": "^7.22.9", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.22.5.tgz", + "integrity": "sha512-+S6kzefN/E1vkSsKx8kmQuqeQsvCKCd1fraCM7zXm4SFoggI099Tr4G8U81+5gtMdUeMQ4ipdQffbKLX0/7dBQ==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz", + "integrity": "sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.22.5.tgz", + "integrity": "sha512-AsF7K0Fx/cNKVyk3a+DW0JLo+Ua598/NxMRvxDnkpCIGFh43+h/v2xyhRUYf6oD8gE4QtL83C7zZVghMjHd+iw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.22.11.tgz", + "integrity": "sha512-YZWOw4HxXrotb5xsjMJUDlLgcDXSfO9eCmdl1bgW4+/lAGdkjaEvOnQ4p5WKKdUgSzO39dgPl0pTnfxm0OAXcg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.22.11.tgz", + "integrity": "sha512-3dzU4QGPsILdJbASKhF/V2TVP+gJya1PsueQCxIPCEcerqF21oEcrob4mzjsp2Py/1nLfF5m+xYNMDpmA8vffg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.22.15.tgz", + "integrity": "sha512-fEB+I1+gAmfAyxZcX1+ZUwLeAuuf8VIg67CTznZE0MqVFumWkh8xWtn58I4dxdVf080wn7gzWoF8vndOViJe9Q==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.22.9", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.22.5.tgz", + "integrity": "sha512-klXqyaT9trSjIUrcsYIfETAzmOEZL3cBYqOYLJxBHfMFFggmXOv+NYSX/Jbs9mzMVESw/WycLFPRx8ba/b2Ipw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.22.11.tgz", + "integrity": "sha512-rli0WxesXUeCJnMYhzAglEjLWVDF6ahb45HuprcmQuLidBJFWjNnOzssk2kuc6e33FlLaiZhG/kUIzUMWdBKaQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.22.15.tgz", + "integrity": "sha512-ngQ2tBhq5vvSJw2Q2Z9i7ealNkpDMU0rGWnHPKqRZO0tzZ5tlaoz4hDvhXioOoaE0X2vfNss1djwg0DXlfu30A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.22.15.tgz", + "integrity": "sha512-hjk7qKIqhyzhhUvRT683TYQOFa/4cQKwQy7ALvTpODswN40MljzNDa0YldevS6tGbxwaEKVn502JmY0dP7qEtQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.22.5.tgz", + "integrity": "sha512-PPjh4gyrQnGe97JTalgRGMuU4icsZFnWkzicB/fUtzlKUqvsWBKEpPPfr5a2JiyirZkHxnAqkQMO5Z5B2kK3fA==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.22.11.tgz", + "integrity": "sha512-sSCbqZDBKHetvjSwpyWzhuHkmW5RummxJBVbYLkGkaiTOWGxml7SXt0iWa03bzxFIx7wOj3g/ILRd0RcJKBeSQ==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.22.11", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.22.5.tgz", + "integrity": "sha512-TiOArgddK3mK/x1Qwf5hay2pxI6wCZnvQqrFSqbtg1GLl2JcNMitVH/YnqjP+M31pLUeTfzY1HAXFDnUBV30rQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.22.10.tgz", + "integrity": "sha512-F28b1mDt8KcT5bUyJc/U9nwzw6cV+UmTeRlXYIl2TNqMMJif0Jeey9/RQ3C4NOd2zp0/TRsDns9ttj2L523rsw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "regenerator-transform": "^0.15.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.22.5.tgz", + "integrity": "sha512-DTtGKFRQUDm8svigJzZHzb/2xatPc6TzNvAIJ5GqOKDsGFYgAskjRulbR/vGsPKq3OPqtexnz327qYpP57RFyA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.22.5.tgz", + "integrity": "sha512-vM4fq9IXHscXVKzDv5itkO1X52SmdFBFcMIBZ2FRn2nqVYqw6dBexUgMvAjHW+KXpPPViD/Yo3GrDEBaRC0QYA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.22.5.tgz", + "integrity": "sha512-5ZzDQIGyvN4w8+dMmpohL6MBo+l2G7tfC/O2Dg7/hjpgeWvUx8FzfeOKxGog9IimPa4YekaQ9PlDqTLOljkcxg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.22.5.tgz", + "integrity": "sha512-zf7LuNpHG0iEeiyCNwX4j3gDg1jgt1k3ZdXBKbZSoA3BbGQGvMiSvfbZRR3Dr3aeJe3ooWFZxOOG3IRStYp2Bw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.22.5.tgz", + "integrity": "sha512-5ciOehRNf+EyUeewo8NkbQiUs4d6ZxiHo6BcBcnFlgiJfu16q0bQUw9Jvo0b0gBKFG1SMhDSjeKXSYuJLeFSMA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.22.5.tgz", + "integrity": "sha512-bYkI5lMzL4kPii4HHEEChkD0rkc+nvnlR6+o/qdqR6zrm0Sv/nodmyLhlq2DO0YKLUNd2VePmPRjJXSBh9OIdA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.22.10.tgz", + "integrity": "sha512-lRfaRKGZCBqDlRU3UIFovdp9c9mEvlylmpod0/OatICsSfuQ9YFthRo1tpTkGsklEefZdqlEFdY4A2dwTb6ohg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.22.5.tgz", + "integrity": "sha512-HCCIb+CbJIAE6sXn5CjFQXMwkCClcOfPCzTlilJ8cUatfzwHlWQkbtV0zD338u9dZskwvuOYTuuaMaA8J5EI5A==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.22.5.tgz", + "integrity": "sha512-028laaOKptN5vHJf9/Arr/HiJekMd41hOEZYvNsrsXqJ7YPYuX2bQxh31fkZzGmq3YqHRJzYFFAVYvKfMPKqyg==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.22.5.tgz", + "integrity": "sha512-lhMfi4FC15j13eKrh3DnYHjpGj6UKQHtNKTbtc1igvAhRy4+kLhV07OpLcsN0VgDEw/MjAvJO4BdMJsHwMhzCg==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.22.20.tgz", + "integrity": "sha512-11MY04gGC4kSzlPHRfvVkNAZhUxOvm7DCJ37hPDnUENwe06npjIRAfInEMTGSb4LZK5ZgDFkv5hw0lGebHeTyg==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.22.20", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-option": "^7.22.15", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.22.15", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.22.15", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.22.5", + "@babel/plugin-syntax-import-attributes": "^7.22.5", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.22.5", + "@babel/plugin-transform-async-generator-functions": "^7.22.15", + "@babel/plugin-transform-async-to-generator": "^7.22.5", + "@babel/plugin-transform-block-scoped-functions": "^7.22.5", + "@babel/plugin-transform-block-scoping": "^7.22.15", + "@babel/plugin-transform-class-properties": "^7.22.5", + "@babel/plugin-transform-class-static-block": "^7.22.11", + "@babel/plugin-transform-classes": "^7.22.15", + "@babel/plugin-transform-computed-properties": "^7.22.5", + "@babel/plugin-transform-destructuring": "^7.22.15", + "@babel/plugin-transform-dotall-regex": "^7.22.5", + "@babel/plugin-transform-duplicate-keys": "^7.22.5", + "@babel/plugin-transform-dynamic-import": "^7.22.11", + "@babel/plugin-transform-exponentiation-operator": "^7.22.5", + "@babel/plugin-transform-export-namespace-from": "^7.22.11", + "@babel/plugin-transform-for-of": "^7.22.15", + "@babel/plugin-transform-function-name": "^7.22.5", + "@babel/plugin-transform-json-strings": "^7.22.11", + "@babel/plugin-transform-literals": "^7.22.5", + "@babel/plugin-transform-logical-assignment-operators": "^7.22.11", + "@babel/plugin-transform-member-expression-literals": "^7.22.5", + "@babel/plugin-transform-modules-amd": "^7.22.5", + "@babel/plugin-transform-modules-commonjs": "^7.22.15", + "@babel/plugin-transform-modules-systemjs": "^7.22.11", + "@babel/plugin-transform-modules-umd": "^7.22.5", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5", + "@babel/plugin-transform-new-target": "^7.22.5", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.22.11", + "@babel/plugin-transform-numeric-separator": "^7.22.11", + "@babel/plugin-transform-object-rest-spread": "^7.22.15", + "@babel/plugin-transform-object-super": "^7.22.5", + "@babel/plugin-transform-optional-catch-binding": "^7.22.11", + "@babel/plugin-transform-optional-chaining": "^7.22.15", + "@babel/plugin-transform-parameters": "^7.22.15", + "@babel/plugin-transform-private-methods": "^7.22.5", + "@babel/plugin-transform-private-property-in-object": "^7.22.11", + "@babel/plugin-transform-property-literals": "^7.22.5", + "@babel/plugin-transform-regenerator": "^7.22.10", + "@babel/plugin-transform-reserved-words": "^7.22.5", + "@babel/plugin-transform-shorthand-properties": "^7.22.5", + "@babel/plugin-transform-spread": "^7.22.5", + "@babel/plugin-transform-sticky-regex": "^7.22.5", + "@babel/plugin-transform-template-literals": "^7.22.5", + "@babel/plugin-transform-typeof-symbol": "^7.22.5", + "@babel/plugin-transform-unicode-escapes": "^7.22.10", + "@babel/plugin-transform-unicode-property-regex": "^7.22.5", + "@babel/plugin-transform-unicode-regex": "^7.22.5", + "@babel/plugin-transform-unicode-sets-regex": "^7.22.5", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "@babel/types": "^7.22.19", + "babel-plugin-polyfill-corejs2": "^0.4.5", + "babel-plugin-polyfill-corejs3": "^0.8.3", + "babel-plugin-polyfill-regenerator": "^0.5.2", + "core-js-compat": "^3.31.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/register": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.22.15.tgz", + "integrity": "sha512-V3Q3EqoQdn65RCgTLwauZaTfd1ShhwPmbBv+1dkZV/HpCGMKVyn6oFcRlI7RaKqiDQjX2Qd3AuoEguBgdjIKlg==", + "dev": true, + "dependencies": { + "clone-deep": "^4.0.1", + "find-cache-dir": "^2.0.0", + "make-dir": "^2.1.0", + "pirates": "^4.0.5", + "source-map-support": "^0.5.16" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==", + "dev": true + }, + "node_modules/@babel/runtime": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.15.tgz", + "integrity": "sha512-T0O+aa+4w0u06iNmapipJXMV4HoUir03hpx3/YqXXhu9xim3w+dVphjFWl1OH8NbZHw5Lbm9k45drDkgq2VNNA==", + "dev": true, + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.20.tgz", + "integrity": "sha512-eU260mPZbU7mZ0N+X10pxXhQFMGTeLb9eFS0mxehS8HZp9o1uSnFeWQuG1UPrlxgA7QoUzFhOnilHDp0AXCyHw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.22.15", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.22.16", + "@babel/types": "^7.22.19", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.22.19", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.19.tgz", + "integrity": "sha512-P7LAw/LbojPzkgp5oznjE6tQEIWbp4PkkfrZDINTro9zgBRtI324/EYsiSI7lhPbpIQ+DCeR2NNmMWANGGfZsg==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.19", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.19", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz", + "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@nicolo-ribaudo/chokidar-2": { + "version": "2.1.8-no-fsevents.3", + "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz", + "integrity": "sha512-s88O1aVtXftvp5bCPB7WnmXc5IwOZZ7YPuwNPt+GtOOXpPvad1LfbmjYv+qII7zP6RU2QGnqve27dnLycEnyEQ==", + "dev": true, + "optional": true + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", + "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "is-array-buffer": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.reduce": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/array.prototype.reduce/-/array.prototype.reduce-1.0.6.tgz", + "integrity": "sha512-UW+Mz8LG/sPSU8jRDCjVr6J/ZKAGpHfwrZ6kWTG5qCxIEiXdVshqGnu5vEZA8S1y6X4aCSbQZ0/EEsfvEvBiSg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-array-method-boxes-properly": "^1.0.0", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz", + "integrity": "sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "is-array-buffer": "^3.0.2", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.5.tgz", + "integrity": "sha512-19hwUH5FKl49JEsvyTcoHakh6BE0wgXLLptIyKZ3PijHc/Ci521wygORCUCCred+E/twuqRyAkE02BAWPmsHOg==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.4.2", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.3.tgz", + "integrity": "sha512-z41XaniZL26WLrvjy7soabMXrfPWARN25PZoriDEiLMxAp50AUW3t35BGQUMg5xK3UrpVTtagIDklxYa+MhiNA==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.4.2", + "core-js-compat": "^3.31.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.2.tgz", + "integrity": "sha512-tAlOptU0Xj34V1Y2PNTL4Y0FOJMDB6bZmoW39FeCQIhigGLkqu3Fj6uiXpxIf6Ij274ENdYx64y6Au+ZKlb1IA==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.4.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.21.10", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz", + "integrity": "sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001517", + "electron-to-chromium": "^1.4.477", + "node-releases": "^2.0.13", + "update-browserslist-db": "^1.0.11" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001535", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001535.tgz", + "integrity": "sha512-48jLyUkiWFfhm/afF7cQPqPjaUmSraEhK4j+FCTJpgnGGEZHqyLe3hmWH7lIooZdSzXL0ReMvHz0vKDoTBsrwg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true + }, + "node_modules/core-js": { + "version": "3.32.2", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.32.2.tgz", + "integrity": "sha512-pxXSw1mYZPDGvTQqEc5vgIb83jGQKFGYWY76z4a7weZXUolw3G+OvpZqSRcfYOoOVUQJYEPsWeQK8pKEnUtWxQ==", + "dev": true, + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-compat": { + "version": "3.32.2", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.32.2.tgz", + "integrity": "sha512-+GjlguTDINOijtVRUxrQOv3kfu9rl+qPNdX2LTbJ/ZyVTuxK+ksVSAGX1nHstu4hrv1En/uPTtWgq2gI5wt4AQ==", + "dev": true, + "dependencies": { + "browserslist": "^4.21.10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/define-data-property": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.0.tgz", + "integrity": "sha512-UzGwzcjyv3OtAvolTj1GoyNYzfFR+iqbGjcnBEENZVCpM4/Ng1yhGNvS3lR/xDS74Tb2wGG9WzNSNIOS9UVb2g==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.523", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.523.tgz", + "integrity": "sha512-9AreocSUWnzNtvLcbpng6N+GkXnCcBR80IQkxRC9Dfdyg4gaWNUPBujAHUpKkiUkoSoR9UlhA4zD/IgBklmhzg==", + "dev": true + }, + "node_modules/es-abstract": { + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.2.tgz", + "integrity": "sha512-YoxfFcDmhjOgWPWsV13+2RNjq1F6UQnfs+8TftwNqtzlmFzEXvlUwdrNrYeaizfjQzRMxkZ6ElWMOJIFKdVqwA==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "arraybuffer.prototype.slice": "^1.0.2", + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "es-set-tostringtag": "^2.0.1", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.1", + "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.5", + "is-array-buffer": "^3.0.2", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.12", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.3", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.1", + "safe-array-concat": "^1.0.1", + "safe-regex-test": "^1.0.0", + "string.prototype.trim": "^1.2.8", + "string.prototype.trimend": "^1.0.7", + "string.prototype.trimstart": "^1.0.7", + "typed-array-buffer": "^1.0.0", + "typed-array-byte-length": "^1.0.0", + "typed-array-byte-offset": "^1.0.0", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.11" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-array-method-boxes-properly": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", + "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==", + "dev": true + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", + "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "dev": true, + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/fs-readdir-recursive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz", + "integrity": "sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==", + "dev": true + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/function.prototype.name": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", + "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "dev": true, + "dependencies": { + "parse-passwd": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==" + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/internal-slot": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", + "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", + "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "is-typed-array": "^1.1.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz", + "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", + "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", + "dev": true, + "dependencies": { + "which-typed-array": "^1.1.11" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/node-environment-flags": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.6.tgz", + "integrity": "sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw==", + "dev": true, + "dependencies": { + "object.getownpropertydescriptors": "^2.0.3", + "semver": "^5.7.0" + } + }, + "node_modules/node-environment-flags/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/node-releases": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", + "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==", + "dev": true + }, + "node_modules/nodemon": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.0.1.tgz", + "integrity": "sha512-g9AZ7HmkhQkqXkRc20w+ZfQ73cHLbE8hnPbtaFbFtCumZsjyMhKk9LajQ07U5Ux28lvFjZ5X7HvWR1xzU8jHVw==", + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^3.2.7", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/nodemon/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/nodemon/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/nodemon/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/nodemon/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.getownpropertydescriptors": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.7.tgz", + "integrity": "sha512-PrJz0C2xJ58FNn11XV2lr4Jt5Gzl94qpy9Lu0JlfEj14z88sqbSBJCBEzdlNUCzY2gburhbrwOZ5BHCmuNUy0g==", + "dev": true, + "dependencies": { + "array.prototype.reduce": "^1.0.6", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "safe-array-concat": "^1.0.0" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "dependencies": { + "find-up": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==" + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", + "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", + "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==", + "dev": true + }, + "node_modules/regenerator-transform": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", + "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "set-function-name": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpu-core": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", + "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", + "dev": true, + "dependencies": { + "@babel/regjsgen": "^0.8.0", + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "dev": true, + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + } + }, + "node_modules/resolve": { + "version": "1.22.6", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.6.tgz", + "integrity": "sha512-njhxM7mV12JfufShqGy3Rz8j11RPdLy4xi15UurGJeoHLfJpVXKdh3ueuOqbYUcDZnffr6X739JBo5LzyahEsw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-array-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.1.tgz", + "integrity": "sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/set-function-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz", + "integrity": "sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==", + "dev": true, + "dependencies": { + "define-data-property": "^1.0.1", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/simple-update-notifier/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/simple-update-notifier/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/simple-update-notifier/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", + "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", + "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", + "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/touch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "dependencies": { + "nopt": "~1.0.10" + }, + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", + "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", + "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", + "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typescript": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==" + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", + "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", + "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/v8flags": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.2.0.tgz", + "integrity": "sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg==", + "dev": true, + "dependencies": { + "homedir-polyfill": "^1.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.11.tgz", + "integrity": "sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + } + } +} diff --git a/app/gui2/parser-codegen/package.json b/app/gui2/parser-codegen/package.json new file mode 100644 index 000000000000..1e2582e7fc96 --- /dev/null +++ b/app/gui2/parser-codegen/package.json @@ -0,0 +1,22 @@ +{ + "name": "parser-codegen", + "version": "1.0.0", + "description": "", + "main": "dist/codegen.js", + "scripts": { + "start": "tsc && node node_modules/.bin/babel-node dist/codegen.js" + }, + "keywords": [], + "author": "", + "license": "ISC", + "devDependencies": { + "@babel/cli": "^7.22.15", + "@babel/core": "^7.22.20", + "@babel/node": "^7.22.19", + "@babel/preset-env": "^7.22.20", + "typescript": "^5.2.2" + }, + "dependencies": { + "nodemon": "^3.0.1" + } +} diff --git a/app/gui2/parser-codegen/src/codegen.ts b/app/gui2/parser-codegen/src/codegen.ts new file mode 100644 index 000000000000..d2b9199178bc --- /dev/null +++ b/app/gui2/parser-codegen/src/codegen.ts @@ -0,0 +1,556 @@ +import * as ts from "typescript" +import {SyntaxKind} from "typescript" +import * as fs from "fs" +//import * as decoding from 'lib0/decoding' + +type Schema = { + types: [string: Schema.Type] +} +module Schema { + export type Type = { + name: string + fields: [string, Field][] + parent: string | null + discriminants: [number: string] + size: number + } + export type Field = { + type: TypeRef + offset: number + } + export type TypeRef = Class | Primitive | Sequence | Option | Result + export type Class = { class: "type"; id: string } + export type Primitive = { class: "primitive"; type: PrimitiveType } + export type Sequence = { class: "sequence"; type: TypeRef } + export type Option = { class: "option"; type: TypeRef } + export type Result = { class: "result"; type0: TypeRef, type1: TypeRef } + export type PrimitiveType = "bool" | "u32" | "u64" | "i32" | "i64" | "char" | "string" +} + +function fromSnake(ident: string, to: "camel" | "pascal", prefix?: string): string { + const segments = [] + if (prefix !== undefined) { + segments.push(...prefix.split("_")) + } + segments.push(...ident.split("_")) + return segments.map((seg, i) => { + if (to === "camel" && i === 0) { + return seg + } else { + return seg.charAt(0).toUpperCase() + seg.slice(1) + } + }).join("") +} + +function toPascal(ident: string, prefix?: string): string { + return fromSnake(ident, "pascal", prefix) +} + +function toCamel(ident: string, prefix?: string): string { + return fromSnake(ident, "camel", prefix) +} + +function legalizeIdent(ident: string): string { + // FIXME: We should accept a renaming table as an input alongside the schema, then emit an error if a keyword is + // encountered ("constructor") or a field name is duplicated ("type"). + switch (ident) { + case "constructor": + return "ident" + case "type": + return "typeNode" + default: + return ident + } +} + +type ExpressionTransformer = ((expression: ts.Expression) => ts.Expression) + +function primitiveReader(name: string): ExpressionTransformer { + return cursor => ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(cursor, name), [], []) +} + +function readerTransformer(name: string): (readElement: ExpressionTransformer) => ExpressionTransformer { + const innerParameter = ts.factory.createIdentifier("element") + return (readElement: ExpressionTransformer) => (cursor: ts.Expression) => { + return ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(cursor, name), + [], + [ + ts.factory.createArrowFunction( + [], + [], + [ts.factory.createParameterDeclaration([], undefined, innerParameter, undefined, cursorType, undefined)], + undefined, + undefined, + readElement(innerParameter) + ) + ] + ) + } +} + +function readerTransformer2(name: string): (readOk: ExpressionTransformer, readErr: ExpressionTransformer) => ExpressionTransformer { + function makeArrow(reader: ExpressionTransformer, data: ts.Identifier) { + return ts.factory.createArrowFunction( + [], + [], + [ts.factory.createParameterDeclaration([], undefined, data, undefined, cursorType, undefined)], + undefined, + undefined, + reader(data) + ) + } + const okData = ts.factory.createIdentifier("okData") + const errData = ts.factory.createIdentifier("errData") + return (readOk: ExpressionTransformer, readErr: ExpressionTransformer) => (cursor: ts.Expression) => { + return ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(cursor, name), + [], + [makeArrow(readOk, okData), makeArrow(readErr, errData)] + ) + } +} + +function readerTransformerSized(name: string): (readElement: ExpressionTransformer, size: number) => ExpressionTransformer { + const innerParameter = ts.factory.createIdentifier("element") + return (readElement: ExpressionTransformer, size: number) => (cursor: ts.Expression) => { + return ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(cursor, name), + [], + [ + ts.factory.createArrowFunction( + [], + [], + [ts.factory.createParameterDeclaration([], undefined, innerParameter, undefined, cursorType, undefined)], + undefined, + undefined, + readElement(innerParameter) + ), + ts.factory.createNumericLiteral(size) + ] + ) + } +} + +function namespacedName(name: string, namespace?: string): string { + if (namespace === undefined) { + return toPascal(name) + } else { + return toPascal(namespace) + "." + toPascal(name) + } +} + +function abstractTypeReader(name: string): ExpressionTransformer { + return (cursor: ts.Expression) => + ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(toPascal(name)), "read"), + [], + [cursorMethods.readPointer(cursor)] + ) +} + +function concreteTypeReader(name: string): ExpressionTransformer { + return (cursor: ts.Expression) => + ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(toPascal(name)), "read"), + [], + [cursor] + ) +} + +class Type { + readonly type: ts.TypeNode + readonly reader: ExpressionTransformer + readonly size: number + + constructor(type: ts.TypeNode, reader: ExpressionTransformer, size: number) { + this.type = type + this.reader = reader + this.size = size + } + + static new(ref: Schema.TypeRef, types: [string: Schema.Type]): Type { + const c = ref.class + switch (c) { + case "type": + const ty = types[ref.id] + const parent = types[ty.parent] + const typeName = namespacedName(ty.name, parent?.name) + const type = ts.factory.createTypeReferenceNode(typeName) + if (Object.entries(ty.discriminants).length !== 0) { + return new Type(type, abstractTypeReader(typeName), POINTER_SIZE) + } else { + return new Type(type, concreteTypeReader(typeName), ty.size) + } + case "primitive": + const p = ref.type + switch (p) { + case "bool": + return new Type(ts.factory.createTypeReferenceNode("boolean"), cursorMethods.readBool, 1) + case "u32": + return new Type(ts.factory.createTypeReferenceNode("number"), cursorMethods.readU32, 4) + case "i32": + return new Type(ts.factory.createTypeReferenceNode("number"), cursorMethods.readI32, 4) + case "u64": + return new Type(ts.factory.createTypeReferenceNode("number"), cursorMethods.readU64, 8) + case "i64": + return new Type(ts.factory.createTypeReferenceNode("number"), cursorMethods.readI64, 8) + case "char": + return new Type(ts.factory.createTypeReferenceNode("number"), cursorMethods.readU32, 4) + case "string": + return new Type(ts.factory.createTypeReferenceNode("string"), cursorMethods.readString, POINTER_SIZE) + default: + const _ = p satisfies never + throw new Error("unreachable: PrimitiveType.type='" + p + "'") + } + case "sequence": + return Type.sequence(Type.new(ref.type, types)) + case "option": + return Type.option(Type.new(ref.type, types)) + case "result": + return Type.result(Type.new(ref.type0, types), Type.new(ref.type1, types)) + default: + const _ = c satisfies never + throw new Error("unreachable: TypeRef.class='" + c + "' in " + JSON.stringify(ref)) + } + } + + static sequence(element: Type): Type { + return new Type( + ts.factory.createTypeReferenceNode("Iterable", [element.type]), + cursorMethods.readSequence(element.reader, element.size), + POINTER_SIZE + ) + } + + static option(element: Type): Type { + return new Type( + ts.factory.createUnionTypeNode([element.type, nullType]), + cursorMethods.readOption(element.reader), + POINTER_SIZE + 1 + ) + } + + static result(ok: Type, err: Type): Type { + return new Type( + ts.factory.createUnionTypeNode([ok.type, err.type]), + cursorMethods.readResult(ok.reader, err.reader), + POINTER_SIZE + ) + } +} + +function seekCursor(cursor: ts.Expression, offset: number): ts.Expression { + if (offset === 0) { + return cursor + } else { + return ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(cursor, "seek"), + [], + [ts.factory.createNumericLiteral(offset)] + ) + } +} + +function makeGetter(fieldName: string, fieldData: Schema.Field, types: [string: Schema.Type]): ts.GetAccessorDeclaration { + const type = Type.new(fieldData.type, types) + return ts.factory.createGetAccessorDeclaration( + [], + ts.factory.createIdentifier(legalizeIdent(toCamel(fieldName))), + [], + type.type, + ts.factory.createBlock([ + ts.factory.createReturnStatement( + type.reader( + seekCursor( + ts.factory.createPropertyAccessExpression(ts.factory.createThis(), cursorFieldIdent), + fieldData.offset + ), + ) + ) + ]) + ) +} + +// Helper for a common case of constructing an assignment. +function createAssignmentStatement(left: ts.Expression, right: ts.Expression): ts.Statement { + return ts.factory.createExpressionStatement( + ts.factory.createBinaryExpression( + left, + SyntaxKind.EqualsToken, + right, + ) + ) +} + +function makeConcreteType(id: string, types: [string: Schema.Type]): ts.ClassDeclaration { + const ident = ts.factory.createIdentifier(toPascal(types[id].name)) + const paramIdent = ts.factory.createIdentifier("cursor") + const cursorParam = ts.factory.createParameterDeclaration([], undefined, paramIdent, undefined, cursorType, undefined) + return makeClass( + [modifiers.export], + ident, + [ + forwardToSuper(paramIdent, cursorType), + ts.factory.createMethodDeclaration( + [modifiers.static], + undefined, + "read", + undefined, + [], + [cursorParam], + ts.factory.createTypeReferenceNode(ident), + ts.factory.createBlock([ts.factory.createReturnStatement(ts.factory.createNewExpression(ident, [], [paramIdent]))]) + ) + ], + id, + types + ) +} + +function debugValue(ident: ts.Identifier): ts.Expression { + const value = ts.factory.createPropertyAccessExpression(ts.factory.createThis(), ident) + return ts.factory.createCallExpression(ts.factory.createIdentifier("debugHelper"), [], [value]) +} + +function makeDebugFunction(fields: [string, Schema.Field][]): ts.MethodDeclaration { + const getterIdent = (fieldName: string) => ts.factory.createIdentifier(legalizeIdent(toCamel(fieldName))) + return ts.factory.createMethodDeclaration( + [], + undefined, + "debug", + undefined, + [], + [], + ts.factory.createTypeReferenceNode("any"), + ts.factory.createBlock([ + ts.factory.createReturnStatement( + ts.factory.createObjectLiteralExpression([ + ts.factory.createSpreadAssignment( + ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createSuper(), "debug"), + [], + [] + ) + ), + ...fields.map(([name, field] : [string, Schema.Field]) => + ts.factory.createPropertyAssignment(getterIdent(name), debugValue(getterIdent(name))) + ) + ]) + )] + ) + ) +} + +function makeClass(modifiers: ts.Modifier[], name: ts.Identifier, members: ts.ClassElement[], id: string, types: [string: Schema.Type]): ts.ClassDeclaration { + const ty = types[id] + return ts.factory.createClassDeclaration( + modifiers, + name, + undefined, + [ts.factory.createHeritageClause(ts.SyntaxKind.ExtendsKeyword, [ + ts.factory.createExpressionWithTypeArguments(lazyObjectIdent, []) + ])], + [ + ...members, + ...ty.fields.map(([name, field]: [string, Schema.Field]) => makeGetter(name, field, types)), + makeDebugFunction(ty.fields) + ], + ); +} + +type ChildType = { + definition: ts.ClassDeclaration + reference: ts.TypeNode + enumMember: ts.EnumMember + case: ts.CaseClause +} + +function makeChildType(parentName: string, base: ts.Identifier, id: string, discrim: string, types: [string: Schema.Type]): ChildType { + const ty: Schema.Type = types[id] + const name = toPascal(ty.name) + const ident = ts.factory.createIdentifier(name) + const cursorIdent = ts.factory.createIdentifier("cursor") + const cursorParam = ts.factory.createParameterDeclaration([], undefined, cursorIdent, undefined, cursorType, undefined) + const discrimInt = ts.factory.createNumericLiteral(parseInt(discrim, 10)) + return { + definition: ts.factory.createClassDeclaration( + [modifiers.export], + name, + undefined, + [ts.factory.createHeritageClause(ts.SyntaxKind.ExtendsKeyword, [ + ts.factory.createExpressionWithTypeArguments(base, []) + ])], + [ + ts.factory.createPropertyDeclaration( + [modifiers.readonly], + "type", + undefined, + ts.factory.createTypeReferenceNode("Type." + name), + undefined + ), + ts.factory.createConstructorDeclaration([], [ + ts.factory.createParameterDeclaration([], undefined, cursorIdent, undefined, cursorType, undefined) + ], + ts.factory.createBlock([ + ts.factory.createExpressionStatement(ts.factory.createCallExpression( + ts.factory.createIdentifier("super"), [], [cursorIdent] + )), + createAssignmentStatement( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier("this"), "type"), + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier("Type"), name) + ) + ]) + ), + ts.factory.createMethodDeclaration( + [modifiers.static], + undefined, + "read", + undefined, + [], + [cursorParam], + ts.factory.createTypeReferenceNode(ident), + ts.factory.createBlock([ts.factory.createReturnStatement(ts.factory.createNewExpression(ident, [], [cursorIdent]))]) + ), + ...ty.fields.map(([name, field]: [string, Schema.Field]) => makeGetter(name, field, types)), + makeDebugFunction(ty.fields) + ] + ), + reference: ts.factory.createTypeReferenceNode(name), + enumMember: ts.factory.createEnumMember(toPascal(types[id].name), discrimInt), + case: ts.factory.createCaseClause( + discrimInt, + [ts.factory.createReturnStatement( + ts.factory.createNewExpression(ident, [], [seekCursor(cursorIdent, 4)]) + )] + ) + } +} + +function forwardToSuper(ident: ts.Identifier, type: ts.TypeNode) { + return ts.factory.createConstructorDeclaration([], [ + ts.factory.createParameterDeclaration([], undefined, ident, undefined, type, undefined) + ], + ts.factory.createBlock([ + ts.factory.createExpressionStatement(ts.factory.createCallExpression( + ts.factory.createIdentifier("super"), [], [ident] + )) + ]) + ) +} + +function casesOrThrow(cases: ts.CaseClause[], error: string): ts.CaseBlock { + return ts.factory.createCaseBlock( + [ + ...cases, + ts.factory.createDefaultClause([ + ts.factory.createThrowStatement( + ts.factory.createNewExpression(ts.factory.createIdentifier("Error"), [], [ts.factory.createStringLiteral(error)]) + ) + ]) + ] + ) +} + +function abstractTypeDeserializer(ident: ts.Identifier, cases: ts.CaseClause[]): ts.FunctionDeclaration { + const cursorIdent = ts.factory.createIdentifier("cursor") + return ts.factory.createFunctionDeclaration( + [modifiers.export], + undefined, + "read", + [], + [ts.factory.createParameterDeclaration([], undefined, cursorIdent, undefined, cursorType, undefined)], + ts.factory.createTypeReferenceNode(ident), + ts.factory.createBlock([ + ts.factory.createSwitchStatement( + cursorMethods.readU32(cursorIdent), + casesOrThrow(cases, "Unexpected discriminant while deserializing.") + ) + ]) + ) +} + +function makeAbstractType(id: string, types: [string: Schema.Type]) { + const ty = types[id] + const name = toPascal(ty.name) + const ident = ts.factory.createIdentifier(name) + const baseIdent = ts.factory.createIdentifier("AbstractBase") + const childTypes = Array.from(Object.entries(ty.discriminants), ([discrim, id]: [string, string]) => makeChildType(name, baseIdent, id, discrim, types)) + const cursorIdent = ts.factory.createIdentifier("cursor") + const moduleDecl = + ts.factory.createModuleDeclaration( + [modifiers.export], + ident, + ts.factory.createModuleBlock([ + makeClass([modifiers.abstract], baseIdent, [forwardToSuper(cursorIdent, cursorType)], id, types), + ts.factory.createEnumDeclaration( + [modifiers.export, modifiers.const], + "Type", + childTypes.map(child => child.enumMember) + ), + ...childTypes.map(child => child.definition), + ts.factory.createTypeAliasDeclaration( + [modifiers.export], + ident, + undefined, + ts.factory.createUnionTypeNode(childTypes.map(child => child.reference)) + ), + abstractTypeDeserializer(ident, childTypes.map(child => child.case)) + ]) + ) + const abstractTypeExport = ts.factory.createTypeAliasDeclaration( + [modifiers.export], + ident, + undefined, + ts.factory.createTypeReferenceNode(name + "." + name) + ) + console.log(printer.printNode(ts.EmitHint.Unspecified, moduleDecl, file)) + console.log(printer.printNode(ts.EmitHint.Unspecified, abstractTypeExport, file)) +} + + +// ============ +// === Main === +// ============ + +const file = ts.createSourceFile("source.ts", "", ts.ScriptTarget.ESNext, false, ts.ScriptKind.TS) +const printer = ts.createPrinter({newLine: ts.NewLineKind.LineFeed}) +const lazyObjectIdent = ts.factory.createIdentifier("LazyObject") +const nullType = ts.factory.createTypeReferenceNode("null") +const cursorFieldIdent = ts.factory.createIdentifier("lazyObjectData") +const cursorType = ts.factory.createTypeReferenceNode("Cursor") +const modifiers = { + export: ts.factory.createModifier(ts.SyntaxKind.ExportKeyword), + const: ts.factory.createModifier(ts.SyntaxKind.ConstKeyword), + readonly: ts.factory.createModifier(ts.SyntaxKind.ReadonlyKeyword), + abstract: ts.factory.createModifier(ts.SyntaxKind.AbstractKeyword), + static: ts.factory.createModifier(ts.SyntaxKind.StaticKeyword), +} as const +const cursorMethods = { + readString: primitiveReader("readString"), + readBool: primitiveReader("readBool"), + readU32: primitiveReader("readU32"), + readI32: primitiveReader("readI32"), + readU64: primitiveReader("readU64"), + readI64: primitiveReader("readI64"), + readPointer: primitiveReader("readPointer"), + readSequence: readerTransformerSized("readSequence"), + readOption: readerTransformer("readOption"), + readResult: readerTransformer2("readResult"), +} as const +const POINTER_SIZE: number = 4 + +const data: Schema = JSON.parse(fs.readFileSync(process.argv[2], 'utf8')) +for (const id in data.types) { + const ty = data.types[id] + if (ty.parent === null) { + if (Object.entries(data.types[id].discriminants).length === 0) { + const decl = makeConcreteType(id, data.types) + console.log(printer.printNode(ts.EmitHint.Unspecified, decl, file)) + } else { + makeAbstractType(id, data.types) + } + } else { + // Ignore child types; they are generated when `makeAbstractType` processes the parent. + } +} diff --git a/app/gui2/parser-codegen/src/prototype.ts b/app/gui2/parser-codegen/src/prototype.ts new file mode 100644 index 000000000000..9cbb87d5d8ff --- /dev/null +++ b/app/gui2/parser-codegen/src/prototype.ts @@ -0,0 +1,124 @@ +class LazyObject { + protected readonly blob: Uint8Array + protected readonly address: number +} + +export module Tree { + export type Tree = Ident | NamedApp + + export enum Type { + Ident = 0, + NamedApp = 1 + } + + class Base extends LazyObject { + get span(): Span { + throw new Error("TODO") + } + + children(): Iterable { + throw new Error("TODO") + } + } + + export class Ident extends Base { + readonly type: Type.Ident + + get token(): Token.Ident { + throw new Error("TODO") + } + } + + export class NamedApp extends Base { + readonly type: Type.NamedApp + + get func(): Tree { + throw new Error("TODO") + } + + get open(): Token.OpenSymbol | undefined { + throw new Error("TODO") + } + + get name(): Token.Ident { + throw new Error("TODO") + } + + get equals(): Token.Operator { + throw new Error("TODO") + } + + get arg(): Tree { + throw new Error("TODO") + } + + get close(): Token.CloseSymbol | undefined { + throw new Error("TODO") + } + } +} +export type Tree = Tree.Tree + +function switchTree(tree: Tree) { + const c = tree.type + const span = tree.span + switch (c) { + case Tree.Type.Ident: + return "ident" + case Tree.Type.NamedApp: + return "named app" + default: + const _ = c satisfies never + } +} + +export class Span extends LazyObject { + get start(): number { + throw new Error("TODO") + } + + get len(): number { + throw new Error("TODO") + } +} + +export type Token = Token.Ident | Token.Operator | Token.OpenSymbol | Token.CloseSymbol + +export module Token { + export enum Type { + Ident, + Operator, + OpenSymbol, + CloseSymbol + } + + class Base { + protected readonly blob: Uint8Array + protected readonly address: number + readonly type: Type + + get span(): Span { + throw new Error("TODO") + } + } + + export class Ident extends Base { + readonly type: Type.Ident + + get isTypeOrConstructor(): boolean { + throw new Error("TODO") + } + } + + export class Operator extends Base { + readonly type: Type.Operator + } + + export class OpenSymbol extends Base { + readonly type: Type.OpenSymbol + } + + export class CloseSymbol extends Base { + readonly type: Type.CloseSymbol + } +} diff --git a/app/gui2/parser-codegen/support/serialization.ts b/app/gui2/parser-codegen/support/serialization.ts new file mode 100644 index 000000000000..6dee32e15123 --- /dev/null +++ b/app/gui2/parser-codegen/support/serialization.ts @@ -0,0 +1,140 @@ +export class LazyObject { + protected readonly lazyObjectData: Cursor + + constructor(data: Cursor) { + this.lazyObjectData = data + } + + debug(): {} { + return {} + } +} + +export const builtin = { + Array: Array +} as const + +export class Cursor { + private readonly blob: Uint8Array + private readonly address: number + + constructor(blob: Uint8Array, address: number) { + this.blob = blob + this.address = address + } + + * readSequence( + readElement: (cursor: Cursor) => T, + elementSize: number + ): Iterable { + const data = this.readPointer() + let count = data.readU32() + let offset = 4 + while (count > 0) { + yield readElement(data.seek(offset)) + count-- + offset += elementSize + } + } + + readOption( + readElement: (cursor: Cursor) => T + ): T | null { + const discriminant = this.readU8() + switch (discriminant) { + case 0: + return null + case 1: + return readElement(this.seek(1).readPointer()) + default: + throw new Error(`Invalid Option discriminant: 0x${discriminant.toString(16)}.`) + } + } + + readResult( + readOk: (cursor: Cursor) => Ok, + readErr: (cursor: Cursor) => Err + ): Ok | Err { + const data = this.readPointer() + const discriminant = data.readU32() + switch (discriminant) { + case 0: + return readOk(data.seek(4)) + case 1: + return readErr(data.seek(4)) + default: + throw new Error(`Invalid Result discriminant: 0x${discriminant.toString(16)}.`) + } + } + + readPointer(): Cursor { + return new Cursor(this.blob, this.readU32()) + } + + readU8(): number { + return this.blob.at(this.address)! + } + + readU32(): number { + return this.readU8() + | (this.seek(1).readU8() << 8) + | (this.seek(2).readU8() << 16) + | (this.seek(3).readU8() << 24) + } + + readI32(): number { + const raw = this.readU32() + const value = raw & 0x7fff_ffff + if (value === raw) { + return value + } else { + return -value + } + } + + readU64(): number { + const lo = this.readU32() + const hi = this.seek(4).readU32() + //if (hi !== 0) { + // throw new RangeError() + //} + return lo + } + + readBool(): boolean { + const value = this.readU8() + switch (value) { + case 0: + return false + case 1: + return true + default: + throw new Error(`Invalid boolean: 0x${value.toString(16)} @ 0x${this.address.toString(16)}.`) + } + } + + readString(): string { + const data = this.readPointer() + const len = data.readU32() + const stringData = data.seek(4) + const bytes = stringData.blob.slice(stringData.address, stringData.address + len) + return new TextDecoder().decode(bytes) + } + + seek(offset: number): Cursor { + return new Cursor(this.blob, this.address + offset) + } +} + +export function debugHelper(value: any): object | null { + if (value === null) { + return null + } + if (typeof value["debug"] === "function") { + return value.debug() + } + if (typeof value[Symbol.iterator] === "function") { + return Array.from(value, debugHelper) + } + return value +} diff --git a/app/gui2/parser-codegen/tsconfig.json b/app/gui2/parser-codegen/tsconfig.json new file mode 100644 index 000000000000..ff8700519275 --- /dev/null +++ b/app/gui2/parser-codegen/tsconfig.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "module": "commonjs", + "esModuleInterop": true, + "target": "es6", + "moduleResolution": "node", + "sourceMap": true, + "outDir": "dist" + }, + "lib": ["es2015"] +} diff --git a/app/gui2/parser-codegen/tslint.json b/app/gui2/parser-codegen/tslint.json new file mode 100644 index 000000000000..32fa6e5e8d76 --- /dev/null +++ b/app/gui2/parser-codegen/tslint.json @@ -0,0 +1,9 @@ +{ + "defaultSeverity": "error", + "extends": [ + "tslint:recommended" + ], + "jsRules": {}, + "rules": {}, + "rulesDirectory": [] +} \ No newline at end of file diff --git a/app/gui2/rust-ffi/src/lib.rs b/app/gui2/rust-ffi/src/lib.rs index b9f4ae5f5b5d..90acedad6d7a 100644 --- a/app/gui2/rust-ffi/src/lib.rs +++ b/app/gui2/rust-ffi/src/lib.rs @@ -20,6 +20,12 @@ pub fn parse_to_json(code: &str) -> String { serde_json::to_string(&ast).expect("Failed to serialize AST to JSON") } +#[wasm_bindgen] +pub fn parse_to_binary(code: &str) -> Vec { + let ast = PARSER.with(|parser| parser.run(code)); + enso_parser::format::serialize(&ast, &code).expect("Failed to serialize AST to binary format") +} + #[wasm_bindgen(start)] fn main() { console_error_panic_hook::set_once(); diff --git a/lib/rust/metamodel/src/data_structures.rs b/lib/rust/metamodel/src/data_structures.rs index 655f21c1fdeb..c74ab666c3c2 100644 --- a/lib/rust/metamodel/src/data_structures.rs +++ b/lib/rust/metamodel/src/data_structures.rs @@ -160,6 +160,14 @@ impl std::ops::IndexMut<&Key> for VecMap { &mut self[*key] } } +impl<'a, T> IntoIterator for &'a VecMap { + type Item = (Key, &'a T); + type IntoIter = impl Iterator; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} /// Types used by `VecMap`. pub mod vecmap { diff --git a/lib/rust/metamodel/src/java/from_meta.rs b/lib/rust/metamodel/src/java/from_meta.rs index d5a1114ed1c2..4e9bd864bf35 100644 --- a/lib/rust/metamodel/src/java/from_meta.rs +++ b/lib/rust/metamodel/src/java/from_meta.rs @@ -9,10 +9,10 @@ //! this stage, although [`Dynamic`] methods are used so that if any classes are modified before //! the model is rendered to syntax, the generated methods will reflect the changes. -use crate::java::*; - use crate::meta; +use crate::java::*; + // ====================== diff --git a/lib/rust/metamodel/src/java/implementation.rs b/lib/rust/metamodel/src/java/implementation.rs index fdea1f6d8b9a..0588740bc601 100644 --- a/lib/rust/metamodel/src/java/implementation.rs +++ b/lib/rust/metamodel/src/java/implementation.rs @@ -11,7 +11,7 @@ use std::fmt::Write; // === Implementing Java Datatypes === // =================================== -/// Produce Java syntax implement all the types modeled in a [`TypeGraph`]. +/// Produce Java syntax implementing all the types modeled in a [`TypeGraph`]. pub fn implement(graph: &TypeGraph, package: &str) -> Vec { let mut implementations = BTreeMap::new(); for (id, class) in graph.classes.iter() { diff --git a/lib/rust/metamodel/src/java/mod.rs b/lib/rust/metamodel/src/java/mod.rs index 737a0ecb6663..90c5c3138188 100644 --- a/lib/rust/metamodel/src/java/mod.rs +++ b/lib/rust/metamodel/src/java/mod.rs @@ -1,27 +1,27 @@ //! Representation of datatype definitions in the Java typesystem. +mod from_meta; +#[cfg(feature = "graphviz")] +mod graphviz; +mod implementation; + +use crate::data_structures::VecMap; +use derive_more::Index; +use derive_more::IndexMut; +use std::collections::BTreeMap; + + // ============== // === Export === // ============== pub mod bincode; - - - -mod from_meta; -#[cfg(feature = "graphviz")] -mod graphviz; -mod implementation; pub mod syntax; pub mod transform; -use crate::data_structures::VecMap; -use derive_more::Index; -use derive_more::IndexMut; pub use from_meta::from_meta; pub use implementation::implement as to_syntax; -use std::collections::BTreeMap; @@ -46,8 +46,6 @@ pub const STRING: &str = "String"; pub type FieldId = crate::data_structures::Id; /// Identifies a Java class within a `TypeGraph`. pub type ClassId = crate::data_structures::vecmap::Key; -/// Identifier for a class whose value hasn't been set yet. -pub type UnboundClassId = crate::data_structures::vecmap::UnboundKey; diff --git a/lib/rust/metamodel/src/lib.rs b/lib/rust/metamodel/src/lib.rs index 4992f7d798be..03fb4b25bc20 100644 --- a/lib/rust/metamodel/src/lib.rs +++ b/lib/rust/metamodel/src/lib.rs @@ -7,6 +7,7 @@ //! The core modules define the metamodels, and operations on them: //! - [`rust`]: A metamodel representing data models in the Rust typesystem. //! - [`java`]: A metamodel representing data models in the Java typesystem. +//! - [`typescript`]: A metamodel representing data models in the TypeScript typesystem. //! - [`meta`]: An abstract metamodel, used to perform language-independent analysis of data models, //! and as an intermediate when translating data models between language-specific metamodels. //! @@ -45,6 +46,7 @@ // === Features === #![feature(option_get_or_insert_default)] +#![feature(type_alias_impl_trait)] // === Standard Linter Configuration === #![deny(non_ascii_idents)] #![warn(unsafe_code)] diff --git a/lib/rust/metamodel/src/meta/graphviz.rs b/lib/rust/metamodel/src/meta/graphviz.rs index 0f6a669c89e0..a2c11ad807cb 100644 --- a/lib/rust/metamodel/src/meta/graphviz.rs +++ b/lib/rust/metamodel/src/meta/graphviz.rs @@ -28,8 +28,7 @@ pub fn graph(typegraph: &TypeGraph) -> Graph { let primitive = matches!(&ty.data, Data::Primitive(_)); let label = ty.name.to_string(); graph.nodes.insert(sname.clone(), Node { primitive, node_type, label }); - let parentlike = ty.parent.iter().chain(&ty.mixins); - for id in parentlike { + if let Some(id) = ty.parent.as_ref() { let sparent = format!("{}{}", types[id].name, id); graph.edges.push((sparent.clone(), sname.clone(), EdgeType::Subtype)); } diff --git a/lib/rust/metamodel/src/meta/mod.rs b/lib/rust/metamodel/src/meta/mod.rs index ee5a471253c8..a6030385a611 100644 --- a/lib/rust/metamodel/src/meta/mod.rs +++ b/lib/rust/metamodel/src/meta/mod.rs @@ -48,8 +48,6 @@ pub struct Type { pub data: Data, /// The parent type, if any. pub parent: Option, - /// Types that this type inherits from that are not the parent. - pub mixins: Vec, /// If true, this type cannot be instantiated. pub abstract_: bool, /// If true, this type is not open to extension by children outside those defined with it. @@ -66,12 +64,11 @@ impl Type { /// Create a new datatype, with defaults for most fields. pub fn new(name: TypeName, data: Data) -> Self { let parent = Default::default(); - let mixins = Default::default(); let abstract_ = Default::default(); let closed = Default::default(); let child_field = Default::default(); let discriminants = Default::default(); - Type { name, data, parent, mixins, abstract_, closed, child_field, discriminants } + Type { name, data, parent, abstract_, closed, child_field, discriminants } } } @@ -271,6 +268,10 @@ impl TypeName { pub fn to_pascal_case(&self) -> String { self.0.to_pascal_case() } + /// Render in snake_case. + pub fn to_snake_case(&self) -> String { + self.0.to_snake_case() + } /// Append another `TypeName` to the end of `self`. See `Identifier::append`. pub fn append(&mut self, other: Self) { self.0.append(other.0) @@ -302,6 +303,13 @@ impl FieldName { ident => Some(ident), } } + /// Render in snake_case. + pub fn to_snake_case(&self) -> Option { + match self.0.to_snake_case() { + ident if ident.is_empty() => None, + ident => Some(ident), + } + } /// Append another `FieldName` to the end of `self`. See `Identifier::append`. pub fn append(&mut self, other: Self) { self.0.append(other.0) @@ -355,9 +363,6 @@ impl TypeGraph { if let Some(parent) = &mut ty.parent { rewrite(parent); } - for parent in &mut ty.mixins { - rewrite(parent); - } match &mut ty.data { Data::Struct(fields) => for field in fields { @@ -391,7 +396,6 @@ impl TypeGraph { name: _, data, parent, - mixins, abstract_: _, closed: _, child_field: _, @@ -404,7 +408,6 @@ impl TypeGraph { if let Some(parent) = parent { to_visit.insert(*parent); } - to_visit.extend(mixins); to_visit.extend(discriminants.values()); match data { Data::Struct(fields) => to_visit.extend(fields.iter().map(|field| field.type_)), diff --git a/lib/rust/parser/Cargo.toml b/lib/rust/parser/Cargo.toml index 815caa6c57e9..1c51bdfe6de9 100644 --- a/lib/rust/parser/Cargo.toml +++ b/lib/rust/parser/Cargo.toml @@ -15,7 +15,6 @@ enso-reflect = { path = "../reflect" } enso-data-structures = { path = "../data-structures" } enso-types = { path = "../types" } enso-shapely-macros = { path = "../shapely/macros" } -enso-parser-syntax-tree-visitor = { path = "src/syntax/tree/visitor" } serde = { version = "1.0", features = ["derive"] } serde_json = { workspace = true } uuid = { version = "1.1", features = ["serde"] } diff --git a/lib/rust/parser/generate-ts/Cargo.toml b/lib/rust/parser/generate-ts/Cargo.toml new file mode 100644 index 000000000000..959498a4e248 --- /dev/null +++ b/lib/rust/parser/generate-ts/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "enso-parser-generate-ts" +version = "0.1.0" +authors = ["Enso Team "] +edition = "2021" +description = "Generates TypeScript bindings and deserialization for Enso Parser AST types." +readme = "README.md" +homepage = "https://github.com/enso-org/enso" +repository = "https://github.com/enso-org/enso" +license-file = "../../LICENSE" + +[dependencies] +enso-metamodel = { path = "../../metamodel", features = ["rust"] } +enso-prelude = { path = "../../prelude" } +enso-parser = { path = ".." } +enso-reflect = { path = "../../reflect", features = ["graphviz"] } +derivative = { workspace = true } +serde = { version = "1", features = ["derive"] } +serde_json = { workspace = true } diff --git a/lib/rust/parser/generate-ts/src/lazy_deserialization.rs b/lib/rust/parser/generate-ts/src/lazy_deserialization.rs new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/lib/rust/parser/generate-ts/src/lib.rs b/lib/rust/parser/generate-ts/src/lib.rs new file mode 100644 index 000000000000..8fbe29b1cc71 --- /dev/null +++ b/lib/rust/parser/generate-ts/src/lib.rs @@ -0,0 +1,27 @@ +//! Supports generation of TypeScript types corresponding to `enso-parser`'s AST types, and testing +//! and debugging the translation process. + +// === Standard Linter Configuration === +#![deny(non_ascii_idents)] +#![warn(unsafe_code)] +#![allow(clippy::bool_to_int_with_if)] +#![allow(clippy::let_and_return)] +// === Non-Standard Linter Configuration === +#![allow(clippy::option_map_unit_fn)] +#![allow(clippy::precedence)] +#![allow(dead_code)] +#![deny(unconditional_recursion)] +#![warn(missing_copy_implementations)] +#![warn(missing_debug_implementations)] +#![warn(missing_docs)] +#![warn(trivial_casts)] +#![warn(trivial_numeric_casts)] +#![warn(unused_import_braces)] +#![warn(unused_qualifications)] + + + +// ============== +// === Export === +// ============== + diff --git a/lib/rust/parser/generate-ts/src/main.rs b/lib/rust/parser/generate-ts/src/main.rs new file mode 100644 index 000000000000..73bd4b260b52 --- /dev/null +++ b/lib/rust/parser/generate-ts/src/main.rs @@ -0,0 +1,248 @@ +//! Generate the Java types corresponding to `enso-parser`'s AST types. +//! +//! # Usage +//! +//! Generated files will be placed in the directory given as an argument: +//! ```console +//! $ enso-parser-generate-ts tree/ +//! ``` + +// === Standard Linter Configuration === +#![deny(non_ascii_idents)] +#![warn(unsafe_code)] +// === Non-Standard Linter Configuration === +#![deny(unconditional_recursion)] +#![warn(missing_copy_implementations)] +#![warn(missing_debug_implementations)] +#![warn(missing_docs)] +#![warn(trivial_casts)] +#![warn(trivial_numeric_casts)] +#![warn(unused_import_braces)] +#![warn(unused_qualifications)] + +use enso_metamodel::meta; +use enso_metamodel::rust; +use enso_reflect::Reflect; + + +// ============================= +// === TypeScript Generation === +// ============================= + +fn main() { + let ast = enso_parser::syntax::Tree::reflect(); + let (graph, _) = rust::to_meta(ast); + let schema = schema(&graph); + println!("{}", serde_json::to_string(&schema).unwrap()); +} + + +// ============== +// === Schema === +// ============== + +#[derive(serde::Serialize)] +struct Schema { + types: std::collections::HashMap, +} + +#[derive(serde::Serialize)] +#[serde(rename_all = "camelCase")] +struct Type { + name: String, + fields: Vec<(String, Field)>, + parent: Option, + discriminants: std::collections::BTreeMap, + size: usize, +} + +#[derive(serde::Serialize)] +struct Field { + r#type: TypeRef, + offset: usize, +} + +#[derive(serde::Serialize, Clone, Hash, PartialEq, Eq)] +#[serde(rename_all = "lowercase")] +#[serde(tag = "class")] +enum TypeRef { + Type { id: String }, + Primitive { r#type: Primitive }, + Sequence { r#type: Box }, + Option { r#type: Box }, + Result { r#type0: Box, r#type1: Box }, +} + +#[derive(serde::Serialize, Copy, Clone, Hash, PartialEq, Eq)] +#[serde(rename_all = "lowercase")] +enum Primitive { + Bool, + U32, + U64, + I32, + I64, + Char, + String, +} + +fn schema(graph: &meta::TypeGraph) -> Schema { + let mut next_type_id = 0; + let mut next_type_id = || { + let result = format!("type_{}", next_type_id); + next_type_id += 1; + result + }; + let mut type_refs = std::collections::HashMap::new(); + let mut type_ids = std::collections::HashMap::new(); + let mut primitives = vec![]; + // Map struct types; gather primitive types. + for (key, ty) in &graph.types { + match &ty.data { + meta::Data::Struct(_) => { + let id = next_type_id(); + type_ids.insert(key, id.clone()); + type_refs.insert(key, TypeRef::Type { id }); + } + meta::Data::Primitive(prim) => { + primitives.push((key, prim)); + } + } + } + // Convert primitive types, handling dependencies in a topological order. + while !primitives.is_empty() { + primitives.retain(|(key, prim)| { + let ty = match prim { + meta::Primitive::Bool => Some(TypeRef::Primitive { r#type: Primitive::Bool }), + meta::Primitive::U32 => Some(TypeRef::Primitive { r#type: Primitive::U32 }), + meta::Primitive::U64 => Some(TypeRef::Primitive { r#type: Primitive::U64 }), + meta::Primitive::I32 => Some(TypeRef::Primitive { r#type: Primitive::I32 }), + meta::Primitive::I64 => Some(TypeRef::Primitive { r#type: Primitive::I64 }), + meta::Primitive::Char => Some(TypeRef::Primitive { r#type: Primitive::Char }), + meta::Primitive::String => Some(TypeRef::Primitive { r#type: Primitive::String }), + meta::Primitive::Sequence(id) => + type_refs.get(id).cloned().map(|ty| TypeRef::Sequence { r#type: Box::new(ty) }), + meta::Primitive::Option(id) => + type_refs.get(id).cloned().map(|ty| TypeRef::Option { r#type: Box::new(ty) }), + meta::Primitive::Result(id0, id1) => type_refs.get(id0).cloned().and_then(|ty0| { + type_refs.get(id1).cloned().map(|ty1| TypeRef::Result { + r#type0: Box::new(ty0), + r#type1: Box::new(ty1), + }) + }), + }; + if let Some(ty) = ty { + type_refs.insert(*key, ty); + false + } else { + true + } + }); + } + let mut types: std::collections::HashMap<_, _> = graph + .types + .iter() + .filter_map(|(key, ty)| { + ty.data.as_struct().map(|fields| { + let key_to_id = |id| type_ids[id].clone(); + (key_to_id(&key), Type { + name: ty.name.to_snake_case(), + fields: fields + .iter() + .map(|f| { + let name = f.name.to_snake_case().expect("Tuples not supported."); + let r#type = type_refs[&f.type_].clone(); + let field = Field { r#type, offset: 0 }; + (name, field) + }) + .collect(), + parent: ty.parent.as_ref().map(key_to_id), + discriminants: ty + .discriminants + .iter() + .map(|(k, v)| (*k, key_to_id(v))) + .collect(), + size: 0, + }) + }) + }) + .collect(); + let mut data_size = std::collections::HashMap::new(); + let mut reference_size = std::collections::HashMap::new(); + for key in types.keys() { + let reference = TypeRef::Type { id: key.to_owned() }; + let ref_size = compute_size(reference.clone(), &types, &mut data_size); + if !types[key].discriminants.is_empty() { + reference_size.insert(reference, ref_size); + } + } + for (id, ty) in types.iter_mut() { + let mut offset = ty + .parent + .as_ref() + .map_or(0, |parent| data_size[&TypeRef::Type { id: parent.to_owned() }]); + for (_, field) in &mut ty.fields { + field.offset = offset; + offset += reference_size + .get(&field.r#type) + .copied() + .unwrap_or_else(|| data_size[&field.r#type]); + } + let reference = TypeRef::Type { id: id.to_owned() }; + ty.size = reference_size + .get(&reference) + .copied() + .unwrap_or_else(|| data_size[&reference]); + } + Schema { types } +} + +const POINTER_BYTES: usize = 4; + +/// Writes the size of the object's fields to `data_size`. Returns the size of a reference to the +/// object. +fn compute_size( + ty: TypeRef, + types: &std::collections::HashMap, + data_size: &mut std::collections::HashMap, +) -> usize { + let mut reference = None; + let size = match &ty { + // May be pointer or inline fields. + TypeRef::Type { id } => { + let ty = &types[id]; + if !ty.discriminants.is_empty() { + reference = Some(POINTER_BYTES); + } + let key = TypeRef::Type { id: id.to_owned() }; + if let Some(size) = data_size.get(&key) { + *size + } else { + let mut size = + if let Some(id) = ty.parent.clone() { + let type_ref = TypeRef::Type { id }; + compute_size(type_ref.clone(), types, data_size); + data_size[&type_ref] + } else { + 0 + }; + for (_, field) in &ty.fields { + let field_size = compute_size(field.r#type.to_owned(), types, data_size); + size += field_size; + } + size + } + } + // Pointer. + TypeRef::Primitive { r#type: Primitive::String } => POINTER_BYTES, + TypeRef::Sequence { .. } => POINTER_BYTES, + TypeRef::Result { .. } => POINTER_BYTES, + // Discriminant + pointer. + TypeRef::Option { .. } => 1 + POINTER_BYTES, + // Scalars. + TypeRef::Primitive { r#type: Primitive::Bool } => 1, + TypeRef::Primitive { r#type: Primitive::U32 | Primitive::I32 | Primitive::Char } => 4, + TypeRef::Primitive { r#type: Primitive::U64 | Primitive::I64 } => 8, + }; + data_size.insert(ty, size); + reference.unwrap_or(size) +} diff --git a/lib/rust/parser/generate-ts/src/proto.ts b/lib/rust/parser/generate-ts/src/proto.ts new file mode 100644 index 000000000000..d0c5133fbf72 --- /dev/null +++ b/lib/rust/parser/generate-ts/src/proto.ts @@ -0,0 +1,50 @@ +/** Design: + * + * # "parse" Enso code to binary format. + * # Visit nodes within blob. + * # Visitation protocol requires no allocations; visitor can process the data and allocate only the final types. + * - All visitor arguments are integers within the SMI range. + * + */ + +/* +module Enso { + function parse(text: string, id_map: Map) {} +} + +type Enso = Uint8Array + */ + +type Tree = number + +namespace Token { + export type Any = number + export type OpenSymbol = number + export type CloseSymbol = number + export type Ident = number + export type Operator = number +} + +interface Parsed { + visitTree(tree: Tree, visitor: VisitTree): void; + tokenCode(token: Token.Any): string; + tokenWhitespace(token: Token.Any): number; +} + +// Tree: Visitor implementation. +// Token: External-storage implementation. + +interface VisitTree extends VisitNamedApp {} + +interface VisitNamedApp { + visitNamedApp( + start: number, + len: number, + func: Tree, + open: Token.OpenSymbol | undefined, + name: Token.Ident, + equals: Token.Operator, + arg: Tree, + close: Token.CloseSymbol | undefined + ): void +} diff --git a/lib/rust/parser/generate-ts/src/serialization.rs b/lib/rust/parser/generate-ts/src/serialization.rs new file mode 100644 index 000000000000..e80dbbecb0d1 --- /dev/null +++ b/lib/rust/parser/generate-ts/src/serialization.rs @@ -0,0 +1,180 @@ +//! Serialization overrides for the `enso_parser` types. + +use enso_metamodel::typescript::*; + +use enso_metamodel::typescript::bincode::MapperInput; +use enso_metamodel::typescript::bincode::MaterializerInput; + + + +// ============================== +// === Derive Deserialization === +// ============================== + +// FIXME: After we have implemented a transformation from the raw `Reflect` output to a +// `rust::TypeGraph`, at which time we can assign unique `FieldId`s: We should identify +// generated fields in Java classes by starting from a `str -> rust::FieldId` query on Rust +// type data, and mapping fields analogously to `rust_to_java` for types. +const CODE_GETTER: &str = "codeRepr"; +const WHITESPACE_GETTER: &str = "getWhitespace"; +const TREE_BEGIN: &str = "fieldSpanLeftOffsetCodeReprBegin"; +const TREE_LEN: &str = "fieldSpanLeftOffsetCodeReprLen"; + +/// Derive deserialization for all types in the typegraph. +pub fn derive(graph: &mut TypeGraph, tree: ClassId, token: ClassId) { + let source = "source"; + impl_deserialize(graph, tree, token, source); + graph[token].methods.push(impl_getter(CODE_GETTER)); + graph[token].methods.push(impl_whitespace_getter(WHITESPACE_GETTER)); + graph[tree].methods.push(impl_getter(CODE_GETTER)); + graph[tree].methods.push(impl_whitespace_getter(WHITESPACE_GETTER)); +} + + +// === Deserialization Methods === + +fn impl_deserialize(graph: &mut TypeGraph, tree: ClassId, token: ClassId, source: &str) { + // Add source field to parent types. + let long = Primitive::Long { unsigned: true }; + let mut tree_start_whitespace_ = Field::primitive("startWhitespace", long); + let mut tree_start_code_ = Field::primitive("startCode", long); + let mut tree_end_code_ = Field::primitive("endCode", long); + tree_start_whitespace_.hide_in_tostring(); + tree_start_code_.hide_in_tostring(); + tree_end_code_.hide_in_tostring(); + let tree_start_whitespace = tree_start_whitespace_.id(); + let tree_start_code = tree_start_code_.id(); + let tree_end_code = tree_end_code_.id(); + graph[tree].fields.push(tree_start_whitespace_); + graph[tree].fields.push(tree_start_code_); + *graph[tree].child_field.as_mut().unwrap() += 2; + graph[tree].fields.push(tree_end_code_); + + let mut token_start_whitespace_ = Field::primitive("startWhitespace", long); + let mut token_start_code_ = Field::primitive("startCode", long); + let mut token_end_code_ = Field::primitive("endCode", long); + token_start_whitespace_.hide_in_tostring(); + token_start_code_.hide_in_tostring(); + token_end_code_.hide_in_tostring(); + let token_start_whitespace = token_start_whitespace_.id(); + let token_start_code = token_start_code_.id(); + let token_end_code = token_end_code_.id(); + let index = graph[token].child_field.unwrap(); + graph[token].fields.insert(index, token_start_whitespace_); + graph[token].fields.insert(index + 1, token_start_code_); + graph[token].fields.push(token_end_code_); + + // Add UUIDs to types + let uuid = Class::builtin("java.util.UUID", vec![]); + let uuid = graph.classes.insert(uuid); + let mut tree_id_ = Field::object("uuid", uuid, false); + tree_id_.hide_in_tostring(); + let tree_id = tree_id_.id(); + graph[tree].fields.push(tree_id_); + graph[tree].methods.push(Method::Dynamic(Dynamic::Getter(tree_id))); + + // Getters + let token_getters = [ + Dynamic::getter_named(token_start_whitespace, "getStartWhitespace"), + Dynamic::getter_named(token_start_code, "getStartCode"), + Dynamic::getter_named(token_end_code, "getEndCode"), + ]; + let tree_getters = [ + Dynamic::getter_named(tree_start_whitespace, "getStartWhitespace"), + Dynamic::getter_named(tree_start_code, "getStartCode"), + Dynamic::getter_named(tree_end_code, "getEndCode"), + ]; + graph[token].methods.extend(token_getters.map(Method::Dynamic)); + graph[tree].methods.extend(tree_getters.map(Method::Dynamic)); + + graph[tree].tostring_prefix_fields.push( + r#""\"" + source.subSequence((int)startWhitespace, (int)startCode) + "\"""#.to_string(), + ); + graph[tree] + .tostring_prefix_fields + .push(r#""\"" + source.subSequence((int)startCode, (int)endCode) + "\"""#.to_string()); + graph[token].tostring_prefix_fields.push( + r#""\"" + source.subSequence((int)startWhitespace, (int)startCode) + "\"""#.to_string(), + ); + graph[token] + .tostring_prefix_fields + .push(r#""\"" + source.subSequence((int)startCode, (int)endCode) + "\"""#.to_string()); + + let buffer = Class::builtin("CharSequence", vec![]); + let buffer = graph.classes.insert(buffer); + let mut tree_source_ = Field::object(source, buffer, true); + tree_source_.hide_in_tostring(); + let tree_source = tree_source_.id(); + graph[tree].fields.push(tree_source_); + let mut token_source_ = Field::object(source, buffer, true); + token_source_.hide_in_tostring(); + let token_source = token_source_.id(); + graph[token].fields.push(token_source_); + *graph[token].child_field.as_mut().unwrap() += 1; + + let tree_begin = graph[tree].find_field(TREE_BEGIN).unwrap().id(); + let ids: Vec<_> = graph.classes.keys().collect(); + for id in ids { + let class = &graph[id]; + let mut deserialization = + bincode::DeserializerBuilder::new(id, crate::SERIALIZATION_SUPPORT, crate::EITHER_TYPE); + if id == tree || class.parent == Some(tree) { + deserialization.materialize(tree_source, context_materializer()); + deserialization.materialize(tree_id, uuid_materializer()); + deserialization.materialize(tree_start_whitespace, start_whitespace()); + deserialization.materialize(tree_start_code, start_code_tree()); + deserialization.materialize(tree_end_code, end_code_tree()); + } + if id == token || class.parent == Some(token) { + deserialization.materialize(token_source, context_materializer()); + deserialization.materialize(token_start_whitespace, start_whitespace()); + deserialization.materialize(token_start_code, start_code_token()); + deserialization.materialize(token_end_code, end_code_token()); + } + deserialization.map(tree_begin, offset_mapper()); + let deserializer = deserialization.build(graph); + graph[id].methods.push(deserializer); + } +} + +fn offset_mapper() -> impl for<'a, 'b> Fn(MapperInput<'a, 'b>) -> String + 'static { + |MapperInput { message, value }| format!("{message}.offset({value})") +} + +fn context_materializer() -> impl for<'a> Fn(MaterializerInput<'a>) -> String + 'static { + |MaterializerInput { message }| format!("{message}.context()") +} +fn uuid_materializer() -> impl for<'a> Fn(MaterializerInput<'a>) -> String + 'static { + |MaterializerInput { message }| format!("{message}.getUuid(startCode, endCode - startCode)") +} +fn start_whitespace() -> impl for<'a> Fn(MaterializerInput<'a>) -> String + 'static { + |MaterializerInput { message }| format!("{message}.position()") +} +fn start_code_tree() -> impl for<'a> Fn(MaterializerInput<'a>) -> String + 'static { + |MaterializerInput { message }| format!("{message}.advance(fieldSpanLeftOffsetCodeUtf16)") +} +fn end_code_tree() -> impl for<'a> Fn(MaterializerInput<'a>) -> String + 'static { + |MaterializerInput { message }| format!("{message}.position()") +} +fn start_code_token() -> impl for<'a> Fn(MaterializerInput<'a>) -> String + 'static { + |MaterializerInput { message }| format!("{message}.advance(fieldLeftOffsetCodeUtf16)") +} +fn end_code_token() -> impl for<'a> Fn(MaterializerInput<'a>) -> String + 'static { + |MaterializerInput { message }| format!("{message}.advance(fieldCodeUtf16)") +} + + +// === Source Code Getters === + +fn impl_getter(name: &str) -> Method { + let mut method = syntax::Method::new(name, syntax::Type::named("String")); + method.body = + "return source.subSequence((int)startCode, (int)endCode).toString();\n".to_string(); + Method::Raw(method) +} + +fn impl_whitespace_getter(name: &str) -> Method { + let mut method = syntax::Method::new(name, syntax::Type::named("CharSequence")); + method.body = "return source.subSequence((int)startWhitespace, (int)startCode);\n".to_string(); + Method::Raw(method) +} diff --git a/lib/rust/parser/src/bin/serialize.rs b/lib/rust/parser/src/bin/serialize.rs new file mode 100644 index 000000000000..8a511bb0cbc8 --- /dev/null +++ b/lib/rust/parser/src/bin/serialize.rs @@ -0,0 +1,24 @@ +// === Features === +// === Standard Linter Configuration === +#![deny(non_ascii_idents)] +#![warn(unsafe_code)] +// === Non-Standard Linter Configuration === +#![warn(missing_copy_implementations)] +#![warn(missing_debug_implementations)] +#![warn(missing_docs)] +#![warn(trivial_casts)] +#![warn(trivial_numeric_casts)] +#![warn(unused_import_braces)] +#![warn(unused_qualifications)] + + +use std::io::Write; + +pub fn main() { + use std::io::Read; + let mut input = String::new(); + std::io::stdin().read_to_string(&mut input).unwrap(); + let ast = enso_parser::Parser::new().run(&input); + let blob = enso_parser::format::serialize(&ast, &input).unwrap(); + std::io::stdout().lock().write_all(&blob).unwrap(); +} diff --git a/lib/rust/parser/src/format.rs b/lib/rust/parser/src/format.rs new file mode 100644 index 000000000000..edb052f9c90f --- /dev/null +++ b/lib/rust/parser/src/format.rs @@ -0,0 +1,512 @@ +//! # Design +//! +//! The format produced by this module is not actually "serial", as such there is a bit of an +//! impedance mismatch using the `Serializer` trait: `serde` presents each field to the +//! serializer once, but we ultimately need to write to two different places in the output for +//! each "boxed" field (the data, and the reference to it). +//! +//! The approach used here is to maintain a stack of the fields of incomplete objects as we +//! descend in to them; when an object is completed, it is moved to the heap. This requires +//! moving each boxed object once. +//! +//! Alternatives: +//! - ⏰ Deferred: Generate a proper non-serializer with `metamodel`. This would support higher +//! performance, and a recursion-free implementation that would allow arbitrarily-deep trees. +//! - ❌ Rejected: Use the `len` hints provided by `serde` to pre-allocate objects of the correct +//! size: The requirement that every field have the same size representation would be too onerous. + +use serde::ser; +use serde::Serialize; +use std::fmt::Debug; +use std::fmt::Display; +use std::fmt::Formatter; +use serde::ser::SerializeSeq; + + +// ================= +// === Constants === +// ================= + +/// Maximum allowed nesting depth of compound objects. This is empirically determined to be reached +/// before stack overflow on supported targets. +// FIXME: WASM test required. +const RECURSION_LIMIT: usize = 1024; + + +// ================= +// === Serialize === +// ================= + +pub fn serialize<'s>(value: &crate::syntax::Tree<'s>, code: &'s str) -> Result> { + let mut serializer = Serializer::new(code.as_ptr()); + value.serialize(&mut serializer)?; + serializer.heap.append(&mut serializer.stack); + Ok(serializer.heap) +} + + +// ================== +// === Serializer === +// ================== + +/// Converts Rust values to the portable format. +#[derive(Debug, Default)] +pub struct Serializer { + /// Complete objects, located at their final addresses. + heap: Vec, + /// All the fields of currently-incomplete objects. + stack: Vec, + recursion_depth: usize, + object_depth: usize, + parent_structs: Vec, + // TODO: Subtract this from Cow `begin` fields. + base_address: usize, +} + +impl Serializer { + fn new(base: *const u8) -> Self { + Self { + heap: Default::default(), + stack: Default::default(), + recursion_depth: Default::default(), + object_depth: Default::default(), + parent_structs: Default::default(), + base_address: base as usize, + } + } + + fn object_serializer(&mut self) -> Result { + if self.recursion_depth < RECURSION_LIMIT { + self.recursion_depth += 1; + self.object_depth += 1; + let begin = self.stack.len(); + Ok(ObjectSerializer { serializer: self, begin }) + } else { + Err(Error::RecursionLimitExceeded) + } + } + + fn build_object(&mut self, begin: usize) -> Result<()> { + use serde::ser::Serializer; + self.recursion_depth -= 1; + self.object_depth -= 1; + let address = self.heap.len(); + self.heap.extend(self.stack.drain(begin..)); + self.serialize_u32(u32::try_from(address).unwrap()) + } +} + + +// ==== Object Serializer === + +/// Serializes compound types. +#[derive(Debug)] +pub struct ObjectSerializer<'a> { + serializer: &'a mut Serializer, + begin: usize, +} + +impl<'a> ObjectSerializer<'a> { + fn finish(self) -> Result<()> { + self.serializer.build_object(self.begin) + } +} + + +// ==== Parent Struct === + +/// Information for transforming a struct into a combined parent/child representation. +#[derive(Debug, Copy, Clone)] +struct ParentStruct { + object_depth_inside: usize, + begin: usize, +} + + +// ========================================== +// === Serialization Trait Implementation === +// ========================================== + +impl<'a> ser::Serializer for &'a mut Serializer { + type Ok = Ok; + type Error = Error; + + type SerializeSeq = ObjectSerializer<'a>; + type SerializeTuple = Self; + type SerializeTupleStruct = Self; + type SerializeTupleVariant = ObjectSerializer<'a>; + type SerializeMap = ObjectSerializer<'a>; + type SerializeStruct = Self; + type SerializeStructVariant = ObjectSerializer<'a>; + + fn serialize_bool(self, v: bool) -> Result<()> { + self.stack.push(v as u8); + Ok(()) + } + + fn serialize_i8(self, v: i8) -> Result<()> { + self.stack.push(v as u8); + Ok(()) + } + + fn serialize_i16(self, v: i16) -> Result<()> { + self.stack.extend_from_slice(&v.to_le_bytes()); + Ok(()) + } + + fn serialize_i32(self, v: i32) -> Result<()> { + self.stack.extend_from_slice(&v.to_le_bytes()); + Ok(()) + } + + fn serialize_i64(self, v: i64) -> Result<()> { + self.stack.extend_from_slice(&v.to_le_bytes()); + Ok(()) + } + + fn serialize_u8(self, v: u8) -> Result<()> { + self.stack.push(v); + Ok(()) + } + + fn serialize_u16(self, v: u16) -> Result<()> { + self.stack.extend_from_slice(&v.to_le_bytes()); + Ok(()) + } + + fn serialize_u32(self, v: u32) -> Result<()> { + self.stack.extend_from_slice(&v.to_le_bytes()); + Ok(()) + } + + fn serialize_u64(self, v: u64) -> Result<()> { + self.stack.extend_from_slice(&v.to_le_bytes()); + Ok(()) + } + + fn serialize_f32(self, v: f32) -> Result<()> { + self.serialize_u32(v.to_bits()) + } + + fn serialize_f64(self, v: f64) -> Result<()> { + self.serialize_u64(v.to_bits()) + } + + fn serialize_char(self, v: char) -> Result<()> { + self.serialize_u32(v.into()) + } + + fn serialize_str(self, v: &str) -> Result<()> { + self.serialize_bytes(v.as_bytes()) + } + + fn serialize_bytes(self, v: &[u8]) -> Result<()> { + let ser = self.serialize_seq(Some(v.len()))?; + ser.serializer.stack.extend_from_slice(v); + ser.finish() + } + + fn serialize_none(self) -> Result<()> { + self.serialize_u8(0)?; + self.serialize_u32(0xcdcdcdcd) + } + + fn serialize_some(self, value: &T) -> Result<()> + where T: ?Sized + Serialize { + self.serialize_u8(1)?; + let object = self.object_serializer()?; + value.serialize(&mut *object.serializer)?; + object.finish() + } + + fn serialize_unit(self) -> Result<()> { + Ok(()) + } + + fn serialize_unit_struct(self, _name: &'static str) -> Result<()> { + self.serialize_unit() + } + + fn serialize_unit_variant( + self, + _name: &'static str, + variant_index: u32, + _variant: &'static str, + ) -> Result<()> { + let object = self.object_serializer()?; + variant_index.serialize(&mut *object.serializer)?; + object.finish() + } + + fn serialize_newtype_struct(self, _name: &'static str, value: &T) -> Result<()> + where T: ?Sized + Serialize { + value.serialize(self) + } + + fn serialize_newtype_variant( + self, + name: &'static str, + variant_index: u32, + _variant: &'static str, + value: &T, + ) -> Result<()> + where + T: ?Sized + Serialize, + { + if name == "Variant" + && let Some(ancestor) = self.parent_structs.last() + && ancestor.object_depth_inside == self.object_depth { + let parent_start = ancestor.begin; + // Add the child's fields to the stack (following the parent's fields). + value.serialize(&mut *self)?; + // Build the object on the heap. + let address = self.heap.len(); + self.heap.extend_from_slice(&variant_index.to_le_bytes()); + self.heap.extend(self.stack.drain(parent_start..)); + self.serialize_u32(u32::try_from(address).unwrap())?; + } else { + let mut ser = self.object_serializer()?; + ser.serialize_element(&variant_index)?; + ser.serialize_element(value)?; + ser.finish()?; + } + Ok(()) + } + + fn serialize_seq(self, len: Option) -> Result { + let len = len.unwrap(); + let mut ser = self.object_serializer()?; + ser.serialize_element(&u32::try_from(len).unwrap())?; + Ok(ser) + } + + fn serialize_tuple(self, _len: usize) -> Result { + self.object_depth += 1; + Ok(self) + } + + fn serialize_tuple_struct( + self, + _name: &'static str, + _len: usize, + ) -> Result { + self.object_depth += 1; + Ok(self) + } + + fn serialize_tuple_variant( + self, + _name: &'static str, + variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result { + let ser = self.object_serializer()?; + variant_index.serialize(&mut *ser.serializer)?; + Ok(ser) + } + + fn serialize_map(self, len: Option) -> Result { + self.serialize_seq(len) + } + + fn serialize_struct(self, name: &'static str, _len: usize) -> Result { + self.object_depth += 1; + if matches!(name, "Tree" | "Token") { + let object_depth_inside = self.object_depth; + let begin = self.stack.len(); + self.parent_structs.push(ParentStruct { object_depth_inside, begin }); + } + Ok(self) + } + + fn serialize_struct_variant( + self, + _name: &'static str, + variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result { + let ser = self.object_serializer()?; + variant_index.serialize(&mut *ser.serializer)?; + Ok(ser) + } +} + + +// === Inline Compound Type Trait Implementations === + +impl ser::SerializeStruct for &'_ mut Serializer { + type Ok = Ok; + type Error = Error; + + fn serialize_field(&mut self, _key: &'static str, value: &T) -> Result<()> + where T: ?Sized + Serialize { + value.serialize(&mut **self) + } + + fn end(self) -> Result<()> { + if let Some(ancestor) = self.parent_structs.last() { + if ancestor.object_depth_inside == self.object_depth { + self.parent_structs.pop(); + } + } + self.object_depth -= 1; + Ok(()) + } +} + +impl ser::SerializeTuple for &'_ mut Serializer { + type Ok = Ok; + type Error = Error; + + fn serialize_element(&mut self, value: &T) -> Result<()> + where T: ?Sized + Serialize { + value.serialize(&mut **self) + } + + fn end(self) -> Result<()> { + self.object_depth -= 1; + Ok(()) + } +} + +impl ser::SerializeTupleStruct for &'_ mut Serializer { + type Ok = Ok; + type Error = Error; + + fn serialize_field(&mut self, value: &T) -> Result<()> + where T: ?Sized + Serialize { + value.serialize(&mut **self) + } + + fn end(self) -> Result<()> { + self.object_depth -= 1; + Ok(()) + } +} + + +// === Boxed Compound Type Trait Implementations === + +impl ser::SerializeStructVariant for ObjectSerializer<'_> { + type Ok = Ok; + type Error = Error; + + fn serialize_field(&mut self, _key: &'static str, value: &T) -> Result<()> + where T: ?Sized + Serialize { + value.serialize(&mut *self.serializer) + } + + fn end(self) -> Result<()> { + self.finish() + } +} + +impl SerializeSeq for ObjectSerializer<'_> { + type Ok = Ok; + type Error = Error; + + fn serialize_element(&mut self, value: &T) -> Result<()> + where T: ?Sized + Serialize { + value.serialize(&mut *self.serializer) + } + + fn end(self) -> Result<()> { + self.finish() + } +} + +impl ser::SerializeTupleVariant for ObjectSerializer<'_> { + type Ok = Ok; + type Error = Error; + + fn serialize_field(&mut self, value: &T) -> Result<()> + where T: ?Sized + Serialize { + value.serialize(&mut *self.serializer) + } + + fn end(self) -> Result<()> { + self.finish() + } +} + +impl ser::SerializeMap for ObjectSerializer<'_> { + type Ok = Ok; + type Error = Error; + + fn serialize_key(&mut self, key: &T) -> Result<()> + where T: ?Sized + Serialize { + key.serialize(&mut *self.serializer) + } + + fn serialize_value(&mut self, value: &T) -> Result<()> + where T: ?Sized + Serialize { + value.serialize(&mut *self.serializer) + } + + fn end(self) -> Result<()> { + self.finish() + } +} + + +// ==================== +// === Result Types === +// ==================== + +pub type Ok = (); + +#[derive(Debug)] +pub enum Error { + RecursionLimitExceeded, + Custom(String), +} + +impl ser::StdError for Error {} + +impl Display for Error { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + Debug::fmt(self, f) + } +} + +impl ser::Error for Error { + fn custom(msg: T) -> Self + where T: Display { + Self::Custom(msg.to_string()) + } +} + +pub type Result = std::result::Result; + + +// ============= +// === Tests === +// ============= + +#[cfg(test)] +mod test { + use serde::Serialize; + + #[test] + fn test_infinite_recursion() { + use std::rc::Rc; + use std::cell::RefCell; + /// A serializable object containing a reference to itself. + #[derive(Serialize)] + struct Cyclic { + this: RefCell>>, + } + impl Cyclic { + fn new() -> Rc { + let cyclic = Rc::new(Cyclic { this: RefCell::new(None) }); + *cyclic.this.borrow_mut() = Some(Rc::clone(&cyclic)); + cyclic + } + } + // Note that if recursion is not adequately limited the expected failure mode is aborting + // due to stack overflow. We are just checking `is_err` here for good measure. + assert!(super::serialize(&Cyclic::new(), "").is_err()); + } +} diff --git a/lib/rust/parser/src/lib.rs b/lib/rust/parser/src/lib.rs index 7b1164adab27..5a81d1323db8 100644 --- a/lib/rust/parser/src/lib.rs +++ b/lib/rust/parser/src/lib.rs @@ -77,12 +77,8 @@ #![recursion_limit = "256"] // === Features === -#![allow(incomplete_features)] #![feature(let_chains)] -#![feature(allocator_api)] -#![feature(exact_size_is_empty)] #![feature(test)] -#![feature(specialization)] #![feature(if_let_guard)] #![feature(box_patterns)] #![feature(option_get_or_insert_default)] @@ -107,6 +103,7 @@ use crate::prelude::*; + // ============== // === Export === // ============== @@ -117,7 +114,7 @@ pub mod metadata; pub mod serialization; pub mod source; pub mod syntax; - +pub mod format; /// Popular utilities, imported by most modules of this crate. @@ -129,10 +126,6 @@ pub mod prelude { pub use enso_types::traits::*; pub use enso_types::unit2::Bytes; - /// Wraps return value for functions whose implementations don't handle all cases yet. When the - /// parser is complete, this type will be eliminated. - pub type WipResult = Result; - /// Return type for functions that will only fail in case of a bug in the implementation. #[derive(Debug, Default)] pub struct ParseResult { diff --git a/lib/rust/parser/src/syntax/tree.rs b/lib/rust/parser/src/syntax/tree.rs index 6472453c0c0f..02372b37c558 100644 --- a/lib/rust/parser/src/syntax/tree.rs +++ b/lib/rust/parser/src/syntax/tree.rs @@ -6,10 +6,10 @@ use crate::syntax::*; use crate::span_builder; -use enso_parser_syntax_tree_visitor::Visitor; use enso_shapely_macros::tagged_enum; + // ============== // === Export === // ============== @@ -23,7 +23,7 @@ pub mod block; // ============ /// The Abstract Syntax Tree of the language. -#[derive(Clone, Deref, DerefMut, Eq, PartialEq, Serialize, Reflect, Deserialize)] +#[derive(Debug, Clone, Deref, DerefMut, Eq, PartialEq, Serialize, Reflect, Deserialize)] #[allow(missing_docs)] pub struct Tree<'s> { #[reflect(flatten, hide)] @@ -41,19 +41,6 @@ pub fn Tree<'s>(span: Span<'s>, variant: impl Into>) -> Tree<'s> { Tree { variant, span } } -impl<'s> Debug for Tree<'s> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let max_code_len = 30; - let ellipsis = "..."; - let mut code = self.code(); - if code.len() > max_code_len { - code = format!("{}{}", &code[..max_code_len - ellipsis.len()], ellipsis); - } - write!(f, "[{}:{}:\"{}\"] ", self.span.left_offset.visible, self.span.code_length, code)?; - Debug::fmt(&self.variant, f) - } -} - impl<'s> AsRef> for Tree<'s> { fn as_ref(&self) -> &Span<'s> { &self.span @@ -75,7 +62,7 @@ impl<'s> Default for Tree<'s> { macro_rules! with_ast_definition { ($f:ident ($($args:tt)*)) => { $f! { $($args)* /// [`Tree`] variants definition. See its docs to learn more. #[tagged_enum] - #[derive(Clone, Eq, PartialEq, Visitor, Serialize, Reflect, Deserialize)] + #[derive(Clone, Eq, PartialEq, Serialize, Reflect, Deserialize)] #[allow(clippy::large_enum_variant)] // Inefficient. Will be fixed in #182878443. #[tagged_enum(apply_attributes_to = "variants")] #[reflect(inline)] @@ -390,7 +377,7 @@ with_ast_definition!(generate_ast_definition()); // === Invalid === /// Error of parsing attached to an [`Tree`] node. -#[derive(Clone, Debug, Eq, PartialEq, Visitor, Serialize, Reflect, Deserialize)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Reflect, Deserialize)] #[allow(missing_docs)] #[reflect(transparent)] #[serde(from = "crate::serialization::Error")] @@ -424,7 +411,7 @@ impl<'s> span::Builder<'s> for Error { // === Argument blocks === /// An argument specification on its own line. -#[derive(Clone, Debug, Eq, PartialEq, Visitor, Serialize, Reflect, Deserialize)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Reflect, Deserialize)] pub struct ArgumentDefinitionLine<'s> { /// The token beginning the line. pub newline: token::Newline<'s>, @@ -442,7 +429,7 @@ impl<'s> span::Builder<'s> for ArgumentDefinitionLine<'s> { // === Text literals === /// A component of a text literal, within the quotation marks. -#[derive(Clone, Debug, Eq, PartialEq, Visitor, Serialize, Reflect, Deserialize)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Reflect, Deserialize)] pub enum TextElement<'s> { /// The text content of the literal. If it is multiline, the offset information may contain /// part of the content, after trimming appropriately. @@ -488,7 +475,7 @@ impl<'s> span::Builder<'s> for TextElement<'s> { // === Documentation === /// A documentation comment. -#[derive(Debug, Clone, Eq, PartialEq, Visitor, Serialize, Reflect, Deserialize)] +#[derive(Debug, Clone, Eq, PartialEq, Serialize, Reflect, Deserialize)] pub struct DocComment<'s> { /// The comment-initiating token. pub open: token::TextStart<'s>, @@ -529,7 +516,7 @@ impl<'s> span::Builder<'s> for DocComment<'s> { // === Number literals === -#[derive(Clone, Debug, Eq, PartialEq, Visitor, Serialize, Reflect, Deserialize)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Reflect, Deserialize)] #[allow(missing_docs)] pub struct FractionalDigits<'s> { /// The dot operator. @@ -548,7 +535,7 @@ impl<'s> span::Builder<'s> for FractionalDigits<'s> { // === Functions === /// A function argument definition. -#[derive(Clone, Debug, Eq, PartialEq, Visitor, Serialize, Reflect, Deserialize)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Reflect, Deserialize)] pub struct ArgumentDefinition<'s> { /// Opening parenthesis (outer). pub open: Option>, @@ -583,7 +570,7 @@ impl<'s> span::Builder<'s> for ArgumentDefinition<'s> { } /// A default value specification in a function argument definition. -#[derive(Clone, Debug, Eq, PartialEq, Visitor, Serialize, Reflect, Deserialize)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Reflect, Deserialize)] pub struct ArgumentDefault<'s> { /// The `=` token. pub equals: token::Operator<'s>, @@ -598,7 +585,7 @@ impl<'s> span::Builder<'s> for ArgumentDefault<'s> { } /// A type ascribed to an argument definition. -#[derive(Clone, Debug, Eq, PartialEq, Visitor, Serialize, Reflect, Deserialize)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Reflect, Deserialize)] pub struct ArgumentType<'s> { /// The `:` token. pub operator: token::Operator<'s>, @@ -617,7 +604,7 @@ impl<'s> span::Builder<'s> for ArgumentType<'s> { // === CaseOf === /// A that may contain a case-expression in a case-of expression. -#[derive(Clone, Debug, Default, Eq, PartialEq, Visitor, Serialize, Reflect, Deserialize)] +#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Reflect, Deserialize)] pub struct CaseLine<'s> { /// The token beginning the line. This will always be present, unless the first case-expression /// is on the same line as the initial case-of. @@ -644,7 +631,7 @@ impl<'s> span::Builder<'s> for CaseLine<'s> { } /// A case-expression in a case-of expression. -#[derive(Clone, Debug, Default, Eq, PartialEq, Visitor, Serialize, Reflect, Deserialize)] +#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Reflect, Deserialize)] pub struct Case<'s> { /// Documentation, if present. pub documentation: Option>, @@ -680,7 +667,7 @@ impl<'s> span::Builder<'s> for Case<'s> { pub type OperatorOrError<'s> = Result, MultipleOperatorError<'s>>; /// Error indicating multiple operators found next to each other, like `a + * b`. -#[derive(Clone, Debug, Eq, PartialEq, Visitor, Serialize, Reflect, Deserialize)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Reflect, Deserialize)] #[allow(missing_docs)] pub struct MultipleOperatorError<'s> { pub operators: NonEmptyVec>, @@ -719,7 +706,7 @@ impl<'s> NonEmptyOperatorSequence<'s> for OperatorOrError<'s> { // === MultiSegmentApp === /// A segment of [`MultiSegmentApp`], like `if cond` in the `if cond then ok else fail` expression. -#[derive(Clone, Debug, Eq, PartialEq, Visitor, Serialize, Reflect, Deserialize)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Reflect, Deserialize)] #[allow(missing_docs)] pub struct MultiSegmentAppSegment<'s> { pub header: Token<'s>, @@ -736,7 +723,7 @@ impl<'s> span::Builder<'s> for MultiSegmentAppSegment<'s> { // === Array and Tuple === /// A node following an operator. -#[derive(Clone, Debug, Eq, PartialEq, Visitor, Serialize, Reflect, Deserialize)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Reflect, Deserialize)] pub struct OperatorDelimitedTree<'s> { /// The delimiting operator. pub operator: token::Operator<'s>, @@ -1212,247 +1199,6 @@ spanless_leaf_impls!(bool); spanless_leaf_impls!(VisibleOffset); -// === TreeVisitable special cases === - -impl<'s, 'a> TreeVisitable<'s, 'a> for Tree<'s> { - fn visit>(&'a self, visitor: &mut V) { - if visitor.visit(self) { - self.variant.visit(visitor) - } - } -} - -impl<'s, 'a> TreeVisitableMut<'s, 'a> for Tree<'s> { - fn visit_mut>(&'a mut self, visitor: &mut V) { - if visitor.visit_mut(self) { - self.variant.visit_mut(visitor) - } - } -} - -impl<'s, 'a, T> TreeVisitable<'s, 'a> for Token<'s, T> {} -impl<'s, 'a, T> TreeVisitableMut<'s, 'a> for Token<'s, T> {} - - -// === SpanVisitable special cases === - -impl<'s, 'a> SpanVisitable<'s, 'a> for Tree<'s> { - fn visit_span>(&'a self, visitor: &mut V) { - if visitor.visit(span::Ref { - left_offset: &self.span.left_offset, - code_length: self.span.code_length, - }) { - self.variant.visit_span(visitor) - } - } -} - -impl<'s, 'a> SpanVisitableMut<'s, 'a> for Tree<'s> { - fn visit_span_mut>(&'a mut self, visitor: &mut V) { - if visitor.visit_mut(span::RefMut { - left_offset: &mut self.span.left_offset, - code_length: self.span.code_length, - }) { - self.variant.visit_span_mut(visitor) - } - } -} - -impl<'a, 's, T> SpanVisitable<'s, 'a> for Token<'s, T> { - fn visit_span>(&'a self, visitor: &mut V) { - let code_length = self.code.length(); - visitor.visit(span::Ref { left_offset: &self.left_offset, code_length }); - } -} - -impl<'a, 's, T> SpanVisitableMut<'s, 'a> for Token<'s, T> { - fn visit_span_mut>(&'a mut self, visitor: &mut V) { - let code_length = self.code.length(); - visitor.visit_mut(span::RefMut { left_offset: &mut self.left_offset, code_length }); - } -} - - -// === ItemVisitable special cases === - -impl<'s, 'a> ItemVisitable<'s, 'a> for Tree<'s> { - fn visit_item>(&'a self, visitor: &mut V) { - if visitor.visit_item(item::Ref::Tree(self)) { - self.variant.visit_item(visitor) - } - } -} - -impl<'s: 'a, 'a, T: 'a> ItemVisitable<'s, 'a> for Token<'s, T> -where &'a Token<'s, T>: Into> -{ - fn visit_item>(&'a self, visitor: &mut V) { - visitor.visit_item(item::Ref::Token(self.into())); - } -} - - -// === String === - -impl<'s, 'a> TreeVisitable<'s, 'a> for String {} -impl<'s, 'a> TreeVisitableMut<'s, 'a> for String {} -impl<'a, 's> SpanVisitable<'s, 'a> for String {} -impl<'a, 's> SpanVisitableMut<'s, 'a> for String {} -impl<'a, 's> ItemVisitable<'s, 'a> for String {} -impl<'s> span::Builder<'s> for String { - fn add_to_span(&mut self, span: Span<'s>) -> Span<'s> { - span - } -} - -impl<'s, 'a> TreeVisitable<'s, 'a> for Cow<'static, str> {} -impl<'s, 'a> TreeVisitableMut<'s, 'a> for Cow<'static, str> {} -impl<'a, 's> SpanVisitable<'s, 'a> for Cow<'static, str> {} -impl<'a, 's> SpanVisitableMut<'s, 'a> for Cow<'static, str> {} -impl<'a, 's> ItemVisitable<'s, 'a> for Cow<'static, str> {} -impl<'s> span::Builder<'s> for Cow<'static, str> { - fn add_to_span(&mut self, span: Span<'s>) -> Span<'s> { - span - } -} - - - -// ========================== -// === CodePrinterVisitor === -// ========================== - -/// A visitor collecting code representation of AST nodes. -#[derive(Debug, Default)] -#[allow(missing_docs)] -struct CodePrinterVisitor { - pub code: String, -} - -impl Visitor for CodePrinterVisitor {} -impl<'s, 'a> ItemVisitor<'s, 'a> for CodePrinterVisitor { - fn visit_item(&mut self, item: item::Ref<'s, 'a>) -> bool { - match item { - item::Ref::Tree(tree) => self.code.push_str(&tree.span.left_offset.code), - item::Ref::Token(token) => { - self.code.push_str(&token.left_offset.code); - self.code.push_str(token.code); - } - } - true - } -} - -impl<'s> Tree<'s> { - /// Code generator of this AST. - pub fn code(&self) -> String { - let mut visitor = CodePrinterVisitor::default(); - self.visit_item(&mut visitor); - visitor.code - } - - /// Return source code of this AST, excluding initial whitespace. - pub fn trimmed_code(&self) -> String { - let mut visitor = CodePrinterVisitor::default(); - self.variant.visit_item(&mut visitor); - visitor.code - } -} - - - -// =========================== -// === RefCollectorVisitor === -// =========================== - -/// A visitor collecting references to all [`Tree`] nodes. -#[derive(Debug, Default)] -#[allow(missing_docs)] -struct RefCollectorVisitor<'s, 'a> { - pub vec: Vec<&'a Tree<'s>>, -} - -impl<'s, 'a> Visitor for RefCollectorVisitor<'s, 'a> {} -impl<'s, 'a> TreeVisitor<'s, 'a> for RefCollectorVisitor<'s, 'a> { - fn visit(&mut self, ast: &'a Tree<'s>) -> bool { - self.vec.push(ast); - true - } -} - -impl<'s> Tree<'s> { - /// Collect references to all [`Tree`] nodes and return them in a vector. - pub fn collect_vec_ref(&self) -> Vec<&Tree<'s>> { - let mut visitor = RefCollectorVisitor::default(); - self.visit(&mut visitor); - visitor.vec - } -} - - - -// ================= -// === FnVisitor === -// ================= - -/// A visitor allowing running a function on every [`Tree`] node. -#[derive(Debug, Default)] -#[allow(missing_docs)] -pub struct FnVisitor(pub F); - -impl Visitor for FnVisitor {} -impl<'s: 'a, 'a, T, F: Fn(&'a Tree<'s>) -> T> TreeVisitor<'s, 'a> for FnVisitor { - fn visit(&mut self, ast: &'a Tree<'s>) -> bool { - (self.0)(ast); - true - } -} - -impl<'s, T, F: Fn(&mut Tree<'s>) -> T> TreeVisitorMut<'s> for FnVisitor { - fn visit_mut(&mut self, ast: &mut Tree<'s>) -> bool { - (self.0)(ast); - true - } -} - -impl<'s> Tree<'s> { - /// Map the provided function over each [`Tree`] node. The function results will be discarded. - pub fn map(&self, f: impl Fn(&Tree<'s>) -> T) { - let mut visitor = FnVisitor(f); - self.visit(&mut visitor); - } - - /// Map the provided function over each [`Tree`] node. The function results will be discarded. - pub fn map_mut(&mut self, f: impl Fn(&mut Tree<'s>) -> T) { - let mut visitor = FnVisitor(f); - self.visit_mut(&mut visitor); - } -} - - -// === ItemFnVisitor === - -impl<'s> Tree<'s> { - /// Apply the provided function to each [`Token`] or [`Tree`] that is a child of the node. - pub fn visit_items(&self, f: F) - where F: for<'a> FnMut(item::Ref<'s, 'a>) { - struct ItemFnVisitor { - f: F, - } - impl Visitor for ItemFnVisitor {} - impl<'a, 's: 'a, F> ItemVisitor<'s, 'a> for ItemFnVisitor - where F: FnMut(item::Ref<'s, 'a>) - { - fn visit_item(&mut self, item: item::Ref<'s, 'a>) -> bool { - (self.f)(item); - false - } - } - self.variant.visit_item(&mut ItemFnVisitor { f }); - } -} - - // ================= // === Traversal === diff --git a/lib/rust/parser/src/syntax/tree/block.rs b/lib/rust/parser/src/syntax/tree/block.rs index 1bd5691365b0..0b3218a6c359 100644 --- a/lib/rust/parser/src/syntax/tree/block.rs +++ b/lib/rust/parser/src/syntax/tree/block.rs @@ -12,7 +12,7 @@ use crate::syntax::token; // ============= /// A line of code. -#[derive(Debug, Clone, PartialEq, Eq, Visitor, Reflect, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Reflect, Serialize, Deserialize)] pub struct Line<'s> { /// Token ending the previous line, if any. pub newline: token::Newline<'s>, @@ -195,7 +195,7 @@ impl<'s> From> for Tree<'s> { // ====================== /// The content of a line in an operator block. -#[derive(Debug, Clone, PartialEq, Eq, Visitor, Reflect, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Reflect, Serialize, Deserialize)] pub struct OperatorBlockExpression<'s> { /// The operator at the beginning of the line. pub operator: OperatorOrError<'s>, @@ -231,7 +231,7 @@ impl<'s> span::Builder<'s> for OperatorBlockExpression<'s> { // === Operator block lines ==== /// A line in an operator block. -#[derive(Debug, Clone, PartialEq, Eq, Visitor, Reflect, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Reflect, Serialize, Deserialize)] pub struct OperatorLine<'s> { /// Token ending the previous line, if any. pub newline: token::Newline<'s>, diff --git a/lib/rust/parser/src/syntax/tree/visitor/Cargo.toml b/lib/rust/parser/src/syntax/tree/visitor/Cargo.toml deleted file mode 100644 index a4cdb3b906ff..000000000000 --- a/lib/rust/parser/src/syntax/tree/visitor/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ -[package] -name = "enso-parser-syntax-tree-visitor" -version = "0.1.0" -authors = ["Enso Team "] -edition = "2021" -description = "Enso Parser AST Visitor." -readme = "README.md" -homepage = "https://github.com/enso-org/enso" -repository = "https://github.com/enso-org/enso" -license-file = "../../LICENSE" - -[lib] -proc-macro = true - -[dependencies] -proc-macro2 = { workspace = true } -enso-macro-utils = { path = "../../../../../macro-utils" } -quote = { workspace = true } - -[dependencies.syn] -version = "1.0" -features = ['extra-traits', 'visit', 'full'] diff --git a/lib/rust/parser/src/syntax/tree/visitor/src/lib.rs b/lib/rust/parser/src/syntax/tree/visitor/src/lib.rs deleted file mode 100644 index 66979cf54f7a..000000000000 --- a/lib/rust/parser/src/syntax/tree/visitor/src/lib.rs +++ /dev/null @@ -1,181 +0,0 @@ -//! Definition of [`Visitor`] deriving. It implements the visitor pattern for [`Ast`]. - -// === Standard Linter Configuration === -#![deny(non_ascii_idents)] -#![warn(unsafe_code)] -#![allow(clippy::bool_to_int_with_if)] -#![allow(clippy::let_and_return)] -// === Non-Standard Linter Configuration === -#![allow(clippy::option_map_unit_fn)] -#![allow(clippy::precedence)] -#![allow(dead_code)] -#![deny(unconditional_recursion)] -#![warn(missing_copy_implementations)] -#![warn(missing_debug_implementations)] -#![warn(missing_docs)] -#![warn(trivial_casts)] -#![warn(trivial_numeric_casts)] -#![warn(unused_import_braces)] -#![warn(unused_qualifications)] - - - -extern crate proc_macro; - -use enso_macro_utils::field_names; -use enso_macro_utils::identifier_sequence; -use enso_macro_utils::index_sequence; -use proc_macro2::TokenStream; -use quote::quote; -use syn::Data; -use syn::DataEnum; -use syn::DataStruct; -use syn::DeriveInput; -use syn::Fields; -use syn::Variant; - - - -/// ====================== -/// === Derive Visitor === -/// ====================== -use quote::ToTokens; - -/// Implements [`TreeVisitable`], [`TreeVisitableMut`], [`SpanVisitable`], and [`SpanVisitableMut`]. -/// These traits are defined in the [`crate::ast`] module. Macros in this module hardcode the names -/// of the traits and are not implemented in a generic way because the current Rust implementation -/// does not understand generic definition. See the [`crate::ast`] module to learn more about the -/// design and the Rust compiler issue. -#[proc_macro_derive(Visitor)] -pub fn derive_visitor(input: proc_macro::TokenStream) -> proc_macro::TokenStream { - let decl = syn::parse_macro_input!(input as DeriveInput); - let ident = &decl.ident; - let (impl_generics, ty_generics, _inherent_where_clause_opt) = &decl.generics.split_for_impl(); - let body = gen_body(quote!(TreeVisitable::visit), &decl.data, false); - let body_mut = gen_body(quote!(TreeVisitableMut::visit_mut), &decl.data, true); - let body_span = gen_body(quote!(SpanVisitable::visit_span), &decl.data, false); - let body_span_mut = gen_body(quote!(SpanVisitableMut::visit_span_mut), &decl.data, true); - let body_item = gen_body(quote!(ItemVisitable::visit_item), &decl.data, false); - - let impl_generics_vec: Vec<_> = impl_generics.to_token_stream().into_iter().collect(); - let impl_generics_len = impl_generics_vec.len(); - let mut impl_generics; - if impl_generics_len > 0 { - let v: Vec<_> = impl_generics_vec.into_iter().take(impl_generics_len - 1).skip(1).collect(); - impl_generics = quote!(#(#v)*); - if !v.is_empty() { - impl_generics = quote!(#impl_generics,); - } - } else { - impl_generics = quote!('s,); - } - let impl_generics = quote!(<#impl_generics 'a>); - - let output = quote! { - impl #impl_generics TreeVisitable #impl_generics for #ident #ty_generics { - fn visit(&'a self, visitor:&mut T) { - visitor.before_visiting_children(); - #body - visitor.after_visiting_children(); - } - } - - impl #impl_generics TreeVisitableMut #impl_generics for #ident #ty_generics { - fn visit_mut>(&'a mut self, visitor:&mut T) { - visitor.before_visiting_children(); - #body_mut - visitor.after_visiting_children(); - } - } - - impl #impl_generics SpanVisitable #impl_generics for #ident #ty_generics { - fn visit_span(&'a self, visitor:&mut T) { - visitor.before_visiting_children(); - #body_span - visitor.after_visiting_children(); - } - } - - impl #impl_generics SpanVisitableMut #impl_generics for #ident #ty_generics { - fn visit_span_mut>(&'a mut self, visitor:&mut T) { - visitor.before_visiting_children(); - #body_span_mut - visitor.after_visiting_children(); - } - } - - impl #impl_generics ItemVisitable #impl_generics for #ident #ty_generics { - fn visit_item(&'a self, visitor:&mut T) { - visitor.before_visiting_children(); - #body_item - visitor.after_visiting_children(); - } - } - }; - - // #[allow(missing_docs)] - // pub trait ItemVisitable<'s, 'a> { - // fn visit_item>(&'a self, _visitor: &mut V) {} - // } - - output.into() -} - -fn gen_body(f: TokenStream, data: &Data, is_mut: bool) -> TokenStream { - match data { - Data::Struct(t) => body_for_struct(&f, t, is_mut), - Data::Enum(t) => body_for_enum(&f, t), - Data::Union(_) => panic!("Untagged union types not supported."), - } -} - -fn body_for_struct(f: &TokenStream, data: &DataStruct, is_mut: bool) -> TokenStream { - match &data.fields { - Fields::Unit => quote!({}), - Fields::Unnamed(fields) => { - let indices = index_sequence(fields.unnamed.len()); - if is_mut { - quote!(#( #f(&mut self.#indices, visitor); )*) - } else { - quote!(#( #f(&self.#indices, visitor); )*) - } - } - Fields::Named(fields) => { - let names = field_names(fields); - if is_mut { - quote!(#( #f(&mut self.#names, visitor); )*) - } else { - quote!(#( #f(&self.#names, visitor); )*) - } - } - } -} - -/// Prepares a match arm for a single variant that `clone_ref`s such value. -fn arm_for_variant(f: &TokenStream, variant: &Variant) -> TokenStream { - let variant_ident = &variant.ident; - match &variant.fields { - Fields::Unit => { - quote!(Self::#variant_ident => {}) - } - Fields::Named(fields) => { - let names = field_names(fields); - quote!(Self::#variant_ident { #(#names),* } => { - #( #f(#names, visitor); )* - }) - } - Fields::Unnamed(fields) => { - let names = identifier_sequence(fields.unnamed.len()); - quote!(Self::#variant_ident(#(#names),*) => { - #( #f(#names, visitor); )* - }) - } - } -} - -fn body_for_enum(f: &TokenStream, data: &DataEnum) -> TokenStream { - let make_arm = |variant| arm_for_variant(f, variant); - let arms = data.variants.iter().map(make_arm); - let body = quote!(match self { #(#arms)* }); - body -} From e66605118474bf601043e34b10865962b063cacc Mon Sep 17 00:00:00 2001 From: Kaz Wesley Date: Sun, 24 Sep 2023 13:58:11 +0000 Subject: [PATCH 02/44] deserializeTree --- app/gui2/parser-codegen/out/generated.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/gui2/parser-codegen/out/generated.ts b/app/gui2/parser-codegen/out/generated.ts index f10e316daf5e..ac34d9d030e7 100644 --- a/app/gui2/parser-codegen/out/generated.ts +++ b/app/gui2/parser-codegen/out/generated.ts @@ -898,3 +898,9 @@ export class ArgumentType extends LazyObject { get typeNode(): Tree { return Tree.read(this.lazyObjectData.seek(40).readPointer()); } debug(): any { return { ...super.debug(), operator: debugHelper(this.operator), typeNode: debugHelper(this.typeNode) }; } } + +function deserializeTree(data: ArrayBuffer): Tree { + const buffer = new Uint8Array(data) + const cursor = new Cursor(buffer, buffer.length - 4) + return Tree.read(cursor.readPointer()) +} From 6332acfc49c507be39af4bc6b4a83bfd6a64a32f Mon Sep 17 00:00:00 2001 From: Kaz Wesley Date: Mon, 25 Sep 2023 15:46:07 +0000 Subject: [PATCH 03/44] DataView --- app/gui2/parser-codegen/src/codegen.ts | 1 - .../parser-codegen/support/serialization.ts | 32 ++++++------------- 2 files changed, 10 insertions(+), 23 deletions(-) diff --git a/app/gui2/parser-codegen/src/codegen.ts b/app/gui2/parser-codegen/src/codegen.ts index d2b9199178bc..e6be81988f01 100644 --- a/app/gui2/parser-codegen/src/codegen.ts +++ b/app/gui2/parser-codegen/src/codegen.ts @@ -1,7 +1,6 @@ import * as ts from "typescript" import {SyntaxKind} from "typescript" import * as fs from "fs" -//import * as decoding from 'lib0/decoding' type Schema = { types: [string: Schema.Type] diff --git a/app/gui2/parser-codegen/support/serialization.ts b/app/gui2/parser-codegen/support/serialization.ts index 6dee32e15123..bb28ec38be1b 100644 --- a/app/gui2/parser-codegen/support/serialization.ts +++ b/app/gui2/parser-codegen/support/serialization.ts @@ -15,12 +15,10 @@ export const builtin = { } as const export class Cursor { - private readonly blob: Uint8Array - private readonly address: number + private readonly blob: DataView - constructor(blob: Uint8Array, address: number) { - this.blob = blob - this.address = address + constructor(buffer: ArrayBuffer, address: number) { + this.blob = new DataView(buffer, address) } * readSequence( @@ -68,28 +66,19 @@ export class Cursor { } readPointer(): Cursor { - return new Cursor(this.blob, this.readU32()) + return new Cursor(this.blob.buffer, this.readU32()) } readU8(): number { - return this.blob.at(this.address)! + return this.blob.getUint8(0)! } readU32(): number { - return this.readU8() - | (this.seek(1).readU8() << 8) - | (this.seek(2).readU8() << 16) - | (this.seek(3).readU8() << 24) + return this.blob.getUint32(0, true)! } readI32(): number { - const raw = this.readU32() - const value = raw & 0x7fff_ffff - if (value === raw) { - return value - } else { - return -value - } + return this.blob.getInt32(0, true)! } readU64(): number { @@ -109,20 +98,19 @@ export class Cursor { case 1: return true default: - throw new Error(`Invalid boolean: 0x${value.toString(16)} @ 0x${this.address.toString(16)}.`) + throw new Error(`Invalid boolean: 0x${value.toString(16)} @ 0x${this.blob.byteOffset.toString(16)}.`) } } readString(): string { const data = this.readPointer() const len = data.readU32() - const stringData = data.seek(4) - const bytes = stringData.blob.slice(stringData.address, stringData.address + len) + const bytes = data.blob.buffer.slice(data.blob.byteOffset + 4, data.blob.byteOffset + 4 + len) return new TextDecoder().decode(bytes) } seek(offset: number): Cursor { - return new Cursor(this.blob, this.address + offset) + return new Cursor(this.blob.buffer, this.blob.byteOffset + offset) } } From bcd835f0b96e2b607c28d49598bda304ec475327 Mon Sep 17 00:00:00 2001 From: Kaz Wesley Date: Mon, 25 Sep 2023 15:54:13 +0000 Subject: [PATCH 04/44] No utf8 --- lib/rust/parser/src/bin/serialize.rs | 2 +- lib/rust/parser/src/format.rs | 20 ++++++-------------- lib/rust/parser/src/source/code.rs | 7 ++++--- 3 files changed, 11 insertions(+), 18 deletions(-) diff --git a/lib/rust/parser/src/bin/serialize.rs b/lib/rust/parser/src/bin/serialize.rs index 8a511bb0cbc8..ee5f0c35680b 100644 --- a/lib/rust/parser/src/bin/serialize.rs +++ b/lib/rust/parser/src/bin/serialize.rs @@ -19,6 +19,6 @@ pub fn main() { let mut input = String::new(); std::io::stdin().read_to_string(&mut input).unwrap(); let ast = enso_parser::Parser::new().run(&input); - let blob = enso_parser::format::serialize(&ast, &input).unwrap(); + let blob = enso_parser::format::serialize(&ast).unwrap(); std::io::stdout().lock().write_all(&blob).unwrap(); } diff --git a/lib/rust/parser/src/format.rs b/lib/rust/parser/src/format.rs index edb052f9c90f..5a2271b8d1b9 100644 --- a/lib/rust/parser/src/format.rs +++ b/lib/rust/parser/src/format.rs @@ -33,12 +33,13 @@ use serde::ser::SerializeSeq; const RECURSION_LIMIT: usize = 1024; + // ================= // === Serialize === // ================= -pub fn serialize<'s>(value: &crate::syntax::Tree<'s>, code: &'s str) -> Result> { - let mut serializer = Serializer::new(code.as_ptr()); +pub fn serialize(value: T) -> Result> { + let mut serializer = Serializer::new(); value.serialize(&mut serializer)?; serializer.heap.append(&mut serializer.stack); Ok(serializer.heap) @@ -59,20 +60,11 @@ pub struct Serializer { recursion_depth: usize, object_depth: usize, parent_structs: Vec, - // TODO: Subtract this from Cow `begin` fields. - base_address: usize, } impl Serializer { - fn new(base: *const u8) -> Self { - Self { - heap: Default::default(), - stack: Default::default(), - recursion_depth: Default::default(), - object_depth: Default::default(), - parent_structs: Default::default(), - base_address: base as usize, - } + pub fn new() -> Self { + Self::default() } fn object_serializer(&mut self) -> Result { @@ -507,6 +499,6 @@ mod test { } // Note that if recursion is not adequately limited the expected failure mode is aborting // due to stack overflow. We are just checking `is_err` here for good measure. - assert!(super::serialize(&Cyclic::new(), "").is_err()); + assert!(super::serialize(&Cyclic::new()).is_err()); } } diff --git a/lib/rust/parser/src/source/code.rs b/lib/rust/parser/src/source/code.rs index fde5f6f1d66f..db6e2b927880 100644 --- a/lib/rust/parser/src/source/code.rs +++ b/lib/rust/parser/src/source/code.rs @@ -12,9 +12,8 @@ use crate::prelude::*; #[derive(Clone, Default, Eq, PartialEq, Serialize, Reflect, Deserialize, Deref)] #[allow(missing_docs)] pub struct Code<'s> { - #[serde(serialize_with = "crate::serialization::serialize_cow")] - #[serde(deserialize_with = "crate::serialization::deserialize_cow")] - #[reflect(as = "crate::serialization::Code", flatten, hide)] + #[reflect(skip)] + #[serde(skip)] #[deref] pub repr: Cow<'s, str>, #[reflect(hide)] @@ -113,6 +112,8 @@ impl<'s> AddAssign<&Code<'s>> for Code<'s> { /// The length of a [`Code`] object. #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Serialize, Reflect, Deserialize)] pub struct Length { + #[reflect(skip)] + #[serde(skip)] utf8: usize, utf16: usize, } From df3d29844d4fe88752c400a9506186fd67c5d936 Mon Sep 17 00:00:00 2001 From: Kaz Wesley Date: Tue, 26 Sep 2023 16:42:48 +0000 Subject: [PATCH 05/44] WIP --- Cargo.lock | 18 +- Cargo.toml | 2 +- app/gui2/package.json | 3 +- app/gui2/parser-codegen/out/generated.ts | 906 ------------------ app/gui2/parser-codegen/package-lock.json | 202 +--- app/gui2/parser-codegen/package.json | 17 +- app/gui2/parser-codegen/src/codegen.ts | 287 +++--- app/gui2/rust-ffi/src/lib.rs | 4 +- app/gui2/src/util/ffi.ts | 8 +- .../util/parserSupport.ts} | 0 .../parser/{generate-ts => schema}/Cargo.toml | 8 +- .../src/lazy_deserialization.rs | 0 .../src/main.rs => schema/src/lib.rs} | 34 +- .../src/lib.rs => schema/src/main.rs} | 20 +- .../{generate-ts => schema}/src/proto.ts | 0 .../src/serialization.rs | 0 lib/rust/parser/src/bin/serialize.rs | 24 - lib/rust/parser/src/format.rs | 15 +- package-lock.json | 1 + package.json | 1 + 20 files changed, 273 insertions(+), 1277 deletions(-) delete mode 100644 app/gui2/parser-codegen/out/generated.ts rename app/gui2/{parser-codegen/support/serialization.ts => src/util/parserSupport.ts} (100%) rename lib/rust/parser/{generate-ts => schema}/Cargo.toml (71%) rename lib/rust/parser/{generate-ts => schema}/src/lazy_deserialization.rs (100%) rename lib/rust/parser/{generate-ts/src/main.rs => schema/src/lib.rs} (92%) rename lib/rust/parser/{generate-ts/src/lib.rs => schema/src/main.rs} (50%) rename lib/rust/parser/{generate-ts => schema}/src/proto.ts (100%) rename lib/rust/parser/{generate-ts => schema}/src/serialization.rs (100%) delete mode 100644 lib/rust/parser/src/bin/serialize.rs diff --git a/Cargo.lock b/Cargo.lock index 9d3321006e1e..d3bad93aca54 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2390,26 +2390,24 @@ dependencies = [ ] [[package]] -name = "enso-parser-generate-ts" +name = "enso-parser-jni" version = "0.1.0" dependencies = [ - "derivative", - "enso-metamodel", + "bincode 2.0.0-rc.2", "enso-parser", "enso-prelude", - "enso-reflect", - "serde", - "serde_json", + "jni", ] [[package]] -name = "enso-parser-jni" +name = "enso-parser-schema" version = "0.1.0" dependencies = [ - "bincode 2.0.0-rc.2", + "enso-metamodel", "enso-parser", - "enso-prelude", - "jni", + "enso-reflect", + "serde", + "serde_json", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index d8a8734c8285..d5496fad1f1d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ members = [ "lib/rust/parser/doc-parser", "lib/rust/parser/jni", "lib/rust/parser/generate-java", - "lib/rust/parser/generate-ts", + "lib/rust/parser/schema", "lib/rust/parser/debug", "lib/rust/ensogl/pack", "lib/rust/profiler/data", diff --git a/app/gui2/package.json b/app/gui2/package.json index 97552b9c1e8f..fe85e977ab6b 100644 --- a/app/gui2/package.json +++ b/app/gui2/package.json @@ -19,7 +19,8 @@ "lint": "eslint .", "format": "prettier --write src/ && eslint . --fix", "build-rust-ffi": "cd rust-ffi && wasm-pack build --release --target web", - "preinstall": "npm run build-rust-ffi" + "generate-parser-bindings": "cd parser-codegen && npm install && npm run start && cd .. && rm -rf src/generated && mkdir src/generated && cp parser-codegen/generated/ast.ts src/generated/", + "preinstall": "npm run build-rust-ffi && npm run generate-parser-bindings" }, "dependencies": { "@open-rpc/client-js": "^1.8.1", diff --git a/app/gui2/parser-codegen/out/generated.ts b/app/gui2/parser-codegen/out/generated.ts deleted file mode 100644 index ac34d9d030e7..000000000000 --- a/app/gui2/parser-codegen/out/generated.ts +++ /dev/null @@ -1,906 +0,0 @@ -export class LazyObject { - protected readonly lazyObjectData: Cursor - - constructor(data: Cursor) { - this.lazyObjectData = data - } - - debug(): {} { - return {} - } -} - -export const builtin = { - Array: Array -} as const - -export class Cursor { - private readonly blob: Uint8Array - private readonly address: number - - constructor(blob: Uint8Array, address: number) { - this.blob = blob - this.address = address - } - - * readSequence( - readElement: (cursor: Cursor) => T, - elementSize: number - ): Iterable { - const data = this.readPointer() - let count = data.readU32() - let offset = 4 - while (count > 0) { - yield readElement(data.seek(offset)) - count-- - offset += elementSize - } - } - - readOption( - readElement: (cursor: Cursor) => T - ): T | null { - const discriminant = this.readU8() - switch (discriminant) { - case 0: - return null - case 1: - return readElement(this.seek(1).readPointer()) - default: - throw new Error(`Invalid Option discriminant: 0x${discriminant.toString(16)}.`) - } - } - - readResult( - readOk: (cursor: Cursor) => Ok, - readErr: (cursor: Cursor) => Err - ): Ok | Err { - const data = this.readPointer() - const discriminant = data.readU32() - switch (discriminant) { - case 0: - return readOk(data.seek(4)) - case 1: - return readErr(data.seek(4)) - default: - throw new Error(`Invalid Result discriminant: 0x${discriminant.toString(16)}.`) - } - } - - readPointer(): Cursor { - return new Cursor(this.blob, this.readU32()) - } - - readU8(): number { - return this.blob.at(this.address)! - } - - readU32(): number { - return this.readU8() - | (this.seek(1).readU8() << 8) - | (this.seek(2).readU8() << 16) - | (this.seek(3).readU8() << 24) - } - - readI32(): number { - const raw = this.readU32() - const value = raw & 0x7fff_ffff - if (value === raw) { - return value - } else { - return -value - } - } - - readU64(): number { - const lo = this.readU32() - const hi = this.seek(4).readU32() - //if (hi !== 0) { - // throw new RangeError() - //} - return lo - } - - readBool(): boolean { - const value = this.readU8() - switch (value) { - case 0: - return false - case 1: - return true - default: - throw new Error(`Invalid boolean: 0x${value.toString(16)} @ 0x${this.address.toString(16)}.`) - } - } - - readString(): string { - const data = this.readPointer() - const len = data.readU32() - const stringData = data.seek(4) - const bytes = stringData.blob.slice(stringData.address, stringData.address + len) - return new TextDecoder().decode(bytes) - } - - seek(offset: number): Cursor { - return new Cursor(this.blob, this.address + offset) - } -} - -export function debugHelper(value: any): object | null { - if (value === null) { - return null - } - if (typeof value["debug"] === "function") { - return value.debug() - } - if (typeof value[Symbol.iterator] === "function") { - return Array.from(value, debugHelper) - } - return value -} -export class DocComment extends LazyObject { - constructor(cursor: Cursor) { super(cursor); } - static read(cursor: Cursor): DocComment { return new DocComment(cursor); } - get open(): Token.TextStart { return Token.TextStart.read(this.lazyObjectData); } - get elements(): Iterable { return this.lazyObjectData.seek(40).readSequence((element: Cursor) => TextElement.read(element.readPointer()), 4); } - get newlines(): Iterable { return this.lazyObjectData.seek(44).readSequence((element: Cursor) => Token.Newline.read(element), 40); } - debug(): any { return { ...super.debug(), open: debugHelper(this.open), elements: debugHelper(this.elements), newlines: debugHelper(this.newlines) }; } -} -export module TextElement { - abstract class AbstractBase extends LazyObject { - constructor(cursor: Cursor) { super(cursor); } - debug(): any { return { ...super.debug() }; } - } - export const enum Type { - Section = 0, - Escape = 1, - Newline = 2, - Splice = 3 - } - export class Section extends AbstractBase { - readonly type: Type.Section; - constructor(cursor: Cursor) { super(cursor); this.type = Type.Section; } - static read(cursor: Cursor): Section { return new Section(cursor); } - get text(): Token.TextSection { return Token.TextSection.read(this.lazyObjectData); } - debug(): any { return { ...super.debug(), text: debugHelper(this.text) }; } - } - export class Escape extends AbstractBase { - readonly type: Type.Escape; - constructor(cursor: Cursor) { super(cursor); this.type = Type.Escape; } - static read(cursor: Cursor): Escape { return new Escape(cursor); } - get token(): Token.TextEscape { return Token.TextEscape.read(this.lazyObjectData); } - debug(): any { return { ...super.debug(), token: debugHelper(this.token) }; } - } - export class Newline extends AbstractBase { - readonly type: Type.Newline; - constructor(cursor: Cursor) { super(cursor); this.type = Type.Newline; } - static read(cursor: Cursor): Newline { return new Newline(cursor); } - get newline(): Token.Newline { return Token.Newline.read(this.lazyObjectData); } - debug(): any { return { ...super.debug(), newline: debugHelper(this.newline) }; } - } - export class Splice extends AbstractBase { - readonly type: Type.Splice; - constructor(cursor: Cursor) { super(cursor); this.type = Type.Splice; } - static read(cursor: Cursor): Splice { return new Splice(cursor); } - get open(): Token.OpenSymbol { return Token.OpenSymbol.read(this.lazyObjectData); } - get expression(): Tree | null { return this.lazyObjectData.seek(40).readOption((element: Cursor) => Tree.read(element.readPointer())); } - get close(): Token.CloseSymbol { return Token.CloseSymbol.read(this.lazyObjectData.seek(45)); } - debug(): any { return { ...super.debug(), open: debugHelper(this.open), expression: debugHelper(this.expression), close: debugHelper(this.close) }; } - } - export type TextElement = Section | Escape | Newline | Splice; - export function read(cursor: Cursor): TextElement { switch (cursor.readU32()) { - case 0: return new Section(cursor.seek(4)); - case 1: return new Escape(cursor.seek(4)); - case 2: return new Newline(cursor.seek(4)); - case 3: return new Splice(cursor.seek(4)); - default: throw new Error("Unexpected discriminant while deserializing."); - } } -} -export type TextElement = TextElement.TextElement; -export class OperatorDelimitedTree extends LazyObject { - constructor(cursor: Cursor) { super(cursor); } - static read(cursor: Cursor): OperatorDelimitedTree { return new OperatorDelimitedTree(cursor); } - get operator(): Token.Operator { return Token.Operator.read(this.lazyObjectData); } - get body(): Tree | null { return this.lazyObjectData.seek(40).readOption((element: Cursor) => Tree.read(element.readPointer())); } - debug(): any { return { ...super.debug(), operator: debugHelper(this.operator), body: debugHelper(this.body) }; } -} -export class ArgumentDefault extends LazyObject { - constructor(cursor: Cursor) { super(cursor); } - static read(cursor: Cursor): ArgumentDefault { return new ArgumentDefault(cursor); } - get equals(): Token.Operator { return Token.Operator.read(this.lazyObjectData); } - get expression(): Tree { return Tree.read(this.lazyObjectData.seek(40).readPointer()); } - debug(): any { return { ...super.debug(), equals: debugHelper(this.equals), expression: debugHelper(this.expression) }; } -} -export class ArgumentDefinition extends LazyObject { - constructor(cursor: Cursor) { super(cursor); } - static read(cursor: Cursor): ArgumentDefinition { return new ArgumentDefinition(cursor); } - get open(): Token.OpenSymbol | null { return this.lazyObjectData.readOption((element: Cursor) => Token.OpenSymbol.read(element)); } - get open2(): Token.OpenSymbol | null { return this.lazyObjectData.seek(5).readOption((element: Cursor) => Token.OpenSymbol.read(element)); } - get suspension(): Token.Operator | null { return this.lazyObjectData.seek(10).readOption((element: Cursor) => Token.Operator.read(element)); } - get pattern(): Tree { return Tree.read(this.lazyObjectData.seek(15).readPointer()); } - get typeNode(): ArgumentType | null { return this.lazyObjectData.seek(19).readOption((element: Cursor) => ArgumentType.read(element)); } - get close2(): Token.CloseSymbol | null { return this.lazyObjectData.seek(24).readOption((element: Cursor) => Token.CloseSymbol.read(element)); } - get default(): ArgumentDefault | null { return this.lazyObjectData.seek(29).readOption((element: Cursor) => ArgumentDefault.read(element)); } - get close(): Token.CloseSymbol | null { return this.lazyObjectData.seek(34).readOption((element: Cursor) => Token.CloseSymbol.read(element)); } - debug(): any { return { ...super.debug(), open: debugHelper(this.open), open2: debugHelper(this.open2), suspension: debugHelper(this.suspension), pattern: debugHelper(this.pattern), typeNode: debugHelper(this.typeNode), close2: debugHelper(this.close2), default: debugHelper(this.default), close: debugHelper(this.close) }; } -} -export module Base { - abstract class AbstractBase extends LazyObject { - constructor(cursor: Cursor) { super(cursor); } - debug(): any { return { ...super.debug() }; } - } - export const enum Type { - Binary = 0, - Octal = 1, - Hexadecimal = 2 - } - export class Binary extends AbstractBase { - readonly type: Type.Binary; - constructor(cursor: Cursor) { super(cursor); this.type = Type.Binary; } - static read(cursor: Cursor): Binary { return new Binary(cursor); } - debug(): any { return { ...super.debug() }; } - } - export class Octal extends AbstractBase { - readonly type: Type.Octal; - constructor(cursor: Cursor) { super(cursor); this.type = Type.Octal; } - static read(cursor: Cursor): Octal { return new Octal(cursor); } - debug(): any { return { ...super.debug() }; } - } - export class Hexadecimal extends AbstractBase { - readonly type: Type.Hexadecimal; - constructor(cursor: Cursor) { super(cursor); this.type = Type.Hexadecimal; } - static read(cursor: Cursor): Hexadecimal { return new Hexadecimal(cursor); } - debug(): any { return { ...super.debug() }; } - } - export type Base = Binary | Octal | Hexadecimal; - export function read(cursor: Cursor): Base { switch (cursor.readU32()) { - case 0: return new Binary(cursor.seek(4)); - case 1: return new Octal(cursor.seek(4)); - case 2: return new Hexadecimal(cursor.seek(4)); - default: throw new Error("Unexpected discriminant while deserializing."); - } } -} -export type Base = Base.Base; -export class OperatorLine extends LazyObject { - constructor(cursor: Cursor) { super(cursor); } - static read(cursor: Cursor): OperatorLine { return new OperatorLine(cursor); } - get newline(): Token.Newline { return Token.Newline.read(this.lazyObjectData); } - get expression(): OperatorBlockExpression | null { return this.lazyObjectData.seek(40).readOption((element: Cursor) => OperatorBlockExpression.read(element)); } - debug(): any { return { ...super.debug(), newline: debugHelper(this.newline), expression: debugHelper(this.expression) }; } -} -export class OperatorBlockExpression extends LazyObject { - constructor(cursor: Cursor) { super(cursor); } - static read(cursor: Cursor): OperatorBlockExpression { return new OperatorBlockExpression(cursor); } - get operator(): Token.Operator | MultipleOperatorError { return this.lazyObjectData.readResult((okData: Cursor) => Token.Operator.read(okData), (errData: Cursor) => MultipleOperatorError.read(errData)); } - get expression(): Tree { return Tree.read(this.lazyObjectData.seek(4).readPointer()); } - debug(): any { return { ...super.debug(), operator: debugHelper(this.operator), expression: debugHelper(this.expression) }; } -} -export class ArgumentDefinitionLine extends LazyObject { - constructor(cursor: Cursor) { super(cursor); } - static read(cursor: Cursor): ArgumentDefinitionLine { return new ArgumentDefinitionLine(cursor); } - get newline(): Token.Newline { return Token.Newline.read(this.lazyObjectData); } - get argument(): ArgumentDefinition | null { return this.lazyObjectData.seek(40).readOption((element: Cursor) => ArgumentDefinition.read(element)); } - debug(): any { return { ...super.debug(), newline: debugHelper(this.newline), argument: debugHelper(this.argument) }; } -} -export class Case extends LazyObject { - constructor(cursor: Cursor) { super(cursor); } - static read(cursor: Cursor): Case { return new Case(cursor); } - get documentation(): DocComment | null { return this.lazyObjectData.readOption((element: Cursor) => DocComment.read(element)); } - get pattern(): Tree | null { return this.lazyObjectData.seek(5).readOption((element: Cursor) => Tree.read(element.readPointer())); } - get arrow(): Token.Operator | null { return this.lazyObjectData.seek(10).readOption((element: Cursor) => Token.Operator.read(element)); } - get expression(): Tree | null { return this.lazyObjectData.seek(15).readOption((element: Cursor) => Tree.read(element.readPointer())); } - debug(): any { return { ...super.debug(), documentation: debugHelper(this.documentation), pattern: debugHelper(this.pattern), arrow: debugHelper(this.arrow), expression: debugHelper(this.expression) }; } -} -export module Token { - abstract class AbstractBase extends LazyObject { - constructor(cursor: Cursor) { super(cursor); } - get leftOffsetVisible(): number { return this.lazyObjectData.readU64(); } - get leftOffsetCodeReprBegin(): number { return this.lazyObjectData.seek(8).readU32(); } - get leftOffsetCodeReprLen(): number { return this.lazyObjectData.seek(12).readU32(); } - get leftOffsetCodeUtf16(): number { return this.lazyObjectData.seek(16).readU64(); } - get codeReprBegin(): number { return this.lazyObjectData.seek(24).readU32(); } - get codeReprLen(): number { return this.lazyObjectData.seek(28).readU32(); } - get codeUtf16(): number { return this.lazyObjectData.seek(32).readU64(); } - debug(): any { return { ...super.debug(), leftOffsetVisible: debugHelper(this.leftOffsetVisible), leftOffsetCodeReprBegin: debugHelper(this.leftOffsetCodeReprBegin), leftOffsetCodeReprLen: debugHelper(this.leftOffsetCodeReprLen), leftOffsetCodeUtf16: debugHelper(this.leftOffsetCodeUtf16), codeReprBegin: debugHelper(this.codeReprBegin), codeReprLen: debugHelper(this.codeReprLen), codeUtf16: debugHelper(this.codeUtf16) }; } - } - export const enum Type { - Newline = 0, - OpenSymbol = 1, - CloseSymbol = 2, - BlockStart = 3, - BlockEnd = 4, - Wildcard = 5, - AutoScope = 6, - Ident = 7, - Operator = 8, - Digits = 9, - NumberBase = 10, - TextStart = 11, - TextEnd = 12, - TextSection = 13, - TextEscape = 14, - TextInitialNewline = 15, - TextNewline = 16, - Invalid = 17 - } - export class Newline extends AbstractBase { - readonly type: Type.Newline; - constructor(cursor: Cursor) { super(cursor); this.type = Type.Newline; } - static read(cursor: Cursor): Newline { return new Newline(cursor); } - debug(): any { return { ...super.debug() }; } - } - export class OpenSymbol extends AbstractBase { - readonly type: Type.OpenSymbol; - constructor(cursor: Cursor) { super(cursor); this.type = Type.OpenSymbol; } - static read(cursor: Cursor): OpenSymbol { return new OpenSymbol(cursor); } - debug(): any { return { ...super.debug() }; } - } - export class CloseSymbol extends AbstractBase { - readonly type: Type.CloseSymbol; - constructor(cursor: Cursor) { super(cursor); this.type = Type.CloseSymbol; } - static read(cursor: Cursor): CloseSymbol { return new CloseSymbol(cursor); } - debug(): any { return { ...super.debug() }; } - } - export class BlockStart extends AbstractBase { - readonly type: Type.BlockStart; - constructor(cursor: Cursor) { super(cursor); this.type = Type.BlockStart; } - static read(cursor: Cursor): BlockStart { return new BlockStart(cursor); } - debug(): any { return { ...super.debug() }; } - } - export class BlockEnd extends AbstractBase { - readonly type: Type.BlockEnd; - constructor(cursor: Cursor) { super(cursor); this.type = Type.BlockEnd; } - static read(cursor: Cursor): BlockEnd { return new BlockEnd(cursor); } - debug(): any { return { ...super.debug() }; } - } - export class Wildcard extends AbstractBase { - readonly type: Type.Wildcard; - constructor(cursor: Cursor) { super(cursor); this.type = Type.Wildcard; } - static read(cursor: Cursor): Wildcard { return new Wildcard(cursor); } - get liftLevel(): number { return this.lazyObjectData.seek(40).readU64(); } - debug(): any { return { ...super.debug(), liftLevel: debugHelper(this.liftLevel) }; } - } - export class AutoScope extends AbstractBase { - readonly type: Type.AutoScope; - constructor(cursor: Cursor) { super(cursor); this.type = Type.AutoScope; } - static read(cursor: Cursor): AutoScope { return new AutoScope(cursor); } - debug(): any { return { ...super.debug() }; } - } - export class Ident extends AbstractBase { - readonly type: Type.Ident; - constructor(cursor: Cursor) { super(cursor); this.type = Type.Ident; } - static read(cursor: Cursor): Ident { return new Ident(cursor); } - get isFree(): boolean { return this.lazyObjectData.seek(40).readBool(); } - get liftLevel(): number { return this.lazyObjectData.seek(41).readU64(); } - get isTypeOrConstructor(): boolean { return this.lazyObjectData.seek(49).readBool(); } - get isOperatorLexically(): boolean { return this.lazyObjectData.seek(50).readBool(); } - debug(): any { return { ...super.debug(), isFree: debugHelper(this.isFree), liftLevel: debugHelper(this.liftLevel), isTypeOrConstructor: debugHelper(this.isTypeOrConstructor), isOperatorLexically: debugHelper(this.isOperatorLexically) }; } - } - export class Operator extends AbstractBase { - readonly type: Type.Operator; - constructor(cursor: Cursor) { super(cursor); this.type = Type.Operator; } - static read(cursor: Cursor): Operator { return new Operator(cursor); } - debug(): any { return { ...super.debug() }; } - } - export class Digits extends AbstractBase { - readonly type: Type.Digits; - constructor(cursor: Cursor) { super(cursor); this.type = Type.Digits; } - static read(cursor: Cursor): Digits { return new Digits(cursor); } - get base(): Base | null { return this.lazyObjectData.seek(40).readOption((element: Cursor) => Base.read(element.readPointer())); } - debug(): any { return { ...super.debug(), base: debugHelper(this.base) }; } - } - export class NumberBase extends AbstractBase { - readonly type: Type.NumberBase; - constructor(cursor: Cursor) { super(cursor); this.type = Type.NumberBase; } - static read(cursor: Cursor): NumberBase { return new NumberBase(cursor); } - debug(): any { return { ...super.debug() }; } - } - export class TextStart extends AbstractBase { - readonly type: Type.TextStart; - constructor(cursor: Cursor) { super(cursor); this.type = Type.TextStart; } - static read(cursor: Cursor): TextStart { return new TextStart(cursor); } - debug(): any { return { ...super.debug() }; } - } - export class TextEnd extends AbstractBase { - readonly type: Type.TextEnd; - constructor(cursor: Cursor) { super(cursor); this.type = Type.TextEnd; } - static read(cursor: Cursor): TextEnd { return new TextEnd(cursor); } - debug(): any { return { ...super.debug() }; } - } - export class TextSection extends AbstractBase { - readonly type: Type.TextSection; - constructor(cursor: Cursor) { super(cursor); this.type = Type.TextSection; } - static read(cursor: Cursor): TextSection { return new TextSection(cursor); } - debug(): any { return { ...super.debug() }; } - } - export class TextEscape extends AbstractBase { - readonly type: Type.TextEscape; - constructor(cursor: Cursor) { super(cursor); this.type = Type.TextEscape; } - static read(cursor: Cursor): TextEscape { return new TextEscape(cursor); } - get value(): number { return this.lazyObjectData.seek(40).readU32(); } - debug(): any { return { ...super.debug(), value: debugHelper(this.value) }; } - } - export class TextInitialNewline extends AbstractBase { - readonly type: Type.TextInitialNewline; - constructor(cursor: Cursor) { super(cursor); this.type = Type.TextInitialNewline; } - static read(cursor: Cursor): TextInitialNewline { return new TextInitialNewline(cursor); } - debug(): any { return { ...super.debug() }; } - } - export class TextNewline extends AbstractBase { - readonly type: Type.TextNewline; - constructor(cursor: Cursor) { super(cursor); this.type = Type.TextNewline; } - static read(cursor: Cursor): TextNewline { return new TextNewline(cursor); } - debug(): any { return { ...super.debug() }; } - } - export class Invalid extends AbstractBase { - readonly type: Type.Invalid; - constructor(cursor: Cursor) { super(cursor); this.type = Type.Invalid; } - static read(cursor: Cursor): Invalid { return new Invalid(cursor); } - debug(): any { return { ...super.debug() }; } - } - export type Token = Newline | OpenSymbol | CloseSymbol | BlockStart | BlockEnd | Wildcard | AutoScope | Ident | Operator | Digits | NumberBase | TextStart | TextEnd | TextSection | TextEscape | TextInitialNewline | TextNewline | Invalid; - export function read(cursor: Cursor): Token { switch (cursor.readU32()) { - case 0: return new Newline(cursor.seek(4)); - case 1: return new OpenSymbol(cursor.seek(4)); - case 2: return new CloseSymbol(cursor.seek(4)); - case 3: return new BlockStart(cursor.seek(4)); - case 4: return new BlockEnd(cursor.seek(4)); - case 5: return new Wildcard(cursor.seek(4)); - case 6: return new AutoScope(cursor.seek(4)); - case 7: return new Ident(cursor.seek(4)); - case 8: return new Operator(cursor.seek(4)); - case 9: return new Digits(cursor.seek(4)); - case 10: return new NumberBase(cursor.seek(4)); - case 11: return new TextStart(cursor.seek(4)); - case 12: return new TextEnd(cursor.seek(4)); - case 13: return new TextSection(cursor.seek(4)); - case 14: return new TextEscape(cursor.seek(4)); - case 15: return new TextInitialNewline(cursor.seek(4)); - case 16: return new TextNewline(cursor.seek(4)); - case 17: return new Invalid(cursor.seek(4)); - default: throw new Error("Unexpected discriminant while deserializing."); - } } -} -export type Token = Token.Token; -export class CaseLine extends LazyObject { - constructor(cursor: Cursor) { super(cursor); } - static read(cursor: Cursor): CaseLine { return new CaseLine(cursor); } - get newline(): Token.Newline | null { return this.lazyObjectData.readOption((element: Cursor) => Token.Newline.read(element)); } - get case(): Case | null { return this.lazyObjectData.seek(5).readOption((element: Cursor) => Case.read(element)); } - debug(): any { return { ...super.debug(), newline: debugHelper(this.newline), case: debugHelper(this.case) }; } -} -export class MultipleOperatorError extends LazyObject { - constructor(cursor: Cursor) { super(cursor); } - static read(cursor: Cursor): MultipleOperatorError { return new MultipleOperatorError(cursor); } - get operators(): Iterable { return this.lazyObjectData.readSequence((element: Cursor) => Token.Operator.read(element), 40); } - debug(): any { return { ...super.debug(), operators: debugHelper(this.operators) }; } -} -export module Tree { - abstract class AbstractBase extends LazyObject { - constructor(cursor: Cursor) { super(cursor); } - get spanLeftOffsetVisible(): number { return this.lazyObjectData.readU64(); } - get spanLeftOffsetCodeReprBegin(): number { return this.lazyObjectData.seek(8).readU32(); } - get spanLeftOffsetCodeReprLen(): number { return this.lazyObjectData.seek(12).readU32(); } - get spanLeftOffsetCodeUtf16(): number { return this.lazyObjectData.seek(16).readU64(); } - get spanCodeLengthUtf8(): number { return this.lazyObjectData.seek(24).readU64(); } - get spanCodeLengthUtf16(): number { return this.lazyObjectData.seek(32).readU64(); } - debug(): any { return { ...super.debug(), spanLeftOffsetVisible: debugHelper(this.spanLeftOffsetVisible), spanLeftOffsetCodeReprBegin: debugHelper(this.spanLeftOffsetCodeReprBegin), spanLeftOffsetCodeReprLen: debugHelper(this.spanLeftOffsetCodeReprLen), spanLeftOffsetCodeUtf16: debugHelper(this.spanLeftOffsetCodeUtf16), spanCodeLengthUtf8: debugHelper(this.spanCodeLengthUtf8), spanCodeLengthUtf16: debugHelper(this.spanCodeLengthUtf16) }; } - } - export const enum Type { - Invalid = 0, - BodyBlock = 1, - ArgumentBlockApplication = 2, - OperatorBlockApplication = 3, - Ident = 4, - Number = 5, - Wildcard = 6, - AutoScope = 7, - TextLiteral = 8, - App = 9, - NamedApp = 10, - DefaultApp = 11, - OprApp = 12, - UnaryOprApp = 13, - OprSectionBoundary = 14, - TemplateFunction = 15, - MultiSegmentApp = 16, - TypeDef = 17, - Assignment = 18, - Function = 19, - ForeignFunction = 20, - Import = 21, - Export = 22, - Group = 23, - TypeSignature = 24, - TypeAnnotated = 25, - CaseOf = 26, - Lambda = 27, - Array = 28, - Tuple = 29, - Annotated = 30, - AnnotatedBuiltin = 31, - Documented = 32, - ConstructorDefinition = 33 - } - export class Invalid extends AbstractBase { - readonly type: Type.Invalid; - constructor(cursor: Cursor) { super(cursor); this.type = Type.Invalid; } - static read(cursor: Cursor): Invalid { return new Invalid(cursor); } - get error(): string { return this.lazyObjectData.seek(40).readString(); } - get ast(): Tree { return Tree.read(this.lazyObjectData.seek(44).readPointer()); } - debug(): any { return { ...super.debug(), error: debugHelper(this.error), ast: debugHelper(this.ast) }; } - } - export class BodyBlock extends AbstractBase { - readonly type: Type.BodyBlock; - constructor(cursor: Cursor) { super(cursor); this.type = Type.BodyBlock; } - static read(cursor: Cursor): BodyBlock { return new BodyBlock(cursor); } - get statements(): Iterable { return this.lazyObjectData.seek(40).readSequence((element: Cursor) => Line.read(element), 45); } - debug(): any { return { ...super.debug(), statements: debugHelper(this.statements) }; } - } - export class ArgumentBlockApplication extends AbstractBase { - readonly type: Type.ArgumentBlockApplication; - constructor(cursor: Cursor) { super(cursor); this.type = Type.ArgumentBlockApplication; } - static read(cursor: Cursor): ArgumentBlockApplication { return new ArgumentBlockApplication(cursor); } - get lhs(): Tree | null { return this.lazyObjectData.seek(40).readOption((element: Cursor) => Tree.read(element.readPointer())); } - get arguments(): Iterable { return this.lazyObjectData.seek(45).readSequence((element: Cursor) => Line.read(element), 45); } - debug(): any { return { ...super.debug(), lhs: debugHelper(this.lhs), arguments: debugHelper(this.arguments) }; } - } - export class OperatorBlockApplication extends AbstractBase { - readonly type: Type.OperatorBlockApplication; - constructor(cursor: Cursor) { super(cursor); this.type = Type.OperatorBlockApplication; } - static read(cursor: Cursor): OperatorBlockApplication { return new OperatorBlockApplication(cursor); } - get lhs(): Tree | null { return this.lazyObjectData.seek(40).readOption((element: Cursor) => Tree.read(element.readPointer())); } - get expressions(): Iterable { return this.lazyObjectData.seek(45).readSequence((element: Cursor) => OperatorLine.read(element), 45); } - get excess(): Iterable { return this.lazyObjectData.seek(49).readSequence((element: Cursor) => Line.read(element), 45); } - debug(): any { return { ...super.debug(), lhs: debugHelper(this.lhs), expressions: debugHelper(this.expressions), excess: debugHelper(this.excess) }; } - } - export class Ident extends AbstractBase { - readonly type: Type.Ident; - constructor(cursor: Cursor) { super(cursor); this.type = Type.Ident; } - static read(cursor: Cursor): Ident { return new Ident(cursor); } - get token(): Token.Ident { return Token.Ident.read(this.lazyObjectData.seek(40)); } - debug(): any { return { ...super.debug(), token: debugHelper(this.token) }; } - } - export class Number extends AbstractBase { - readonly type: Type.Number; - constructor(cursor: Cursor) { super(cursor); this.type = Type.Number; } - static read(cursor: Cursor): Number { return new Number(cursor); } - get base(): Token.NumberBase | null { return this.lazyObjectData.seek(40).readOption((element: Cursor) => Token.NumberBase.read(element)); } - get integer(): Token.Digits | null { return this.lazyObjectData.seek(45).readOption((element: Cursor) => Token.Digits.read(element)); } - get fractionalDigits(): FractionalDigits | null { return this.lazyObjectData.seek(50).readOption((element: Cursor) => FractionalDigits.read(element)); } - debug(): any { return { ...super.debug(), base: debugHelper(this.base), integer: debugHelper(this.integer), fractionalDigits: debugHelper(this.fractionalDigits) }; } - } - export class Wildcard extends AbstractBase { - readonly type: Type.Wildcard; - constructor(cursor: Cursor) { super(cursor); this.type = Type.Wildcard; } - static read(cursor: Cursor): Wildcard { return new Wildcard(cursor); } - get token(): Token.Wildcard { return Token.Wildcard.read(this.lazyObjectData.seek(40)); } - get deBruijnIndex(): number { return this.lazyObjectData.seek(88).readI32(); } - debug(): any { return { ...super.debug(), token: debugHelper(this.token), deBruijnIndex: debugHelper(this.deBruijnIndex) }; } - } - export class AutoScope extends AbstractBase { - readonly type: Type.AutoScope; - constructor(cursor: Cursor) { super(cursor); this.type = Type.AutoScope; } - static read(cursor: Cursor): AutoScope { return new AutoScope(cursor); } - get token(): Token.AutoScope { return Token.AutoScope.read(this.lazyObjectData.seek(40)); } - debug(): any { return { ...super.debug(), token: debugHelper(this.token) }; } - } - export class TextLiteral extends AbstractBase { - readonly type: Type.TextLiteral; - constructor(cursor: Cursor) { super(cursor); this.type = Type.TextLiteral; } - static read(cursor: Cursor): TextLiteral { return new TextLiteral(cursor); } - get open(): Token.TextStart | null { return this.lazyObjectData.seek(40).readOption((element: Cursor) => Token.TextStart.read(element)); } - get newline(): Token.Newline | null { return this.lazyObjectData.seek(45).readOption((element: Cursor) => Token.Newline.read(element)); } - get elements(): Iterable { return this.lazyObjectData.seek(50).readSequence((element: Cursor) => TextElement.read(element.readPointer()), 4); } - get close(): Token.TextEnd | null { return this.lazyObjectData.seek(54).readOption((element: Cursor) => Token.TextEnd.read(element)); } - debug(): any { return { ...super.debug(), open: debugHelper(this.open), newline: debugHelper(this.newline), elements: debugHelper(this.elements), close: debugHelper(this.close) }; } - } - export class App extends AbstractBase { - readonly type: Type.App; - constructor(cursor: Cursor) { super(cursor); this.type = Type.App; } - static read(cursor: Cursor): App { return new App(cursor); } - get func(): Tree { return Tree.read(this.lazyObjectData.seek(40).readPointer()); } - get arg(): Tree { return Tree.read(this.lazyObjectData.seek(44).readPointer()); } - debug(): any { return { ...super.debug(), func: debugHelper(this.func), arg: debugHelper(this.arg) }; } - } - export class NamedApp extends AbstractBase { - readonly type: Type.NamedApp; - constructor(cursor: Cursor) { super(cursor); this.type = Type.NamedApp; } - static read(cursor: Cursor): NamedApp { return new NamedApp(cursor); } - get func(): Tree { return Tree.read(this.lazyObjectData.seek(40).readPointer()); } - get open(): Token.OpenSymbol | null { return this.lazyObjectData.seek(44).readOption((element: Cursor) => Token.OpenSymbol.read(element)); } - get name(): Token.Ident { return Token.Ident.read(this.lazyObjectData.seek(49)); } - get equals(): Token.Operator { return Token.Operator.read(this.lazyObjectData.seek(100)); } - get arg(): Tree { return Tree.read(this.lazyObjectData.seek(140).readPointer()); } - get close(): Token.CloseSymbol | null { return this.lazyObjectData.seek(144).readOption((element: Cursor) => Token.CloseSymbol.read(element)); } - debug(): any { return { ...super.debug(), func: debugHelper(this.func), open: debugHelper(this.open), name: debugHelper(this.name), equals: debugHelper(this.equals), arg: debugHelper(this.arg), close: debugHelper(this.close) }; } - } - export class DefaultApp extends AbstractBase { - readonly type: Type.DefaultApp; - constructor(cursor: Cursor) { super(cursor); this.type = Type.DefaultApp; } - static read(cursor: Cursor): DefaultApp { return new DefaultApp(cursor); } - get func(): Tree { return Tree.read(this.lazyObjectData.seek(40).readPointer()); } - get default(): Token.Ident { return Token.Ident.read(this.lazyObjectData.seek(44)); } - debug(): any { return { ...super.debug(), func: debugHelper(this.func), default: debugHelper(this.default) }; } - } - export class OprApp extends AbstractBase { - readonly type: Type.OprApp; - constructor(cursor: Cursor) { super(cursor); this.type = Type.OprApp; } - static read(cursor: Cursor): OprApp { return new OprApp(cursor); } - get lhs(): Tree | null { return this.lazyObjectData.seek(40).readOption((element: Cursor) => Tree.read(element.readPointer())); } - get opr(): Token.Operator | MultipleOperatorError { return this.lazyObjectData.seek(45).readResult((okData: Cursor) => Token.Operator.read(okData), (errData: Cursor) => MultipleOperatorError.read(errData)); } - get rhs(): Tree | null { return this.lazyObjectData.seek(49).readOption((element: Cursor) => Tree.read(element.readPointer())); } - debug(): any { return { ...super.debug(), lhs: debugHelper(this.lhs), opr: debugHelper(this.opr), rhs: debugHelper(this.rhs) }; } - } - export class UnaryOprApp extends AbstractBase { - readonly type: Type.UnaryOprApp; - constructor(cursor: Cursor) { super(cursor); this.type = Type.UnaryOprApp; } - static read(cursor: Cursor): UnaryOprApp { return new UnaryOprApp(cursor); } - get opr(): Token.Operator { return Token.Operator.read(this.lazyObjectData.seek(40)); } - get rhs(): Tree | null { return this.lazyObjectData.seek(80).readOption((element: Cursor) => Tree.read(element.readPointer())); } - debug(): any { return { ...super.debug(), opr: debugHelper(this.opr), rhs: debugHelper(this.rhs) }; } - } - export class OprSectionBoundary extends AbstractBase { - readonly type: Type.OprSectionBoundary; - constructor(cursor: Cursor) { super(cursor); this.type = Type.OprSectionBoundary; } - static read(cursor: Cursor): OprSectionBoundary { return new OprSectionBoundary(cursor); } - get arguments(): number { return this.lazyObjectData.seek(40).readU32(); } - get ast(): Tree { return Tree.read(this.lazyObjectData.seek(44).readPointer()); } - debug(): any { return { ...super.debug(), arguments: debugHelper(this.arguments), ast: debugHelper(this.ast) }; } - } - export class TemplateFunction extends AbstractBase { - readonly type: Type.TemplateFunction; - constructor(cursor: Cursor) { super(cursor); this.type = Type.TemplateFunction; } - static read(cursor: Cursor): TemplateFunction { return new TemplateFunction(cursor); } - get arguments(): number { return this.lazyObjectData.seek(40).readU32(); } - get ast(): Tree { return Tree.read(this.lazyObjectData.seek(44).readPointer()); } - debug(): any { return { ...super.debug(), arguments: debugHelper(this.arguments), ast: debugHelper(this.ast) }; } - } - export class MultiSegmentApp extends AbstractBase { - readonly type: Type.MultiSegmentApp; - constructor(cursor: Cursor) { super(cursor); this.type = Type.MultiSegmentApp; } - static read(cursor: Cursor): MultiSegmentApp { return new MultiSegmentApp(cursor); } - get segments(): Iterable { return this.lazyObjectData.seek(40).readSequence((element: Cursor) => MultiSegmentAppSegment.read(element), 9); } - debug(): any { return { ...super.debug(), segments: debugHelper(this.segments) }; } - } - export class TypeDef extends AbstractBase { - readonly type: Type.TypeDef; - constructor(cursor: Cursor) { super(cursor); this.type = Type.TypeDef; } - static read(cursor: Cursor): TypeDef { return new TypeDef(cursor); } - get keyword(): Token.Ident { return Token.Ident.read(this.lazyObjectData.seek(40)); } - get name(): Token.Ident { return Token.Ident.read(this.lazyObjectData.seek(91)); } - get params(): Iterable { return this.lazyObjectData.seek(142).readSequence((element: Cursor) => ArgumentDefinition.read(element), 39); } - get body(): Iterable { return this.lazyObjectData.seek(146).readSequence((element: Cursor) => Line.read(element), 45); } - debug(): any { return { ...super.debug(), keyword: debugHelper(this.keyword), name: debugHelper(this.name), params: debugHelper(this.params), body: debugHelper(this.body) }; } - } - export class Assignment extends AbstractBase { - readonly type: Type.Assignment; - constructor(cursor: Cursor) { super(cursor); this.type = Type.Assignment; } - static read(cursor: Cursor): Assignment { return new Assignment(cursor); } - get pattern(): Tree { return Tree.read(this.lazyObjectData.seek(40).readPointer()); } - get equals(): Token.Operator { return Token.Operator.read(this.lazyObjectData.seek(44)); } - get expr(): Tree { return Tree.read(this.lazyObjectData.seek(84).readPointer()); } - debug(): any { return { ...super.debug(), pattern: debugHelper(this.pattern), equals: debugHelper(this.equals), expr: debugHelper(this.expr) }; } - } - export class Function extends AbstractBase { - readonly type: Type.Function; - constructor(cursor: Cursor) { super(cursor); this.type = Type.Function; } - static read(cursor: Cursor): Function { return new Function(cursor); } - get name(): Tree { return Tree.read(this.lazyObjectData.seek(40).readPointer()); } - get args(): Iterable { return this.lazyObjectData.seek(44).readSequence((element: Cursor) => ArgumentDefinition.read(element), 39); } - get equals(): Token.Operator { return Token.Operator.read(this.lazyObjectData.seek(48)); } - get body(): Tree | null { return this.lazyObjectData.seek(88).readOption((element: Cursor) => Tree.read(element.readPointer())); } - debug(): any { return { ...super.debug(), name: debugHelper(this.name), args: debugHelper(this.args), equals: debugHelper(this.equals), body: debugHelper(this.body) }; } - } - export class ForeignFunction extends AbstractBase { - readonly type: Type.ForeignFunction; - constructor(cursor: Cursor) { super(cursor); this.type = Type.ForeignFunction; } - static read(cursor: Cursor): ForeignFunction { return new ForeignFunction(cursor); } - get foreign(): Token.Ident { return Token.Ident.read(this.lazyObjectData.seek(40)); } - get language(): Token.Ident { return Token.Ident.read(this.lazyObjectData.seek(91)); } - get name(): Token.Ident { return Token.Ident.read(this.lazyObjectData.seek(142)); } - get args(): Iterable { return this.lazyObjectData.seek(193).readSequence((element: Cursor) => ArgumentDefinition.read(element), 39); } - get equals(): Token.Operator { return Token.Operator.read(this.lazyObjectData.seek(197)); } - get body(): Tree { return Tree.read(this.lazyObjectData.seek(237).readPointer()); } - debug(): any { return { ...super.debug(), foreign: debugHelper(this.foreign), language: debugHelper(this.language), name: debugHelper(this.name), args: debugHelper(this.args), equals: debugHelper(this.equals), body: debugHelper(this.body) }; } - } - export class Import extends AbstractBase { - readonly type: Type.Import; - constructor(cursor: Cursor) { super(cursor); this.type = Type.Import; } - static read(cursor: Cursor): Import { return new Import(cursor); } - get polyglot(): MultiSegmentAppSegment | null { return this.lazyObjectData.seek(40).readOption((element: Cursor) => MultiSegmentAppSegment.read(element)); } - get from(): MultiSegmentAppSegment | null { return this.lazyObjectData.seek(45).readOption((element: Cursor) => MultiSegmentAppSegment.read(element)); } - get import(): MultiSegmentAppSegment { return MultiSegmentAppSegment.read(this.lazyObjectData.seek(50)); } - get all(): Token.Ident | null { return this.lazyObjectData.seek(59).readOption((element: Cursor) => Token.Ident.read(element)); } - get as(): MultiSegmentAppSegment | null { return this.lazyObjectData.seek(64).readOption((element: Cursor) => MultiSegmentAppSegment.read(element)); } - get hiding(): MultiSegmentAppSegment | null { return this.lazyObjectData.seek(69).readOption((element: Cursor) => MultiSegmentAppSegment.read(element)); } - debug(): any { return { ...super.debug(), polyglot: debugHelper(this.polyglot), from: debugHelper(this.from), import: debugHelper(this.import), all: debugHelper(this.all), as: debugHelper(this.as), hiding: debugHelper(this.hiding) }; } - } - export class Export extends AbstractBase { - readonly type: Type.Export; - constructor(cursor: Cursor) { super(cursor); this.type = Type.Export; } - static read(cursor: Cursor): Export { return new Export(cursor); } - get from(): MultiSegmentAppSegment | null { return this.lazyObjectData.seek(40).readOption((element: Cursor) => MultiSegmentAppSegment.read(element)); } - get export(): MultiSegmentAppSegment { return MultiSegmentAppSegment.read(this.lazyObjectData.seek(45)); } - get all(): Token.Ident | null { return this.lazyObjectData.seek(54).readOption((element: Cursor) => Token.Ident.read(element)); } - get as(): MultiSegmentAppSegment | null { return this.lazyObjectData.seek(59).readOption((element: Cursor) => MultiSegmentAppSegment.read(element)); } - get hiding(): MultiSegmentAppSegment | null { return this.lazyObjectData.seek(64).readOption((element: Cursor) => MultiSegmentAppSegment.read(element)); } - debug(): any { return { ...super.debug(), from: debugHelper(this.from), export: debugHelper(this.export), all: debugHelper(this.all), as: debugHelper(this.as), hiding: debugHelper(this.hiding) }; } - } - export class Group extends AbstractBase { - readonly type: Type.Group; - constructor(cursor: Cursor) { super(cursor); this.type = Type.Group; } - static read(cursor: Cursor): Group { return new Group(cursor); } - get open(): Token.OpenSymbol | null { return this.lazyObjectData.seek(40).readOption((element: Cursor) => Token.OpenSymbol.read(element)); } - get body(): Tree | null { return this.lazyObjectData.seek(45).readOption((element: Cursor) => Tree.read(element.readPointer())); } - get close(): Token.CloseSymbol | null { return this.lazyObjectData.seek(50).readOption((element: Cursor) => Token.CloseSymbol.read(element)); } - debug(): any { return { ...super.debug(), open: debugHelper(this.open), body: debugHelper(this.body), close: debugHelper(this.close) }; } - } - export class TypeSignature extends AbstractBase { - readonly type: Type.TypeSignature; - constructor(cursor: Cursor) { super(cursor); this.type = Type.TypeSignature; } - static read(cursor: Cursor): TypeSignature { return new TypeSignature(cursor); } - get variable(): Tree { return Tree.read(this.lazyObjectData.seek(40).readPointer()); } - get operator(): Token.Operator { return Token.Operator.read(this.lazyObjectData.seek(44)); } - get typeNode(): Tree { return Tree.read(this.lazyObjectData.seek(84).readPointer()); } - debug(): any { return { ...super.debug(), variable: debugHelper(this.variable), operator: debugHelper(this.operator), typeNode: debugHelper(this.typeNode) }; } - } - export class TypeAnnotated extends AbstractBase { - readonly type: Type.TypeAnnotated; - constructor(cursor: Cursor) { super(cursor); this.type = Type.TypeAnnotated; } - static read(cursor: Cursor): TypeAnnotated { return new TypeAnnotated(cursor); } - get expression(): Tree { return Tree.read(this.lazyObjectData.seek(40).readPointer()); } - get operator(): Token.Operator { return Token.Operator.read(this.lazyObjectData.seek(44)); } - get typeNode(): Tree { return Tree.read(this.lazyObjectData.seek(84).readPointer()); } - debug(): any { return { ...super.debug(), expression: debugHelper(this.expression), operator: debugHelper(this.operator), typeNode: debugHelper(this.typeNode) }; } - } - export class CaseOf extends AbstractBase { - readonly type: Type.CaseOf; - constructor(cursor: Cursor) { super(cursor); this.type = Type.CaseOf; } - static read(cursor: Cursor): CaseOf { return new CaseOf(cursor); } - get case(): Token.Ident { return Token.Ident.read(this.lazyObjectData.seek(40)); } - get expression(): Tree | null { return this.lazyObjectData.seek(91).readOption((element: Cursor) => Tree.read(element.readPointer())); } - get of(): Token.Ident { return Token.Ident.read(this.lazyObjectData.seek(96)); } - get cases(): Iterable { return this.lazyObjectData.seek(147).readSequence((element: Cursor) => CaseLine.read(element), 10); } - debug(): any { return { ...super.debug(), case: debugHelper(this.case), expression: debugHelper(this.expression), of: debugHelper(this.of), cases: debugHelper(this.cases) }; } - } - export class Lambda extends AbstractBase { - readonly type: Type.Lambda; - constructor(cursor: Cursor) { super(cursor); this.type = Type.Lambda; } - static read(cursor: Cursor): Lambda { return new Lambda(cursor); } - get operator(): Token.Operator { return Token.Operator.read(this.lazyObjectData.seek(40)); } - get arrow(): Tree | null { return this.lazyObjectData.seek(80).readOption((element: Cursor) => Tree.read(element.readPointer())); } - debug(): any { return { ...super.debug(), operator: debugHelper(this.operator), arrow: debugHelper(this.arrow) }; } - } - export class Array extends AbstractBase { - readonly type: Type.Array; - constructor(cursor: Cursor) { super(cursor); this.type = Type.Array; } - static read(cursor: Cursor): Array { return new Array(cursor); } - get left(): Token.OpenSymbol { return Token.OpenSymbol.read(this.lazyObjectData.seek(40)); } - get first(): Tree | null { return this.lazyObjectData.seek(80).readOption((element: Cursor) => Tree.read(element.readPointer())); } - get rest(): Iterable { return this.lazyObjectData.seek(85).readSequence((element: Cursor) => OperatorDelimitedTree.read(element), 45); } - get right(): Token.CloseSymbol { return Token.CloseSymbol.read(this.lazyObjectData.seek(89)); } - debug(): any { return { ...super.debug(), left: debugHelper(this.left), first: debugHelper(this.first), rest: debugHelper(this.rest), right: debugHelper(this.right) }; } - } - export class Tuple extends AbstractBase { - readonly type: Type.Tuple; - constructor(cursor: Cursor) { super(cursor); this.type = Type.Tuple; } - static read(cursor: Cursor): Tuple { return new Tuple(cursor); } - get left(): Token.OpenSymbol { return Token.OpenSymbol.read(this.lazyObjectData.seek(40)); } - get first(): Tree | null { return this.lazyObjectData.seek(80).readOption((element: Cursor) => Tree.read(element.readPointer())); } - get rest(): Iterable { return this.lazyObjectData.seek(85).readSequence((element: Cursor) => OperatorDelimitedTree.read(element), 45); } - get right(): Token.CloseSymbol { return Token.CloseSymbol.read(this.lazyObjectData.seek(89)); } - debug(): any { return { ...super.debug(), left: debugHelper(this.left), first: debugHelper(this.first), rest: debugHelper(this.rest), right: debugHelper(this.right) }; } - } - export class Annotated extends AbstractBase { - readonly type: Type.Annotated; - constructor(cursor: Cursor) { super(cursor); this.type = Type.Annotated; } - static read(cursor: Cursor): Annotated { return new Annotated(cursor); } - get token(): Token.Operator { return Token.Operator.read(this.lazyObjectData.seek(40)); } - get annotation(): Token.Ident { return Token.Ident.read(this.lazyObjectData.seek(80)); } - get argument(): Tree | null { return this.lazyObjectData.seek(131).readOption((element: Cursor) => Tree.read(element.readPointer())); } - get newlines(): Iterable { return this.lazyObjectData.seek(136).readSequence((element: Cursor) => Token.Newline.read(element), 40); } - get expression(): Tree | null { return this.lazyObjectData.seek(140).readOption((element: Cursor) => Tree.read(element.readPointer())); } - debug(): any { return { ...super.debug(), token: debugHelper(this.token), annotation: debugHelper(this.annotation), argument: debugHelper(this.argument), newlines: debugHelper(this.newlines), expression: debugHelper(this.expression) }; } - } - export class AnnotatedBuiltin extends AbstractBase { - readonly type: Type.AnnotatedBuiltin; - constructor(cursor: Cursor) { super(cursor); this.type = Type.AnnotatedBuiltin; } - static read(cursor: Cursor): AnnotatedBuiltin { return new AnnotatedBuiltin(cursor); } - get token(): Token.Operator { return Token.Operator.read(this.lazyObjectData.seek(40)); } - get annotation(): Token.Ident { return Token.Ident.read(this.lazyObjectData.seek(80)); } - get newlines(): Iterable { return this.lazyObjectData.seek(131).readSequence((element: Cursor) => Token.Newline.read(element), 40); } - get expression(): Tree | null { return this.lazyObjectData.seek(135).readOption((element: Cursor) => Tree.read(element.readPointer())); } - debug(): any { return { ...super.debug(), token: debugHelper(this.token), annotation: debugHelper(this.annotation), newlines: debugHelper(this.newlines), expression: debugHelper(this.expression) }; } - } - export class Documented extends AbstractBase { - readonly type: Type.Documented; - constructor(cursor: Cursor) { super(cursor); this.type = Type.Documented; } - static read(cursor: Cursor): Documented { return new Documented(cursor); } - get documentation(): DocComment { return DocComment.read(this.lazyObjectData.seek(40)); } - get expression(): Tree | null { return this.lazyObjectData.seek(88).readOption((element: Cursor) => Tree.read(element.readPointer())); } - debug(): any { return { ...super.debug(), documentation: debugHelper(this.documentation), expression: debugHelper(this.expression) }; } - } - export class ConstructorDefinition extends AbstractBase { - readonly type: Type.ConstructorDefinition; - constructor(cursor: Cursor) { super(cursor); this.type = Type.ConstructorDefinition; } - static read(cursor: Cursor): ConstructorDefinition { return new ConstructorDefinition(cursor); } - get ident(): Token.Ident { return Token.Ident.read(this.lazyObjectData.seek(40)); } - get arguments(): Iterable { return this.lazyObjectData.seek(91).readSequence((element: Cursor) => ArgumentDefinition.read(element), 39); } - get block(): Iterable { return this.lazyObjectData.seek(95).readSequence((element: Cursor) => ArgumentDefinitionLine.read(element), 45); } - debug(): any { return { ...super.debug(), ident: debugHelper(this.ident), arguments: debugHelper(this.arguments), block: debugHelper(this.block) }; } - } - export type Tree = Invalid | BodyBlock | ArgumentBlockApplication | OperatorBlockApplication | Ident | Number | Wildcard | AutoScope | TextLiteral | App | NamedApp | DefaultApp | OprApp | UnaryOprApp | OprSectionBoundary | TemplateFunction | MultiSegmentApp | TypeDef | Assignment | Function | ForeignFunction | Import | Export | Group | TypeSignature | TypeAnnotated | CaseOf | Lambda | Array | Tuple | Annotated | AnnotatedBuiltin | Documented | ConstructorDefinition; - export function read(cursor: Cursor): Tree { switch (cursor.readU32()) { - case 0: return new Invalid(cursor.seek(4)); - case 1: return new BodyBlock(cursor.seek(4)); - case 2: return new ArgumentBlockApplication(cursor.seek(4)); - case 3: return new OperatorBlockApplication(cursor.seek(4)); - case 4: return new Ident(cursor.seek(4)); - case 5: return new Number(cursor.seek(4)); - case 6: return new Wildcard(cursor.seek(4)); - case 7: return new AutoScope(cursor.seek(4)); - case 8: return new TextLiteral(cursor.seek(4)); - case 9: return new App(cursor.seek(4)); - case 10: return new NamedApp(cursor.seek(4)); - case 11: return new DefaultApp(cursor.seek(4)); - case 12: return new OprApp(cursor.seek(4)); - case 13: return new UnaryOprApp(cursor.seek(4)); - case 14: return new OprSectionBoundary(cursor.seek(4)); - case 15: return new TemplateFunction(cursor.seek(4)); - case 16: return new MultiSegmentApp(cursor.seek(4)); - case 17: return new TypeDef(cursor.seek(4)); - case 18: return new Assignment(cursor.seek(4)); - case 19: return new Function(cursor.seek(4)); - case 20: return new ForeignFunction(cursor.seek(4)); - case 21: return new Import(cursor.seek(4)); - case 22: return new Export(cursor.seek(4)); - case 23: return new Group(cursor.seek(4)); - case 24: return new TypeSignature(cursor.seek(4)); - case 25: return new TypeAnnotated(cursor.seek(4)); - case 26: return new CaseOf(cursor.seek(4)); - case 27: return new Lambda(cursor.seek(4)); - case 28: return new Array(cursor.seek(4)); - case 29: return new Tuple(cursor.seek(4)); - case 30: return new Annotated(cursor.seek(4)); - case 31: return new AnnotatedBuiltin(cursor.seek(4)); - case 32: return new Documented(cursor.seek(4)); - case 33: return new ConstructorDefinition(cursor.seek(4)); - default: throw new Error("Unexpected discriminant while deserializing."); - } } -} -export type Tree = Tree.Tree; -export class FractionalDigits extends LazyObject { - constructor(cursor: Cursor) { super(cursor); } - static read(cursor: Cursor): FractionalDigits { return new FractionalDigits(cursor); } - get dot(): Token.Operator { return Token.Operator.read(this.lazyObjectData); } - get digits(): Token.Digits { return Token.Digits.read(this.lazyObjectData.seek(40)); } - debug(): any { return { ...super.debug(), dot: debugHelper(this.dot), digits: debugHelper(this.digits) }; } -} -export class MultiSegmentAppSegment extends LazyObject { - constructor(cursor: Cursor) { super(cursor); } - static read(cursor: Cursor): MultiSegmentAppSegment { return new MultiSegmentAppSegment(cursor); } - get header(): Token { return Token.read(this.lazyObjectData.readPointer()); } - get body(): Tree | null { return this.lazyObjectData.seek(4).readOption((element: Cursor) => Tree.read(element.readPointer())); } - debug(): any { return { ...super.debug(), header: debugHelper(this.header), body: debugHelper(this.body) }; } -} -export class Line extends LazyObject { - constructor(cursor: Cursor) { super(cursor); } - static read(cursor: Cursor): Line { return new Line(cursor); } - get newline(): Token.Newline { return Token.Newline.read(this.lazyObjectData); } - get expression(): Tree | null { return this.lazyObjectData.seek(40).readOption((element: Cursor) => Tree.read(element.readPointer())); } - debug(): any { return { ...super.debug(), newline: debugHelper(this.newline), expression: debugHelper(this.expression) }; } -} -export class ArgumentType extends LazyObject { - constructor(cursor: Cursor) { super(cursor); } - static read(cursor: Cursor): ArgumentType { return new ArgumentType(cursor); } - get operator(): Token.Operator { return Token.Operator.read(this.lazyObjectData); } - get typeNode(): Tree { return Tree.read(this.lazyObjectData.seek(40).readPointer()); } - debug(): any { return { ...super.debug(), operator: debugHelper(this.operator), typeNode: debugHelper(this.typeNode) }; } -} - -function deserializeTree(data: ArrayBuffer): Tree { - const buffer = new Uint8Array(data) - const cursor = new Cursor(buffer, buffer.length - 4) - return Tree.read(cursor.readPointer()) -} diff --git a/app/gui2/parser-codegen/package-lock.json b/app/gui2/parser-codegen/package-lock.json index d1203d9214fb..7cef63947ded 100644 --- a/app/gui2/parser-codegen/package-lock.json +++ b/app/gui2/parser-codegen/package-lock.json @@ -1,16 +1,13 @@ { - "name": "parser-codegen", + "name": "enso-parser-codegen", "version": "1.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "parser-codegen", + "name": "enso-parser-codegen", "version": "1.0.0", - "license": "ISC", - "dependencies": { - "nodemon": "^3.0.1" - }, + "hasInstallScript": true, "devDependencies": { "@babel/cli": "^7.22.15", "@babel/core": "^7.22.20", @@ -1796,11 +1793,6 @@ "dev": true, "optional": true }, - "node_modules/abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" - }, "node_modules/ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", @@ -1817,6 +1809,8 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "optional": true, "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -1932,12 +1926,15 @@ "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true }, "node_modules/binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "optional": true, "engines": { "node": ">=8" } @@ -1946,6 +1943,7 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -1955,6 +1953,8 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "optional": true, "dependencies": { "fill-range": "^7.0.1" }, @@ -2051,12 +2051,14 @@ "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, "funding": [ { "type": "individual", "url": "https://paulmillr.com/funding/" } ], + "optional": true, "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -2120,7 +2122,8 @@ "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true }, "node_modules/convert-source-map": { "version": "1.9.0", @@ -2327,6 +2330,8 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "optional": true, "dependencies": { "to-regex-range": "^5.0.1" }, @@ -2385,6 +2390,7 @@ "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, "hasInstallScript": true, "optional": true, "os": [ @@ -2491,6 +2497,8 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "optional": true, "dependencies": { "is-glob": "^4.0.1" }, @@ -2559,6 +2567,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, "engines": { "node": ">=4" } @@ -2626,11 +2635,6 @@ "node": ">=0.10.0" } }, - "node_modules/ignore-by-default": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", - "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==" - }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -2691,6 +2695,8 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "optional": true, "dependencies": { "binary-extensions": "^2.0.0" }, @@ -2757,6 +2763,8 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "optional": true, "engines": { "node": ">=0.10.0" } @@ -2765,6 +2773,8 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "optional": true, "dependencies": { "is-extglob": "^2.1.1" }, @@ -2788,6 +2798,8 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "optional": true, "engines": { "node": ">=0.12.0" } @@ -3012,6 +3024,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -3022,7 +3035,8 @@ "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true }, "node_modules/node-environment-flags": { "version": "1.0.6", @@ -3049,89 +3063,12 @@ "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==", "dev": true }, - "node_modules/nodemon": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.0.1.tgz", - "integrity": "sha512-g9AZ7HmkhQkqXkRc20w+ZfQ73cHLbE8hnPbtaFbFtCumZsjyMhKk9LajQ07U5Ux28lvFjZ5X7HvWR1xzU8jHVw==", - "dependencies": { - "chokidar": "^3.5.2", - "debug": "^3.2.7", - "ignore-by-default": "^1.0.1", - "minimatch": "^3.1.2", - "pstree.remy": "^1.1.8", - "semver": "^7.5.3", - "simple-update-notifier": "^2.0.0", - "supports-color": "^5.5.0", - "touch": "^3.1.0", - "undefsafe": "^2.0.5" - }, - "bin": { - "nodemon": "bin/nodemon.js" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/nodemon" - } - }, - "node_modules/nodemon/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/nodemon/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/nodemon/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/nodemon/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "node_modules/nopt": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", - "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", - "dependencies": { - "abbrev": "1" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": "*" - } - }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "optional": true, "engines": { "node": ">=0.10.0" } @@ -3279,6 +3216,8 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "optional": true, "engines": { "node": ">=8.6" }, @@ -3316,15 +3255,12 @@ "node": ">=6" } }, - "node_modules/pstree.remy": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", - "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==" - }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "optional": true, "dependencies": { "picomatch": "^2.2.1" }, @@ -3518,47 +3454,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/simple-update-notifier": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", - "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", - "dependencies": { - "semver": "^7.5.3" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/simple-update-notifier/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/simple-update-notifier/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/simple-update-notifier/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, "node_modules/slash": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", @@ -3636,6 +3531,7 @@ "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, "dependencies": { "has-flag": "^3.0.0" }, @@ -3668,6 +3564,8 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "optional": true, "dependencies": { "is-number": "^7.0.0" }, @@ -3675,17 +3573,6 @@ "node": ">=8.0" } }, - "node_modules/touch": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", - "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", - "dependencies": { - "nopt": "~1.0.10" - }, - "bin": { - "nodetouch": "bin/nodetouch.js" - } - }, "node_modules/typed-array-buffer": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", @@ -3779,11 +3666,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/undefsafe": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", - "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==" - }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", diff --git a/app/gui2/parser-codegen/package.json b/app/gui2/parser-codegen/package.json index 1e2582e7fc96..cacb94246aaf 100644 --- a/app/gui2/parser-codegen/package.json +++ b/app/gui2/parser-codegen/package.json @@ -1,22 +1,23 @@ { - "name": "parser-codegen", + "name": "enso-parser-codegen", "version": "1.0.0", - "description": "", + "private": true, + "author": { + "name": "Enso Team", + "email": "contact@enso.org" + }, "main": "dist/codegen.js", "scripts": { - "start": "tsc && node node_modules/.bin/babel-node dist/codegen.js" + "generate-ast-schema": "rm -rf generated && mkdir generated && cargo run -p enso-parser-schema > generated/ast-schema.json", + "preinstall": "npm run generate-ast-schema", + "start": "tsc && node node_modules/.bin/babel-node dist/codegen.js generated/ast-schema.json generated/ast.ts" }, "keywords": [], - "author": "", - "license": "ISC", "devDependencies": { "@babel/cli": "^7.22.15", "@babel/core": "^7.22.20", "@babel/node": "^7.22.19", "@babel/preset-env": "^7.22.20", "typescript": "^5.2.2" - }, - "dependencies": { - "nodemon": "^3.0.1" } } diff --git a/app/gui2/parser-codegen/src/codegen.ts b/app/gui2/parser-codegen/src/codegen.ts index e6be81988f01..60df7a51547a 100644 --- a/app/gui2/parser-codegen/src/codegen.ts +++ b/app/gui2/parser-codegen/src/codegen.ts @@ -1,5 +1,5 @@ import * as ts from "typescript" -import {SyntaxKind} from "typescript" +import { factory as tsf } from "typescript" import * as fs from "fs" type Schema = { @@ -65,20 +65,20 @@ function legalizeIdent(ident: string): string { type ExpressionTransformer = ((expression: ts.Expression) => ts.Expression) function primitiveReader(name: string): ExpressionTransformer { - return cursor => ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(cursor, name), [], []) + return cursor => tsf.createCallExpression(tsf.createPropertyAccessExpression(cursor, name), [], []) } function readerTransformer(name: string): (readElement: ExpressionTransformer) => ExpressionTransformer { - const innerParameter = ts.factory.createIdentifier("element") + const innerParameter = tsf.createIdentifier("element") return (readElement: ExpressionTransformer) => (cursor: ts.Expression) => { - return ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(cursor, name), + return tsf.createCallExpression( + tsf.createPropertyAccessExpression(cursor, name), [], [ - ts.factory.createArrowFunction( + tsf.createArrowFunction( [], [], - [ts.factory.createParameterDeclaration([], undefined, innerParameter, undefined, cursorType, undefined)], + [tsf.createParameterDeclaration([], undefined, innerParameter, undefined, support.Cursor, undefined)], undefined, undefined, readElement(innerParameter) @@ -90,20 +90,20 @@ function readerTransformer(name: string): (readElement: ExpressionTransformer) = function readerTransformer2(name: string): (readOk: ExpressionTransformer, readErr: ExpressionTransformer) => ExpressionTransformer { function makeArrow(reader: ExpressionTransformer, data: ts.Identifier) { - return ts.factory.createArrowFunction( + return tsf.createArrowFunction( [], [], - [ts.factory.createParameterDeclaration([], undefined, data, undefined, cursorType, undefined)], + [tsf.createParameterDeclaration([], undefined, data, undefined, support.Cursor, undefined)], undefined, undefined, reader(data) ) } - const okData = ts.factory.createIdentifier("okData") - const errData = ts.factory.createIdentifier("errData") + const okData = tsf.createIdentifier("okData") + const errData = tsf.createIdentifier("errData") return (readOk: ExpressionTransformer, readErr: ExpressionTransformer) => (cursor: ts.Expression) => { - return ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(cursor, name), + return tsf.createCallExpression( + tsf.createPropertyAccessExpression(cursor, name), [], [makeArrow(readOk, okData), makeArrow(readErr, errData)] ) @@ -111,21 +111,21 @@ function readerTransformer2(name: string): (readOk: ExpressionTransformer, readE } function readerTransformerSized(name: string): (readElement: ExpressionTransformer, size: number) => ExpressionTransformer { - const innerParameter = ts.factory.createIdentifier("element") + const innerParameter = tsf.createIdentifier("element") return (readElement: ExpressionTransformer, size: number) => (cursor: ts.Expression) => { - return ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(cursor, name), + return tsf.createCallExpression( + tsf.createPropertyAccessExpression(cursor, name), [], [ - ts.factory.createArrowFunction( + tsf.createArrowFunction( [], [], - [ts.factory.createParameterDeclaration([], undefined, innerParameter, undefined, cursorType, undefined)], + [tsf.createParameterDeclaration([], undefined, innerParameter, undefined, support.Cursor, undefined)], undefined, undefined, readElement(innerParameter) ), - ts.factory.createNumericLiteral(size) + tsf.createNumericLiteral(size) ] ) } @@ -141,8 +141,8 @@ function namespacedName(name: string, namespace?: string): string { function abstractTypeReader(name: string): ExpressionTransformer { return (cursor: ts.Expression) => - ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(toPascal(name)), "read"), + tsf.createCallExpression( + tsf.createPropertyAccessExpression(tsf.createIdentifier(toPascal(name)), "read"), [], [cursorMethods.readPointer(cursor)] ) @@ -150,8 +150,8 @@ function abstractTypeReader(name: string): ExpressionTransformer { function concreteTypeReader(name: string): ExpressionTransformer { return (cursor: ts.Expression) => - ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(toPascal(name)), "read"), + tsf.createCallExpression( + tsf.createPropertyAccessExpression(tsf.createIdentifier(toPascal(name)), "read"), [], [cursor] ) @@ -175,7 +175,7 @@ class Type { const ty = types[ref.id] const parent = types[ty.parent] const typeName = namespacedName(ty.name, parent?.name) - const type = ts.factory.createTypeReferenceNode(typeName) + const type = tsf.createTypeReferenceNode(typeName) if (Object.entries(ty.discriminants).length !== 0) { return new Type(type, abstractTypeReader(typeName), POINTER_SIZE) } else { @@ -185,19 +185,19 @@ class Type { const p = ref.type switch (p) { case "bool": - return new Type(ts.factory.createTypeReferenceNode("boolean"), cursorMethods.readBool, 1) + return new Type(tsf.createTypeReferenceNode("boolean"), cursorMethods.readBool, 1) case "u32": - return new Type(ts.factory.createTypeReferenceNode("number"), cursorMethods.readU32, 4) + return new Type(tsf.createTypeReferenceNode("number"), cursorMethods.readU32, 4) case "i32": - return new Type(ts.factory.createTypeReferenceNode("number"), cursorMethods.readI32, 4) + return new Type(tsf.createTypeReferenceNode("number"), cursorMethods.readI32, 4) case "u64": - return new Type(ts.factory.createTypeReferenceNode("number"), cursorMethods.readU64, 8) + return new Type(tsf.createTypeReferenceNode("number"), cursorMethods.readU64, 8) case "i64": - return new Type(ts.factory.createTypeReferenceNode("number"), cursorMethods.readI64, 8) + return new Type(tsf.createTypeReferenceNode("number"), cursorMethods.readI64, 8) case "char": - return new Type(ts.factory.createTypeReferenceNode("number"), cursorMethods.readU32, 4) + return new Type(tsf.createTypeReferenceNode("number"), cursorMethods.readU32, 4) case "string": - return new Type(ts.factory.createTypeReferenceNode("string"), cursorMethods.readString, POINTER_SIZE) + return new Type(tsf.createTypeReferenceNode("string"), cursorMethods.readString, POINTER_SIZE) default: const _ = p satisfies never throw new Error("unreachable: PrimitiveType.type='" + p + "'") @@ -216,7 +216,7 @@ class Type { static sequence(element: Type): Type { return new Type( - ts.factory.createTypeReferenceNode("Iterable", [element.type]), + tsf.createTypeReferenceNode("Iterable", [element.type]), cursorMethods.readSequence(element.reader, element.size), POINTER_SIZE ) @@ -224,7 +224,7 @@ class Type { static option(element: Type): Type { return new Type( - ts.factory.createUnionTypeNode([element.type, nullType]), + tsf.createUnionTypeNode([element.type, nullType]), cursorMethods.readOption(element.reader), POINTER_SIZE + 1 ) @@ -232,7 +232,7 @@ class Type { static result(ok: Type, err: Type): Type { return new Type( - ts.factory.createUnionTypeNode([ok.type, err.type]), + tsf.createUnionTypeNode([ok.type, err.type]), cursorMethods.readResult(ok.reader, err.reader), POINTER_SIZE ) @@ -243,26 +243,26 @@ function seekCursor(cursor: ts.Expression, offset: number): ts.Expression { if (offset === 0) { return cursor } else { - return ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(cursor, "seek"), + return tsf.createCallExpression( + tsf.createPropertyAccessExpression(cursor, "seek"), [], - [ts.factory.createNumericLiteral(offset)] + [tsf.createNumericLiteral(offset)] ) } } function makeGetter(fieldName: string, fieldData: Schema.Field, types: [string: Schema.Type]): ts.GetAccessorDeclaration { const type = Type.new(fieldData.type, types) - return ts.factory.createGetAccessorDeclaration( + return tsf.createGetAccessorDeclaration( [], - ts.factory.createIdentifier(legalizeIdent(toCamel(fieldName))), + tsf.createIdentifier(legalizeIdent(toCamel(fieldName))), [], type.type, - ts.factory.createBlock([ - ts.factory.createReturnStatement( + tsf.createBlock([ + tsf.createReturnStatement( type.reader( seekCursor( - ts.factory.createPropertyAccessExpression(ts.factory.createThis(), cursorFieldIdent), + tsf.createPropertyAccessExpression(tsf.createThis(), cursorFieldIdent), fieldData.offset ), ) @@ -273,33 +273,33 @@ function makeGetter(fieldName: string, fieldData: Schema.Field, types: [string: // Helper for a common case of constructing an assignment. function createAssignmentStatement(left: ts.Expression, right: ts.Expression): ts.Statement { - return ts.factory.createExpressionStatement( - ts.factory.createBinaryExpression( + return tsf.createExpressionStatement( + tsf.createBinaryExpression( left, - SyntaxKind.EqualsToken, + ts.SyntaxKind.EqualsToken, right, ) ) } function makeConcreteType(id: string, types: [string: Schema.Type]): ts.ClassDeclaration { - const ident = ts.factory.createIdentifier(toPascal(types[id].name)) - const paramIdent = ts.factory.createIdentifier("cursor") - const cursorParam = ts.factory.createParameterDeclaration([], undefined, paramIdent, undefined, cursorType, undefined) + const ident = tsf.createIdentifier(toPascal(types[id].name)) + const paramIdent = tsf.createIdentifier("cursor") + const cursorParam = tsf.createParameterDeclaration([], undefined, paramIdent, undefined, support.Cursor, undefined) return makeClass( [modifiers.export], ident, [ - forwardToSuper(paramIdent, cursorType), - ts.factory.createMethodDeclaration( + forwardToSuper(paramIdent, support.Cursor), + tsf.createMethodDeclaration( [modifiers.static], undefined, "read", undefined, [], [cursorParam], - ts.factory.createTypeReferenceNode(ident), - ts.factory.createBlock([ts.factory.createReturnStatement(ts.factory.createNewExpression(ident, [], [paramIdent]))]) + tsf.createTypeReferenceNode(ident), + tsf.createBlock([tsf.createReturnStatement(tsf.createNewExpression(ident, [], [paramIdent]))]) ) ], id, @@ -308,32 +308,32 @@ function makeConcreteType(id: string, types: [string: Schema.Type]): ts.ClassDec } function debugValue(ident: ts.Identifier): ts.Expression { - const value = ts.factory.createPropertyAccessExpression(ts.factory.createThis(), ident) - return ts.factory.createCallExpression(ts.factory.createIdentifier("debugHelper"), [], [value]) + const value = tsf.createPropertyAccessExpression(tsf.createThis(), ident) + return tsf.createCallExpression(support.debugHelper, [], [value]) } function makeDebugFunction(fields: [string, Schema.Field][]): ts.MethodDeclaration { - const getterIdent = (fieldName: string) => ts.factory.createIdentifier(legalizeIdent(toCamel(fieldName))) - return ts.factory.createMethodDeclaration( + const getterIdent = (fieldName: string) => tsf.createIdentifier(legalizeIdent(toCamel(fieldName))) + return tsf.createMethodDeclaration( [], undefined, "debug", undefined, [], [], - ts.factory.createTypeReferenceNode("any"), - ts.factory.createBlock([ - ts.factory.createReturnStatement( - ts.factory.createObjectLiteralExpression([ - ts.factory.createSpreadAssignment( - ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createSuper(), "debug"), + tsf.createTypeReferenceNode("any"), + tsf.createBlock([ + tsf.createReturnStatement( + tsf.createObjectLiteralExpression([ + tsf.createSpreadAssignment( + tsf.createCallExpression( + tsf.createPropertyAccessExpression(tsf.createSuper(), "debug"), [], [] ) ), ...fields.map(([name, field] : [string, Schema.Field]) => - ts.factory.createPropertyAssignment(getterIdent(name), debugValue(getterIdent(name))) + tsf.createPropertyAssignment(getterIdent(name), debugValue(getterIdent(name))) ) ]) )] @@ -343,12 +343,12 @@ function makeDebugFunction(fields: [string, Schema.Field][]): ts.MethodDeclarati function makeClass(modifiers: ts.Modifier[], name: ts.Identifier, members: ts.ClassElement[], id: string, types: [string: Schema.Type]): ts.ClassDeclaration { const ty = types[id] - return ts.factory.createClassDeclaration( + return tsf.createClassDeclaration( modifiers, name, undefined, - [ts.factory.createHeritageClause(ts.SyntaxKind.ExtendsKeyword, [ - ts.factory.createExpressionWithTypeArguments(lazyObjectIdent, []) + [tsf.createHeritageClause(ts.SyntaxKind.ExtendsKeyword, [ + tsf.createExpressionWithTypeArguments(support.LazyObject, []) ])], [ ...members, @@ -368,83 +368,83 @@ type ChildType = { function makeChildType(parentName: string, base: ts.Identifier, id: string, discrim: string, types: [string: Schema.Type]): ChildType { const ty: Schema.Type = types[id] const name = toPascal(ty.name) - const ident = ts.factory.createIdentifier(name) - const cursorIdent = ts.factory.createIdentifier("cursor") - const cursorParam = ts.factory.createParameterDeclaration([], undefined, cursorIdent, undefined, cursorType, undefined) - const discrimInt = ts.factory.createNumericLiteral(parseInt(discrim, 10)) + const ident = tsf.createIdentifier(name) + const cursorIdent = tsf.createIdentifier("cursor") + const cursorParam = tsf.createParameterDeclaration([], undefined, cursorIdent, undefined, support.Cursor, undefined) + const discrimInt = tsf.createNumericLiteral(parseInt(discrim, 10)) return { - definition: ts.factory.createClassDeclaration( + definition: tsf.createClassDeclaration( [modifiers.export], name, undefined, - [ts.factory.createHeritageClause(ts.SyntaxKind.ExtendsKeyword, [ - ts.factory.createExpressionWithTypeArguments(base, []) + [tsf.createHeritageClause(ts.SyntaxKind.ExtendsKeyword, [ + tsf.createExpressionWithTypeArguments(base, []) ])], [ - ts.factory.createPropertyDeclaration( + tsf.createPropertyDeclaration( [modifiers.readonly], "type", undefined, - ts.factory.createTypeReferenceNode("Type." + name), + tsf.createTypeReferenceNode("Type." + name), undefined ), - ts.factory.createConstructorDeclaration([], [ - ts.factory.createParameterDeclaration([], undefined, cursorIdent, undefined, cursorType, undefined) + tsf.createConstructorDeclaration([], [ + tsf.createParameterDeclaration([], undefined, cursorIdent, undefined, support.Cursor, undefined) ], - ts.factory.createBlock([ - ts.factory.createExpressionStatement(ts.factory.createCallExpression( - ts.factory.createIdentifier("super"), [], [cursorIdent] + tsf.createBlock([ + tsf.createExpressionStatement(tsf.createCallExpression( + tsf.createIdentifier("super"), [], [cursorIdent] )), createAssignmentStatement( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier("this"), "type"), - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier("Type"), name) + tsf.createPropertyAccessExpression(tsf.createIdentifier("this"), "type"), + tsf.createPropertyAccessExpression(tsf.createIdentifier("Type"), name) ) ]) ), - ts.factory.createMethodDeclaration( + tsf.createMethodDeclaration( [modifiers.static], undefined, "read", undefined, [], [cursorParam], - ts.factory.createTypeReferenceNode(ident), - ts.factory.createBlock([ts.factory.createReturnStatement(ts.factory.createNewExpression(ident, [], [cursorIdent]))]) + tsf.createTypeReferenceNode(ident), + tsf.createBlock([tsf.createReturnStatement(tsf.createNewExpression(ident, [], [cursorIdent]))]) ), ...ty.fields.map(([name, field]: [string, Schema.Field]) => makeGetter(name, field, types)), makeDebugFunction(ty.fields) ] ), - reference: ts.factory.createTypeReferenceNode(name), - enumMember: ts.factory.createEnumMember(toPascal(types[id].name), discrimInt), - case: ts.factory.createCaseClause( + reference: tsf.createTypeReferenceNode(name), + enumMember: tsf.createEnumMember(toPascal(types[id].name), discrimInt), + case: tsf.createCaseClause( discrimInt, - [ts.factory.createReturnStatement( - ts.factory.createNewExpression(ident, [], [seekCursor(cursorIdent, 4)]) + [tsf.createReturnStatement( + tsf.createNewExpression(ident, [], [seekCursor(cursorIdent, 4)]) )] ) } } function forwardToSuper(ident: ts.Identifier, type: ts.TypeNode) { - return ts.factory.createConstructorDeclaration([], [ - ts.factory.createParameterDeclaration([], undefined, ident, undefined, type, undefined) + return tsf.createConstructorDeclaration([], [ + tsf.createParameterDeclaration([], undefined, ident, undefined, type, undefined) ], - ts.factory.createBlock([ - ts.factory.createExpressionStatement(ts.factory.createCallExpression( - ts.factory.createIdentifier("super"), [], [ident] + tsf.createBlock([ + tsf.createExpressionStatement(tsf.createCallExpression( + tsf.createIdentifier("super"), [], [ident] )) ]) ) } function casesOrThrow(cases: ts.CaseClause[], error: string): ts.CaseBlock { - return ts.factory.createCaseBlock( + return tsf.createCaseBlock( [ ...cases, - ts.factory.createDefaultClause([ - ts.factory.createThrowStatement( - ts.factory.createNewExpression(ts.factory.createIdentifier("Error"), [], [ts.factory.createStringLiteral(error)]) + tsf.createDefaultClause([ + tsf.createThrowStatement( + tsf.createNewExpression(tsf.createIdentifier("Error"), [], [tsf.createStringLiteral(error)]) ) ]) ] @@ -452,16 +452,16 @@ function casesOrThrow(cases: ts.CaseClause[], error: string): ts.CaseBlock { } function abstractTypeDeserializer(ident: ts.Identifier, cases: ts.CaseClause[]): ts.FunctionDeclaration { - const cursorIdent = ts.factory.createIdentifier("cursor") - return ts.factory.createFunctionDeclaration( + const cursorIdent = tsf.createIdentifier("cursor") + return tsf.createFunctionDeclaration( [modifiers.export], undefined, "read", [], - [ts.factory.createParameterDeclaration([], undefined, cursorIdent, undefined, cursorType, undefined)], - ts.factory.createTypeReferenceNode(ident), - ts.factory.createBlock([ - ts.factory.createSwitchStatement( + [tsf.createParameterDeclaration([], undefined, cursorIdent, undefined, support.Cursor, undefined)], + tsf.createTypeReferenceNode(ident), + tsf.createBlock([ + tsf.createSwitchStatement( cursorMethods.readU32(cursorIdent), casesOrThrow(cases, "Unexpected discriminant while deserializing.") ) @@ -472,39 +472,44 @@ function abstractTypeDeserializer(ident: ts.Identifier, cases: ts.CaseClause[]): function makeAbstractType(id: string, types: [string: Schema.Type]) { const ty = types[id] const name = toPascal(ty.name) - const ident = ts.factory.createIdentifier(name) - const baseIdent = ts.factory.createIdentifier("AbstractBase") + const ident = tsf.createIdentifier(name) + const baseIdent = tsf.createIdentifier("AbstractBase") const childTypes = Array.from(Object.entries(ty.discriminants), ([discrim, id]: [string, string]) => makeChildType(name, baseIdent, id, discrim, types)) - const cursorIdent = ts.factory.createIdentifier("cursor") + const cursorIdent = tsf.createIdentifier("cursor") const moduleDecl = - ts.factory.createModuleDeclaration( + tsf.createModuleDeclaration( [modifiers.export], ident, - ts.factory.createModuleBlock([ - makeClass([modifiers.abstract], baseIdent, [forwardToSuper(cursorIdent, cursorType)], id, types), - ts.factory.createEnumDeclaration( + tsf.createModuleBlock([ + makeClass([modifiers.abstract], baseIdent, [forwardToSuper(cursorIdent, support.Cursor)], id, types), + tsf.createEnumDeclaration( [modifiers.export, modifiers.const], "Type", childTypes.map(child => child.enumMember) ), ...childTypes.map(child => child.definition), - ts.factory.createTypeAliasDeclaration( + tsf.createTypeAliasDeclaration( [modifiers.export], ident, undefined, - ts.factory.createUnionTypeNode(childTypes.map(child => child.reference)) + tsf.createUnionTypeNode(childTypes.map(child => child.reference)) ), abstractTypeDeserializer(ident, childTypes.map(child => child.case)) ]) ) - const abstractTypeExport = ts.factory.createTypeAliasDeclaration( + const abstractTypeExport = tsf.createTypeAliasDeclaration( [modifiers.export], ident, undefined, - ts.factory.createTypeReferenceNode(name + "." + name) + tsf.createTypeReferenceNode(name + "." + name) ) - console.log(printer.printNode(ts.EmitHint.Unspecified, moduleDecl, file)) - console.log(printer.printNode(ts.EmitHint.Unspecified, abstractTypeExport, file)) + emit(moduleDecl) + emit(abstractTypeExport) +} + +function emit(data: ts.Node) { + output += printer.printNode(ts.EmitHint.Unspecified, data, file) + output += "\n" } @@ -512,18 +517,18 @@ function makeAbstractType(id: string, types: [string: Schema.Type]) { // === Main === // ============ +const data: Schema = JSON.parse(fs.readFileSync(process.argv[2], 'utf8')) +let output = "// *** THIS FILE GENERATED BY `parser-codegen` ***\n" const file = ts.createSourceFile("source.ts", "", ts.ScriptTarget.ESNext, false, ts.ScriptKind.TS) const printer = ts.createPrinter({newLine: ts.NewLineKind.LineFeed}) -const lazyObjectIdent = ts.factory.createIdentifier("LazyObject") -const nullType = ts.factory.createTypeReferenceNode("null") -const cursorFieldIdent = ts.factory.createIdentifier("lazyObjectData") -const cursorType = ts.factory.createTypeReferenceNode("Cursor") +const nullType = tsf.createTypeReferenceNode("null") +const cursorFieldIdent = tsf.createIdentifier("lazyObjectData") const modifiers = { - export: ts.factory.createModifier(ts.SyntaxKind.ExportKeyword), - const: ts.factory.createModifier(ts.SyntaxKind.ConstKeyword), - readonly: ts.factory.createModifier(ts.SyntaxKind.ReadonlyKeyword), - abstract: ts.factory.createModifier(ts.SyntaxKind.AbstractKeyword), - static: ts.factory.createModifier(ts.SyntaxKind.StaticKeyword), + export: tsf.createModifier(ts.SyntaxKind.ExportKeyword), + const: tsf.createModifier(ts.SyntaxKind.ConstKeyword), + readonly: tsf.createModifier(ts.SyntaxKind.ReadonlyKeyword), + abstract: tsf.createModifier(ts.SyntaxKind.AbstractKeyword), + static: tsf.createModifier(ts.SyntaxKind.StaticKeyword), } as const const cursorMethods = { readString: primitiveReader("readString"), @@ -538,14 +543,29 @@ const cursorMethods = { readResult: readerTransformer2("readResult"), } as const const POINTER_SIZE: number = 4 +// Symbols exported by the `parserSupport` module. +const support = { + LazyObject: tsf.createIdentifier("LazyObject"), + Cursor: tsf.createTypeReferenceNode(tsf.createIdentifier("Cursor")), + debugHelper: tsf.createIdentifier("debugHelper"), +} as const -const data: Schema = JSON.parse(fs.readFileSync(process.argv[2], 'utf8')) +emit(tsf.createImportDeclaration( + [], + tsf.createImportClause( + false, + undefined, + tsf.createNamedImports(Array.from(Object.entries(support), ([name, _value]) => + tsf.createImportSpecifier(undefined, undefined, tsf.createIdentifier(name)))) + ), + tsf.createStringLiteral("@/util/parserSupport", true), + undefined +)) for (const id in data.types) { const ty = data.types[id] if (ty.parent === null) { if (Object.entries(data.types[id].discriminants).length === 0) { - const decl = makeConcreteType(id, data.types) - console.log(printer.printNode(ts.EmitHint.Unspecified, decl, file)) + emit(makeConcreteType(id, data.types)) } else { makeAbstractType(id, data.types) } @@ -553,3 +573,8 @@ for (const id in data.types) { // Ignore child types; they are generated when `makeAbstractType` processes the parent. } } +output += `export function deserializeTree(data: ArrayBuffer): Tree { + const cursor = new Cursor(data, data.byteLength - 4) + return Tree.read(cursor.readPointer()) +}` +fs.writeFileSync(process.argv[3], output) diff --git a/app/gui2/rust-ffi/src/lib.rs b/app/gui2/rust-ffi/src/lib.rs index 90acedad6d7a..ea4b645ec4ee 100644 --- a/app/gui2/rust-ffi/src/lib.rs +++ b/app/gui2/rust-ffi/src/lib.rs @@ -21,9 +21,9 @@ pub fn parse_to_json(code: &str) -> String { } #[wasm_bindgen] -pub fn parse_to_binary(code: &str) -> Vec { +pub fn parse(code: &str) -> Vec { let ast = PARSER.with(|parser| parser.run(code)); - enso_parser::format::serialize(&ast, &code).expect("Failed to serialize AST to binary format") + enso_parser::format::serialize(&ast).expect("Failed to serialize AST to binary format") } #[wasm_bindgen(start)] diff --git a/app/gui2/src/util/ffi.ts b/app/gui2/src/util/ffi.ts index 17cb6c2b68ff..02c428ab44eb 100644 --- a/app/gui2/src/util/ffi.ts +++ b/app/gui2/src/util/ffi.ts @@ -1,6 +1,7 @@ -import init, { parse_to_json } from '../../rust-ffi/pkg/rust_ffi' +import init, { parse_to_json, parse } from '../../rust-ffi/pkg/rust_ffi' import type { NonEmptyArray } from './array' import type { Opt } from './opt' +import * as Ast2 from '../generated/ast' const _wasm = await init() @@ -9,6 +10,11 @@ export function parseEnso(code: string): Ast.Tree { return JSON.parse(json) } +export function parseEnso2(code: string): Ast2.Tree { + const blob = parse(code) + return Ast2.deserializeTree(blob) +} + export namespace Ast { export interface Tree { span: Span diff --git a/app/gui2/parser-codegen/support/serialization.ts b/app/gui2/src/util/parserSupport.ts similarity index 100% rename from app/gui2/parser-codegen/support/serialization.ts rename to app/gui2/src/util/parserSupport.ts diff --git a/lib/rust/parser/generate-ts/Cargo.toml b/lib/rust/parser/schema/Cargo.toml similarity index 71% rename from lib/rust/parser/generate-ts/Cargo.toml rename to lib/rust/parser/schema/Cargo.toml index 959498a4e248..8c701480873b 100644 --- a/lib/rust/parser/generate-ts/Cargo.toml +++ b/lib/rust/parser/schema/Cargo.toml @@ -1,9 +1,9 @@ [package] -name = "enso-parser-generate-ts" +name = "enso-parser-schema" version = "0.1.0" authors = ["Enso Team "] edition = "2021" -description = "Generates TypeScript bindings and deserialization for Enso Parser AST types." +description = "Generates schema describing Enso Parser AST types." readme = "README.md" homepage = "https://github.com/enso-org/enso" repository = "https://github.com/enso-org/enso" @@ -11,9 +11,9 @@ license-file = "../../LICENSE" [dependencies] enso-metamodel = { path = "../../metamodel", features = ["rust"] } -enso-prelude = { path = "../../prelude" } enso-parser = { path = ".." } enso-reflect = { path = "../../reflect", features = ["graphviz"] } -derivative = { workspace = true } serde = { version = "1", features = ["derive"] } + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] serde_json = { workspace = true } diff --git a/lib/rust/parser/generate-ts/src/lazy_deserialization.rs b/lib/rust/parser/schema/src/lazy_deserialization.rs similarity index 100% rename from lib/rust/parser/generate-ts/src/lazy_deserialization.rs rename to lib/rust/parser/schema/src/lazy_deserialization.rs diff --git a/lib/rust/parser/generate-ts/src/main.rs b/lib/rust/parser/schema/src/lib.rs similarity index 92% rename from lib/rust/parser/generate-ts/src/main.rs rename to lib/rust/parser/schema/src/lib.rs index 73bd4b260b52..2354b4ce616b 100644 --- a/lib/rust/parser/generate-ts/src/main.rs +++ b/lib/rust/parser/schema/src/lib.rs @@ -1,16 +1,15 @@ -//! Generate the Java types corresponding to `enso-parser`'s AST types. -//! -//! # Usage -//! -//! Generated files will be placed in the directory given as an argument: -//! ```console -//! $ enso-parser-generate-ts tree/ -//! ``` +//! Supports generation of TypeScript types corresponding to `enso-parser`'s AST types, and testing +//! and debugging the translation process. // === Standard Linter Configuration === #![deny(non_ascii_idents)] #![warn(unsafe_code)] +#![allow(clippy::bool_to_int_with_if)] +#![allow(clippy::let_and_return)] // === Non-Standard Linter Configuration === +#![allow(clippy::option_map_unit_fn)] +#![allow(clippy::precedence)] +#![allow(dead_code)] #![deny(unconditional_recursion)] #![warn(missing_copy_implementations)] #![warn(missing_debug_implementations)] @@ -25,18 +24,19 @@ use enso_metamodel::rust; use enso_reflect::Reflect; -// ============================= -// === TypeScript Generation === -// ============================= -fn main() { - let ast = enso_parser::syntax::Tree::reflect(); - let (graph, _) = rust::to_meta(ast); - let schema = schema(&graph); - println!("{}", serde_json::to_string(&schema).unwrap()); +// =================== +// === Entry Point === +// =================== + +/// Return a serializable [`Schema`] describing the parser types. +pub fn types() -> impl serde::Serialize { + let (graph, _) = rust::to_meta(enso_parser::syntax::Tree::reflect()); + schema(&graph) } + // ============== // === Schema === // ============== @@ -88,7 +88,7 @@ enum Primitive { fn schema(graph: &meta::TypeGraph) -> Schema { let mut next_type_id = 0; let mut next_type_id = || { - let result = format!("type_{}", next_type_id); + let result = format!("type_{next_type_id}"); next_type_id += 1; result }; diff --git a/lib/rust/parser/generate-ts/src/lib.rs b/lib/rust/parser/schema/src/main.rs similarity index 50% rename from lib/rust/parser/generate-ts/src/lib.rs rename to lib/rust/parser/schema/src/main.rs index 8fbe29b1cc71..63856b334b22 100644 --- a/lib/rust/parser/generate-ts/src/lib.rs +++ b/lib/rust/parser/schema/src/main.rs @@ -1,15 +1,12 @@ -//! Supports generation of TypeScript types corresponding to `enso-parser`'s AST types, and testing -//! and debugging the translation process. +//! Generate a schema representing `enso-parser`'s AST types. This schema can be used to generate +//! AST representations and (de)serialization. +//! +//! The JSON schema data will be emitted to standard output. // === Standard Linter Configuration === #![deny(non_ascii_idents)] #![warn(unsafe_code)] -#![allow(clippy::bool_to_int_with_if)] -#![allow(clippy::let_and_return)] // === Non-Standard Linter Configuration === -#![allow(clippy::option_map_unit_fn)] -#![allow(clippy::precedence)] -#![allow(dead_code)] #![deny(unconditional_recursion)] #![warn(missing_copy_implementations)] #![warn(missing_debug_implementations)] @@ -21,7 +18,10 @@ -// ============== -// === Export === -// ============== +// ========================= +// === Schema Generation === +// ========================= +fn main() { + println!("{}", serde_json::to_string(&enso_parser_schema::types()).unwrap()); +} diff --git a/lib/rust/parser/generate-ts/src/proto.ts b/lib/rust/parser/schema/src/proto.ts similarity index 100% rename from lib/rust/parser/generate-ts/src/proto.ts rename to lib/rust/parser/schema/src/proto.ts diff --git a/lib/rust/parser/generate-ts/src/serialization.rs b/lib/rust/parser/schema/src/serialization.rs similarity index 100% rename from lib/rust/parser/generate-ts/src/serialization.rs rename to lib/rust/parser/schema/src/serialization.rs diff --git a/lib/rust/parser/src/bin/serialize.rs b/lib/rust/parser/src/bin/serialize.rs deleted file mode 100644 index ee5f0c35680b..000000000000 --- a/lib/rust/parser/src/bin/serialize.rs +++ /dev/null @@ -1,24 +0,0 @@ -// === Features === -// === Standard Linter Configuration === -#![deny(non_ascii_idents)] -#![warn(unsafe_code)] -// === Non-Standard Linter Configuration === -#![warn(missing_copy_implementations)] -#![warn(missing_debug_implementations)] -#![warn(missing_docs)] -#![warn(trivial_casts)] -#![warn(trivial_numeric_casts)] -#![warn(unused_import_braces)] -#![warn(unused_qualifications)] - - -use std::io::Write; - -pub fn main() { - use std::io::Read; - let mut input = String::new(); - std::io::stdin().read_to_string(&mut input).unwrap(); - let ast = enso_parser::Parser::new().run(&input); - let blob = enso_parser::format::serialize(&ast).unwrap(); - std::io::stdout().lock().write_all(&blob).unwrap(); -} diff --git a/lib/rust/parser/src/format.rs b/lib/rust/parser/src/format.rs index 5a2271b8d1b9..499a8f2cfcac 100644 --- a/lib/rust/parser/src/format.rs +++ b/lib/rust/parser/src/format.rs @@ -38,6 +38,7 @@ const RECURSION_LIMIT: usize = 1024; // === Serialize === // ================= +/// Generate a binary representation of the value. pub fn serialize(value: T) -> Result> { let mut serializer = Serializer::new(); value.serialize(&mut serializer)?; @@ -46,6 +47,7 @@ pub fn serialize(value: T) -> Result> { } + // ================== // === Serializer === // ================== @@ -63,6 +65,7 @@ pub struct Serializer { } impl Serializer { + /// Return a new [`Serializer`]. pub fn new() -> Self { Self::default() } @@ -115,6 +118,7 @@ struct ParentStruct { } + // ========================================== // === Serialization Trait Implementation === // ========================================== @@ -443,15 +447,21 @@ impl ser::SerializeMap for ObjectSerializer<'_> { } + // ==================== // === Result Types === // ==================== -pub type Ok = (); +type Ok = (); +/// Describes a serialization failure. #[derive(Debug)] pub enum Error { + /// Indicates that the nested object depth of the input exceeded [`RECURSION_LIMIT`], and + /// serialization was aborted to prevent a stack overflow. This is not expected to occur for + /// "reasonable" syntax trees. RecursionLimitExceeded, + /// A serialization failure described by a message. Custom(String), } @@ -470,6 +480,7 @@ impl ser::Error for Error { } } +/// The result of a serialization attempt. pub type Result = std::result::Result; @@ -499,6 +510,6 @@ mod test { } // Note that if recursion is not adequately limited the expected failure mode is aborting // due to stack overflow. We are just checking `is_err` here for good measure. - assert!(super::serialize(&Cyclic::new()).is_err()); + assert!(super::serialize(Cyclic::new()).is_err()); } } diff --git a/package-lock.json b/package-lock.json index 8073485ef2c9..289bab49280e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ ], "dependencies": { "chromedriver": "^106.0.1", + "enso-gui2": "^0.1.0", "lint": "^0.8.19", "run": "^1.4.0", "tslib": "^2.6.2" diff --git a/package.json b/package.json index c24e749e11f8..7ae0a2e56d44 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ }, "dependencies": { "chromedriver": "^106.0.1", + "enso-gui2": "^0.1.0", "lint": "^0.8.19", "run": "^1.4.0", "tslib": "^2.6.2" From 3005f06162d2641c2aaa7957b287f935bd8d6d05 Mon Sep 17 00:00:00 2001 From: Kaz Wesley Date: Tue, 26 Sep 2023 16:50:07 +0000 Subject: [PATCH 06/44] Fix. --- Cargo.lock | 11 + Cargo.toml | 1 + lib/rust/parser/Cargo.toml | 1 + lib/rust/parser/src/syntax/tree.rs | 286 +++++++++++++++++- lib/rust/parser/src/syntax/tree/block.rs | 6 +- .../parser/src/syntax/tree/visitor/Cargo.toml | 22 ++ .../parser/src/syntax/tree/visitor/src/lib.rs | 181 +++++++++++ 7 files changed, 489 insertions(+), 19 deletions(-) create mode 100644 lib/rust/parser/src/syntax/tree/visitor/Cargo.toml create mode 100644 lib/rust/parser/src/syntax/tree/visitor/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index d3bad93aca54..35d978e7f8b2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2353,6 +2353,7 @@ dependencies = [ "enso-data-structures", "enso-metamodel", "enso-metamodel-lexpr", + "enso-parser-syntax-tree-visitor", "enso-prelude", "enso-reflect", "enso-shapely-macros", @@ -2410,6 +2411,16 @@ dependencies = [ "serde_json", ] +[[package]] +name = "enso-parser-syntax-tree-visitor" +version = "0.1.0" +dependencies = [ + "enso-macro-utils", + "proc-macro2", + "quote", + "syn 1.0.107", +] + [[package]] name = "enso-prelude" version = "0.2.6" diff --git a/Cargo.toml b/Cargo.toml index d5496fad1f1d..3acba36dfbc5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,7 @@ members = [ "build/shader-tools", "lib/rust/*", "lib/rust/parser/doc-parser", + "lib/rust/parser/src/syntax/tree/visitor", "lib/rust/parser/jni", "lib/rust/parser/generate-java", "lib/rust/parser/schema", diff --git a/lib/rust/parser/Cargo.toml b/lib/rust/parser/Cargo.toml index 1c51bdfe6de9..815caa6c57e9 100644 --- a/lib/rust/parser/Cargo.toml +++ b/lib/rust/parser/Cargo.toml @@ -15,6 +15,7 @@ enso-reflect = { path = "../reflect" } enso-data-structures = { path = "../data-structures" } enso-types = { path = "../types" } enso-shapely-macros = { path = "../shapely/macros" } +enso-parser-syntax-tree-visitor = { path = "src/syntax/tree/visitor" } serde = { version = "1.0", features = ["derive"] } serde_json = { workspace = true } uuid = { version = "1.1", features = ["serde"] } diff --git a/lib/rust/parser/src/syntax/tree.rs b/lib/rust/parser/src/syntax/tree.rs index 02372b37c558..6472453c0c0f 100644 --- a/lib/rust/parser/src/syntax/tree.rs +++ b/lib/rust/parser/src/syntax/tree.rs @@ -6,10 +6,10 @@ use crate::syntax::*; use crate::span_builder; +use enso_parser_syntax_tree_visitor::Visitor; use enso_shapely_macros::tagged_enum; - // ============== // === Export === // ============== @@ -23,7 +23,7 @@ pub mod block; // ============ /// The Abstract Syntax Tree of the language. -#[derive(Debug, Clone, Deref, DerefMut, Eq, PartialEq, Serialize, Reflect, Deserialize)] +#[derive(Clone, Deref, DerefMut, Eq, PartialEq, Serialize, Reflect, Deserialize)] #[allow(missing_docs)] pub struct Tree<'s> { #[reflect(flatten, hide)] @@ -41,6 +41,19 @@ pub fn Tree<'s>(span: Span<'s>, variant: impl Into>) -> Tree<'s> { Tree { variant, span } } +impl<'s> Debug for Tree<'s> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let max_code_len = 30; + let ellipsis = "..."; + let mut code = self.code(); + if code.len() > max_code_len { + code = format!("{}{}", &code[..max_code_len - ellipsis.len()], ellipsis); + } + write!(f, "[{}:{}:\"{}\"] ", self.span.left_offset.visible, self.span.code_length, code)?; + Debug::fmt(&self.variant, f) + } +} + impl<'s> AsRef> for Tree<'s> { fn as_ref(&self) -> &Span<'s> { &self.span @@ -62,7 +75,7 @@ impl<'s> Default for Tree<'s> { macro_rules! with_ast_definition { ($f:ident ($($args:tt)*)) => { $f! { $($args)* /// [`Tree`] variants definition. See its docs to learn more. #[tagged_enum] - #[derive(Clone, Eq, PartialEq, Serialize, Reflect, Deserialize)] + #[derive(Clone, Eq, PartialEq, Visitor, Serialize, Reflect, Deserialize)] #[allow(clippy::large_enum_variant)] // Inefficient. Will be fixed in #182878443. #[tagged_enum(apply_attributes_to = "variants")] #[reflect(inline)] @@ -377,7 +390,7 @@ with_ast_definition!(generate_ast_definition()); // === Invalid === /// Error of parsing attached to an [`Tree`] node. -#[derive(Clone, Debug, Eq, PartialEq, Serialize, Reflect, Deserialize)] +#[derive(Clone, Debug, Eq, PartialEq, Visitor, Serialize, Reflect, Deserialize)] #[allow(missing_docs)] #[reflect(transparent)] #[serde(from = "crate::serialization::Error")] @@ -411,7 +424,7 @@ impl<'s> span::Builder<'s> for Error { // === Argument blocks === /// An argument specification on its own line. -#[derive(Clone, Debug, Eq, PartialEq, Serialize, Reflect, Deserialize)] +#[derive(Clone, Debug, Eq, PartialEq, Visitor, Serialize, Reflect, Deserialize)] pub struct ArgumentDefinitionLine<'s> { /// The token beginning the line. pub newline: token::Newline<'s>, @@ -429,7 +442,7 @@ impl<'s> span::Builder<'s> for ArgumentDefinitionLine<'s> { // === Text literals === /// A component of a text literal, within the quotation marks. -#[derive(Clone, Debug, Eq, PartialEq, Serialize, Reflect, Deserialize)] +#[derive(Clone, Debug, Eq, PartialEq, Visitor, Serialize, Reflect, Deserialize)] pub enum TextElement<'s> { /// The text content of the literal. If it is multiline, the offset information may contain /// part of the content, after trimming appropriately. @@ -475,7 +488,7 @@ impl<'s> span::Builder<'s> for TextElement<'s> { // === Documentation === /// A documentation comment. -#[derive(Debug, Clone, Eq, PartialEq, Serialize, Reflect, Deserialize)] +#[derive(Debug, Clone, Eq, PartialEq, Visitor, Serialize, Reflect, Deserialize)] pub struct DocComment<'s> { /// The comment-initiating token. pub open: token::TextStart<'s>, @@ -516,7 +529,7 @@ impl<'s> span::Builder<'s> for DocComment<'s> { // === Number literals === -#[derive(Clone, Debug, Eq, PartialEq, Serialize, Reflect, Deserialize)] +#[derive(Clone, Debug, Eq, PartialEq, Visitor, Serialize, Reflect, Deserialize)] #[allow(missing_docs)] pub struct FractionalDigits<'s> { /// The dot operator. @@ -535,7 +548,7 @@ impl<'s> span::Builder<'s> for FractionalDigits<'s> { // === Functions === /// A function argument definition. -#[derive(Clone, Debug, Eq, PartialEq, Serialize, Reflect, Deserialize)] +#[derive(Clone, Debug, Eq, PartialEq, Visitor, Serialize, Reflect, Deserialize)] pub struct ArgumentDefinition<'s> { /// Opening parenthesis (outer). pub open: Option>, @@ -570,7 +583,7 @@ impl<'s> span::Builder<'s> for ArgumentDefinition<'s> { } /// A default value specification in a function argument definition. -#[derive(Clone, Debug, Eq, PartialEq, Serialize, Reflect, Deserialize)] +#[derive(Clone, Debug, Eq, PartialEq, Visitor, Serialize, Reflect, Deserialize)] pub struct ArgumentDefault<'s> { /// The `=` token. pub equals: token::Operator<'s>, @@ -585,7 +598,7 @@ impl<'s> span::Builder<'s> for ArgumentDefault<'s> { } /// A type ascribed to an argument definition. -#[derive(Clone, Debug, Eq, PartialEq, Serialize, Reflect, Deserialize)] +#[derive(Clone, Debug, Eq, PartialEq, Visitor, Serialize, Reflect, Deserialize)] pub struct ArgumentType<'s> { /// The `:` token. pub operator: token::Operator<'s>, @@ -604,7 +617,7 @@ impl<'s> span::Builder<'s> for ArgumentType<'s> { // === CaseOf === /// A that may contain a case-expression in a case-of expression. -#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Reflect, Deserialize)] +#[derive(Clone, Debug, Default, Eq, PartialEq, Visitor, Serialize, Reflect, Deserialize)] pub struct CaseLine<'s> { /// The token beginning the line. This will always be present, unless the first case-expression /// is on the same line as the initial case-of. @@ -631,7 +644,7 @@ impl<'s> span::Builder<'s> for CaseLine<'s> { } /// A case-expression in a case-of expression. -#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Reflect, Deserialize)] +#[derive(Clone, Debug, Default, Eq, PartialEq, Visitor, Serialize, Reflect, Deserialize)] pub struct Case<'s> { /// Documentation, if present. pub documentation: Option>, @@ -667,7 +680,7 @@ impl<'s> span::Builder<'s> for Case<'s> { pub type OperatorOrError<'s> = Result, MultipleOperatorError<'s>>; /// Error indicating multiple operators found next to each other, like `a + * b`. -#[derive(Clone, Debug, Eq, PartialEq, Serialize, Reflect, Deserialize)] +#[derive(Clone, Debug, Eq, PartialEq, Visitor, Serialize, Reflect, Deserialize)] #[allow(missing_docs)] pub struct MultipleOperatorError<'s> { pub operators: NonEmptyVec>, @@ -706,7 +719,7 @@ impl<'s> NonEmptyOperatorSequence<'s> for OperatorOrError<'s> { // === MultiSegmentApp === /// A segment of [`MultiSegmentApp`], like `if cond` in the `if cond then ok else fail` expression. -#[derive(Clone, Debug, Eq, PartialEq, Serialize, Reflect, Deserialize)] +#[derive(Clone, Debug, Eq, PartialEq, Visitor, Serialize, Reflect, Deserialize)] #[allow(missing_docs)] pub struct MultiSegmentAppSegment<'s> { pub header: Token<'s>, @@ -723,7 +736,7 @@ impl<'s> span::Builder<'s> for MultiSegmentAppSegment<'s> { // === Array and Tuple === /// A node following an operator. -#[derive(Clone, Debug, Eq, PartialEq, Serialize, Reflect, Deserialize)] +#[derive(Clone, Debug, Eq, PartialEq, Visitor, Serialize, Reflect, Deserialize)] pub struct OperatorDelimitedTree<'s> { /// The delimiting operator. pub operator: token::Operator<'s>, @@ -1199,6 +1212,247 @@ spanless_leaf_impls!(bool); spanless_leaf_impls!(VisibleOffset); +// === TreeVisitable special cases === + +impl<'s, 'a> TreeVisitable<'s, 'a> for Tree<'s> { + fn visit>(&'a self, visitor: &mut V) { + if visitor.visit(self) { + self.variant.visit(visitor) + } + } +} + +impl<'s, 'a> TreeVisitableMut<'s, 'a> for Tree<'s> { + fn visit_mut>(&'a mut self, visitor: &mut V) { + if visitor.visit_mut(self) { + self.variant.visit_mut(visitor) + } + } +} + +impl<'s, 'a, T> TreeVisitable<'s, 'a> for Token<'s, T> {} +impl<'s, 'a, T> TreeVisitableMut<'s, 'a> for Token<'s, T> {} + + +// === SpanVisitable special cases === + +impl<'s, 'a> SpanVisitable<'s, 'a> for Tree<'s> { + fn visit_span>(&'a self, visitor: &mut V) { + if visitor.visit(span::Ref { + left_offset: &self.span.left_offset, + code_length: self.span.code_length, + }) { + self.variant.visit_span(visitor) + } + } +} + +impl<'s, 'a> SpanVisitableMut<'s, 'a> for Tree<'s> { + fn visit_span_mut>(&'a mut self, visitor: &mut V) { + if visitor.visit_mut(span::RefMut { + left_offset: &mut self.span.left_offset, + code_length: self.span.code_length, + }) { + self.variant.visit_span_mut(visitor) + } + } +} + +impl<'a, 's, T> SpanVisitable<'s, 'a> for Token<'s, T> { + fn visit_span>(&'a self, visitor: &mut V) { + let code_length = self.code.length(); + visitor.visit(span::Ref { left_offset: &self.left_offset, code_length }); + } +} + +impl<'a, 's, T> SpanVisitableMut<'s, 'a> for Token<'s, T> { + fn visit_span_mut>(&'a mut self, visitor: &mut V) { + let code_length = self.code.length(); + visitor.visit_mut(span::RefMut { left_offset: &mut self.left_offset, code_length }); + } +} + + +// === ItemVisitable special cases === + +impl<'s, 'a> ItemVisitable<'s, 'a> for Tree<'s> { + fn visit_item>(&'a self, visitor: &mut V) { + if visitor.visit_item(item::Ref::Tree(self)) { + self.variant.visit_item(visitor) + } + } +} + +impl<'s: 'a, 'a, T: 'a> ItemVisitable<'s, 'a> for Token<'s, T> +where &'a Token<'s, T>: Into> +{ + fn visit_item>(&'a self, visitor: &mut V) { + visitor.visit_item(item::Ref::Token(self.into())); + } +} + + +// === String === + +impl<'s, 'a> TreeVisitable<'s, 'a> for String {} +impl<'s, 'a> TreeVisitableMut<'s, 'a> for String {} +impl<'a, 's> SpanVisitable<'s, 'a> for String {} +impl<'a, 's> SpanVisitableMut<'s, 'a> for String {} +impl<'a, 's> ItemVisitable<'s, 'a> for String {} +impl<'s> span::Builder<'s> for String { + fn add_to_span(&mut self, span: Span<'s>) -> Span<'s> { + span + } +} + +impl<'s, 'a> TreeVisitable<'s, 'a> for Cow<'static, str> {} +impl<'s, 'a> TreeVisitableMut<'s, 'a> for Cow<'static, str> {} +impl<'a, 's> SpanVisitable<'s, 'a> for Cow<'static, str> {} +impl<'a, 's> SpanVisitableMut<'s, 'a> for Cow<'static, str> {} +impl<'a, 's> ItemVisitable<'s, 'a> for Cow<'static, str> {} +impl<'s> span::Builder<'s> for Cow<'static, str> { + fn add_to_span(&mut self, span: Span<'s>) -> Span<'s> { + span + } +} + + + +// ========================== +// === CodePrinterVisitor === +// ========================== + +/// A visitor collecting code representation of AST nodes. +#[derive(Debug, Default)] +#[allow(missing_docs)] +struct CodePrinterVisitor { + pub code: String, +} + +impl Visitor for CodePrinterVisitor {} +impl<'s, 'a> ItemVisitor<'s, 'a> for CodePrinterVisitor { + fn visit_item(&mut self, item: item::Ref<'s, 'a>) -> bool { + match item { + item::Ref::Tree(tree) => self.code.push_str(&tree.span.left_offset.code), + item::Ref::Token(token) => { + self.code.push_str(&token.left_offset.code); + self.code.push_str(token.code); + } + } + true + } +} + +impl<'s> Tree<'s> { + /// Code generator of this AST. + pub fn code(&self) -> String { + let mut visitor = CodePrinterVisitor::default(); + self.visit_item(&mut visitor); + visitor.code + } + + /// Return source code of this AST, excluding initial whitespace. + pub fn trimmed_code(&self) -> String { + let mut visitor = CodePrinterVisitor::default(); + self.variant.visit_item(&mut visitor); + visitor.code + } +} + + + +// =========================== +// === RefCollectorVisitor === +// =========================== + +/// A visitor collecting references to all [`Tree`] nodes. +#[derive(Debug, Default)] +#[allow(missing_docs)] +struct RefCollectorVisitor<'s, 'a> { + pub vec: Vec<&'a Tree<'s>>, +} + +impl<'s, 'a> Visitor for RefCollectorVisitor<'s, 'a> {} +impl<'s, 'a> TreeVisitor<'s, 'a> for RefCollectorVisitor<'s, 'a> { + fn visit(&mut self, ast: &'a Tree<'s>) -> bool { + self.vec.push(ast); + true + } +} + +impl<'s> Tree<'s> { + /// Collect references to all [`Tree`] nodes and return them in a vector. + pub fn collect_vec_ref(&self) -> Vec<&Tree<'s>> { + let mut visitor = RefCollectorVisitor::default(); + self.visit(&mut visitor); + visitor.vec + } +} + + + +// ================= +// === FnVisitor === +// ================= + +/// A visitor allowing running a function on every [`Tree`] node. +#[derive(Debug, Default)] +#[allow(missing_docs)] +pub struct FnVisitor(pub F); + +impl Visitor for FnVisitor {} +impl<'s: 'a, 'a, T, F: Fn(&'a Tree<'s>) -> T> TreeVisitor<'s, 'a> for FnVisitor { + fn visit(&mut self, ast: &'a Tree<'s>) -> bool { + (self.0)(ast); + true + } +} + +impl<'s, T, F: Fn(&mut Tree<'s>) -> T> TreeVisitorMut<'s> for FnVisitor { + fn visit_mut(&mut self, ast: &mut Tree<'s>) -> bool { + (self.0)(ast); + true + } +} + +impl<'s> Tree<'s> { + /// Map the provided function over each [`Tree`] node. The function results will be discarded. + pub fn map(&self, f: impl Fn(&Tree<'s>) -> T) { + let mut visitor = FnVisitor(f); + self.visit(&mut visitor); + } + + /// Map the provided function over each [`Tree`] node. The function results will be discarded. + pub fn map_mut(&mut self, f: impl Fn(&mut Tree<'s>) -> T) { + let mut visitor = FnVisitor(f); + self.visit_mut(&mut visitor); + } +} + + +// === ItemFnVisitor === + +impl<'s> Tree<'s> { + /// Apply the provided function to each [`Token`] or [`Tree`] that is a child of the node. + pub fn visit_items(&self, f: F) + where F: for<'a> FnMut(item::Ref<'s, 'a>) { + struct ItemFnVisitor { + f: F, + } + impl Visitor for ItemFnVisitor {} + impl<'a, 's: 'a, F> ItemVisitor<'s, 'a> for ItemFnVisitor + where F: FnMut(item::Ref<'s, 'a>) + { + fn visit_item(&mut self, item: item::Ref<'s, 'a>) -> bool { + (self.f)(item); + false + } + } + self.variant.visit_item(&mut ItemFnVisitor { f }); + } +} + + // ================= // === Traversal === diff --git a/lib/rust/parser/src/syntax/tree/block.rs b/lib/rust/parser/src/syntax/tree/block.rs index 0b3218a6c359..1bd5691365b0 100644 --- a/lib/rust/parser/src/syntax/tree/block.rs +++ b/lib/rust/parser/src/syntax/tree/block.rs @@ -12,7 +12,7 @@ use crate::syntax::token; // ============= /// A line of code. -#[derive(Debug, Clone, PartialEq, Eq, Reflect, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Visitor, Reflect, Serialize, Deserialize)] pub struct Line<'s> { /// Token ending the previous line, if any. pub newline: token::Newline<'s>, @@ -195,7 +195,7 @@ impl<'s> From> for Tree<'s> { // ====================== /// The content of a line in an operator block. -#[derive(Debug, Clone, PartialEq, Eq, Reflect, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Visitor, Reflect, Serialize, Deserialize)] pub struct OperatorBlockExpression<'s> { /// The operator at the beginning of the line. pub operator: OperatorOrError<'s>, @@ -231,7 +231,7 @@ impl<'s> span::Builder<'s> for OperatorBlockExpression<'s> { // === Operator block lines ==== /// A line in an operator block. -#[derive(Debug, Clone, PartialEq, Eq, Reflect, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Visitor, Reflect, Serialize, Deserialize)] pub struct OperatorLine<'s> { /// Token ending the previous line, if any. pub newline: token::Newline<'s>, diff --git a/lib/rust/parser/src/syntax/tree/visitor/Cargo.toml b/lib/rust/parser/src/syntax/tree/visitor/Cargo.toml new file mode 100644 index 000000000000..a4cdb3b906ff --- /dev/null +++ b/lib/rust/parser/src/syntax/tree/visitor/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "enso-parser-syntax-tree-visitor" +version = "0.1.0" +authors = ["Enso Team "] +edition = "2021" +description = "Enso Parser AST Visitor." +readme = "README.md" +homepage = "https://github.com/enso-org/enso" +repository = "https://github.com/enso-org/enso" +license-file = "../../LICENSE" + +[lib] +proc-macro = true + +[dependencies] +proc-macro2 = { workspace = true } +enso-macro-utils = { path = "../../../../../macro-utils" } +quote = { workspace = true } + +[dependencies.syn] +version = "1.0" +features = ['extra-traits', 'visit', 'full'] diff --git a/lib/rust/parser/src/syntax/tree/visitor/src/lib.rs b/lib/rust/parser/src/syntax/tree/visitor/src/lib.rs new file mode 100644 index 000000000000..66979cf54f7a --- /dev/null +++ b/lib/rust/parser/src/syntax/tree/visitor/src/lib.rs @@ -0,0 +1,181 @@ +//! Definition of [`Visitor`] deriving. It implements the visitor pattern for [`Ast`]. + +// === Standard Linter Configuration === +#![deny(non_ascii_idents)] +#![warn(unsafe_code)] +#![allow(clippy::bool_to_int_with_if)] +#![allow(clippy::let_and_return)] +// === Non-Standard Linter Configuration === +#![allow(clippy::option_map_unit_fn)] +#![allow(clippy::precedence)] +#![allow(dead_code)] +#![deny(unconditional_recursion)] +#![warn(missing_copy_implementations)] +#![warn(missing_debug_implementations)] +#![warn(missing_docs)] +#![warn(trivial_casts)] +#![warn(trivial_numeric_casts)] +#![warn(unused_import_braces)] +#![warn(unused_qualifications)] + + + +extern crate proc_macro; + +use enso_macro_utils::field_names; +use enso_macro_utils::identifier_sequence; +use enso_macro_utils::index_sequence; +use proc_macro2::TokenStream; +use quote::quote; +use syn::Data; +use syn::DataEnum; +use syn::DataStruct; +use syn::DeriveInput; +use syn::Fields; +use syn::Variant; + + + +/// ====================== +/// === Derive Visitor === +/// ====================== +use quote::ToTokens; + +/// Implements [`TreeVisitable`], [`TreeVisitableMut`], [`SpanVisitable`], and [`SpanVisitableMut`]. +/// These traits are defined in the [`crate::ast`] module. Macros in this module hardcode the names +/// of the traits and are not implemented in a generic way because the current Rust implementation +/// does not understand generic definition. See the [`crate::ast`] module to learn more about the +/// design and the Rust compiler issue. +#[proc_macro_derive(Visitor)] +pub fn derive_visitor(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let decl = syn::parse_macro_input!(input as DeriveInput); + let ident = &decl.ident; + let (impl_generics, ty_generics, _inherent_where_clause_opt) = &decl.generics.split_for_impl(); + let body = gen_body(quote!(TreeVisitable::visit), &decl.data, false); + let body_mut = gen_body(quote!(TreeVisitableMut::visit_mut), &decl.data, true); + let body_span = gen_body(quote!(SpanVisitable::visit_span), &decl.data, false); + let body_span_mut = gen_body(quote!(SpanVisitableMut::visit_span_mut), &decl.data, true); + let body_item = gen_body(quote!(ItemVisitable::visit_item), &decl.data, false); + + let impl_generics_vec: Vec<_> = impl_generics.to_token_stream().into_iter().collect(); + let impl_generics_len = impl_generics_vec.len(); + let mut impl_generics; + if impl_generics_len > 0 { + let v: Vec<_> = impl_generics_vec.into_iter().take(impl_generics_len - 1).skip(1).collect(); + impl_generics = quote!(#(#v)*); + if !v.is_empty() { + impl_generics = quote!(#impl_generics,); + } + } else { + impl_generics = quote!('s,); + } + let impl_generics = quote!(<#impl_generics 'a>); + + let output = quote! { + impl #impl_generics TreeVisitable #impl_generics for #ident #ty_generics { + fn visit(&'a self, visitor:&mut T) { + visitor.before_visiting_children(); + #body + visitor.after_visiting_children(); + } + } + + impl #impl_generics TreeVisitableMut #impl_generics for #ident #ty_generics { + fn visit_mut>(&'a mut self, visitor:&mut T) { + visitor.before_visiting_children(); + #body_mut + visitor.after_visiting_children(); + } + } + + impl #impl_generics SpanVisitable #impl_generics for #ident #ty_generics { + fn visit_span(&'a self, visitor:&mut T) { + visitor.before_visiting_children(); + #body_span + visitor.after_visiting_children(); + } + } + + impl #impl_generics SpanVisitableMut #impl_generics for #ident #ty_generics { + fn visit_span_mut>(&'a mut self, visitor:&mut T) { + visitor.before_visiting_children(); + #body_span_mut + visitor.after_visiting_children(); + } + } + + impl #impl_generics ItemVisitable #impl_generics for #ident #ty_generics { + fn visit_item(&'a self, visitor:&mut T) { + visitor.before_visiting_children(); + #body_item + visitor.after_visiting_children(); + } + } + }; + + // #[allow(missing_docs)] + // pub trait ItemVisitable<'s, 'a> { + // fn visit_item>(&'a self, _visitor: &mut V) {} + // } + + output.into() +} + +fn gen_body(f: TokenStream, data: &Data, is_mut: bool) -> TokenStream { + match data { + Data::Struct(t) => body_for_struct(&f, t, is_mut), + Data::Enum(t) => body_for_enum(&f, t), + Data::Union(_) => panic!("Untagged union types not supported."), + } +} + +fn body_for_struct(f: &TokenStream, data: &DataStruct, is_mut: bool) -> TokenStream { + match &data.fields { + Fields::Unit => quote!({}), + Fields::Unnamed(fields) => { + let indices = index_sequence(fields.unnamed.len()); + if is_mut { + quote!(#( #f(&mut self.#indices, visitor); )*) + } else { + quote!(#( #f(&self.#indices, visitor); )*) + } + } + Fields::Named(fields) => { + let names = field_names(fields); + if is_mut { + quote!(#( #f(&mut self.#names, visitor); )*) + } else { + quote!(#( #f(&self.#names, visitor); )*) + } + } + } +} + +/// Prepares a match arm for a single variant that `clone_ref`s such value. +fn arm_for_variant(f: &TokenStream, variant: &Variant) -> TokenStream { + let variant_ident = &variant.ident; + match &variant.fields { + Fields::Unit => { + quote!(Self::#variant_ident => {}) + } + Fields::Named(fields) => { + let names = field_names(fields); + quote!(Self::#variant_ident { #(#names),* } => { + #( #f(#names, visitor); )* + }) + } + Fields::Unnamed(fields) => { + let names = identifier_sequence(fields.unnamed.len()); + quote!(Self::#variant_ident(#(#names),*) => { + #( #f(#names, visitor); )* + }) + } + } +} + +fn body_for_enum(f: &TokenStream, data: &DataEnum) -> TokenStream { + let make_arm = |variant| arm_for_variant(f, variant); + let arms = data.variants.iter().map(make_arm); + let body = quote!(match self { #(#arms)* }); + body +} From a06e873e7862eaa10f42bdb5a1e778fe521039fc Mon Sep 17 00:00:00 2001 From: Kaz Wesley Date: Tue, 26 Sep 2023 16:51:53 +0000 Subject: [PATCH 07/44] Lint. --- lib/rust/metamodel/src/data_structures.rs | 2 +- lib/rust/parser/schema/src/lib.rs | 22 +++++------- lib/rust/parser/src/format.rs | 42 +++++++++++------------ lib/rust/parser/src/lib.rs | 2 +- lib/rust/parser/src/serialization.rs | 37 -------------------- 5 files changed, 32 insertions(+), 73 deletions(-) diff --git a/lib/rust/metamodel/src/data_structures.rs b/lib/rust/metamodel/src/data_structures.rs index c74ab666c3c2..ce814bb3e0bd 100644 --- a/lib/rust/metamodel/src/data_structures.rs +++ b/lib/rust/metamodel/src/data_structures.rs @@ -162,7 +162,7 @@ impl std::ops::IndexMut<&Key> for VecMap { } impl<'a, T> IntoIterator for &'a VecMap { type Item = (Key, &'a T); - type IntoIter = impl Iterator; + type IntoIter = impl Iterator; fn into_iter(self) -> Self::IntoIter { self.iter() diff --git a/lib/rust/parser/schema/src/lib.rs b/lib/rust/parser/schema/src/lib.rs index 2354b4ce616b..711d243b3908 100644 --- a/lib/rust/parser/schema/src/lib.rs +++ b/lib/rust/parser/schema/src/lib.rs @@ -161,7 +161,7 @@ fn schema(graph: &meta::TypeGraph) -> Schema { .iter() .map(|(k, v)| (*k, key_to_id(v))) .collect(), - size: 0, + size: 0, }) }) }) @@ -188,10 +188,7 @@ fn schema(graph: &meta::TypeGraph) -> Schema { .unwrap_or_else(|| data_size[&field.r#type]); } let reference = TypeRef::Type { id: id.to_owned() }; - ty.size = reference_size - .get(&reference) - .copied() - .unwrap_or_else(|| data_size[&reference]); + ty.size = reference_size.get(&reference).copied().unwrap_or_else(|| data_size[&reference]); } Schema { types } } @@ -217,14 +214,13 @@ fn compute_size( if let Some(size) = data_size.get(&key) { *size } else { - let mut size = - if let Some(id) = ty.parent.clone() { - let type_ref = TypeRef::Type { id }; - compute_size(type_ref.clone(), types, data_size); - data_size[&type_ref] - } else { - 0 - }; + let mut size = if let Some(id) = ty.parent.clone() { + let type_ref = TypeRef::Type { id }; + compute_size(type_ref.clone(), types, data_size); + data_size[&type_ref] + } else { + 0 + }; for (_, field) in &ty.fields { let field_size = compute_size(field.r#type.to_owned(), types, data_size); size += field_size; diff --git a/lib/rust/parser/src/format.rs b/lib/rust/parser/src/format.rs index 499a8f2cfcac..7d82d3cdddfb 100644 --- a/lib/rust/parser/src/format.rs +++ b/lib/rust/parser/src/format.rs @@ -16,11 +16,11 @@ //! size: The requirement that every field have the same size representation would be too onerous. use serde::ser; +use serde::ser::SerializeSeq; use serde::Serialize; use std::fmt::Debug; use std::fmt::Display; use std::fmt::Formatter; -use serde::ser::SerializeSeq; // ================= @@ -56,12 +56,12 @@ pub fn serialize(value: T) -> Result> { #[derive(Debug, Default)] pub struct Serializer { /// Complete objects, located at their final addresses. - heap: Vec, + heap: Vec, /// All the fields of currently-incomplete objects. - stack: Vec, + stack: Vec, recursion_depth: usize, - object_depth: usize, - parent_structs: Vec, + object_depth: usize, + parent_structs: Vec, } impl Serializer { @@ -98,7 +98,7 @@ impl Serializer { #[derive(Debug)] pub struct ObjectSerializer<'a> { serializer: &'a mut Serializer, - begin: usize, + begin: usize, } impl<'a> ObjectSerializer<'a> { @@ -114,7 +114,7 @@ impl<'a> ObjectSerializer<'a> { #[derive(Debug, Copy, Clone)] struct ParentStruct { object_depth_inside: usize, - begin: usize, + begin: usize, } @@ -208,7 +208,7 @@ impl<'a> ser::Serializer for &'a mut Serializer { } fn serialize_some(self, value: &T) -> Result<()> - where T: ?Sized + Serialize { + where T: ?Sized + Serialize { self.serialize_u8(1)?; let object = self.object_serializer()?; value.serialize(&mut *object.serializer)?; @@ -235,7 +235,7 @@ impl<'a> ser::Serializer for &'a mut Serializer { } fn serialize_newtype_struct(self, _name: &'static str, value: &T) -> Result<()> - where T: ?Sized + Serialize { + where T: ?Sized + Serialize { value.serialize(self) } @@ -246,8 +246,8 @@ impl<'a> ser::Serializer for &'a mut Serializer { _variant: &'static str, value: &T, ) -> Result<()> - where - T: ?Sized + Serialize, + where + T: ?Sized + Serialize, { if name == "Variant" && let Some(ancestor) = self.parent_structs.last() @@ -337,7 +337,7 @@ impl ser::SerializeStruct for &'_ mut Serializer { type Error = Error; fn serialize_field(&mut self, _key: &'static str, value: &T) -> Result<()> - where T: ?Sized + Serialize { + where T: ?Sized + Serialize { value.serialize(&mut **self) } @@ -357,7 +357,7 @@ impl ser::SerializeTuple for &'_ mut Serializer { type Error = Error; fn serialize_element(&mut self, value: &T) -> Result<()> - where T: ?Sized + Serialize { + where T: ?Sized + Serialize { value.serialize(&mut **self) } @@ -372,7 +372,7 @@ impl ser::SerializeTupleStruct for &'_ mut Serializer { type Error = Error; fn serialize_field(&mut self, value: &T) -> Result<()> - where T: ?Sized + Serialize { + where T: ?Sized + Serialize { value.serialize(&mut **self) } @@ -390,7 +390,7 @@ impl ser::SerializeStructVariant for ObjectSerializer<'_> { type Error = Error; fn serialize_field(&mut self, _key: &'static str, value: &T) -> Result<()> - where T: ?Sized + Serialize { + where T: ?Sized + Serialize { value.serialize(&mut *self.serializer) } @@ -404,7 +404,7 @@ impl SerializeSeq for ObjectSerializer<'_> { type Error = Error; fn serialize_element(&mut self, value: &T) -> Result<()> - where T: ?Sized + Serialize { + where T: ?Sized + Serialize { value.serialize(&mut *self.serializer) } @@ -418,7 +418,7 @@ impl ser::SerializeTupleVariant for ObjectSerializer<'_> { type Error = Error; fn serialize_field(&mut self, value: &T) -> Result<()> - where T: ?Sized + Serialize { + where T: ?Sized + Serialize { value.serialize(&mut *self.serializer) } @@ -432,12 +432,12 @@ impl ser::SerializeMap for ObjectSerializer<'_> { type Error = Error; fn serialize_key(&mut self, key: &T) -> Result<()> - where T: ?Sized + Serialize { + where T: ?Sized + Serialize { key.serialize(&mut *self.serializer) } fn serialize_value(&mut self, value: &T) -> Result<()> - where T: ?Sized + Serialize { + where T: ?Sized + Serialize { value.serialize(&mut *self.serializer) } @@ -475,7 +475,7 @@ impl Display for Error { impl ser::Error for Error { fn custom(msg: T) -> Self - where T: Display { + where T: Display { Self::Custom(msg.to_string()) } } @@ -494,8 +494,8 @@ mod test { #[test] fn test_infinite_recursion() { - use std::rc::Rc; use std::cell::RefCell; + use std::rc::Rc; /// A serializable object containing a reference to itself. #[derive(Serialize)] struct Cyclic { diff --git a/lib/rust/parser/src/lib.rs b/lib/rust/parser/src/lib.rs index 5a81d1323db8..565c9c2611d7 100644 --- a/lib/rust/parser/src/lib.rs +++ b/lib/rust/parser/src/lib.rs @@ -108,13 +108,13 @@ use crate::prelude::*; // === Export === // ============== +pub mod format; pub mod lexer; pub mod macros; pub mod metadata; pub mod serialization; pub mod source; pub mod syntax; -pub mod format; /// Popular utilities, imported by most modules of this crate. diff --git a/lib/rust/parser/src/serialization.rs b/lib/rust/parser/src/serialization.rs index 7b6c73bed343..cb3d64c1bd38 100644 --- a/lib/rust/parser/src/serialization.rs +++ b/lib/rust/parser/src/serialization.rs @@ -27,43 +27,6 @@ pub fn deserialize_tree(data: &[u8]) -> Result(cow: &Cow<'_, str>, ser: S) -> Result -where S: serde::Serializer { - let s = match cow { - Cow::Borrowed(s) => { - let begin = str::as_ptr(s) as u32; - let len = s.len() as u32; - Code { begin, len } - } - Cow::Owned(s) if s.is_empty() => Code { begin: 0, len: 0 }, - Cow::Owned(_) => panic!(), - }; - s.serialize(ser) -} - -pub(crate) fn deserialize_cow<'c, 'de, D>(deserializer: D) -> Result, D::Error> -where D: serde::Deserializer<'de> { - let _ = deserializer.deserialize_u64(DeserializeU64); - Ok(Cow::Owned(String::new())) -} - - - // ============== // === Tokens === // ============== From 26368661572930bc069c747e35e94ba8a4ecf520 Mon Sep 17 00:00:00 2001 From: Kaz Wesley Date: Tue, 26 Sep 2023 16:56:22 +0000 Subject: [PATCH 08/44] prettier --- app/gui2/parser-codegen/.babelrc | 4 +- app/gui2/parser-codegen/src/codegen.ts | 539 ++++++++++++++--------- app/gui2/parser-codegen/src/prototype.ts | 34 +- app/gui2/parser-codegen/tsconfig.json | 18 +- app/gui2/parser-codegen/tslint.json | 14 +- app/gui2/src/util/ffi.ts | 4 +- app/gui2/src/util/parserSupport.ts | 34 +- lib/rust/parser/schema/src/proto.ts | 6 +- 8 files changed, 372 insertions(+), 281 deletions(-) diff --git a/app/gui2/parser-codegen/.babelrc b/app/gui2/parser-codegen/.babelrc index a29ac9986c16..1320b9a3272a 100644 --- a/app/gui2/parser-codegen/.babelrc +++ b/app/gui2/parser-codegen/.babelrc @@ -1,5 +1,3 @@ { - "presets": [ - "@babel/preset-env" - ] + "presets": ["@babel/preset-env"] } diff --git a/app/gui2/parser-codegen/src/codegen.ts b/app/gui2/parser-codegen/src/codegen.ts index 60df7a51547a..aa95f362990f 100644 --- a/app/gui2/parser-codegen/src/codegen.ts +++ b/app/gui2/parser-codegen/src/codegen.ts @@ -1,6 +1,6 @@ -import * as ts from "typescript" -import { factory as tsf } from "typescript" -import * as fs from "fs" +import * as fs from 'fs' +import * as ts from 'typescript' +import { factory as tsf } from 'typescript' type Schema = { types: [string: Schema.Type] @@ -18,58 +18,63 @@ module Schema { offset: number } export type TypeRef = Class | Primitive | Sequence | Option | Result - export type Class = { class: "type"; id: string } - export type Primitive = { class: "primitive"; type: PrimitiveType } - export type Sequence = { class: "sequence"; type: TypeRef } - export type Option = { class: "option"; type: TypeRef } - export type Result = { class: "result"; type0: TypeRef, type1: TypeRef } - export type PrimitiveType = "bool" | "u32" | "u64" | "i32" | "i64" | "char" | "string" + export type Class = { class: 'type'; id: string } + export type Primitive = { class: 'primitive'; type: PrimitiveType } + export type Sequence = { class: 'sequence'; type: TypeRef } + export type Option = { class: 'option'; type: TypeRef } + export type Result = { class: 'result'; type0: TypeRef; type1: TypeRef } + export type PrimitiveType = 'bool' | 'u32' | 'u64' | 'i32' | 'i64' | 'char' | 'string' } -function fromSnake(ident: string, to: "camel" | "pascal", prefix?: string): string { +function fromSnake(ident: string, to: 'camel' | 'pascal', prefix?: string): string { const segments = [] if (prefix !== undefined) { - segments.push(...prefix.split("_")) + segments.push(...prefix.split('_')) } - segments.push(...ident.split("_")) - return segments.map((seg, i) => { - if (to === "camel" && i === 0) { - return seg - } else { - return seg.charAt(0).toUpperCase() + seg.slice(1) - } - }).join("") + segments.push(...ident.split('_')) + return segments + .map((seg, i) => { + if (to === 'camel' && i === 0) { + return seg + } else { + return seg.charAt(0).toUpperCase() + seg.slice(1) + } + }) + .join('') } function toPascal(ident: string, prefix?: string): string { - return fromSnake(ident, "pascal", prefix) + return fromSnake(ident, 'pascal', prefix) } function toCamel(ident: string, prefix?: string): string { - return fromSnake(ident, "camel", prefix) + return fromSnake(ident, 'camel', prefix) } function legalizeIdent(ident: string): string { // FIXME: We should accept a renaming table as an input alongside the schema, then emit an error if a keyword is // encountered ("constructor") or a field name is duplicated ("type"). switch (ident) { - case "constructor": - return "ident" - case "type": - return "typeNode" + case 'constructor': + return 'ident' + case 'type': + return 'typeNode' default: return ident } } -type ExpressionTransformer = ((expression: ts.Expression) => ts.Expression) +type ExpressionTransformer = (expression: ts.Expression) => ts.Expression function primitiveReader(name: string): ExpressionTransformer { - return cursor => tsf.createCallExpression(tsf.createPropertyAccessExpression(cursor, name), [], []) + return (cursor) => + tsf.createCallExpression(tsf.createPropertyAccessExpression(cursor, name), [], []) } -function readerTransformer(name: string): (readElement: ExpressionTransformer) => ExpressionTransformer { - const innerParameter = tsf.createIdentifier("element") +function readerTransformer( + name: string, +): (readElement: ExpressionTransformer) => ExpressionTransformer { + const innerParameter = tsf.createIdentifier('element') return (readElement: ExpressionTransformer) => (cursor: ts.Expression) => { return tsf.createCallExpression( tsf.createPropertyAccessExpression(cursor, name), @@ -78,17 +83,28 @@ function readerTransformer(name: string): (readElement: ExpressionTransformer) = tsf.createArrowFunction( [], [], - [tsf.createParameterDeclaration([], undefined, innerParameter, undefined, support.Cursor, undefined)], + [ + tsf.createParameterDeclaration( + [], + undefined, + innerParameter, + undefined, + support.Cursor, + undefined, + ), + ], undefined, undefined, - readElement(innerParameter) - ) - ] + readElement(innerParameter), + ), + ], ) } } -function readerTransformer2(name: string): (readOk: ExpressionTransformer, readErr: ExpressionTransformer) => ExpressionTransformer { +function readerTransformer2( + name: string, +): (readOk: ExpressionTransformer, readErr: ExpressionTransformer) => ExpressionTransformer { function makeArrow(reader: ExpressionTransformer, data: ts.Identifier) { return tsf.createArrowFunction( [], @@ -96,22 +112,25 @@ function readerTransformer2(name: string): (readOk: ExpressionTransformer, readE [tsf.createParameterDeclaration([], undefined, data, undefined, support.Cursor, undefined)], undefined, undefined, - reader(data) - ) - } - const okData = tsf.createIdentifier("okData") - const errData = tsf.createIdentifier("errData") - return (readOk: ExpressionTransformer, readErr: ExpressionTransformer) => (cursor: ts.Expression) => { - return tsf.createCallExpression( - tsf.createPropertyAccessExpression(cursor, name), - [], - [makeArrow(readOk, okData), makeArrow(readErr, errData)] + reader(data), ) } + const okData = tsf.createIdentifier('okData') + const errData = tsf.createIdentifier('errData') + return (readOk: ExpressionTransformer, readErr: ExpressionTransformer) => + (cursor: ts.Expression) => { + return tsf.createCallExpression( + tsf.createPropertyAccessExpression(cursor, name), + [], + [makeArrow(readOk, okData), makeArrow(readErr, errData)], + ) + } } -function readerTransformerSized(name: string): (readElement: ExpressionTransformer, size: number) => ExpressionTransformer { - const innerParameter = tsf.createIdentifier("element") +function readerTransformerSized( + name: string, +): (readElement: ExpressionTransformer, size: number) => ExpressionTransformer { + const innerParameter = tsf.createIdentifier('element') return (readElement: ExpressionTransformer, size: number) => (cursor: ts.Expression) => { return tsf.createCallExpression( tsf.createPropertyAccessExpression(cursor, name), @@ -120,13 +139,22 @@ function readerTransformerSized(name: string): (readElement: ExpressionTransform tsf.createArrowFunction( [], [], - [tsf.createParameterDeclaration([], undefined, innerParameter, undefined, support.Cursor, undefined)], + [ + tsf.createParameterDeclaration( + [], + undefined, + innerParameter, + undefined, + support.Cursor, + undefined, + ), + ], undefined, undefined, - readElement(innerParameter) + readElement(innerParameter), ), - tsf.createNumericLiteral(size) - ] + tsf.createNumericLiteral(size), + ], ) } } @@ -135,25 +163,25 @@ function namespacedName(name: string, namespace?: string): string { if (namespace === undefined) { return toPascal(name) } else { - return toPascal(namespace) + "." + toPascal(name) + return toPascal(namespace) + '.' + toPascal(name) } } function abstractTypeReader(name: string): ExpressionTransformer { return (cursor: ts.Expression) => tsf.createCallExpression( - tsf.createPropertyAccessExpression(tsf.createIdentifier(toPascal(name)), "read"), + tsf.createPropertyAccessExpression(tsf.createIdentifier(toPascal(name)), 'read'), [], - [cursorMethods.readPointer(cursor)] + [cursorMethods.readPointer(cursor)], ) } function concreteTypeReader(name: string): ExpressionTransformer { return (cursor: ts.Expression) => tsf.createCallExpression( - tsf.createPropertyAccessExpression(tsf.createIdentifier(toPascal(name)), "read"), + tsf.createPropertyAccessExpression(tsf.createIdentifier(toPascal(name)), 'read'), [], - [cursor] + [cursor], ) } @@ -171,7 +199,7 @@ class Type { static new(ref: Schema.TypeRef, types: [string: Schema.Type]): Type { const c = ref.class switch (c) { - case "type": + case 'type': const ty = types[ref.id] const parent = types[ty.parent] const typeName = namespacedName(ty.name, parent?.name) @@ -181,32 +209,36 @@ class Type { } else { return new Type(type, concreteTypeReader(typeName), ty.size) } - case "primitive": + case 'primitive': const p = ref.type switch (p) { - case "bool": - return new Type(tsf.createTypeReferenceNode("boolean"), cursorMethods.readBool, 1) - case "u32": - return new Type(tsf.createTypeReferenceNode("number"), cursorMethods.readU32, 4) - case "i32": - return new Type(tsf.createTypeReferenceNode("number"), cursorMethods.readI32, 4) - case "u64": - return new Type(tsf.createTypeReferenceNode("number"), cursorMethods.readU64, 8) - case "i64": - return new Type(tsf.createTypeReferenceNode("number"), cursorMethods.readI64, 8) - case "char": - return new Type(tsf.createTypeReferenceNode("number"), cursorMethods.readU32, 4) - case "string": - return new Type(tsf.createTypeReferenceNode("string"), cursorMethods.readString, POINTER_SIZE) + case 'bool': + return new Type(tsf.createTypeReferenceNode('boolean'), cursorMethods.readBool, 1) + case 'u32': + return new Type(tsf.createTypeReferenceNode('number'), cursorMethods.readU32, 4) + case 'i32': + return new Type(tsf.createTypeReferenceNode('number'), cursorMethods.readI32, 4) + case 'u64': + return new Type(tsf.createTypeReferenceNode('number'), cursorMethods.readU64, 8) + case 'i64': + return new Type(tsf.createTypeReferenceNode('number'), cursorMethods.readI64, 8) + case 'char': + return new Type(tsf.createTypeReferenceNode('number'), cursorMethods.readU32, 4) + case 'string': + return new Type( + tsf.createTypeReferenceNode('string'), + cursorMethods.readString, + POINTER_SIZE, + ) default: const _ = p satisfies never throw new Error("unreachable: PrimitiveType.type='" + p + "'") } - case "sequence": + case 'sequence': return Type.sequence(Type.new(ref.type, types)) - case "option": + case 'option': return Type.option(Type.new(ref.type, types)) - case "result": + case 'result': return Type.result(Type.new(ref.type0, types), Type.new(ref.type1, types)) default: const _ = c satisfies never @@ -216,9 +248,9 @@ class Type { static sequence(element: Type): Type { return new Type( - tsf.createTypeReferenceNode("Iterable", [element.type]), + tsf.createTypeReferenceNode('Iterable', [element.type]), cursorMethods.readSequence(element.reader, element.size), - POINTER_SIZE + POINTER_SIZE, ) } @@ -226,7 +258,7 @@ class Type { return new Type( tsf.createUnionTypeNode([element.type, nullType]), cursorMethods.readOption(element.reader), - POINTER_SIZE + 1 + POINTER_SIZE + 1, ) } @@ -234,7 +266,7 @@ class Type { return new Type( tsf.createUnionTypeNode([ok.type, err.type]), cursorMethods.readResult(ok.reader, err.reader), - POINTER_SIZE + POINTER_SIZE, ) } } @@ -244,14 +276,18 @@ function seekCursor(cursor: ts.Expression, offset: number): ts.Expression { return cursor } else { return tsf.createCallExpression( - tsf.createPropertyAccessExpression(cursor, "seek"), + tsf.createPropertyAccessExpression(cursor, 'seek'), [], - [tsf.createNumericLiteral(offset)] + [tsf.createNumericLiteral(offset)], ) } } -function makeGetter(fieldName: string, fieldData: Schema.Field, types: [string: Schema.Type]): ts.GetAccessorDeclaration { +function makeGetter( + fieldName: string, + fieldData: Schema.Field, + types: [string: Schema.Type], +): ts.GetAccessorDeclaration { const type = Type.new(fieldData.type, types) return tsf.createGetAccessorDeclaration( [], @@ -263,29 +299,32 @@ function makeGetter(fieldName: string, fieldData: Schema.Field, types: [string: type.reader( seekCursor( tsf.createPropertyAccessExpression(tsf.createThis(), cursorFieldIdent), - fieldData.offset + fieldData.offset, ), - ) - ) - ]) + ), + ), + ]), ) } // Helper for a common case of constructing an assignment. function createAssignmentStatement(left: ts.Expression, right: ts.Expression): ts.Statement { return tsf.createExpressionStatement( - tsf.createBinaryExpression( - left, - ts.SyntaxKind.EqualsToken, - right, - ) + tsf.createBinaryExpression(left, ts.SyntaxKind.EqualsToken, right), ) } function makeConcreteType(id: string, types: [string: Schema.Type]): ts.ClassDeclaration { const ident = tsf.createIdentifier(toPascal(types[id].name)) - const paramIdent = tsf.createIdentifier("cursor") - const cursorParam = tsf.createParameterDeclaration([], undefined, paramIdent, undefined, support.Cursor, undefined) + const paramIdent = tsf.createIdentifier('cursor') + const cursorParam = tsf.createParameterDeclaration( + [], + undefined, + paramIdent, + undefined, + support.Cursor, + undefined, + ) return makeClass( [modifiers.export], ident, @@ -294,16 +333,18 @@ function makeConcreteType(id: string, types: [string: Schema.Type]): ts.ClassDec tsf.createMethodDeclaration( [modifiers.static], undefined, - "read", + 'read', undefined, [], [cursorParam], tsf.createTypeReferenceNode(ident), - tsf.createBlock([tsf.createReturnStatement(tsf.createNewExpression(ident, [], [paramIdent]))]) - ) + tsf.createBlock([ + tsf.createReturnStatement(tsf.createNewExpression(ident, [], [paramIdent])), + ]), + ), ], id, - types + types, ) } @@ -317,45 +358,53 @@ function makeDebugFunction(fields: [string, Schema.Field][]): ts.MethodDeclarati return tsf.createMethodDeclaration( [], undefined, - "debug", + 'debug', undefined, [], [], - tsf.createTypeReferenceNode("any"), + tsf.createTypeReferenceNode('any'), tsf.createBlock([ tsf.createReturnStatement( tsf.createObjectLiteralExpression([ tsf.createSpreadAssignment( tsf.createCallExpression( - tsf.createPropertyAccessExpression(tsf.createSuper(), "debug"), + tsf.createPropertyAccessExpression(tsf.createSuper(), 'debug'), [], - [] - ) + [], + ), ), - ...fields.map(([name, field] : [string, Schema.Field]) => - tsf.createPropertyAssignment(getterIdent(name), debugValue(getterIdent(name))) - ) - ]) - )] - ) + ...fields.map(([name, field]: [string, Schema.Field]) => + tsf.createPropertyAssignment(getterIdent(name), debugValue(getterIdent(name))), + ), + ]), + ), + ]), ) } -function makeClass(modifiers: ts.Modifier[], name: ts.Identifier, members: ts.ClassElement[], id: string, types: [string: Schema.Type]): ts.ClassDeclaration { +function makeClass( + modifiers: ts.Modifier[], + name: ts.Identifier, + members: ts.ClassElement[], + id: string, + types: [string: Schema.Type], +): ts.ClassDeclaration { const ty = types[id] return tsf.createClassDeclaration( modifiers, name, undefined, - [tsf.createHeritageClause(ts.SyntaxKind.ExtendsKeyword, [ - tsf.createExpressionWithTypeArguments(support.LazyObject, []) - ])], + [ + tsf.createHeritageClause(ts.SyntaxKind.ExtendsKeyword, [ + tsf.createExpressionWithTypeArguments(support.LazyObject, []), + ]), + ], [ ...members, ...ty.fields.map(([name, field]: [string, Schema.Field]) => makeGetter(name, field, types)), - makeDebugFunction(ty.fields) + makeDebugFunction(ty.fields), ], - ); + ) } type ChildType = { @@ -365,107 +414,144 @@ type ChildType = { case: ts.CaseClause } -function makeChildType(parentName: string, base: ts.Identifier, id: string, discrim: string, types: [string: Schema.Type]): ChildType { +function makeChildType( + parentName: string, + base: ts.Identifier, + id: string, + discrim: string, + types: [string: Schema.Type], +): ChildType { const ty: Schema.Type = types[id] const name = toPascal(ty.name) const ident = tsf.createIdentifier(name) - const cursorIdent = tsf.createIdentifier("cursor") - const cursorParam = tsf.createParameterDeclaration([], undefined, cursorIdent, undefined, support.Cursor, undefined) + const cursorIdent = tsf.createIdentifier('cursor') + const cursorParam = tsf.createParameterDeclaration( + [], + undefined, + cursorIdent, + undefined, + support.Cursor, + undefined, + ) const discrimInt = tsf.createNumericLiteral(parseInt(discrim, 10)) return { definition: tsf.createClassDeclaration( [modifiers.export], name, undefined, - [tsf.createHeritageClause(ts.SyntaxKind.ExtendsKeyword, [ - tsf.createExpressionWithTypeArguments(base, []) - ])], + [ + tsf.createHeritageClause(ts.SyntaxKind.ExtendsKeyword, [ + tsf.createExpressionWithTypeArguments(base, []), + ]), + ], [ tsf.createPropertyDeclaration( [modifiers.readonly], - "type", + 'type', + undefined, + tsf.createTypeReferenceNode('Type.' + name), undefined, - tsf.createTypeReferenceNode("Type." + name), - undefined ), - tsf.createConstructorDeclaration([], [ - tsf.createParameterDeclaration([], undefined, cursorIdent, undefined, support.Cursor, undefined) + tsf.createConstructorDeclaration( + [], + [ + tsf.createParameterDeclaration( + [], + undefined, + cursorIdent, + undefined, + support.Cursor, + undefined, + ), ], tsf.createBlock([ - tsf.createExpressionStatement(tsf.createCallExpression( - tsf.createIdentifier("super"), [], [cursorIdent] - )), + tsf.createExpressionStatement( + tsf.createCallExpression(tsf.createIdentifier('super'), [], [cursorIdent]), + ), createAssignmentStatement( - tsf.createPropertyAccessExpression(tsf.createIdentifier("this"), "type"), - tsf.createPropertyAccessExpression(tsf.createIdentifier("Type"), name) - ) - ]) + tsf.createPropertyAccessExpression(tsf.createIdentifier('this'), 'type'), + tsf.createPropertyAccessExpression(tsf.createIdentifier('Type'), name), + ), + ]), ), tsf.createMethodDeclaration( [modifiers.static], undefined, - "read", + 'read', undefined, [], [cursorParam], tsf.createTypeReferenceNode(ident), - tsf.createBlock([tsf.createReturnStatement(tsf.createNewExpression(ident, [], [cursorIdent]))]) + tsf.createBlock([ + tsf.createReturnStatement(tsf.createNewExpression(ident, [], [cursorIdent])), + ]), ), ...ty.fields.map(([name, field]: [string, Schema.Field]) => makeGetter(name, field, types)), - makeDebugFunction(ty.fields) - ] + makeDebugFunction(ty.fields), + ], ), reference: tsf.createTypeReferenceNode(name), enumMember: tsf.createEnumMember(toPascal(types[id].name), discrimInt), - case: tsf.createCaseClause( - discrimInt, - [tsf.createReturnStatement( - tsf.createNewExpression(ident, [], [seekCursor(cursorIdent, 4)]) - )] - ) + case: tsf.createCaseClause(discrimInt, [ + tsf.createReturnStatement(tsf.createNewExpression(ident, [], [seekCursor(cursorIdent, 4)])), + ]), } } function forwardToSuper(ident: ts.Identifier, type: ts.TypeNode) { - return tsf.createConstructorDeclaration([], [ - tsf.createParameterDeclaration([], undefined, ident, undefined, type, undefined) - ], + return tsf.createConstructorDeclaration( + [], + [tsf.createParameterDeclaration([], undefined, ident, undefined, type, undefined)], tsf.createBlock([ - tsf.createExpressionStatement(tsf.createCallExpression( - tsf.createIdentifier("super"), [], [ident] - )) - ]) + tsf.createExpressionStatement( + tsf.createCallExpression(tsf.createIdentifier('super'), [], [ident]), + ), + ]), ) } function casesOrThrow(cases: ts.CaseClause[], error: string): ts.CaseBlock { - return tsf.createCaseBlock( - [ - ...cases, - tsf.createDefaultClause([ - tsf.createThrowStatement( - tsf.createNewExpression(tsf.createIdentifier("Error"), [], [tsf.createStringLiteral(error)]) - ) - ]) - ] - ) + return tsf.createCaseBlock([ + ...cases, + tsf.createDefaultClause([ + tsf.createThrowStatement( + tsf.createNewExpression( + tsf.createIdentifier('Error'), + [], + [tsf.createStringLiteral(error)], + ), + ), + ]), + ]) } -function abstractTypeDeserializer(ident: ts.Identifier, cases: ts.CaseClause[]): ts.FunctionDeclaration { - const cursorIdent = tsf.createIdentifier("cursor") +function abstractTypeDeserializer( + ident: ts.Identifier, + cases: ts.CaseClause[], +): ts.FunctionDeclaration { + const cursorIdent = tsf.createIdentifier('cursor') return tsf.createFunctionDeclaration( [modifiers.export], undefined, - "read", + 'read', [], - [tsf.createParameterDeclaration([], undefined, cursorIdent, undefined, support.Cursor, undefined)], + [ + tsf.createParameterDeclaration( + [], + undefined, + cursorIdent, + undefined, + support.Cursor, + undefined, + ), + ], tsf.createTypeReferenceNode(ident), tsf.createBlock([ tsf.createSwitchStatement( cursorMethods.readU32(cursorIdent), - casesOrThrow(cases, "Unexpected discriminant while deserializing.") - ) - ]) + casesOrThrow(cases, 'Unexpected discriminant while deserializing.'), + ), + ]), ) } @@ -473,35 +559,46 @@ function makeAbstractType(id: string, types: [string: Schema.Type]) { const ty = types[id] const name = toPascal(ty.name) const ident = tsf.createIdentifier(name) - const baseIdent = tsf.createIdentifier("AbstractBase") - const childTypes = Array.from(Object.entries(ty.discriminants), ([discrim, id]: [string, string]) => makeChildType(name, baseIdent, id, discrim, types)) - const cursorIdent = tsf.createIdentifier("cursor") - const moduleDecl = - tsf.createModuleDeclaration( - [modifiers.export], - ident, - tsf.createModuleBlock([ - makeClass([modifiers.abstract], baseIdent, [forwardToSuper(cursorIdent, support.Cursor)], id, types), - tsf.createEnumDeclaration( - [modifiers.export, modifiers.const], - "Type", - childTypes.map(child => child.enumMember) - ), - ...childTypes.map(child => child.definition), - tsf.createTypeAliasDeclaration( - [modifiers.export], - ident, - undefined, - tsf.createUnionTypeNode(childTypes.map(child => child.reference)) - ), - abstractTypeDeserializer(ident, childTypes.map(child => child.case)) - ]) - ) + const baseIdent = tsf.createIdentifier('AbstractBase') + const childTypes = Array.from( + Object.entries(ty.discriminants), + ([discrim, id]: [string, string]) => makeChildType(name, baseIdent, id, discrim, types), + ) + const cursorIdent = tsf.createIdentifier('cursor') + const moduleDecl = tsf.createModuleDeclaration( + [modifiers.export], + ident, + tsf.createModuleBlock([ + makeClass( + [modifiers.abstract], + baseIdent, + [forwardToSuper(cursorIdent, support.Cursor)], + id, + types, + ), + tsf.createEnumDeclaration( + [modifiers.export, modifiers.const], + 'Type', + childTypes.map((child) => child.enumMember), + ), + ...childTypes.map((child) => child.definition), + tsf.createTypeAliasDeclaration( + [modifiers.export], + ident, + undefined, + tsf.createUnionTypeNode(childTypes.map((child) => child.reference)), + ), + abstractTypeDeserializer( + ident, + childTypes.map((child) => child.case), + ), + ]), + ) const abstractTypeExport = tsf.createTypeAliasDeclaration( [modifiers.export], ident, undefined, - tsf.createTypeReferenceNode(name + "." + name) + tsf.createTypeReferenceNode(name + '.' + name), ) emit(moduleDecl) emit(abstractTypeExport) @@ -509,20 +606,19 @@ function makeAbstractType(id: string, types: [string: Schema.Type]) { function emit(data: ts.Node) { output += printer.printNode(ts.EmitHint.Unspecified, data, file) - output += "\n" + output += '\n' } - // ============ // === Main === // ============ const data: Schema = JSON.parse(fs.readFileSync(process.argv[2], 'utf8')) -let output = "// *** THIS FILE GENERATED BY `parser-codegen` ***\n" -const file = ts.createSourceFile("source.ts", "", ts.ScriptTarget.ESNext, false, ts.ScriptKind.TS) -const printer = ts.createPrinter({newLine: ts.NewLineKind.LineFeed}) -const nullType = tsf.createTypeReferenceNode("null") -const cursorFieldIdent = tsf.createIdentifier("lazyObjectData") +let output = '// *** THIS FILE GENERATED BY `parser-codegen` ***\n' +const file = ts.createSourceFile('source.ts', '', ts.ScriptTarget.ESNext, false, ts.ScriptKind.TS) +const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed }) +const nullType = tsf.createTypeReferenceNode('null') +const cursorFieldIdent = tsf.createIdentifier('lazyObjectData') const modifiers = { export: tsf.createModifier(ts.SyntaxKind.ExportKeyword), const: tsf.createModifier(ts.SyntaxKind.ConstKeyword), @@ -531,36 +627,41 @@ const modifiers = { static: tsf.createModifier(ts.SyntaxKind.StaticKeyword), } as const const cursorMethods = { - readString: primitiveReader("readString"), - readBool: primitiveReader("readBool"), - readU32: primitiveReader("readU32"), - readI32: primitiveReader("readI32"), - readU64: primitiveReader("readU64"), - readI64: primitiveReader("readI64"), - readPointer: primitiveReader("readPointer"), - readSequence: readerTransformerSized("readSequence"), - readOption: readerTransformer("readOption"), - readResult: readerTransformer2("readResult"), + readString: primitiveReader('readString'), + readBool: primitiveReader('readBool'), + readU32: primitiveReader('readU32'), + readI32: primitiveReader('readI32'), + readU64: primitiveReader('readU64'), + readI64: primitiveReader('readI64'), + readPointer: primitiveReader('readPointer'), + readSequence: readerTransformerSized('readSequence'), + readOption: readerTransformer('readOption'), + readResult: readerTransformer2('readResult'), } as const const POINTER_SIZE: number = 4 // Symbols exported by the `parserSupport` module. const support = { - LazyObject: tsf.createIdentifier("LazyObject"), - Cursor: tsf.createTypeReferenceNode(tsf.createIdentifier("Cursor")), - debugHelper: tsf.createIdentifier("debugHelper"), + LazyObject: tsf.createIdentifier('LazyObject'), + Cursor: tsf.createTypeReferenceNode(tsf.createIdentifier('Cursor')), + debugHelper: tsf.createIdentifier('debugHelper'), } as const -emit(tsf.createImportDeclaration( - [], - tsf.createImportClause( - false, +emit( + tsf.createImportDeclaration( + [], + tsf.createImportClause( + false, + undefined, + tsf.createNamedImports( + Array.from(Object.entries(support), ([name, _value]) => + tsf.createImportSpecifier(undefined, undefined, tsf.createIdentifier(name)), + ), + ), + ), + tsf.createStringLiteral('@/util/parserSupport', true), undefined, - tsf.createNamedImports(Array.from(Object.entries(support), ([name, _value]) => - tsf.createImportSpecifier(undefined, undefined, tsf.createIdentifier(name)))) ), - tsf.createStringLiteral("@/util/parserSupport", true), - undefined -)) +) for (const id in data.types) { const ty = data.types[id] if (ty.parent === null) { diff --git a/app/gui2/parser-codegen/src/prototype.ts b/app/gui2/parser-codegen/src/prototype.ts index 9cbb87d5d8ff..cee459722077 100644 --- a/app/gui2/parser-codegen/src/prototype.ts +++ b/app/gui2/parser-codegen/src/prototype.ts @@ -8,16 +8,16 @@ export module Tree { export enum Type { Ident = 0, - NamedApp = 1 + NamedApp = 1, } class Base extends LazyObject { get span(): Span { - throw new Error("TODO") + throw new Error('TODO') } children(): Iterable { - throw new Error("TODO") + throw new Error('TODO') } } @@ -25,7 +25,7 @@ export module Tree { readonly type: Type.Ident get token(): Token.Ident { - throw new Error("TODO") + throw new Error('TODO') } } @@ -33,27 +33,27 @@ export module Tree { readonly type: Type.NamedApp get func(): Tree { - throw new Error("TODO") + throw new Error('TODO') } get open(): Token.OpenSymbol | undefined { - throw new Error("TODO") + throw new Error('TODO') } get name(): Token.Ident { - throw new Error("TODO") + throw new Error('TODO') } get equals(): Token.Operator { - throw new Error("TODO") + throw new Error('TODO') } get arg(): Tree { - throw new Error("TODO") + throw new Error('TODO') } get close(): Token.CloseSymbol | undefined { - throw new Error("TODO") + throw new Error('TODO') } } } @@ -64,9 +64,9 @@ function switchTree(tree: Tree) { const span = tree.span switch (c) { case Tree.Type.Ident: - return "ident" + return 'ident' case Tree.Type.NamedApp: - return "named app" + return 'named app' default: const _ = c satisfies never } @@ -74,11 +74,11 @@ function switchTree(tree: Tree) { export class Span extends LazyObject { get start(): number { - throw new Error("TODO") + throw new Error('TODO') } get len(): number { - throw new Error("TODO") + throw new Error('TODO') } } @@ -89,7 +89,7 @@ export module Token { Ident, Operator, OpenSymbol, - CloseSymbol + CloseSymbol, } class Base { @@ -98,7 +98,7 @@ export module Token { readonly type: Type get span(): Span { - throw new Error("TODO") + throw new Error('TODO') } } @@ -106,7 +106,7 @@ export module Token { readonly type: Type.Ident get isTypeOrConstructor(): boolean { - throw new Error("TODO") + throw new Error('TODO') } } diff --git a/app/gui2/parser-codegen/tsconfig.json b/app/gui2/parser-codegen/tsconfig.json index ff8700519275..d58a717dccd5 100644 --- a/app/gui2/parser-codegen/tsconfig.json +++ b/app/gui2/parser-codegen/tsconfig.json @@ -1,11 +1,11 @@ { - "compilerOptions": { - "module": "commonjs", - "esModuleInterop": true, - "target": "es6", - "moduleResolution": "node", - "sourceMap": true, - "outDir": "dist" - }, - "lib": ["es2015"] + "compilerOptions": { + "module": "commonjs", + "esModuleInterop": true, + "target": "es6", + "moduleResolution": "node", + "sourceMap": true, + "outDir": "dist" + }, + "lib": ["es2015"] } diff --git a/app/gui2/parser-codegen/tslint.json b/app/gui2/parser-codegen/tslint.json index 32fa6e5e8d76..9e97bd249e15 100644 --- a/app/gui2/parser-codegen/tslint.json +++ b/app/gui2/parser-codegen/tslint.json @@ -1,9 +1,7 @@ { - "defaultSeverity": "error", - "extends": [ - "tslint:recommended" - ], - "jsRules": {}, - "rules": {}, - "rulesDirectory": [] -} \ No newline at end of file + "defaultSeverity": "error", + "extends": ["tslint:recommended"], + "jsRules": {}, + "rules": {}, + "rulesDirectory": [] +} diff --git a/app/gui2/src/util/ffi.ts b/app/gui2/src/util/ffi.ts index 02c428ab44eb..97236471a07f 100644 --- a/app/gui2/src/util/ffi.ts +++ b/app/gui2/src/util/ffi.ts @@ -1,7 +1,7 @@ -import init, { parse_to_json, parse } from '../../rust-ffi/pkg/rust_ffi' +import init, { parse, parse_to_json } from '../../rust-ffi/pkg/rust_ffi' +import * as Ast2 from '../generated/ast' import type { NonEmptyArray } from './array' import type { Opt } from './opt' -import * as Ast2 from '../generated/ast' const _wasm = await init() diff --git a/app/gui2/src/util/parserSupport.ts b/app/gui2/src/util/parserSupport.ts index bb28ec38be1b..0f715e9208e0 100644 --- a/app/gui2/src/util/parserSupport.ts +++ b/app/gui2/src/util/parserSupport.ts @@ -11,7 +11,7 @@ export class LazyObject { } export const builtin = { - Array: Array + Array: Array, } as const export class Cursor { @@ -21,10 +21,7 @@ export class Cursor { this.blob = new DataView(buffer, address) } - * readSequence( - readElement: (cursor: Cursor) => T, - elementSize: number - ): Iterable { + *readSequence(readElement: (cursor: Cursor) => T, elementSize: number): Iterable { const data = this.readPointer() let count = data.readU32() let offset = 4 @@ -35,9 +32,7 @@ export class Cursor { } } - readOption( - readElement: (cursor: Cursor) => T - ): T | null { + readOption(readElement: (cursor: Cursor) => T): T | null { const discriminant = this.readU8() switch (discriminant) { case 0: @@ -49,10 +44,7 @@ export class Cursor { } } - readResult( - readOk: (cursor: Cursor) => Ok, - readErr: (cursor: Cursor) => Err - ): Ok | Err { + readResult(readOk: (cursor: Cursor) => Ok, readErr: (cursor: Cursor) => Err): Ok | Err { const data = this.readPointer() const discriminant = data.readU32() switch (discriminant) { @@ -93,12 +85,14 @@ export class Cursor { readBool(): boolean { const value = this.readU8() switch (value) { - case 0: - return false - case 1: - return true - default: - throw new Error(`Invalid boolean: 0x${value.toString(16)} @ 0x${this.blob.byteOffset.toString(16)}.`) + case 0: + return false + case 1: + return true + default: + throw new Error( + `Invalid boolean: 0x${value.toString(16)} @ 0x${this.blob.byteOffset.toString(16)}.`, + ) } } @@ -118,10 +112,10 @@ export function debugHelper(value: any): object | null { if (value === null) { return null } - if (typeof value["debug"] === "function") { + if (typeof value['debug'] === 'function') { return value.debug() } - if (typeof value[Symbol.iterator] === "function") { + if (typeof value[Symbol.iterator] === 'function') { return Array.from(value, debugHelper) } return value diff --git a/lib/rust/parser/schema/src/proto.ts b/lib/rust/parser/schema/src/proto.ts index d0c5133fbf72..8f2a747bdccd 100644 --- a/lib/rust/parser/schema/src/proto.ts +++ b/lib/rust/parser/schema/src/proto.ts @@ -26,9 +26,9 @@ namespace Token { } interface Parsed { - visitTree(tree: Tree, visitor: VisitTree): void; - tokenCode(token: Token.Any): string; - tokenWhitespace(token: Token.Any): number; + visitTree(tree: Tree, visitor: VisitTree): void + tokenCode(token: Token.Any): string + tokenWhitespace(token: Token.Any): number } // Tree: Visitor implementation. From eef76e2e40f68b394d9fe155a9f20b6072035cbd Mon Sep 17 00:00:00 2001 From: Kaz Wesley Date: Tue, 26 Sep 2023 17:01:24 +0000 Subject: [PATCH 09/44] Cleanup. --- app/gui2/parser-codegen/src/prototype.ts | 124 ----------------------- 1 file changed, 124 deletions(-) delete mode 100644 app/gui2/parser-codegen/src/prototype.ts diff --git a/app/gui2/parser-codegen/src/prototype.ts b/app/gui2/parser-codegen/src/prototype.ts deleted file mode 100644 index cee459722077..000000000000 --- a/app/gui2/parser-codegen/src/prototype.ts +++ /dev/null @@ -1,124 +0,0 @@ -class LazyObject { - protected readonly blob: Uint8Array - protected readonly address: number -} - -export module Tree { - export type Tree = Ident | NamedApp - - export enum Type { - Ident = 0, - NamedApp = 1, - } - - class Base extends LazyObject { - get span(): Span { - throw new Error('TODO') - } - - children(): Iterable { - throw new Error('TODO') - } - } - - export class Ident extends Base { - readonly type: Type.Ident - - get token(): Token.Ident { - throw new Error('TODO') - } - } - - export class NamedApp extends Base { - readonly type: Type.NamedApp - - get func(): Tree { - throw new Error('TODO') - } - - get open(): Token.OpenSymbol | undefined { - throw new Error('TODO') - } - - get name(): Token.Ident { - throw new Error('TODO') - } - - get equals(): Token.Operator { - throw new Error('TODO') - } - - get arg(): Tree { - throw new Error('TODO') - } - - get close(): Token.CloseSymbol | undefined { - throw new Error('TODO') - } - } -} -export type Tree = Tree.Tree - -function switchTree(tree: Tree) { - const c = tree.type - const span = tree.span - switch (c) { - case Tree.Type.Ident: - return 'ident' - case Tree.Type.NamedApp: - return 'named app' - default: - const _ = c satisfies never - } -} - -export class Span extends LazyObject { - get start(): number { - throw new Error('TODO') - } - - get len(): number { - throw new Error('TODO') - } -} - -export type Token = Token.Ident | Token.Operator | Token.OpenSymbol | Token.CloseSymbol - -export module Token { - export enum Type { - Ident, - Operator, - OpenSymbol, - CloseSymbol, - } - - class Base { - protected readonly blob: Uint8Array - protected readonly address: number - readonly type: Type - - get span(): Span { - throw new Error('TODO') - } - } - - export class Ident extends Base { - readonly type: Type.Ident - - get isTypeOrConstructor(): boolean { - throw new Error('TODO') - } - } - - export class Operator extends Base { - readonly type: Type.Operator - } - - export class OpenSymbol extends Base { - readonly type: Type.OpenSymbol - } - - export class CloseSymbol extends Base { - readonly type: Type.CloseSymbol - } -} From 13eaf719e7e487d4329c36bc1f75010aba01dc06 Mon Sep 17 00:00:00 2001 From: Kaz Wesley Date: Tue, 26 Sep 2023 17:04:40 +0000 Subject: [PATCH 10/44] Cleanup. --- app/gui2/src/util/parserSupport.ts | 1 + lib/rust/metamodel/src/lib.rs | 1 - .../parser/schema/src/lazy_deserialization.rs | 0 lib/rust/parser/schema/src/lib.rs | 3 +- lib/rust/parser/schema/src/main.rs | 2 +- lib/rust/parser/schema/src/proto.ts | 50 ------------------- 6 files changed, 3 insertions(+), 54 deletions(-) delete mode 100644 lib/rust/parser/schema/src/lazy_deserialization.rs delete mode 100644 lib/rust/parser/schema/src/proto.ts diff --git a/app/gui2/src/util/parserSupport.ts b/app/gui2/src/util/parserSupport.ts index 0f715e9208e0..ad20d59d6350 100644 --- a/app/gui2/src/util/parserSupport.ts +++ b/app/gui2/src/util/parserSupport.ts @@ -1,3 +1,4 @@ +// This file supports the module in `../generated/ast.ts` that is produced by `parser-codegen`. export class LazyObject { protected readonly lazyObjectData: Cursor diff --git a/lib/rust/metamodel/src/lib.rs b/lib/rust/metamodel/src/lib.rs index 03fb4b25bc20..cd5411980947 100644 --- a/lib/rust/metamodel/src/lib.rs +++ b/lib/rust/metamodel/src/lib.rs @@ -7,7 +7,6 @@ //! The core modules define the metamodels, and operations on them: //! - [`rust`]: A metamodel representing data models in the Rust typesystem. //! - [`java`]: A metamodel representing data models in the Java typesystem. -//! - [`typescript`]: A metamodel representing data models in the TypeScript typesystem. //! - [`meta`]: An abstract metamodel, used to perform language-independent analysis of data models, //! and as an intermediate when translating data models between language-specific metamodels. //! diff --git a/lib/rust/parser/schema/src/lazy_deserialization.rs b/lib/rust/parser/schema/src/lazy_deserialization.rs deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/lib/rust/parser/schema/src/lib.rs b/lib/rust/parser/schema/src/lib.rs index 711d243b3908..1bd98b7fb6e9 100644 --- a/lib/rust/parser/schema/src/lib.rs +++ b/lib/rust/parser/schema/src/lib.rs @@ -1,5 +1,4 @@ -//! Supports generation of TypeScript types corresponding to `enso-parser`'s AST types, and testing -//! and debugging the translation process. +//! Supports generation of a schema describing `enso-parser`'s AST types. // === Standard Linter Configuration === #![deny(non_ascii_idents)] diff --git a/lib/rust/parser/schema/src/main.rs b/lib/rust/parser/schema/src/main.rs index 63856b334b22..7ab288b85b0e 100644 --- a/lib/rust/parser/schema/src/main.rs +++ b/lib/rust/parser/schema/src/main.rs @@ -23,5 +23,5 @@ // ========================= fn main() { - println!("{}", serde_json::to_string(&enso_parser_schema::types()).unwrap()); + serde_json::to_writer(std::io::stdout(), &enso_parser_schema::types()).unwrap() } diff --git a/lib/rust/parser/schema/src/proto.ts b/lib/rust/parser/schema/src/proto.ts deleted file mode 100644 index 8f2a747bdccd..000000000000 --- a/lib/rust/parser/schema/src/proto.ts +++ /dev/null @@ -1,50 +0,0 @@ -/** Design: - * - * # "parse" Enso code to binary format. - * # Visit nodes within blob. - * # Visitation protocol requires no allocations; visitor can process the data and allocate only the final types. - * - All visitor arguments are integers within the SMI range. - * - */ - -/* -module Enso { - function parse(text: string, id_map: Map) {} -} - -type Enso = Uint8Array - */ - -type Tree = number - -namespace Token { - export type Any = number - export type OpenSymbol = number - export type CloseSymbol = number - export type Ident = number - export type Operator = number -} - -interface Parsed { - visitTree(tree: Tree, visitor: VisitTree): void - tokenCode(token: Token.Any): string - tokenWhitespace(token: Token.Any): number -} - -// Tree: Visitor implementation. -// Token: External-storage implementation. - -interface VisitTree extends VisitNamedApp {} - -interface VisitNamedApp { - visitNamedApp( - start: number, - len: number, - func: Tree, - open: Token.OpenSymbol | undefined, - name: Token.Ident, - equals: Token.Operator, - arg: Tree, - close: Token.CloseSymbol | undefined - ): void -} From 475a66ab00ef315423843b209232fc2299da2dd0 Mon Sep 17 00:00:00 2001 From: Kaz Wesley Date: Tue, 26 Sep 2023 17:17:09 +0000 Subject: [PATCH 11/44] Restore cow powers for the time being. --- lib/rust/parser/schema/src/serialization.rs | 180 -------------------- lib/rust/parser/src/serialization.rs | 37 ++++ lib/rust/parser/src/source/code.rs | 5 +- 3 files changed, 40 insertions(+), 182 deletions(-) delete mode 100644 lib/rust/parser/schema/src/serialization.rs diff --git a/lib/rust/parser/schema/src/serialization.rs b/lib/rust/parser/schema/src/serialization.rs deleted file mode 100644 index e80dbbecb0d1..000000000000 --- a/lib/rust/parser/schema/src/serialization.rs +++ /dev/null @@ -1,180 +0,0 @@ -//! Serialization overrides for the `enso_parser` types. - -use enso_metamodel::typescript::*; - -use enso_metamodel::typescript::bincode::MapperInput; -use enso_metamodel::typescript::bincode::MaterializerInput; - - - -// ============================== -// === Derive Deserialization === -// ============================== - -// FIXME: After we have implemented a transformation from the raw `Reflect` output to a -// `rust::TypeGraph`, at which time we can assign unique `FieldId`s: We should identify -// generated fields in Java classes by starting from a `str -> rust::FieldId` query on Rust -// type data, and mapping fields analogously to `rust_to_java` for types. -const CODE_GETTER: &str = "codeRepr"; -const WHITESPACE_GETTER: &str = "getWhitespace"; -const TREE_BEGIN: &str = "fieldSpanLeftOffsetCodeReprBegin"; -const TREE_LEN: &str = "fieldSpanLeftOffsetCodeReprLen"; - -/// Derive deserialization for all types in the typegraph. -pub fn derive(graph: &mut TypeGraph, tree: ClassId, token: ClassId) { - let source = "source"; - impl_deserialize(graph, tree, token, source); - graph[token].methods.push(impl_getter(CODE_GETTER)); - graph[token].methods.push(impl_whitespace_getter(WHITESPACE_GETTER)); - graph[tree].methods.push(impl_getter(CODE_GETTER)); - graph[tree].methods.push(impl_whitespace_getter(WHITESPACE_GETTER)); -} - - -// === Deserialization Methods === - -fn impl_deserialize(graph: &mut TypeGraph, tree: ClassId, token: ClassId, source: &str) { - // Add source field to parent types. - let long = Primitive::Long { unsigned: true }; - let mut tree_start_whitespace_ = Field::primitive("startWhitespace", long); - let mut tree_start_code_ = Field::primitive("startCode", long); - let mut tree_end_code_ = Field::primitive("endCode", long); - tree_start_whitespace_.hide_in_tostring(); - tree_start_code_.hide_in_tostring(); - tree_end_code_.hide_in_tostring(); - let tree_start_whitespace = tree_start_whitespace_.id(); - let tree_start_code = tree_start_code_.id(); - let tree_end_code = tree_end_code_.id(); - graph[tree].fields.push(tree_start_whitespace_); - graph[tree].fields.push(tree_start_code_); - *graph[tree].child_field.as_mut().unwrap() += 2; - graph[tree].fields.push(tree_end_code_); - - let mut token_start_whitespace_ = Field::primitive("startWhitespace", long); - let mut token_start_code_ = Field::primitive("startCode", long); - let mut token_end_code_ = Field::primitive("endCode", long); - token_start_whitespace_.hide_in_tostring(); - token_start_code_.hide_in_tostring(); - token_end_code_.hide_in_tostring(); - let token_start_whitespace = token_start_whitespace_.id(); - let token_start_code = token_start_code_.id(); - let token_end_code = token_end_code_.id(); - let index = graph[token].child_field.unwrap(); - graph[token].fields.insert(index, token_start_whitespace_); - graph[token].fields.insert(index + 1, token_start_code_); - graph[token].fields.push(token_end_code_); - - // Add UUIDs to types - let uuid = Class::builtin("java.util.UUID", vec![]); - let uuid = graph.classes.insert(uuid); - let mut tree_id_ = Field::object("uuid", uuid, false); - tree_id_.hide_in_tostring(); - let tree_id = tree_id_.id(); - graph[tree].fields.push(tree_id_); - graph[tree].methods.push(Method::Dynamic(Dynamic::Getter(tree_id))); - - // Getters - let token_getters = [ - Dynamic::getter_named(token_start_whitespace, "getStartWhitespace"), - Dynamic::getter_named(token_start_code, "getStartCode"), - Dynamic::getter_named(token_end_code, "getEndCode"), - ]; - let tree_getters = [ - Dynamic::getter_named(tree_start_whitespace, "getStartWhitespace"), - Dynamic::getter_named(tree_start_code, "getStartCode"), - Dynamic::getter_named(tree_end_code, "getEndCode"), - ]; - graph[token].methods.extend(token_getters.map(Method::Dynamic)); - graph[tree].methods.extend(tree_getters.map(Method::Dynamic)); - - graph[tree].tostring_prefix_fields.push( - r#""\"" + source.subSequence((int)startWhitespace, (int)startCode) + "\"""#.to_string(), - ); - graph[tree] - .tostring_prefix_fields - .push(r#""\"" + source.subSequence((int)startCode, (int)endCode) + "\"""#.to_string()); - graph[token].tostring_prefix_fields.push( - r#""\"" + source.subSequence((int)startWhitespace, (int)startCode) + "\"""#.to_string(), - ); - graph[token] - .tostring_prefix_fields - .push(r#""\"" + source.subSequence((int)startCode, (int)endCode) + "\"""#.to_string()); - - let buffer = Class::builtin("CharSequence", vec![]); - let buffer = graph.classes.insert(buffer); - let mut tree_source_ = Field::object(source, buffer, true); - tree_source_.hide_in_tostring(); - let tree_source = tree_source_.id(); - graph[tree].fields.push(tree_source_); - let mut token_source_ = Field::object(source, buffer, true); - token_source_.hide_in_tostring(); - let token_source = token_source_.id(); - graph[token].fields.push(token_source_); - *graph[token].child_field.as_mut().unwrap() += 1; - - let tree_begin = graph[tree].find_field(TREE_BEGIN).unwrap().id(); - let ids: Vec<_> = graph.classes.keys().collect(); - for id in ids { - let class = &graph[id]; - let mut deserialization = - bincode::DeserializerBuilder::new(id, crate::SERIALIZATION_SUPPORT, crate::EITHER_TYPE); - if id == tree || class.parent == Some(tree) { - deserialization.materialize(tree_source, context_materializer()); - deserialization.materialize(tree_id, uuid_materializer()); - deserialization.materialize(tree_start_whitespace, start_whitespace()); - deserialization.materialize(tree_start_code, start_code_tree()); - deserialization.materialize(tree_end_code, end_code_tree()); - } - if id == token || class.parent == Some(token) { - deserialization.materialize(token_source, context_materializer()); - deserialization.materialize(token_start_whitespace, start_whitespace()); - deserialization.materialize(token_start_code, start_code_token()); - deserialization.materialize(token_end_code, end_code_token()); - } - deserialization.map(tree_begin, offset_mapper()); - let deserializer = deserialization.build(graph); - graph[id].methods.push(deserializer); - } -} - -fn offset_mapper() -> impl for<'a, 'b> Fn(MapperInput<'a, 'b>) -> String + 'static { - |MapperInput { message, value }| format!("{message}.offset({value})") -} - -fn context_materializer() -> impl for<'a> Fn(MaterializerInput<'a>) -> String + 'static { - |MaterializerInput { message }| format!("{message}.context()") -} -fn uuid_materializer() -> impl for<'a> Fn(MaterializerInput<'a>) -> String + 'static { - |MaterializerInput { message }| format!("{message}.getUuid(startCode, endCode - startCode)") -} -fn start_whitespace() -> impl for<'a> Fn(MaterializerInput<'a>) -> String + 'static { - |MaterializerInput { message }| format!("{message}.position()") -} -fn start_code_tree() -> impl for<'a> Fn(MaterializerInput<'a>) -> String + 'static { - |MaterializerInput { message }| format!("{message}.advance(fieldSpanLeftOffsetCodeUtf16)") -} -fn end_code_tree() -> impl for<'a> Fn(MaterializerInput<'a>) -> String + 'static { - |MaterializerInput { message }| format!("{message}.position()") -} -fn start_code_token() -> impl for<'a> Fn(MaterializerInput<'a>) -> String + 'static { - |MaterializerInput { message }| format!("{message}.advance(fieldLeftOffsetCodeUtf16)") -} -fn end_code_token() -> impl for<'a> Fn(MaterializerInput<'a>) -> String + 'static { - |MaterializerInput { message }| format!("{message}.advance(fieldCodeUtf16)") -} - - -// === Source Code Getters === - -fn impl_getter(name: &str) -> Method { - let mut method = syntax::Method::new(name, syntax::Type::named("String")); - method.body = - "return source.subSequence((int)startCode, (int)endCode).toString();\n".to_string(); - Method::Raw(method) -} - -fn impl_whitespace_getter(name: &str) -> Method { - let mut method = syntax::Method::new(name, syntax::Type::named("CharSequence")); - method.body = "return source.subSequence((int)startWhitespace, (int)startCode);\n".to_string(); - Method::Raw(method) -} diff --git a/lib/rust/parser/src/serialization.rs b/lib/rust/parser/src/serialization.rs index cb3d64c1bd38..7b6c73bed343 100644 --- a/lib/rust/parser/src/serialization.rs +++ b/lib/rust/parser/src/serialization.rs @@ -27,6 +27,43 @@ pub fn deserialize_tree(data: &[u8]) -> Result(cow: &Cow<'_, str>, ser: S) -> Result +where S: serde::Serializer { + let s = match cow { + Cow::Borrowed(s) => { + let begin = str::as_ptr(s) as u32; + let len = s.len() as u32; + Code { begin, len } + } + Cow::Owned(s) if s.is_empty() => Code { begin: 0, len: 0 }, + Cow::Owned(_) => panic!(), + }; + s.serialize(ser) +} + +pub(crate) fn deserialize_cow<'c, 'de, D>(deserializer: D) -> Result, D::Error> +where D: serde::Deserializer<'de> { + let _ = deserializer.deserialize_u64(DeserializeU64); + Ok(Cow::Owned(String::new())) +} + + + // ============== // === Tokens === // ============== diff --git a/lib/rust/parser/src/source/code.rs b/lib/rust/parser/src/source/code.rs index db6e2b927880..aba63791abd0 100644 --- a/lib/rust/parser/src/source/code.rs +++ b/lib/rust/parser/src/source/code.rs @@ -12,8 +12,9 @@ use crate::prelude::*; #[derive(Clone, Default, Eq, PartialEq, Serialize, Reflect, Deserialize, Deref)] #[allow(missing_docs)] pub struct Code<'s> { - #[reflect(skip)] - #[serde(skip)] + #[serde(serialize_with = "crate::serialization::serialize_cow")] + #[serde(deserialize_with = "crate::serialization::deserialize_cow")] + #[reflect(as = "crate::serialization::Code", flatten, hide)] #[deref] pub repr: Cow<'s, str>, #[reflect(hide)] From 9523e8ca097c947f09aca2c55d5f3424da7170a3 Mon Sep 17 00:00:00 2001 From: Kaz Wesley Date: Tue, 26 Sep 2023 17:53:41 +0000 Subject: [PATCH 12/44] Testing. --- app/gui2/src/util/ffi.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/gui2/src/util/ffi.ts b/app/gui2/src/util/ffi.ts index 0d115ac75977..161be44d4474 100644 --- a/app/gui2/src/util/ffi.ts +++ b/app/gui2/src/util/ffi.ts @@ -15,6 +15,13 @@ export function parseEnso2(code: string): Ast2.Tree { return Ast2.deserializeTree(blob) } +if (import.meta.vitest) { + const { test, expect } = import.meta.vitest + test('equality', () => { + expect(2 + 2).toBe(5) + }) +} + export namespace Ast { export interface Tree { span: Span From bedf476c0e2823be168c29e217d3e583f81060f8 Mon Sep 17 00:00:00 2001 From: Kaz Wesley Date: Tue, 26 Sep 2023 18:18:29 +0000 Subject: [PATCH 13/44] Simplify. --- app/gui2/parser-codegen/.babelrc | 3 - app/gui2/parser-codegen/package-lock.json | 3770 --------------------- app/gui2/parser-codegen/package.json | 6 +- 3 files changed, 1 insertion(+), 3778 deletions(-) delete mode 100644 app/gui2/parser-codegen/.babelrc diff --git a/app/gui2/parser-codegen/.babelrc b/app/gui2/parser-codegen/.babelrc deleted file mode 100644 index 1320b9a3272a..000000000000 --- a/app/gui2/parser-codegen/.babelrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "presets": ["@babel/preset-env"] -} diff --git a/app/gui2/parser-codegen/package-lock.json b/app/gui2/parser-codegen/package-lock.json index 7cef63947ded..0647e783887f 100644 --- a/app/gui2/parser-codegen/package-lock.json +++ b/app/gui2/parser-codegen/package-lock.json @@ -9,3635 +9,9 @@ "version": "1.0.0", "hasInstallScript": true, "devDependencies": { - "@babel/cli": "^7.22.15", - "@babel/core": "^7.22.20", - "@babel/node": "^7.22.19", - "@babel/preset-env": "^7.22.20", "typescript": "^5.2.2" } }, - "node_modules/@ampproject/remapping": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", - "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/cli": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.22.15.tgz", - "integrity": "sha512-prtg5f6zCERIaECeTZzd2fMtVjlfjhUcO+fBLQ6DXXdq5FljN+excVitJ2nogsusdf31LeqkjAfXZ7Xq+HmN8g==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.17", - "commander": "^4.0.1", - "convert-source-map": "^1.1.0", - "fs-readdir-recursive": "^1.1.0", - "glob": "^7.2.0", - "make-dir": "^2.1.0", - "slash": "^2.0.0" - }, - "bin": { - "babel": "bin/babel.js", - "babel-external-helpers": "bin/babel-external-helpers.js" - }, - "engines": { - "node": ">=6.9.0" - }, - "optionalDependencies": { - "@nicolo-ribaudo/chokidar-2": "2.1.8-no-fsevents.3", - "chokidar": "^3.4.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.22.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", - "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.22.13", - "chalk": "^2.4.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.20.tgz", - "integrity": "sha512-BQYjKbpXjoXwFW5jGqiizJQQT/aC7pFm9Ok1OWssonuguICi264lbgMzRp2ZMmRSlfkX6DsWDDcsrctK8Rwfiw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.20.tgz", - "integrity": "sha512-Y6jd1ahLubuYweD/zJH+vvOY141v4f9igNQAQ+MBgq9JlHS2iTsZKn1aMsb3vGccZsXI16VzTBw52Xx0DWmtnA==", - "dev": true, - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.22.15", - "@babel/helper-compilation-targets": "^7.22.15", - "@babel/helper-module-transforms": "^7.22.20", - "@babel/helpers": "^7.22.15", - "@babel/parser": "^7.22.16", - "@babel/template": "^7.22.15", - "@babel/traverse": "^7.22.20", - "@babel/types": "^7.22.19", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/generator": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.15.tgz", - "integrity": "sha512-Zu9oWARBqeVOW0dZOjXc3JObrzuqothQ3y/n1kUtrjCoCPLkXUwMvOo/F/TCfoHMbWIFlWwpZtkZVb9ga4U2pA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.15", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", - "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.15.tgz", - "integrity": "sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.15" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", - "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.22.9", - "@babel/helper-validator-option": "^7.22.15", - "browserslist": "^4.21.9", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.15.tgz", - "integrity": "sha512-jKkwA59IXcvSaiK2UN45kKwSC9o+KuoXsBDvHvU/7BecYIp8GQ2UwrVvFgJASUT+hBnwJx6MhvMCuMzwZZ7jlg==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-function-name": "^7.22.5", - "@babel/helper-member-expression-to-functions": "^7.22.15", - "@babel/helper-optimise-call-expression": "^7.22.5", - "@babel/helper-replace-supers": "^7.22.9", - "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.15.tgz", - "integrity": "sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "regexpu-core": "^5.3.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.2.tgz", - "integrity": "sha512-k0qnnOqHn5dK9pZpfD5XXZ9SojAITdCKRn2Lp6rnDGzIbaP0rHyMPk/4wsSxVBVz4RfN0q6VpXWP2pDGIoQ7hw==", - "dev": true, - "dependencies": { - "@babel/helper-compilation-targets": "^7.22.6", - "@babel/helper-plugin-utils": "^7.22.5", - "debug": "^4.1.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", - "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", - "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", - "dev": true, - "dependencies": { - "@babel/template": "^7.22.5", - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", - "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.22.15.tgz", - "integrity": "sha512-qLNsZbgrNh0fDQBCPocSL8guki1hcPvltGDv/NxvUoABwFq7GkKSu1nRXeJkVZc+wJvne2E0RKQz+2SQrz6eAA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.15" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", - "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.15" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.20.tgz", - "integrity": "sha512-dLT7JVWIUUxKOs1UnJUBR3S70YK+pKX6AbJgB2vMIvEkZkrfJDbYDJesnPshtKV4LhDOR3Oc5YULeDizRek+5A==", - "dev": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-module-imports": "^7.22.15", - "@babel/helper-simple-access": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/helper-validator-identifier": "^7.22.20" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz", - "integrity": "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.20.tgz", - "integrity": "sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-wrap-function": "^7.22.20" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-replace-supers": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.20.tgz", - "integrity": "sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw==", - "dev": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-member-expression-to-functions": "^7.22.15", - "@babel/helper-optimise-call-expression": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", - "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz", - "integrity": "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", - "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz", - "integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-wrap-function": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.20.tgz", - "integrity": "sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw==", - "dev": true, - "dependencies": { - "@babel/helper-function-name": "^7.22.5", - "@babel/template": "^7.22.15", - "@babel/types": "^7.22.19" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.15.tgz", - "integrity": "sha512-7pAjK0aSdxOwR+CcYAqgWOGy5dcfvzsTIfFTb2odQqW47MDfv14UaJDY6eng8ylM2EaeKXdxaSWESbkmaQHTmw==", - "dev": true, - "dependencies": { - "@babel/template": "^7.22.15", - "@babel/traverse": "^7.22.15", - "@babel/types": "^7.22.15" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", - "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.22.20", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/node": { - "version": "7.22.19", - "resolved": "https://registry.npmjs.org/@babel/node/-/node-7.22.19.tgz", - "integrity": "sha512-VsKSO9aEHdO16NdtqkJfrXZ9Sxlna1BVnBbToWr1KGdI3cyIk6KqOoa8mWvpK280lJDOwJqxvnl994KmLhq1Yw==", - "dev": true, - "dependencies": { - "@babel/register": "^7.22.15", - "commander": "^4.0.1", - "core-js": "^3.30.2", - "node-environment-flags": "^1.0.5", - "regenerator-runtime": "^0.14.0", - "v8flags": "^3.1.1" - }, - "bin": { - "babel-node": "bin/babel-node.js" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/parser": { - "version": "7.22.16", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.16.tgz", - "integrity": "sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.22.15.tgz", - "integrity": "sha512-FB9iYlz7rURmRJyXRKEnalYPPdn87H5no108cyuQQyMwlpJ2SJtpIUBI27kdTin956pz+LPypkPVPUTlxOmrsg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.22.15.tgz", - "integrity": "sha512-Hyph9LseGvAeeXzikV88bczhsrLrIZqDPxO+sSmAunMPaGrBGhfMWzCPYTtiW9t+HzSE2wtV8e5cc5P6r1xMDQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", - "@babel/plugin-transform-optional-chaining": "^7.22.15" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.13.0" - } - }, - "node_modules/@babel/plugin-proposal-private-property-in-object": { - "version": "7.21.0-placeholder-for-preset-env.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", - "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", - "dev": true, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-dynamic-import": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-export-namespace-from": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", - "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.22.5.tgz", - "integrity": "sha512-rdV97N7KqsRzeNGoWUOK6yUsWarLjE5Su/Snk9IYPU9CwkWHs4t+rTGOvffTR8XGkJMTAdLfO0xVnXm8wugIJg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.22.5.tgz", - "integrity": "sha512-KwvoWDeNKPETmozyFE0P2rOLqh39EoQHNjqizrI5B8Vt0ZNS7M56s7dAiAqbYfiAYOuIzIh96z3iR2ktgu3tEg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-private-property-in-object": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-unicode-sets-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", - "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.22.5.tgz", - "integrity": "sha512-26lTNXoVRdAnsaDXPpvCNUq+OVWEVC6bx7Vvz9rC53F2bagUWW4u4ii2+h8Fejfh7RYqPxn+libeFBBck9muEw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.22.15.tgz", - "integrity": "sha512-jBm1Es25Y+tVoTi5rfd5t1KLmL8ogLKpXszboWOTTtGFGz2RKnQe2yn7HbZ+kb/B8N0FVSGQo874NSlOU1T4+w==", - "dev": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-remap-async-to-generator": "^7.22.9", - "@babel/plugin-syntax-async-generators": "^7.8.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.22.5.tgz", - "integrity": "sha512-b1A8D8ZzE/VhNDoV1MSJTnpKkCG5bJo+19R4o4oy03zM7ws8yEMK755j61Dc3EyvdysbqH5BOOTquJ7ZX9C6vQ==", - "dev": true, - "dependencies": { - "@babel/helper-module-imports": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-remap-async-to-generator": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.22.5.tgz", - "integrity": "sha512-tdXZ2UdknEKQWKJP1KMNmuF5Lx3MymtMN/pvA+p/VEkhK8jVcQ1fzSy8KM9qRYhAf2/lV33hoMPKI/xaI9sADA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.22.15.tgz", - "integrity": "sha512-G1czpdJBZCtngoK1sJgloLiOHUnkb/bLZwqVZD8kXmq0ZnVfTTWUcs9OWtp0mBtYJ+4LQY1fllqBkOIPhXmFmw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-class-properties": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.22.5.tgz", - "integrity": "sha512-nDkQ0NfkOhPTq8YCLiWNxp1+f9fCobEjCb0n8WdbNUBc4IB5V7P1QnX9IjpSoquKrXF5SKojHleVNs2vGeHCHQ==", - "dev": true, - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-class-static-block": { - "version": "7.22.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.22.11.tgz", - "integrity": "sha512-GMM8gGmqI7guS/llMFk1bJDkKfn3v3C4KHK9Yg1ey5qcHcOlKb0QvcMrgzvxo+T03/4szNh5lghY+fEC98Kq9g==", - "dev": true, - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.22.11", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-class-static-block": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.12.0" - } - }, - "node_modules/@babel/plugin-transform-classes": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.22.15.tgz", - "integrity": "sha512-VbbC3PGjBdE0wAWDdHM9G8Gm977pnYI0XpqMd6LrKISj8/DJXEsWqgRuTYaNE9Bv0JGhTZUzHDlMk18IpOuoqw==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-compilation-targets": "^7.22.15", - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-function-name": "^7.22.5", - "@babel/helper-optimise-call-expression": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-replace-supers": "^7.22.9", - "@babel/helper-split-export-declaration": "^7.22.6", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.22.5.tgz", - "integrity": "sha512-4GHWBgRf0krxPX+AaPtgBAlTgTeZmqDynokHOX7aqqAB4tHs3U2Y02zH6ETFdLZGcg9UQSD1WCmkVrE9ErHeOg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/template": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.22.15.tgz", - "integrity": "sha512-HzG8sFl1ZVGTme74Nw+X01XsUTqERVQ6/RLHo3XjGRzm7XD6QTtfS3NJotVgCGy8BzkDqRjRBD8dAyJn5TuvSQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.22.5.tgz", - "integrity": "sha512-5/Yk9QxCQCl+sOIB1WelKnVRxTJDSAIxtJLL2/pqL14ZVlbH0fUQUZa/T5/UnQtBNgghR7mfB8ERBKyKPCi7Vw==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.22.5.tgz", - "integrity": "sha512-dEnYD+9BBgld5VBXHnF/DbYGp3fqGMsyxKbtD1mDyIA7AkTSpKXFhCVuj/oQVOoALfBs77DudA0BE4d5mcpmqw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-dynamic-import": { - "version": "7.22.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.22.11.tgz", - "integrity": "sha512-g/21plo58sfteWjaO0ZNVb+uEOkJNjAaHhbejrnBmu011l/eNDScmkbjCC3l4FKb10ViaGU4aOkFznSu2zRHgA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-dynamic-import": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.22.5.tgz", - "integrity": "sha512-vIpJFNM/FjZ4rh1myqIya9jXwrwwgFRHPjT3DkUA9ZLHuzox8jiXkOLvwm1H+PQIP3CqfC++WPKeuDi0Sjdj1g==", - "dev": true, - "dependencies": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-export-namespace-from": { - "version": "7.22.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.22.11.tgz", - "integrity": "sha512-xa7aad7q7OiT8oNZ1mU7NrISjlSkVdMbNxn9IuLZyL9AJEhs1Apba3I+u5riX1dIkdptP5EKDG5XDPByWxtehw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-for-of": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.22.15.tgz", - "integrity": "sha512-me6VGeHsx30+xh9fbDLLPi0J1HzmeIIyenoOQHuw2D4m2SAU3NrspX5XxJLBpqn5yrLzrlw2Iy3RA//Bx27iOA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-function-name": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.22.5.tgz", - "integrity": "sha512-UIzQNMS0p0HHiQm3oelztj+ECwFnj+ZRV4KnguvlsD2of1whUeM6o7wGNj6oLwcDoAXQ8gEqfgC24D+VdIcevg==", - "dev": true, - "dependencies": { - "@babel/helper-compilation-targets": "^7.22.5", - "@babel/helper-function-name": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-json-strings": { - "version": "7.22.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.22.11.tgz", - "integrity": "sha512-CxT5tCqpA9/jXFlme9xIBCc5RPtdDq3JpkkhgHQqtDdiTnTI0jtZ0QzXhr5DILeYifDPp2wvY2ad+7+hLMW5Pw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-json-strings": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-literals": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.22.5.tgz", - "integrity": "sha512-fTLj4D79M+mepcw3dgFBTIDYpbcB9Sm0bpm4ppXPaO+U+PKFFyV9MGRvS0gvGw62sd10kT5lRMKXAADb9pWy8g==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-logical-assignment-operators": { - "version": "7.22.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.22.11.tgz", - "integrity": "sha512-qQwRTP4+6xFCDV5k7gZBF3C31K34ut0tbEcTKxlX/0KXxm9GLcO14p570aWxFvVzx6QAfPgq7gaeIHXJC8LswQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.22.5.tgz", - "integrity": "sha512-RZEdkNtzzYCFl9SE9ATaUMTj2hqMb4StarOJLrZRbqqU4HSBE7UlBw9WBWQiDzrJZJdUWiMTVDI6Gv/8DPvfew==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.22.5.tgz", - "integrity": "sha512-R+PTfLTcYEmb1+kK7FNkhQ1gP4KgjpSO6HfH9+f8/yfp2Nt3ggBjiVpRwmwTlfqZLafYKJACy36yDXlEmI9HjQ==", - "dev": true, - "dependencies": { - "@babel/helper-module-transforms": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.22.15.tgz", - "integrity": "sha512-jWL4eh90w0HQOTKP2MoXXUpVxilxsB2Vl4ji69rSjS3EcZ/v4sBmn+A3NpepuJzBhOaEBbR7udonlHHn5DWidg==", - "dev": true, - "dependencies": { - "@babel/helper-module-transforms": "^7.22.15", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-simple-access": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.22.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.22.11.tgz", - "integrity": "sha512-rIqHmHoMEOhI3VkVf5jQ15l539KrwhzqcBO6wdCNWPWc/JWt9ILNYNUssbRpeq0qWns8svuw8LnMNCvWBIJ8wA==", - "dev": true, - "dependencies": { - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-module-transforms": "^7.22.9", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.22.5.tgz", - "integrity": "sha512-+S6kzefN/E1vkSsKx8kmQuqeQsvCKCd1fraCM7zXm4SFoggI099Tr4G8U81+5gtMdUeMQ4ipdQffbKLX0/7dBQ==", - "dev": true, - "dependencies": { - "@babel/helper-module-transforms": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz", - "integrity": "sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-transform-new-target": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.22.5.tgz", - "integrity": "sha512-AsF7K0Fx/cNKVyk3a+DW0JLo+Ua598/NxMRvxDnkpCIGFh43+h/v2xyhRUYf6oD8gE4QtL83C7zZVghMjHd+iw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { - "version": "7.22.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.22.11.tgz", - "integrity": "sha512-YZWOw4HxXrotb5xsjMJUDlLgcDXSfO9eCmdl1bgW4+/lAGdkjaEvOnQ4p5WKKdUgSzO39dgPl0pTnfxm0OAXcg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-numeric-separator": { - "version": "7.22.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.22.11.tgz", - "integrity": "sha512-3dzU4QGPsILdJbASKhF/V2TVP+gJya1PsueQCxIPCEcerqF21oEcrob4mzjsp2Py/1nLfF5m+xYNMDpmA8vffg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-numeric-separator": "^7.10.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-object-rest-spread": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.22.15.tgz", - "integrity": "sha512-fEB+I1+gAmfAyxZcX1+ZUwLeAuuf8VIg67CTznZE0MqVFumWkh8xWtn58I4dxdVf080wn7gzWoF8vndOViJe9Q==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.22.9", - "@babel/helper-compilation-targets": "^7.22.15", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.22.15" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-object-super": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.22.5.tgz", - "integrity": "sha512-klXqyaT9trSjIUrcsYIfETAzmOEZL3cBYqOYLJxBHfMFFggmXOv+NYSX/Jbs9mzMVESw/WycLFPRx8ba/b2Ipw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-replace-supers": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-optional-catch-binding": { - "version": "7.22.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.22.11.tgz", - "integrity": "sha512-rli0WxesXUeCJnMYhzAglEjLWVDF6ahb45HuprcmQuLidBJFWjNnOzssk2kuc6e33FlLaiZhG/kUIzUMWdBKaQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.22.15.tgz", - "integrity": "sha512-ngQ2tBhq5vvSJw2Q2Z9i7ealNkpDMU0rGWnHPKqRZO0tzZ5tlaoz4hDvhXioOoaE0X2vfNss1djwg0DXlfu30A==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-parameters": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.22.15.tgz", - "integrity": "sha512-hjk7qKIqhyzhhUvRT683TYQOFa/4cQKwQy7ALvTpODswN40MljzNDa0YldevS6tGbxwaEKVn502JmY0dP7qEtQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-private-methods": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.22.5.tgz", - "integrity": "sha512-PPjh4gyrQnGe97JTalgRGMuU4icsZFnWkzicB/fUtzlKUqvsWBKEpPPfr5a2JiyirZkHxnAqkQMO5Z5B2kK3fA==", - "dev": true, - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-private-property-in-object": { - "version": "7.22.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.22.11.tgz", - "integrity": "sha512-sSCbqZDBKHetvjSwpyWzhuHkmW5RummxJBVbYLkGkaiTOWGxml7SXt0iWa03bzxFIx7wOj3g/ILRd0RcJKBeSQ==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-create-class-features-plugin": "^7.22.11", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.22.5.tgz", - "integrity": "sha512-TiOArgddK3mK/x1Qwf5hay2pxI6wCZnvQqrFSqbtg1GLl2JcNMitVH/YnqjP+M31pLUeTfzY1HAXFDnUBV30rQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.22.10.tgz", - "integrity": "sha512-F28b1mDt8KcT5bUyJc/U9nwzw6cV+UmTeRlXYIl2TNqMMJif0Jeey9/RQ3C4NOd2zp0/TRsDns9ttj2L523rsw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "regenerator-transform": "^0.15.2" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.22.5.tgz", - "integrity": "sha512-DTtGKFRQUDm8svigJzZHzb/2xatPc6TzNvAIJ5GqOKDsGFYgAskjRulbR/vGsPKq3OPqtexnz327qYpP57RFyA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.22.5.tgz", - "integrity": "sha512-vM4fq9IXHscXVKzDv5itkO1X52SmdFBFcMIBZ2FRn2nqVYqw6dBexUgMvAjHW+KXpPPViD/Yo3GrDEBaRC0QYA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-spread": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.22.5.tgz", - "integrity": "sha512-5ZzDQIGyvN4w8+dMmpohL6MBo+l2G7tfC/O2Dg7/hjpgeWvUx8FzfeOKxGog9IimPa4YekaQ9PlDqTLOljkcxg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.22.5.tgz", - "integrity": "sha512-zf7LuNpHG0iEeiyCNwX4j3gDg1jgt1k3ZdXBKbZSoA3BbGQGvMiSvfbZRR3Dr3aeJe3ooWFZxOOG3IRStYp2Bw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.22.5.tgz", - "integrity": "sha512-5ciOehRNf+EyUeewo8NkbQiUs4d6ZxiHo6BcBcnFlgiJfu16q0bQUw9Jvo0b0gBKFG1SMhDSjeKXSYuJLeFSMA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.22.5.tgz", - "integrity": "sha512-bYkI5lMzL4kPii4HHEEChkD0rkc+nvnlR6+o/qdqR6zrm0Sv/nodmyLhlq2DO0YKLUNd2VePmPRjJXSBh9OIdA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.22.10.tgz", - "integrity": "sha512-lRfaRKGZCBqDlRU3UIFovdp9c9mEvlylmpod0/OatICsSfuQ9YFthRo1tpTkGsklEefZdqlEFdY4A2dwTb6ohg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-property-regex": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.22.5.tgz", - "integrity": "sha512-HCCIb+CbJIAE6sXn5CjFQXMwkCClcOfPCzTlilJ8cUatfzwHlWQkbtV0zD338u9dZskwvuOYTuuaMaA8J5EI5A==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.22.5.tgz", - "integrity": "sha512-028laaOKptN5vHJf9/Arr/HiJekMd41hOEZYvNsrsXqJ7YPYuX2bQxh31fkZzGmq3YqHRJzYFFAVYvKfMPKqyg==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-sets-regex": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.22.5.tgz", - "integrity": "sha512-lhMfi4FC15j13eKrh3DnYHjpGj6UKQHtNKTbtc1igvAhRy4+kLhV07OpLcsN0VgDEw/MjAvJO4BdMJsHwMhzCg==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/preset-env": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.22.20.tgz", - "integrity": "sha512-11MY04gGC4kSzlPHRfvVkNAZhUxOvm7DCJ37hPDnUENwe06npjIRAfInEMTGSb4LZK5ZgDFkv5hw0lGebHeTyg==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.22.20", - "@babel/helper-compilation-targets": "^7.22.15", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-validator-option": "^7.22.15", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.22.15", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.22.15", - "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-class-static-block": "^7.14.5", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-import-assertions": "^7.22.5", - "@babel/plugin-syntax-import-attributes": "^7.22.5", - "@babel/plugin-syntax-import-meta": "^7.10.4", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5", - "@babel/plugin-syntax-top-level-await": "^7.14.5", - "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", - "@babel/plugin-transform-arrow-functions": "^7.22.5", - "@babel/plugin-transform-async-generator-functions": "^7.22.15", - "@babel/plugin-transform-async-to-generator": "^7.22.5", - "@babel/plugin-transform-block-scoped-functions": "^7.22.5", - "@babel/plugin-transform-block-scoping": "^7.22.15", - "@babel/plugin-transform-class-properties": "^7.22.5", - "@babel/plugin-transform-class-static-block": "^7.22.11", - "@babel/plugin-transform-classes": "^7.22.15", - "@babel/plugin-transform-computed-properties": "^7.22.5", - "@babel/plugin-transform-destructuring": "^7.22.15", - "@babel/plugin-transform-dotall-regex": "^7.22.5", - "@babel/plugin-transform-duplicate-keys": "^7.22.5", - "@babel/plugin-transform-dynamic-import": "^7.22.11", - "@babel/plugin-transform-exponentiation-operator": "^7.22.5", - "@babel/plugin-transform-export-namespace-from": "^7.22.11", - "@babel/plugin-transform-for-of": "^7.22.15", - "@babel/plugin-transform-function-name": "^7.22.5", - "@babel/plugin-transform-json-strings": "^7.22.11", - "@babel/plugin-transform-literals": "^7.22.5", - "@babel/plugin-transform-logical-assignment-operators": "^7.22.11", - "@babel/plugin-transform-member-expression-literals": "^7.22.5", - "@babel/plugin-transform-modules-amd": "^7.22.5", - "@babel/plugin-transform-modules-commonjs": "^7.22.15", - "@babel/plugin-transform-modules-systemjs": "^7.22.11", - "@babel/plugin-transform-modules-umd": "^7.22.5", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5", - "@babel/plugin-transform-new-target": "^7.22.5", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.22.11", - "@babel/plugin-transform-numeric-separator": "^7.22.11", - "@babel/plugin-transform-object-rest-spread": "^7.22.15", - "@babel/plugin-transform-object-super": "^7.22.5", - "@babel/plugin-transform-optional-catch-binding": "^7.22.11", - "@babel/plugin-transform-optional-chaining": "^7.22.15", - "@babel/plugin-transform-parameters": "^7.22.15", - "@babel/plugin-transform-private-methods": "^7.22.5", - "@babel/plugin-transform-private-property-in-object": "^7.22.11", - "@babel/plugin-transform-property-literals": "^7.22.5", - "@babel/plugin-transform-regenerator": "^7.22.10", - "@babel/plugin-transform-reserved-words": "^7.22.5", - "@babel/plugin-transform-shorthand-properties": "^7.22.5", - "@babel/plugin-transform-spread": "^7.22.5", - "@babel/plugin-transform-sticky-regex": "^7.22.5", - "@babel/plugin-transform-template-literals": "^7.22.5", - "@babel/plugin-transform-typeof-symbol": "^7.22.5", - "@babel/plugin-transform-unicode-escapes": "^7.22.10", - "@babel/plugin-transform-unicode-property-regex": "^7.22.5", - "@babel/plugin-transform-unicode-regex": "^7.22.5", - "@babel/plugin-transform-unicode-sets-regex": "^7.22.5", - "@babel/preset-modules": "0.1.6-no-external-plugins", - "@babel/types": "^7.22.19", - "babel-plugin-polyfill-corejs2": "^0.4.5", - "babel-plugin-polyfill-corejs3": "^0.8.3", - "babel-plugin-polyfill-regenerator": "^0.5.2", - "core-js-compat": "^3.31.0", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-modules": { - "version": "0.1.6-no-external-plugins", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", - "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/types": "^7.4.4", - "esutils": "^2.0.2" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/@babel/register": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.22.15.tgz", - "integrity": "sha512-V3Q3EqoQdn65RCgTLwauZaTfd1ShhwPmbBv+1dkZV/HpCGMKVyn6oFcRlI7RaKqiDQjX2Qd3AuoEguBgdjIKlg==", - "dev": true, - "dependencies": { - "clone-deep": "^4.0.1", - "find-cache-dir": "^2.0.0", - "make-dir": "^2.1.0", - "pirates": "^4.0.5", - "source-map-support": "^0.5.16" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/regjsgen": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", - "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==", - "dev": true - }, - "node_modules/@babel/runtime": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.15.tgz", - "integrity": "sha512-T0O+aa+4w0u06iNmapipJXMV4HoUir03hpx3/YqXXhu9xim3w+dVphjFWl1OH8NbZHw5Lbm9k45drDkgq2VNNA==", - "dev": true, - "dependencies": { - "regenerator-runtime": "^0.14.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/template": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.20.tgz", - "integrity": "sha512-eU260mPZbU7mZ0N+X10pxXhQFMGTeLb9eFS0mxehS8HZp9o1uSnFeWQuG1UPrlxgA7QoUzFhOnilHDp0AXCyHw==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.22.15", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.22.5", - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.22.16", - "@babel/types": "^7.22.19", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.22.19", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.19.tgz", - "integrity": "sha512-P7LAw/LbojPzkgp5oznjE6tQEIWbp4PkkfrZDINTro9zgBRtI324/EYsiSI7lhPbpIQ+DCeR2NNmMWANGGfZsg==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.19", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", - "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.19", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz", - "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@nicolo-ribaudo/chokidar-2": { - "version": "2.1.8-no-fsevents.3", - "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz", - "integrity": "sha512-s88O1aVtXftvp5bCPB7WnmXc5IwOZZ7YPuwNPt+GtOOXpPvad1LfbmjYv+qII7zP6RU2QGnqve27dnLycEnyEQ==", - "dev": true, - "optional": true - }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "optional": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/array-buffer-byte-length": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", - "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "is-array-buffer": "^3.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.reduce": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/array.prototype.reduce/-/array.prototype.reduce-1.0.6.tgz", - "integrity": "sha512-UW+Mz8LG/sPSU8jRDCjVr6J/ZKAGpHfwrZ6kWTG5qCxIEiXdVshqGnu5vEZA8S1y6X4aCSbQZ0/EEsfvEvBiSg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-array-method-boxes-properly": "^1.0.0", - "is-string": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/arraybuffer.prototype.slice": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz", - "integrity": "sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==", - "dev": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", - "is-array-buffer": "^3.0.2", - "is-shared-array-buffer": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/available-typed-arrays": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", - "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.4.5", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.5.tgz", - "integrity": "sha512-19hwUH5FKl49JEsvyTcoHakh6BE0wgXLLptIyKZ3PijHc/Ci521wygORCUCCred+E/twuqRyAkE02BAWPmsHOg==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.22.6", - "@babel/helper-define-polyfill-provider": "^0.4.2", - "semver": "^6.3.1" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.3.tgz", - "integrity": "sha512-z41XaniZL26WLrvjy7soabMXrfPWARN25PZoriDEiLMxAp50AUW3t35BGQUMg5xK3UrpVTtagIDklxYa+MhiNA==", - "dev": true, - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.4.2", - "core-js-compat": "^3.31.0" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.2.tgz", - "integrity": "sha512-tAlOptU0Xj34V1Y2PNTL4Y0FOJMDB6bZmoW39FeCQIhigGLkqu3Fj6uiXpxIf6Ij274ENdYx64y6Au+ZKlb1IA==", - "dev": true, - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.4.2" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true, - "optional": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "optional": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browserslist": { - "version": "4.21.10", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz", - "integrity": "sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "caniuse-lite": "^1.0.30001517", - "electron-to-chromium": "^1.4.477", - "node-releases": "^2.0.13", - "update-browserslist-db": "^1.0.11" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001535", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001535.tgz", - "integrity": "sha512-48jLyUkiWFfhm/afF7cQPqPjaUmSraEhK4j+FCTJpgnGGEZHqyLe3hmWH7lIooZdSzXL0ReMvHz0vKDoTBsrwg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ] - }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "optional": true, - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/clone-deep": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", - "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", - "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.2", - "shallow-clone": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", - "dev": true - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true - }, - "node_modules/core-js": { - "version": "3.32.2", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.32.2.tgz", - "integrity": "sha512-pxXSw1mYZPDGvTQqEc5vgIb83jGQKFGYWY76z4a7weZXUolw3G+OvpZqSRcfYOoOVUQJYEPsWeQK8pKEnUtWxQ==", - "dev": true, - "hasInstallScript": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, - "node_modules/core-js-compat": { - "version": "3.32.2", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.32.2.tgz", - "integrity": "sha512-+GjlguTDINOijtVRUxrQOv3kfu9rl+qPNdX2LTbJ/ZyVTuxK+ksVSAGX1nHstu4hrv1En/uPTtWgq2gI5wt4AQ==", - "dev": true, - "dependencies": { - "browserslist": "^4.21.10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/define-data-property": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.0.tgz", - "integrity": "sha512-UzGwzcjyv3OtAvolTj1GoyNYzfFR+iqbGjcnBEENZVCpM4/Ng1yhGNvS3lR/xDS74Tb2wGG9WzNSNIOS9UVb2g==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.1", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/define-properties": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", - "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", - "dev": true, - "dependencies": { - "define-data-property": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.4.523", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.523.tgz", - "integrity": "sha512-9AreocSUWnzNtvLcbpng6N+GkXnCcBR80IQkxRC9Dfdyg4gaWNUPBujAHUpKkiUkoSoR9UlhA4zD/IgBklmhzg==", - "dev": true - }, - "node_modules/es-abstract": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.2.tgz", - "integrity": "sha512-YoxfFcDmhjOgWPWsV13+2RNjq1F6UQnfs+8TftwNqtzlmFzEXvlUwdrNrYeaizfjQzRMxkZ6ElWMOJIFKdVqwA==", - "dev": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "arraybuffer.prototype.slice": "^1.0.2", - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-set-tostringtag": "^2.0.1", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.6", - "get-intrinsic": "^1.2.1", - "get-symbol-description": "^1.0.0", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", - "has": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.5", - "is-array-buffer": "^3.0.2", - "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.12", - "is-weakref": "^1.0.2", - "object-inspect": "^1.12.3", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.1", - "safe-array-concat": "^1.0.1", - "safe-regex-test": "^1.0.0", - "string.prototype.trim": "^1.2.8", - "string.prototype.trimend": "^1.0.7", - "string.prototype.trimstart": "^1.0.7", - "typed-array-buffer": "^1.0.0", - "typed-array-byte-length": "^1.0.0", - "typed-array-byte-offset": "^1.0.0", - "typed-array-length": "^1.0.4", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.11" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-array-method-boxes-properly": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", - "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==", - "dev": true - }, - "node_modules/es-set-tostringtag": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", - "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.3", - "has": "^1.0.3", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "optional": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-cache-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", - "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", - "dev": true, - "dependencies": { - "commondir": "^1.0.1", - "make-dir": "^2.0.0", - "pkg-dir": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "dependencies": { - "locate-path": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.3" - } - }, - "node_modules/fs-readdir-recursive": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz", - "integrity": "sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==", - "dev": true - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "node_modules/function.prototype.name": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", - "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "functions-have-names": "^1.2.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-intrinsic": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", - "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "optional": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/globalthis": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", - "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/homedir-polyfill": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", - "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", - "dev": true, - "dependencies": { - "parse-passwd": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/internal-slot": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", - "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/is-array-buffer": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", - "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.0", - "is-typed-array": "^1.1.10" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, - "dependencies": { - "has-bigints": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "optional": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-core-module": { - "version": "2.13.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz", - "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==", - "dev": true, - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "optional": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", - "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typed-array": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", - "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", - "dev": true, - "dependencies": { - "which-typed-array": "^1.1.11" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true - }, - "node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "dependencies": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", - "dev": true - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "dev": true, - "dependencies": { - "pify": "^4.0.1", - "semver": "^5.6.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/make-dir/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/node-environment-flags": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.6.tgz", - "integrity": "sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw==", - "dev": true, - "dependencies": { - "object.getownpropertydescriptors": "^2.0.3", - "semver": "^5.7.0" - } - }, - "node_modules/node-environment-flags/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/node-releases": { - "version": "2.0.13", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", - "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==", - "dev": true - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", - "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.getownpropertydescriptors": { - "version": "2.1.7", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.7.tgz", - "integrity": "sha512-PrJz0C2xJ58FNn11XV2lr4Jt5Gzl94qpy9Lu0JlfEj14z88sqbSBJCBEzdlNUCzY2gburhbrwOZ5BHCmuNUy0g==", - "dev": true, - "dependencies": { - "array.prototype.reduce": "^1.0.6", - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "safe-array-concat": "^1.0.0" - }, - "engines": { - "node": ">= 0.8" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "dependencies": { - "p-limit": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-passwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", - "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "optional": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/pirates": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", - "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/pkg-dir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", - "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", - "dev": true, - "dependencies": { - "find-up": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "optional": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/regenerate": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", - "dev": true - }, - "node_modules/regenerate-unicode-properties": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", - "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", - "dev": true, - "dependencies": { - "regenerate": "^1.4.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/regenerator-runtime": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", - "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==", - "dev": true - }, - "node_modules/regenerator-transform": { - "version": "0.15.2", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", - "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.8.4" - } - }, - "node_modules/regexp.prototype.flags": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", - "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "set-function-name": "^2.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/regexpu-core": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", - "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", - "dev": true, - "dependencies": { - "@babel/regjsgen": "^0.8.0", - "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.1.0", - "regjsparser": "^0.9.1", - "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/regjsparser": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", - "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", - "dev": true, - "dependencies": { - "jsesc": "~0.5.0" - }, - "bin": { - "regjsparser": "bin/parser" - } - }, - "node_modules/regjsparser/node_modules/jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - } - }, - "node_modules/resolve": { - "version": "1.22.6", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.6.tgz", - "integrity": "sha512-njhxM7mV12JfufShqGy3Rz8j11RPdLy4xi15UurGJeoHLfJpVXKdh3ueuOqbYUcDZnffr6X739JBo5LzyahEsw==", - "dev": true, - "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/safe-array-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.1.tgz", - "integrity": "sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1", - "has-symbols": "^1.0.3", - "isarray": "^2.0.5" - }, - "engines": { - "node": ">=0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/safe-regex-test": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", - "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "is-regex": "^1.1.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/set-function-name": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz", - "integrity": "sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==", - "dev": true, - "dependencies": { - "define-data-property": "^1.0.1", - "functions-have-names": "^1.2.3", - "has-property-descriptors": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/shallow-clone": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", - "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/slash": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/string.prototype.trim": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", - "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", - "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", - "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "optional": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/typed-array-buffer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", - "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1", - "is-typed-array": "^1.1.10" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/typed-array-byte-length": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", - "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "has-proto": "^1.0.1", - "is-typed-array": "^1.1.10" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-byte-offset": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", - "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", - "dev": true, - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "has-proto": "^1.0.1", - "is-typed-array": "^1.1.10" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-length": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", - "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "is-typed-array": "^1.1.9" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/typescript": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", @@ -3650,150 +24,6 @@ "engines": { "node": ">=14.17" } - }, - "node_modules/unbox-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/unicode-canonical-property-names-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", - "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-match-property-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", - "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", - "dev": true, - "dependencies": { - "unicode-canonical-property-names-ecmascript": "^2.0.0", - "unicode-property-aliases-ecmascript": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-match-property-value-ecmascript": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", - "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-property-aliases-ecmascript": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", - "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", - "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/v8flags": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.2.0.tgz", - "integrity": "sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg==", - "dev": true, - "dependencies": { - "homedir-polyfill": "^1.0.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, - "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-typed-array": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.11.tgz", - "integrity": "sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==", - "dev": true, - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true } } } diff --git a/app/gui2/parser-codegen/package.json b/app/gui2/parser-codegen/package.json index cacb94246aaf..8b4d66cc8711 100644 --- a/app/gui2/parser-codegen/package.json +++ b/app/gui2/parser-codegen/package.json @@ -10,14 +10,10 @@ "scripts": { "generate-ast-schema": "rm -rf generated && mkdir generated && cargo run -p enso-parser-schema > generated/ast-schema.json", "preinstall": "npm run generate-ast-schema", - "start": "tsc && node node_modules/.bin/babel-node dist/codegen.js generated/ast-schema.json generated/ast.ts" + "start": "tsc && node dist/codegen.js generated/ast-schema.json generated/ast.ts" }, "keywords": [], "devDependencies": { - "@babel/cli": "^7.22.15", - "@babel/core": "^7.22.20", - "@babel/node": "^7.22.19", - "@babel/preset-env": "^7.22.20", "typescript": "^5.2.2" } } From 599641b1f403c1403afe7de59a7021c1494e83d3 Mon Sep 17 00:00:00 2001 From: Kaz Wesley Date: Tue, 26 Sep 2023 20:29:52 +0000 Subject: [PATCH 14/44] Testing. --- app/gui2/parser-codegen/package-lock.json | 3 +-- app/gui2/parser-codegen/package.json | 4 ++-- app/gui2/parser-codegen/src/codegen.ts | 26 +++++++++++++---------- app/gui2/parser-codegen/tsconfig.json | 5 +++-- 4 files changed, 21 insertions(+), 17 deletions(-) diff --git a/app/gui2/parser-codegen/package-lock.json b/app/gui2/parser-codegen/package-lock.json index 0647e783887f..9755eb259404 100644 --- a/app/gui2/parser-codegen/package-lock.json +++ b/app/gui2/parser-codegen/package-lock.json @@ -8,7 +8,7 @@ "name": "enso-parser-codegen", "version": "1.0.0", "hasInstallScript": true, - "devDependencies": { + "dependencies": { "typescript": "^5.2.2" } }, @@ -16,7 +16,6 @@ "version": "5.2.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", - "dev": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" diff --git a/app/gui2/parser-codegen/package.json b/app/gui2/parser-codegen/package.json index 8b4d66cc8711..5e766f178d4b 100644 --- a/app/gui2/parser-codegen/package.json +++ b/app/gui2/parser-codegen/package.json @@ -10,10 +10,10 @@ "scripts": { "generate-ast-schema": "rm -rf generated && mkdir generated && cargo run -p enso-parser-schema > generated/ast-schema.json", "preinstall": "npm run generate-ast-schema", - "start": "tsc && node dist/codegen.js generated/ast-schema.json generated/ast.ts" + "start": "tsc --build && node dist/codegen.js generated/ast-schema.json generated/ast.ts" }, "keywords": [], - "devDependencies": { + "dependencies": { "typescript": "^5.2.2" } } diff --git a/app/gui2/parser-codegen/src/codegen.ts b/app/gui2/parser-codegen/src/codegen.ts index aa95f362990f..16ec205a87bd 100644 --- a/app/gui2/parser-codegen/src/codegen.ts +++ b/app/gui2/parser-codegen/src/codegen.ts @@ -2,9 +2,6 @@ import * as fs from 'fs' import * as ts from 'typescript' import { factory as tsf } from 'typescript' -type Schema = { - types: [string: Schema.Type] -} module Schema { export type Type = { name: string @@ -25,6 +22,12 @@ module Schema { export type Result = { class: 'result'; type0: TypeRef; type1: TypeRef } export type PrimitiveType = 'bool' | 'u32' | 'u64' | 'i32' | 'i64' | 'char' | 'string' } +type TypeGraph = { + [id: string]: Schema.Type +} +type Schema = { + types: TypeGraph +} function fromSnake(ident: string, to: 'camel' | 'pascal', prefix?: string): string { const segments = [] @@ -196,12 +199,13 @@ class Type { this.size = size } - static new(ref: Schema.TypeRef, types: [string: Schema.Type]): Type { + static new(ref: Schema.TypeRef, types: TypeGraph): Type { const c = ref.class switch (c) { case 'type': const ty = types[ref.id] - const parent = types[ty.parent] + const parentId = ty.parent + const parent = ty.parent != null ? types[ty.parent] : null const typeName = namespacedName(ty.name, parent?.name) const type = tsf.createTypeReferenceNode(typeName) if (Object.entries(ty.discriminants).length !== 0) { @@ -286,7 +290,7 @@ function seekCursor(cursor: ts.Expression, offset: number): ts.Expression { function makeGetter( fieldName: string, fieldData: Schema.Field, - types: [string: Schema.Type], + types: TypeGraph, ): ts.GetAccessorDeclaration { const type = Type.new(fieldData.type, types) return tsf.createGetAccessorDeclaration( @@ -314,7 +318,7 @@ function createAssignmentStatement(left: ts.Expression, right: ts.Expression): t ) } -function makeConcreteType(id: string, types: [string: Schema.Type]): ts.ClassDeclaration { +function makeConcreteType(id: string, types: TypeGraph): ts.ClassDeclaration { const ident = tsf.createIdentifier(toPascal(types[id].name)) const paramIdent = tsf.createIdentifier('cursor') const cursorParam = tsf.createParameterDeclaration( @@ -387,7 +391,7 @@ function makeClass( name: ts.Identifier, members: ts.ClassElement[], id: string, - types: [string: Schema.Type], + types: TypeGraph, ): ts.ClassDeclaration { const ty = types[id] return tsf.createClassDeclaration( @@ -419,7 +423,7 @@ function makeChildType( base: ts.Identifier, id: string, discrim: string, - types: [string: Schema.Type], + types: TypeGraph, ): ChildType { const ty: Schema.Type = types[id] const name = toPascal(ty.name) @@ -555,7 +559,7 @@ function abstractTypeDeserializer( ) } -function makeAbstractType(id: string, types: [string: Schema.Type]) { +function makeAbstractType(id: string, types: TypeGraph) { const ty = types[id] const name = toPascal(ty.name) const ident = tsf.createIdentifier(name) @@ -654,7 +658,7 @@ emit( undefined, tsf.createNamedImports( Array.from(Object.entries(support), ([name, _value]) => - tsf.createImportSpecifier(undefined, undefined, tsf.createIdentifier(name)), + tsf.createImportSpecifier(false, undefined, tsf.createIdentifier(name)), ), ), ), diff --git a/app/gui2/parser-codegen/tsconfig.json b/app/gui2/parser-codegen/tsconfig.json index d58a717dccd5..8b3d6f6d979f 100644 --- a/app/gui2/parser-codegen/tsconfig.json +++ b/app/gui2/parser-codegen/tsconfig.json @@ -1,11 +1,12 @@ { + "extends": "@tsconfig/node18/tsconfig.json", "compilerOptions": { "module": "commonjs", + "moduleResolution": "node", "esModuleInterop": true, "target": "es6", - "moduleResolution": "node", "sourceMap": true, "outDir": "dist" }, - "lib": ["es2015"] + "lib": ["es2015"], } From 986bc842e24cda3f399253d8eaecada392287ad6 Mon Sep 17 00:00:00 2001 From: Kaz Wesley Date: Wed, 27 Sep 2023 13:40:26 +0000 Subject: [PATCH 15/44] Cleanup. --- app/gui2/.prettierignore | 4 +++- app/gui2/parser-codegen/src/codegen.ts | 14 ++++++++------ app/gui2/parser-codegen/tsconfig.json | 5 ----- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/app/gui2/.prettierignore b/app/gui2/.prettierignore index 766e0a799a36..bb6b39b75420 100644 --- a/app/gui2/.prettierignore +++ b/app/gui2/.prettierignore @@ -1,2 +1,4 @@ *.html -*.css \ No newline at end of file +*.css + +**/generated diff --git a/app/gui2/parser-codegen/src/codegen.ts b/app/gui2/parser-codegen/src/codegen.ts index 16ec205a87bd..e00ac7ccffcf 100644 --- a/app/gui2/parser-codegen/src/codegen.ts +++ b/app/gui2/parser-codegen/src/codegen.ts @@ -2,12 +2,18 @@ import * as fs from 'fs' import * as ts from 'typescript' import { factory as tsf } from 'typescript' +type DiscriminantMap = { + [discriminant: number]: string +} +type TypeGraph = { + [id: string]: Schema.Type +} module Schema { export type Type = { name: string fields: [string, Field][] parent: string | null - discriminants: [number: string] + discriminants: DiscriminantMap size: number } export type Field = { @@ -22,9 +28,6 @@ module Schema { export type Result = { class: 'result'; type0: TypeRef; type1: TypeRef } export type PrimitiveType = 'bool' | 'u32' | 'u64' | 'i32' | 'i64' | 'char' | 'string' } -type TypeGraph = { - [id: string]: Schema.Type -} type Schema = { types: TypeGraph } @@ -204,7 +207,6 @@ class Type { switch (c) { case 'type': const ty = types[ref.id] - const parentId = ty.parent const parent = ty.parent != null ? types[ty.parent] : null const typeName = namespacedName(ty.name, parent?.name) const type = tsf.createTypeReferenceNode(typeName) @@ -377,7 +379,7 @@ function makeDebugFunction(fields: [string, Schema.Field][]): ts.MethodDeclarati [], ), ), - ...fields.map(([name, field]: [string, Schema.Field]) => + ...fields.map(([name, _field]: [string, Schema.Field]) => tsf.createPropertyAssignment(getterIdent(name), debugValue(getterIdent(name))), ), ]), diff --git a/app/gui2/parser-codegen/tsconfig.json b/app/gui2/parser-codegen/tsconfig.json index 8b3d6f6d979f..8bc485587375 100644 --- a/app/gui2/parser-codegen/tsconfig.json +++ b/app/gui2/parser-codegen/tsconfig.json @@ -1,12 +1,7 @@ { "extends": "@tsconfig/node18/tsconfig.json", "compilerOptions": { - "module": "commonjs", - "moduleResolution": "node", - "esModuleInterop": true, - "target": "es6", "sourceMap": true, "outDir": "dist" }, - "lib": ["es2015"], } From d9ac1c8433b6911a6cd5d443beec5f090bd683d2 Mon Sep 17 00:00:00 2001 From: Kaz Wesley Date: Wed, 27 Sep 2023 17:03:59 +0000 Subject: [PATCH 16/44] Finish u64/Result support. --- app/gui2/parser-codegen/src/codegen.ts | 4 ++-- app/gui2/src/util/parserSupport.ts | 21 +++++++++++---------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/app/gui2/parser-codegen/src/codegen.ts b/app/gui2/parser-codegen/src/codegen.ts index e00ac7ccffcf..18049314fc74 100644 --- a/app/gui2/parser-codegen/src/codegen.ts +++ b/app/gui2/parser-codegen/src/codegen.ts @@ -225,9 +225,9 @@ class Type { case 'i32': return new Type(tsf.createTypeReferenceNode('number'), cursorMethods.readI32, 4) case 'u64': - return new Type(tsf.createTypeReferenceNode('number'), cursorMethods.readU64, 8) + return new Type(tsf.createTypeReferenceNode('bigint'), cursorMethods.readU64, 8) case 'i64': - return new Type(tsf.createTypeReferenceNode('number'), cursorMethods.readI64, 8) + return new Type(tsf.createTypeReferenceNode('bigint'), cursorMethods.readI64, 8) case 'char': return new Type(tsf.createTypeReferenceNode('number'), cursorMethods.readU32, 4) case 'string': diff --git a/app/gui2/src/util/parserSupport.ts b/app/gui2/src/util/parserSupport.ts index ad20d59d6350..0587a2fac71e 100644 --- a/app/gui2/src/util/parserSupport.ts +++ b/app/gui2/src/util/parserSupport.ts @@ -11,6 +11,8 @@ export class LazyObject { } } +export type Result = { Ok: T } | { Err: E } + export const builtin = { Array: Array, } as const @@ -45,14 +47,14 @@ export class Cursor { } } - readResult(readOk: (cursor: Cursor) => Ok, readErr: (cursor: Cursor) => Err): Ok | Err { + readResult(readOk: (cursor: Cursor) => Ok, readErr: (cursor: Cursor) => Err): Result { const data = this.readPointer() const discriminant = data.readU32() switch (discriminant) { case 0: - return readOk(data.seek(4)) + return { Ok: readOk(data.seek(4)) } case 1: - return readErr(data.seek(4)) + return { Err: readErr(data.seek(4)) } default: throw new Error(`Invalid Result discriminant: 0x${discriminant.toString(16)}.`) } @@ -74,13 +76,12 @@ export class Cursor { return this.blob.getInt32(0, true)! } - readU64(): number { - const lo = this.readU32() - const hi = this.seek(4).readU32() - //if (hi !== 0) { - // throw new RangeError() - //} - return lo + readU64(): bigint { + return this.blob.getBigUint64(0, true)! + } + + readI64(): bigint { + return this.blob.getBigInt64(0, true)! } readBool(): boolean { From fca9b19c2ae30517636906832513d2465a414097 Mon Sep 17 00:00:00 2001 From: Kaz Wesley Date: Wed, 27 Sep 2023 17:05:41 +0000 Subject: [PATCH 17/44] Remove test. --- app/gui2/src/util/ffi.ts | 7 ------- 1 file changed, 7 deletions(-) diff --git a/app/gui2/src/util/ffi.ts b/app/gui2/src/util/ffi.ts index 161be44d4474..0d115ac75977 100644 --- a/app/gui2/src/util/ffi.ts +++ b/app/gui2/src/util/ffi.ts @@ -15,13 +15,6 @@ export function parseEnso2(code: string): Ast2.Tree { return Ast2.deserializeTree(blob) } -if (import.meta.vitest) { - const { test, expect } = import.meta.vitest - test('equality', () => { - expect(2 + 2).toBe(5) - }) -} - export namespace Ast { export interface Tree { span: Span From 3666517767716397b809c4314338206684f11f84 Mon Sep 17 00:00:00 2001 From: Kaz Wesley Date: Wed, 27 Sep 2023 18:51:46 +0000 Subject: [PATCH 18/44] Format, fix Windows. --- app/gui2/package.json | 2 +- app/gui2/parser-codegen/generated/.gitkeep | 0 app/gui2/parser-codegen/package.json | 2 +- app/gui2/src/generated/.gitkeep | 0 app/gui2/src/util/parserSupport.ts | 5 ++++- 5 files changed, 6 insertions(+), 3 deletions(-) create mode 100644 app/gui2/parser-codegen/generated/.gitkeep create mode 100644 app/gui2/src/generated/.gitkeep diff --git a/app/gui2/package.json b/app/gui2/package.json index 20847ecfea94..f38c3251656f 100644 --- a/app/gui2/package.json +++ b/app/gui2/package.json @@ -19,7 +19,7 @@ "lint": "eslint .", "format": "prettier --write src/ && eslint . --fix", "build-rust-ffi": "cd rust-ffi && wasm-pack build --release --target web", - "generate-parser-bindings": "cd parser-codegen && npm install && npm run start && cd .. && rm -rf src/generated && mkdir src/generated && cp parser-codegen/generated/ast.ts src/generated/", + "generate-parser-bindings": "cd parser-codegen && npm install && npm run start && cd .. && cp parser-codegen/generated/ast.ts src/generated/", "preinstall": "npm run build-rust-ffi && npm run generate-parser-bindings" }, "dependencies": { diff --git a/app/gui2/parser-codegen/generated/.gitkeep b/app/gui2/parser-codegen/generated/.gitkeep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/app/gui2/parser-codegen/package.json b/app/gui2/parser-codegen/package.json index 5e766f178d4b..51b0fc07e20e 100644 --- a/app/gui2/parser-codegen/package.json +++ b/app/gui2/parser-codegen/package.json @@ -8,7 +8,7 @@ }, "main": "dist/codegen.js", "scripts": { - "generate-ast-schema": "rm -rf generated && mkdir generated && cargo run -p enso-parser-schema > generated/ast-schema.json", + "generate-ast-schema": "cargo run -p enso-parser-schema > generated/ast-schema.json", "preinstall": "npm run generate-ast-schema", "start": "tsc --build && node dist/codegen.js generated/ast-schema.json generated/ast.ts" }, diff --git a/app/gui2/src/generated/.gitkeep b/app/gui2/src/generated/.gitkeep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/app/gui2/src/util/parserSupport.ts b/app/gui2/src/util/parserSupport.ts index 0587a2fac71e..41dd1f3ca5e0 100644 --- a/app/gui2/src/util/parserSupport.ts +++ b/app/gui2/src/util/parserSupport.ts @@ -47,7 +47,10 @@ export class Cursor { } } - readResult(readOk: (cursor: Cursor) => Ok, readErr: (cursor: Cursor) => Err): Result { + readResult( + readOk: (cursor: Cursor) => Ok, + readErr: (cursor: Cursor) => Err, + ): Result { const data = this.readPointer() const discriminant = data.readU32() switch (discriminant) { From 458dca86f6525ed5721a8ff76cc3e295cbb6a430 Mon Sep 17 00:00:00 2001 From: Kaz Wesley Date: Thu, 28 Sep 2023 14:08:40 +0000 Subject: [PATCH 19/44] Fix Windows --- app/gui2/package.json | 2 +- app/gui2/parser-codegen/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/gui2/package.json b/app/gui2/package.json index f38c3251656f..9eba8ab2bf1b 100644 --- a/app/gui2/package.json +++ b/app/gui2/package.json @@ -19,7 +19,7 @@ "lint": "eslint .", "format": "prettier --write src/ && eslint . --fix", "build-rust-ffi": "cd rust-ffi && wasm-pack build --release --target web", - "generate-parser-bindings": "cd parser-codegen && npm install && npm run start && cd .. && cp parser-codegen/generated/ast.ts src/generated/", + "generate-parser-bindings": "cd parser-codegen && npm install && npm run generate-bindings ../src/generated/ast.ts", "preinstall": "npm run build-rust-ffi && npm run generate-parser-bindings" }, "dependencies": { diff --git a/app/gui2/parser-codegen/package.json b/app/gui2/parser-codegen/package.json index 51b0fc07e20e..33e2d098b45c 100644 --- a/app/gui2/parser-codegen/package.json +++ b/app/gui2/parser-codegen/package.json @@ -10,7 +10,7 @@ "scripts": { "generate-ast-schema": "cargo run -p enso-parser-schema > generated/ast-schema.json", "preinstall": "npm run generate-ast-schema", - "start": "tsc --build && node dist/codegen.js generated/ast-schema.json generated/ast.ts" + "generate-bindings": "tsc --build && node dist/codegen.js generated/ast-schema.json" }, "keywords": [], "dependencies": { From 86dfd121eb87fe51c90e5cc0dfdfcb8992c8f605 Mon Sep 17 00:00:00 2001 From: Kaz Wesley Date: Thu, 28 Sep 2023 14:09:35 +0000 Subject: [PATCH 20/44] Lint --- app/gui2/parser-codegen/tsconfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/gui2/parser-codegen/tsconfig.json b/app/gui2/parser-codegen/tsconfig.json index 8bc485587375..14eedeedc478 100644 --- a/app/gui2/parser-codegen/tsconfig.json +++ b/app/gui2/parser-codegen/tsconfig.json @@ -3,5 +3,5 @@ "compilerOptions": { "sourceMap": true, "outDir": "dist" - }, + } } From 8ff1c714d9238a63aa5589d2cc38f8a928e75d0c Mon Sep 17 00:00:00 2001 From: Kaz Wesley Date: Thu, 28 Sep 2023 17:48:29 +0000 Subject: [PATCH 21/44] Fix typing. --- app/gui2/parser-codegen/src/codegen.ts | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/app/gui2/parser-codegen/src/codegen.ts b/app/gui2/parser-codegen/src/codegen.ts index 18049314fc74..769607a8cd57 100644 --- a/app/gui2/parser-codegen/src/codegen.ts +++ b/app/gui2/parser-codegen/src/codegen.ts @@ -270,7 +270,7 @@ class Type { static result(ok: Type, err: Type): Type { return new Type( - tsf.createUnionTypeNode([ok.type, err.type]), + support.Result(ok.type, err.type), cursorMethods.readResult(ok.reader, err.reader), POINTER_SIZE, ) @@ -646,12 +646,19 @@ const cursorMethods = { } as const const POINTER_SIZE: number = 4 // Symbols exported by the `parserSupport` module. +const supportImports = { + LazyObject: false, + Cursor: false, + debugHelper: false, + Result: true, +} as const const support = { LazyObject: tsf.createIdentifier('LazyObject'), Cursor: tsf.createTypeReferenceNode(tsf.createIdentifier('Cursor')), debugHelper: tsf.createIdentifier('debugHelper'), + Result: (t0: ts.TypeNode, t1: ts.TypeNode) => + tsf.createTypeReferenceNode(tsf.createIdentifier('Result'), [t0, t1]), } as const - emit( tsf.createImportDeclaration( [], @@ -659,8 +666,8 @@ emit( false, undefined, tsf.createNamedImports( - Array.from(Object.entries(support), ([name, _value]) => - tsf.createImportSpecifier(false, undefined, tsf.createIdentifier(name)), + Array.from(Object.entries(supportImports), ([name, isTypeOnly]) => + tsf.createImportSpecifier(isTypeOnly, undefined, tsf.createIdentifier(name)), ), ), ), From f8708c6487d158d1d4287211f60e9a12dc96c402 Mon Sep 17 00:00:00 2001 From: Kaz Wesley Date: Sat, 30 Sep 2023 14:23:10 +0000 Subject: [PATCH 22/44] Review. --- Cargo.lock | 1 + app/gui2/parser-codegen/src/codegen.ts | 140 ++++++------ app/gui2/src/util/ffi.ts | 30 ++- app/gui2/src/util/parserSupport.ts | 16 +- lib/rust/metamodel/lexpr/src/lib.rs | 6 +- lib/rust/metamodel/src/meta/mod.rs | 2 +- lib/rust/parser/Cargo.toml | 5 +- lib/rust/parser/schema/src/lib.rs | 283 ++++++++++++++++--------- lib/rust/parser/schema/src/main.rs | 2 +- lib/rust/parser/src/format.rs | 18 +- lib/rust/parser/src/lib.rs | 2 + 11 files changed, 324 insertions(+), 181 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 35d978e7f8b2..1c7e05e02e5a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2365,6 +2365,7 @@ dependencies = [ "serde", "serde_json", "uuid 1.2.2", + "wasm-bindgen-test", ] [[package]] diff --git a/app/gui2/parser-codegen/src/codegen.ts b/app/gui2/parser-codegen/src/codegen.ts index 769607a8cd57..c70f3635551a 100644 --- a/app/gui2/parser-codegen/src/codegen.ts +++ b/app/gui2/parser-codegen/src/codegen.ts @@ -2,39 +2,47 @@ import * as fs from 'fs' import * as ts from 'typescript' import { factory as tsf } from 'typescript' -type DiscriminantMap = { - [discriminant: number]: string -} -type TypeGraph = { - [id: string]: Schema.Type -} module Schema { + export type TypeId = string + export type Types = { + [id: TypeId]: Type + } export type Type = { name: string - fields: [string, Field][] - parent: string | null - discriminants: DiscriminantMap - size: number + fields: Fields + parent?: string } - export type Field = { - type: TypeRef - offset: number + export type Fields = { + [name: string]: TypeRef } export type TypeRef = Class | Primitive | Sequence | Option | Result - export type Class = { class: 'type'; id: string } + export type Class = { class: 'type'; id: TypeId } export type Primitive = { class: 'primitive'; type: PrimitiveType } export type Sequence = { class: 'sequence'; type: TypeRef } export type Option = { class: 'option'; type: TypeRef } export type Result = { class: 'result'; type0: TypeRef; type1: TypeRef } export type PrimitiveType = 'bool' | 'u32' | 'u64' | 'i32' | 'i64' | 'char' | 'string' + + export type Serialization = { + [id: TypeId]: Layout + } + export type Layout = { + discriminants?: DiscriminantMap + fields: [name: string, offset: number][] + size: number + } + export type DiscriminantMap = { + [discriminant: number]: TypeId + } } type Schema = { - types: TypeGraph + types: Schema.Types + serialization: Schema.Serialization } function fromSnake(ident: string, to: 'camel' | 'pascal', prefix?: string): string { const segments = [] - if (prefix !== undefined) { + if (prefix != null) { segments.push(...prefix.split('_')) } segments.push(...ident.split('_')) @@ -77,6 +85,12 @@ function primitiveReader(name: string): ExpressionTransformer { tsf.createCallExpression(tsf.createPropertyAccessExpression(cursor, name), [], []) } +/** + * Given the name of a runtime `Cursor` method that deserializes a derived type given a function to deserialize a + * base type, return a codegen-time function that generates a *reader* for a derived type from a *reader* for the base + * type, where a *reader* is a function producing a deserialization expression from an expression that evaluates to a + * `Cursor`. + */ function readerTransformer( name: string, ): (readElement: ExpressionTransformer) => ExpressionTransformer { @@ -108,7 +122,7 @@ function readerTransformer( } } -function readerTransformer2( +function readerTransformerTwoTyped( name: string, ): (readOk: ExpressionTransformer, readErr: ExpressionTransformer) => ExpressionTransformer { function makeArrow(reader: ExpressionTransformer, data: ts.Identifier) { @@ -166,7 +180,7 @@ function readerTransformerSized( } function namespacedName(name: string, namespace?: string): string { - if (namespace === undefined) { + if (namespace == null) { return toPascal(name) } else { return toPascal(namespace) + '.' + toPascal(name) @@ -202,18 +216,19 @@ class Type { this.size = size } - static new(ref: Schema.TypeRef, types: TypeGraph): Type { + static new(ref: Schema.TypeRef, schema: Schema): Type { const c = ref.class switch (c) { case 'type': - const ty = types[ref.id] - const parent = ty.parent != null ? types[ty.parent] : null + const ty = schema.types[ref.id] + const parent = ty.parent != null ? schema.types[ty.parent] : undefined const typeName = namespacedName(ty.name, parent?.name) const type = tsf.createTypeReferenceNode(typeName) - if (Object.entries(ty.discriminants).length !== 0) { + const layout = schema.serialization[ref.id] + if (layout.discriminants != null) { return new Type(type, abstractTypeReader(typeName), POINTER_SIZE) } else { - return new Type(type, concreteTypeReader(typeName), ty.size) + return new Type(type, concreteTypeReader(typeName), layout.size) } case 'primitive': const p = ref.type @@ -241,11 +256,11 @@ class Type { throw new Error("unreachable: PrimitiveType.type='" + p + "'") } case 'sequence': - return Type.sequence(Type.new(ref.type, types)) + return Type.sequence(Type.new(ref.type, schema)) case 'option': - return Type.option(Type.new(ref.type, types)) + return Type.option(Type.new(ref.type, schema)) case 'result': - return Type.result(Type.new(ref.type0, types), Type.new(ref.type1, types)) + return Type.result(Type.new(ref.type0, schema), Type.new(ref.type1, schema)) default: const _ = c satisfies never throw new Error("unreachable: TypeRef.class='" + c + "' in " + JSON.stringify(ref)) @@ -262,7 +277,7 @@ class Type { static option(element: Type): Type { return new Type( - tsf.createUnionTypeNode([element.type, nullType]), + tsf.createUnionTypeNode([element.type, noneType]), cursorMethods.readOption(element.reader), POINTER_SIZE + 1, ) @@ -291,10 +306,11 @@ function seekCursor(cursor: ts.Expression, offset: number): ts.Expression { function makeGetter( fieldName: string, - fieldData: Schema.Field, - types: TypeGraph, + typeRef: Schema.TypeRef, + offset: number, + schema: Schema, ): ts.GetAccessorDeclaration { - const type = Type.new(fieldData.type, types) + const type = Type.new(typeRef, schema) return tsf.createGetAccessorDeclaration( [], tsf.createIdentifier(legalizeIdent(toCamel(fieldName))), @@ -305,7 +321,7 @@ function makeGetter( type.reader( seekCursor( tsf.createPropertyAccessExpression(tsf.createThis(), cursorFieldIdent), - fieldData.offset, + offset, ), ), ), @@ -320,8 +336,8 @@ function createAssignmentStatement(left: ts.Expression, right: ts.Expression): t ) } -function makeConcreteType(id: string, types: TypeGraph): ts.ClassDeclaration { - const ident = tsf.createIdentifier(toPascal(types[id].name)) +function makeConcreteType(id: string, schema: Schema): ts.ClassDeclaration { + const ident = tsf.createIdentifier(toPascal(schema.types[id].name)) const paramIdent = tsf.createIdentifier('cursor') const cursorParam = tsf.createParameterDeclaration( [], @@ -350,7 +366,7 @@ function makeConcreteType(id: string, types: TypeGraph): ts.ClassDeclaration { ), ], id, - types, + schema, ) } @@ -359,7 +375,7 @@ function debugValue(ident: ts.Identifier): ts.Expression { return tsf.createCallExpression(support.debugHelper, [], [value]) } -function makeDebugFunction(fields: [string, Schema.Field][]): ts.MethodDeclaration { +function makeDebugFunction(fields: string[]): ts.MethodDeclaration { const getterIdent = (fieldName: string) => tsf.createIdentifier(legalizeIdent(toCamel(fieldName))) return tsf.createMethodDeclaration( [], @@ -379,7 +395,7 @@ function makeDebugFunction(fields: [string, Schema.Field][]): ts.MethodDeclarati [], ), ), - ...fields.map(([name, _field]: [string, Schema.Field]) => + ...fields.map((name: string) => tsf.createPropertyAssignment(getterIdent(name), debugValue(getterIdent(name))), ), ]), @@ -388,14 +404,18 @@ function makeDebugFunction(fields: [string, Schema.Field][]): ts.MethodDeclarati ) } +function makeGetters(id: string, schema: Schema): ts.ClassElement[] { + return schema.serialization[id].fields.map(([name, offset]: [string, number]) => + makeGetter(name, schema.types[id].fields[name], offset, schema)) +} + function makeClass( modifiers: ts.Modifier[], name: ts.Identifier, members: ts.ClassElement[], id: string, - types: TypeGraph, + schema: Schema, ): ts.ClassDeclaration { - const ty = types[id] return tsf.createClassDeclaration( modifiers, name, @@ -407,8 +427,8 @@ function makeClass( ], [ ...members, - ...ty.fields.map(([name, field]: [string, Schema.Field]) => makeGetter(name, field, types)), - makeDebugFunction(ty.fields), + ...makeGetters(id, schema), + makeDebugFunction(Object.getOwnPropertyNames(schema.types[id].fields)), ], ) } @@ -421,13 +441,12 @@ type ChildType = { } function makeChildType( - parentName: string, base: ts.Identifier, id: string, discrim: string, - types: TypeGraph, + schema: Schema, ): ChildType { - const ty: Schema.Type = types[id] + const ty: Schema.Type = schema.types[id] const name = toPascal(ty.name) const ident = tsf.createIdentifier(name) const cursorIdent = tsf.createIdentifier('cursor') @@ -492,12 +511,12 @@ function makeChildType( tsf.createReturnStatement(tsf.createNewExpression(ident, [], [cursorIdent])), ]), ), - ...ty.fields.map(([name, field]: [string, Schema.Field]) => makeGetter(name, field, types)), - makeDebugFunction(ty.fields), + ...makeGetters(id, schema), + makeDebugFunction(Object.getOwnPropertyNames(ty.fields)), ], ), reference: tsf.createTypeReferenceNode(name), - enumMember: tsf.createEnumMember(toPascal(types[id].name), discrimInt), + enumMember: tsf.createEnumMember(toPascal(schema.types[id].name), discrimInt), case: tsf.createCaseClause(discrimInt, [ tsf.createReturnStatement(tsf.createNewExpression(ident, [], [seekCursor(cursorIdent, 4)])), ]), @@ -561,14 +580,14 @@ function abstractTypeDeserializer( ) } -function makeAbstractType(id: string, types: TypeGraph) { - const ty = types[id] +function makeAbstractType(id: string, discriminants: Schema.DiscriminantMap, schema: Schema) { + const ty = schema.types[id] const name = toPascal(ty.name) const ident = tsf.createIdentifier(name) const baseIdent = tsf.createIdentifier('AbstractBase') const childTypes = Array.from( - Object.entries(ty.discriminants), - ([discrim, id]: [string, string]) => makeChildType(name, baseIdent, id, discrim, types), + Object.entries(discriminants), + ([discrim, id]: [string, string]) => makeChildType(baseIdent, id, discrim, schema), ) const cursorIdent = tsf.createIdentifier('cursor') const moduleDecl = tsf.createModuleDeclaration( @@ -580,7 +599,7 @@ function makeAbstractType(id: string, types: TypeGraph) { baseIdent, [forwardToSuper(cursorIdent, support.Cursor)], id, - types, + schema, ), tsf.createEnumDeclaration( [modifiers.export, modifiers.const], @@ -619,11 +638,11 @@ function emit(data: ts.Node) { // === Main === // ============ -const data: Schema = JSON.parse(fs.readFileSync(process.argv[2], 'utf8')) +const schema: Schema = JSON.parse(fs.readFileSync(process.argv[2], 'utf8')) let output = '// *** THIS FILE GENERATED BY `parser-codegen` ***\n' const file = ts.createSourceFile('source.ts', '', ts.ScriptTarget.ESNext, false, ts.ScriptKind.TS) const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed }) -const nullType = tsf.createTypeReferenceNode('null') +const noneType = tsf.createTypeReferenceNode('undefined') const cursorFieldIdent = tsf.createIdentifier('lazyObjectData') const modifiers = { export: tsf.createModifier(ts.SyntaxKind.ExportKeyword), @@ -642,7 +661,7 @@ const cursorMethods = { readPointer: primitiveReader('readPointer'), readSequence: readerTransformerSized('readSequence'), readOption: readerTransformer('readOption'), - readResult: readerTransformer2('readResult'), + readResult: readerTransformerTwoTyped('readResult'), } as const const POINTER_SIZE: number = 4 // Symbols exported by the `parserSupport` module. @@ -675,13 +694,14 @@ emit( undefined, ), ) -for (const id in data.types) { - const ty = data.types[id] - if (ty.parent === null) { - if (Object.entries(data.types[id].discriminants).length === 0) { - emit(makeConcreteType(id, data.types)) +for (const id in schema.types) { + const ty = schema.types[id] + if (ty.parent == null) { + const discriminants = schema.serialization[id].discriminants + if (discriminants == null) { + emit(makeConcreteType(id, schema)) } else { - makeAbstractType(id, data.types) + makeAbstractType(id, discriminants, schema) } } else { // Ignore child types; they are generated when `makeAbstractType` processes the parent. diff --git a/app/gui2/src/util/ffi.ts b/app/gui2/src/util/ffi.ts index 0d115ac75977..d57737e1850d 100644 --- a/app/gui2/src/util/ffi.ts +++ b/app/gui2/src/util/ffi.ts @@ -3,16 +3,23 @@ import type { Opt } from '@/util/opt' import init, { parse, parse_to_json } from '../../rust-ffi/pkg/rust_ffi' import * as Ast2 from '../generated/ast' -const _wasm = await init() +if (import.meta.vitest) { + const fs = await import('node:fs/promises') + const buffer = await fs.readFile('./rust-ffi/pkg/rust_ffi_bg.wasm') + await init(buffer) +} else { + await init() +} export function parseEnso(code: string): Ast.Tree { const json = parse_to_json(code) return JSON.parse(json) } +// TODO (#7791): Replace `parseEnso` with this. export function parseEnso2(code: string): Ast2.Tree { const blob = parse(code) - return Ast2.deserializeTree(blob) + return Ast2.deserializeTree(blob.buffer) } export namespace Ast { @@ -455,3 +462,22 @@ export namespace Ast { message: string } } + +if (import.meta.vitest) { + const { test, expect } = import.meta.vitest + test('testParse', () => { + const identInput = 'foo' + const tree0 = parseEnso2(identInput) + expect(Number(tree0.spanLeftOffsetCodeUtf16)).toBe(0) + expect(Number(tree0.spanCodeLengthUtf16)).toBe(identInput.length) + expect(tree0.type).toBe(Ast2.Tree.Type.BodyBlock) + if (tree0.type === Ast2.Tree.Type.BodyBlock) { + const statements = Array.from(tree0.statements) + const tree1 = statements[0]!.expression! + expect(tree1.type).toBe(Ast2.Tree.Type.Ident) + if (tree1.type === Ast2.Tree.Type.Ident) { + expect(Number(tree1.token.codeUtf16)).toBe(identInput.length) + } + } + }) +} diff --git a/app/gui2/src/util/parserSupport.ts b/app/gui2/src/util/parserSupport.ts index 41dd1f3ca5e0..1252249f3216 100644 --- a/app/gui2/src/util/parserSupport.ts +++ b/app/gui2/src/util/parserSupport.ts @@ -1,8 +1,10 @@ // This file supports the module in `../generated/ast.ts` that is produced by `parser-codegen`. -export class LazyObject { + +/** Base class for objects that lazily deserialize fields when accessed. */ +export abstract class LazyObject { protected readonly lazyObjectData: Cursor - constructor(data: Cursor) { + protected constructor(data: Cursor) { this.lazyObjectData = data } @@ -35,11 +37,11 @@ export class Cursor { } } - readOption(readElement: (cursor: Cursor) => T): T | null { + readOption(readElement: (cursor: Cursor) => T): T | undefined { const discriminant = this.readU8() switch (discriminant) { case 0: - return null + return undefined case 1: return readElement(this.seek(1).readPointer()) default: @@ -113,9 +115,9 @@ export class Cursor { } } -export function debugHelper(value: any): object | null { - if (value === null) { - return null +export function debugHelper(value: any): object | undefined { + if (value == null) { + return undefined } if (typeof value['debug'] === 'function') { return value.debug() diff --git a/lib/rust/metamodel/lexpr/src/lib.rs b/lib/rust/metamodel/lexpr/src/lib.rs index 0bcd9d2e7301..b2502f3e3117 100644 --- a/lib/rust/metamodel/lexpr/src/lib.rs +++ b/lib/rust/metamodel/lexpr/src/lib.rs @@ -128,7 +128,7 @@ impl<'g> ToSExpr<'g> { let mut child = None; for id in hierarchy.iter().rev() { let ty = &self.graph[id]; - let mut fields = ty.data.as_struct().unwrap(); + let mut fields = ty.data.fields().unwrap(); if let Some(i) = ty.child_field { fields = &fields[..i]; } @@ -138,14 +138,14 @@ impl<'g> ToSExpr<'g> { if !discriminants.is_empty() { let discriminant_index = read_u32(data); let id = discriminants[&(discriminant_index as usize)]; - let fields = self.graph[id].data.as_struct().unwrap(); + let fields = self.graph[id].data.fields().unwrap(); out.extend(fields.iter().filter_map(|field| self.field(field, data))); child = Some(id); } for id in hierarchy { let ty = &self.graph[id]; if let Some(i) = ty.child_field { - let mut fields = ty.data.as_struct().unwrap(); + let mut fields = ty.data.fields().unwrap(); fields = &fields[i..]; out.extend(fields.iter().filter_map(|field| self.field(field, data))); } diff --git a/lib/rust/metamodel/src/meta/mod.rs b/lib/rust/metamodel/src/meta/mod.rs index a6030385a611..9e1db21434c6 100644 --- a/lib/rust/metamodel/src/meta/mod.rs +++ b/lib/rust/metamodel/src/meta/mod.rs @@ -83,7 +83,7 @@ pub enum Data { impl Data { /// If this is a [`Data::Struct`], return its fields. - pub fn as_struct(&self) -> Option<&[Field]> { + pub fn fields(&self) -> Option<&[Field]> { match self { Data::Struct(fields) => Some(&fields[..]), _ => None, diff --git a/lib/rust/parser/Cargo.toml b/lib/rust/parser/Cargo.toml index 815caa6c57e9..06f2abfc7cd5 100644 --- a/lib/rust/parser/Cargo.toml +++ b/lib/rust/parser/Cargo.toml @@ -21,10 +21,13 @@ serde_json = { workspace = true } uuid = { version = "1.1", features = ["serde"] } bincode = "1.3" -[dev-dependencies] +[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies] enso-metamodel = { path = "../metamodel", features = ["rust"] } enso-metamodel-lexpr = { path = "../metamodel/lexpr" } lexpr = "0.2.6" rand = "0.8.5" rand_chacha = "0.3.1" rand_distr = "0.4.3" + +[target.'cfg(target_arch = "wasm32")'.dev-dependencies] +wasm-bindgen-test = { workspace = true } diff --git a/lib/rust/parser/schema/src/lib.rs b/lib/rust/parser/schema/src/lib.rs index 1bd98b7fb6e9..7418edb02885 100644 --- a/lib/rust/parser/schema/src/lib.rs +++ b/lib/rust/parser/schema/src/lib.rs @@ -19,8 +19,11 @@ #![warn(unused_qualifications)] use enso_metamodel::meta; -use enso_metamodel::rust; +use enso_metamodel::meta::Data; use enso_reflect::Reflect; +use std::collections::BTreeMap; +use std::collections::HashMap; +use std::rc::Rc; @@ -29,9 +32,13 @@ use enso_reflect::Reflect; // =================== /// Return a serializable [`Schema`] describing the parser types. -pub fn types() -> impl serde::Serialize { - let (graph, _) = rust::to_meta(enso_parser::syntax::Tree::reflect()); - schema(&graph) +pub fn schema() -> impl serde::Serialize { + let (graph, _) = enso_metamodel::rust::to_meta(enso_parser::syntax::Tree::reflect()); + let Types { types, ids } = types(&graph); + let serialization = serialization(&graph) + .filter_map(|(k, v)| ids.get(&k).map(|k| (k.clone(), v.map_ids(|k| ids[&k].clone())))) + .collect(); + Schema { types, serialization } } @@ -42,30 +49,33 @@ pub fn types() -> impl serde::Serialize { #[derive(serde::Serialize)] struct Schema { - types: std::collections::HashMap, + types: HashMap, + serialization: HashMap, } + +// === Type graph === + #[derive(serde::Serialize)] #[serde(rename_all = "camelCase")] struct Type { - name: String, - fields: Vec<(String, Field)>, - parent: Option, - discriminants: std::collections::BTreeMap, - size: usize, + name: Rc, + fields: HashMap, + #[serde(skip_serializing_if = "Option::is_none")] + parent: Option, } -#[derive(serde::Serialize)] -struct Field { - r#type: TypeRef, - offset: usize, -} +#[derive(serde::Serialize, Clone, Hash, PartialEq, Eq)] +struct TypeId(Rc); + +#[derive(serde::Serialize, Clone, Hash, PartialEq, Eq)] +struct FieldName(Rc); #[derive(serde::Serialize, Clone, Hash, PartialEq, Eq)] #[serde(rename_all = "lowercase")] #[serde(tag = "class")] enum TypeRef { - Type { id: String }, + Type { id: TypeId }, Primitive { r#type: Primitive }, Sequence { r#type: Box }, Option { r#type: Box }, @@ -84,25 +94,51 @@ enum Primitive { String, } -fn schema(graph: &meta::TypeGraph) -> Schema { + +// === Serialization === + +#[derive(serde::Serialize)] +#[serde(rename_all = "camelCase")] +struct Layout { + fields: Vec<(FieldName, usize)>, + #[serde(skip_serializing_if = "Option::is_none")] + discriminants: Option>, + size: usize, +} + +#[derive(serde::Serialize, Clone, PartialEq, Eq, PartialOrd, Ord)] +struct Discriminant(u32); + + + +// ================== +// === Type Graph === +// ================== + +struct Types { + types: HashMap, + ids: HashMap, +} + +fn types(graph: &meta::TypeGraph) -> Types { let mut next_type_id = 0; let mut next_type_id = || { - let result = format!("type_{next_type_id}"); + let result = TypeId(format!("type_{next_type_id}").into()); next_type_id += 1; result }; - let mut type_refs = std::collections::HashMap::new(); - let mut type_ids = std::collections::HashMap::new(); + let mut type_refs = HashMap::new(); + let mut ids = HashMap::new(); let mut primitives = vec![]; // Map struct types; gather primitive types. for (key, ty) in &graph.types { match &ty.data { - meta::Data::Struct(_) => { + Data::Struct(_) => { let id = next_type_id(); - type_ids.insert(key, id.clone()); + ids.insert(key, id.clone()); type_refs.insert(key, TypeRef::Type { id }); } - meta::Data::Primitive(prim) => { + Data::Primitive(prim) => { primitives.push((key, prim)); } } @@ -137,107 +173,146 @@ fn schema(graph: &meta::TypeGraph) -> Schema { } }); } - let mut types: std::collections::HashMap<_, _> = graph + let types: HashMap<_, _> = graph .types .iter() .filter_map(|(key, ty)| { - ty.data.as_struct().map(|fields| { - let key_to_id = |id| type_ids[id].clone(); + ty.data.fields().map(|fields| { + let key_to_id = |id| ids[id].clone(); (key_to_id(&key), Type { - name: ty.name.to_snake_case(), - fields: fields + name: ty.name.to_snake_case().into(), + fields: fields .iter() .map(|f| { let name = f.name.to_snake_case().expect("Tuples not supported."); let r#type = type_refs[&f.type_].clone(); - let field = Field { r#type, offset: 0 }; - (name, field) + (FieldName(name.into()), r#type) }) .collect(), - parent: ty.parent.as_ref().map(key_to_id), - discriminants: ty - .discriminants - .iter() - .map(|(k, v)| (*k, key_to_id(v))) - .collect(), - size: 0, + parent: ty.parent.as_ref().map(key_to_id), }) }) }) .collect(); - let mut data_size = std::collections::HashMap::new(); - let mut reference_size = std::collections::HashMap::new(); - for key in types.keys() { - let reference = TypeRef::Type { id: key.to_owned() }; - let ref_size = compute_size(reference.clone(), &types, &mut data_size); - if !types[key].discriminants.is_empty() { - reference_size.insert(reference, ref_size); - } - } - for (id, ty) in types.iter_mut() { - let mut offset = ty - .parent - .as_ref() - .map_or(0, |parent| data_size[&TypeRef::Type { id: parent.to_owned() }]); - for (_, field) in &mut ty.fields { - field.offset = offset; - offset += reference_size - .get(&field.r#type) - .copied() - .unwrap_or_else(|| data_size[&field.r#type]); - } - let reference = TypeRef::Type { id: id.to_owned() }; - ty.size = reference_size.get(&reference).copied().unwrap_or_else(|| data_size[&reference]); - } - Schema { types } + Types { types, ids } } -const POINTER_BYTES: usize = 4; -/// Writes the size of the object's fields to `data_size`. Returns the size of a reference to the -/// object. + +// ===================== +// === Serialization === +// ===================== + +fn serialization<'g>( + graph: &'g meta::TypeGraph, +) -> impl Iterator)> + 'g + '_ { + let sizes = solve_sizes(graph); + layouts(graph, sizes) +} + +const POINTER: usize = 4; + +/// Returns the inheritance-size of the object, if `sizes` contains all the needed information to +/// compute this type. The inheritance-size is the shallow size of all the type's fields, including +/// fields inherited from ancestor types. fn compute_size( - ty: TypeRef, - types: &std::collections::HashMap, - data_size: &mut std::collections::HashMap, -) -> usize { - let mut reference = None; - let size = match &ty { - // May be pointer or inline fields. - TypeRef::Type { id } => { - let ty = &types[id]; - if !ty.discriminants.is_empty() { - reference = Some(POINTER_BYTES); - } - let key = TypeRef::Type { id: id.to_owned() }; - if let Some(size) = data_size.get(&key) { - *size - } else { - let mut size = if let Some(id) = ty.parent.clone() { - let type_ref = TypeRef::Type { id }; - compute_size(type_ref.clone(), types, data_size); - data_size[&type_ref] + graph: &meta::TypeGraph, + key: meta::TypeId, + sizes: &HashMap, +) -> Option { + use meta::Primitive; + let ty = &graph[key]; + Some(match &ty.data { + Data::Primitive(Primitive::Bool) => 1, + Data::Primitive(Primitive::U32 | Primitive::I32 | Primitive::Char) => 4, + Data::Primitive(Primitive::U64 | Primitive::I64) => 8, + Data::Primitive(Primitive::Option(_)) => 1 + POINTER, + Data::Primitive(Primitive::String | Primitive::Sequence(_) | Primitive::Result(_, _)) => + POINTER, + Data::Struct(fields) => { + let inherited_size = + if let Some(parent) = ty.parent { *sizes.get(&parent)? } else { 0 }; + let mut fields_size = 0; + for field in fields { + let ty = &graph[&field.type_]; + fields_size += if !ty.discriminants.is_empty() { + POINTER } else { - 0 + *sizes.get(&field.type_)? }; - for (_, field) in &ty.fields { - let field_size = compute_size(field.r#type.to_owned(), types, data_size); - size += field_size; - } - size } + inherited_size + fields_size } - // Pointer. - TypeRef::Primitive { r#type: Primitive::String } => POINTER_BYTES, - TypeRef::Sequence { .. } => POINTER_BYTES, - TypeRef::Result { .. } => POINTER_BYTES, - // Discriminant + pointer. - TypeRef::Option { .. } => 1 + POINTER_BYTES, - // Scalars. - TypeRef::Primitive { r#type: Primitive::Bool } => 1, - TypeRef::Primitive { r#type: Primitive::U32 | Primitive::I32 | Primitive::Char } => 4, - TypeRef::Primitive { r#type: Primitive::U64 | Primitive::I64 } => 8, - }; - data_size.insert(ty, size); - reference.unwrap_or(size) + }) +} + +fn solve_sizes(graph: &meta::TypeGraph) -> HashMap { + let mut uncomputed: Vec<_> = graph.types.keys().collect(); + let mut sizes = HashMap::new(); + // Termination: Each step will make progress as long as there is no cycle in the type + // dependencies. Only an unconditional reference to a type creates a dependency. A cycle in + // unconditional type references would only occur if the input contained an infinite-sized type. + // + // Performance: In the worst case, this implementation requires time quadratic in the number of + // types (for inputs with deep composition graphs). However, it is simpler and more efficient + // for *reasonable* inputs than an implementation with better worst-case behavior. + while !uncomputed.is_empty() { + let uncomputed_before_step = uncomputed.len(); + uncomputed.retain(|key| match compute_size(graph, *key, &sizes) { + Some(size) => { + sizes.insert(*key, size); + false + } + None => true, + }); + assert_ne!(uncomputed.len(), uncomputed_before_step); + } + sizes +} + +/// Given the sizes of all types in the graph, compute the field offsets and return the layouts for +/// all the types. +fn layouts<'g>( + graph: &'g meta::TypeGraph, + sizes: HashMap, +) -> impl Iterator)> + 'g + '_ { + graph.types.iter().map(move |(key, ty)| { + (key, { + let mut offset = ty.parent.map_or(0, |key| sizes[&key]); + let fields = ty + .data + .fields() + .map(|fields| { + fields + .iter() + .map(|field| { + let entry = + (FieldName(field.name.to_snake_case().unwrap().into()), offset); + offset += sizes[&field.type_]; + entry + }) + .collect() + }) + .unwrap_or_default(); + if ty.discriminants.is_empty() { + Layout { fields, discriminants: None, size: sizes[&key] } + } else { + let discriminants = ty + .discriminants + .iter() + .map(|(k, v)| (Discriminant((*k).try_into().unwrap()), *v)) + .collect(); + Layout { fields, discriminants: Some(discriminants), size: POINTER } + } + }) + }) +} + +impl Layout { + fn map_ids(self, f: impl Fn(Id) -> Id2) -> Layout { + let Layout { fields, discriminants, size } = self; + let discriminants = discriminants + .map(|discriminants| discriminants.into_iter().map(|(k, v)| (k, f(v))).collect()); + Layout { fields, discriminants, size } + } } diff --git a/lib/rust/parser/schema/src/main.rs b/lib/rust/parser/schema/src/main.rs index 7ab288b85b0e..7870e06a47c4 100644 --- a/lib/rust/parser/schema/src/main.rs +++ b/lib/rust/parser/schema/src/main.rs @@ -23,5 +23,5 @@ // ========================= fn main() { - serde_json::to_writer(std::io::stdout(), &enso_parser_schema::types()).unwrap() + serde_json::to_writer(std::io::stdout(), &enso_parser_schema::schema()).unwrap() } diff --git a/lib/rust/parser/src/format.rs b/lib/rust/parser/src/format.rs index 7d82d3cdddfb..0c3ab0dd232b 100644 --- a/lib/rust/parser/src/format.rs +++ b/lib/rust/parser/src/format.rs @@ -28,8 +28,8 @@ use std::fmt::Formatter; // ================= /// Maximum allowed nesting depth of compound objects. This is empirically determined to be reached -/// before stack overflow on supported targets. -// FIXME: WASM test required. +/// before stack overflow on supported targets (see [`test::test_infinite_recursion`] and +/// [`test::wasm::test_infinite_recursion`]). const RECURSION_LIMIT: usize = 1024; @@ -512,4 +512,18 @@ mod test { // due to stack overflow. We are just checking `is_err` here for good measure. assert!(super::serialize(Cyclic::new()).is_err()); } + + #[cfg(target_arch = "wasm32")] + mod wasm { + + use wasm_bindgen_test::wasm_bindgen_test; + use wasm_bindgen_test::wasm_bindgen_test_configure; + + wasm_bindgen_test_configure!(run_in_browser); + + #[wasm_bindgen_test] + fn test_infinite_recursion() { + super::test_infinite_recursion() + } + } } diff --git a/lib/rust/parser/src/lib.rs b/lib/rust/parser/src/lib.rs index 565c9c2611d7..28ddea679210 100644 --- a/lib/rust/parser/src/lib.rs +++ b/lib/rust/parser/src/lib.rs @@ -478,6 +478,7 @@ mod benches { } #[bench] + #[cfg(not(target_arch = "wasm32"))] fn bench_blocks(bencher: &mut Bencher) { use rand::prelude::*; use rand_chacha::ChaCha8Rng; @@ -519,6 +520,7 @@ mod benches { } #[bench] + #[cfg(not(target_arch = "wasm32"))] fn bench_expressions(bencher: &mut Bencher) { use rand::prelude::*; use rand_chacha::ChaCha8Rng; From af7bece51d418289ad59dff5c990c31c41f01f89 Mon Sep 17 00:00:00 2001 From: Kaz Wesley Date: Mon, 2 Oct 2023 13:38:47 +0000 Subject: [PATCH 23/44] new Result --- app/gui2/src/util/parserSupport.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/gui2/src/util/parserSupport.ts b/app/gui2/src/util/parserSupport.ts index 1252249f3216..d326b7411ea2 100644 --- a/app/gui2/src/util/parserSupport.ts +++ b/app/gui2/src/util/parserSupport.ts @@ -1,4 +1,6 @@ -// This file supports the module in `../generated/ast.ts` that is produced by `parser-codegen`. +/** This file supports the module in `../generated/ast.ts` that is produced by `parser-codegen`. */ + +import { Err, Ok, type Result } from '@/util/result' /** Base class for objects that lazily deserialize fields when accessed. */ export abstract class LazyObject { @@ -13,8 +15,6 @@ export abstract class LazyObject { } } -export type Result = { Ok: T } | { Err: E } - export const builtin = { Array: Array, } as const @@ -57,9 +57,9 @@ export class Cursor { const discriminant = data.readU32() switch (discriminant) { case 0: - return { Ok: readOk(data.seek(4)) } + return Ok(readOk(data.seek(4))) case 1: - return { Err: readErr(data.seek(4)) } + return Err(readErr(data.seek(4))) default: throw new Error(`Invalid Result discriminant: 0x${discriminant.toString(16)}.`) } From 5d8e1684565f109477e7fe45001e3e5cc3110e87 Mon Sep 17 00:00:00 2001 From: Kaz Wesley Date: Mon, 2 Oct 2023 16:24:25 +0000 Subject: [PATCH 24/44] Compute utf16 offsets while lexing. --- lib/rust/parser/src/lexer.rs | 129 ++++++++++++++----------- lib/rust/parser/src/macros/built_in.rs | 13 ++- lib/rust/parser/src/macros/resolver.rs | 3 +- lib/rust/parser/src/source/code.rs | 63 ++++++++---- lib/rust/parser/src/source/span.rs | 9 +- lib/rust/parser/src/syntax/token.rs | 12 +-- 6 files changed, 140 insertions(+), 89 deletions(-) diff --git a/lib/rust/parser/src/lexer.rs b/lib/rust/parser/src/lexer.rs index 150b1a76d80a..86689d92bea0 100644 --- a/lib/rust/parser/src/lexer.rs +++ b/lib/rust/parser/src/lexer.rs @@ -95,7 +95,9 @@ pub struct Lexer<'s> { pub struct LexerState { pub current_char: Option, pub current_offset: Bytes, + pub current_offset16: u32, pub last_spaces_offset: Bytes, + pub last_spaces_offset16: u32, pub last_spaces_visible_offset: VisibleOffset, pub current_block_indent: VisibleOffset, pub block_indent_stack: Vec, @@ -117,6 +119,8 @@ pub enum State { }, } +type Mark<'s> = (Bytes, u32, Offset<'s>); + impl<'s> Lexer<'s> { /// Constructor. pub fn new(input: &'s str) -> Self { @@ -193,9 +197,9 @@ impl<'s> Lexer<'s> { let left_offset_start = start - self.last_spaces_offset; let offset_code = self.input.slice(left_offset_start..start); let visible_offset = self.last_spaces_visible_offset; - let offset = Offset(visible_offset, offset_code); + let offset = Offset(visible_offset, Code::from_str_at_offset(offset_code, 0)); self.spaces_after_lexeme(); - Token(offset, code, elem) + Token(offset, Code::from_str_at_offset(code, 0), elem) }) } @@ -204,10 +208,8 @@ impl<'s> Lexer<'s> { #[inline(always)] pub fn marker_token(&mut self, elem: T) -> Token<'s, T> { let visible_offset = VisibleOffset(0); - let start = self.current_offset - self.last_spaces_offset; - let code = self.input.slice(start..start); - let offset = Offset(visible_offset, code); - Token(offset, code, elem) + let offset = Offset(visible_offset, Code::empty()); + Token(offset, Code::empty(), elem) } /// Push the [`token`] to the result stream. @@ -640,7 +642,7 @@ impl<'s> Lexer<'s> { // have different precedences; this is a special case here because the distinction // requires lookahead. "." if self.last_spaces_visible_offset.width_in_spaces == 0 - && let Some(char) = self.current_char && char.is_ascii_digit() => { + && let Some(char) = self.current_char && char.is_ascii_digit() => { let opr = token::OperatorProperties::new() .with_binary_infix_precedence(81) .as_decimal(); @@ -860,7 +862,11 @@ impl<'s> Lexer<'s> { let joiner = token::OperatorProperties::new() .with_binary_infix_precedence(usize::MAX) .as_token_joiner(); - self.submit_token(Token("", "", token::Variant::operator(joiner))); + self.submit_token(Token( + Code::empty(), + Code::empty(), + token::Variant::operator(joiner), + )); // Every number has a digits-token, even if it's zero-length. let token = token.unwrap_or_default(); self.submit_token(token.with_variant(token::Variant::digits(Some(base)))); @@ -916,17 +922,17 @@ impl<'s> Lexer<'s> { // Exactly two quote characters: Open and shut case. let close_quote_end = self.mark(); let token = self.make_token(open_quote_start, close_quote_start.clone(), - token::Variant::text_start()); + token::Variant::text_start()); self.output.push(token); let token = self.make_token(close_quote_start, close_quote_end, - token::Variant::text_end()); + token::Variant::text_end()); self.output.push(token); } } else { // One quote followed by non-quote character: Inline quote. let open_quote_end = self.mark(); let token = self.make_token(open_quote_start, open_quote_end, - token::Variant::text_start()); + token::Variant::text_start()); self.output.push(token); self.inline_quote(quote_char, text_type); } @@ -935,7 +941,7 @@ impl<'s> Lexer<'s> { fn multiline_text( &mut self, - open_quote_start: (Bytes, Offset<'s>), + open_quote_start: Mark<'s>, block_indent: VisibleOffset, text_type: TextType, ) { @@ -1037,12 +1043,14 @@ impl<'s> Lexer<'s> { } if let Some(indent) = new_indent { if indent <= *block_indent { - self.output.push(Token::from(token::text_end("", ""))); + self.output + .push(Token::from(token::text_end(Code::empty(), Code::empty()))); self.end_blocks(indent); self.output.extend(newlines); if self.current_offset == text_start.0 { - self.last_spaces_visible_offset = text_start.1.visible; - self.last_spaces_offset = text_start.1.code.len(); + self.last_spaces_visible_offset = text_start.2.visible; + self.last_spaces_offset = text_start.2.code.len(); + self.last_spaces_offset16 = text_start.2.code.utf16; } return TextEndedAt::End; } @@ -1107,17 +1115,13 @@ impl<'s> Lexer<'s> { let close_quote_end = self.mark(); self.make_token(text_end, close_quote_end, token::Variant::text_end()) } else { - Token::from(token::text_end("", "")) + Token::from(token::text_end(Code::empty(), Code::empty())) }; self.output.push(end_token); TextEndedAt::End } - fn text_escape( - &mut self, - backslash_start: (Bytes, Offset<'s>), - char: char, - ) -> (Bytes, Offset<'s>) { + fn text_escape(&mut self, backslash_start: Mark<'s>, char: char) -> Mark<'s> { let leader = match char { 'x' => Some((2, false)), 'u' => Some((4, true)), @@ -1180,27 +1184,29 @@ impl<'s> Lexer<'s> { } } - fn mark(&mut self) -> (Bytes, Offset<'s>) { + fn mark(&mut self) -> Mark<'s> { let start = self.current_offset; let left_offset_start = start - self.last_spaces_offset; + let start16 = self.current_offset16; + let left_offset_start16 = start16 - self.last_spaces_offset16; let offset_code = self.input.slice(left_offset_start..start); let visible_offset = self.last_spaces_visible_offset; self.last_spaces_visible_offset = VisibleOffset(0); self.last_spaces_offset = Bytes(0); - (start, Offset(visible_offset, offset_code)) + self.last_spaces_offset16 = 0; + ( + start, + start16, + Offset(visible_offset, Code::from_str_at_offset(offset_code, left_offset_start16)), + ) } - fn make_token( - &self, - from: (Bytes, Offset<'s>), - to: (Bytes, Offset<'s>), - variant: token::Variant, - ) -> Token<'s> { - let (start, offset) = from; + fn make_token(&self, from: Mark<'s>, to: Mark<'s>, variant: token::Variant) -> Token<'s> { + let (start, start16, offset) = from; let end = to.0; let start = start.unchecked_raw(); let end = end.unchecked_raw(); - Token(offset, &self.input[start..end], variant) + Token(offset, Code::from_str_at_offset(&self.input[start..end], start16), variant) } } @@ -1364,11 +1370,13 @@ impl<'s> Lexer<'s> { } if self.last_spaces_visible_offset != VisibleOffset(0) { let left_offset_start = self.current_offset - self.last_spaces_offset; + let left_offset_start16 = self.current_offset16 - self.last_spaces_offset16; let offset_code = self.input.slice(left_offset_start..self.current_offset); let visible_offset = self.last_spaces_visible_offset; - let offset = Offset(visible_offset, offset_code); + let offset = + Offset(visible_offset, Code::from_str_at_offset(offset_code, left_offset_start16)); let eof = token::variant::Variant::Newline(token::variant::Newline()); - self.submit_token(Token(offset, "", eof)); + self.submit_token(Token(offset, Code::empty(), eof)); } let mut internal_error = self.internal_error.take(); if self.current_char.is_some() { @@ -1404,18 +1412,25 @@ pub mod test { let lift_level = code.chars().rev().take_while(|t| *t == '\'').count(); let is_uppercase = code.chars().next().map(|c| c.is_uppercase()).unwrap_or_default(); let is_operator = false; + let left_offset = Code::from_str_without_offset(left_offset); + let code = Code::from_str_without_offset(code); token::ident_(left_offset, code, is_free, lift_level, is_uppercase, is_operator, false) } /// Constructor. pub fn wildcard_<'s>(left_offset: &'s str, code: &'s str) -> Token<'s> { let lift_level = code.chars().rev().take_while(|t| *t == '\'').count(); + let left_offset = Code::from_str_without_offset(left_offset); + let code = Code::from_str_without_offset(code); token::wildcard_(left_offset, code, lift_level) } /// Constructor. pub fn operator_<'s>(left_offset: &'s str, code: &'s str) -> Token<'s> { - Token(left_offset, code, token::Variant::operator(analyze_operator(code))) + let variant = token::Variant::operator(analyze_operator(code)); + let left_offset = Code::from_str_without_offset(left_offset); + let code = Code::from_str_without_offset(code); + Token(left_offset, code, variant) } } @@ -1452,43 +1467,45 @@ mod tests { #[test] fn test_case_block() { + let newline = newline_(Code::empty(), Code::from_str_without_offset("\n")); test_lexer_many(vec![ - ("\n", vec![newline_("", "\n")]), + ("\n", vec![newline_(Code::empty(), Code::from_str_without_offset("\n"))]), ("\n foo\n bar", vec![ - block_start_("", ""), - newline_("", "\n"), + block_start_(Code::empty(), Code::empty()), + newline.clone(), ident_(" ", "foo"), - newline_("", "\n"), + newline.clone(), ident_(" ", "bar"), - block_end_("", ""), + block_end_(Code::empty(), Code::empty()), ]), ("foo\n +", vec![ ident_("", "foo"), - block_start_("", ""), - newline_("", "\n"), + block_start_(Code::empty(), Code::empty()), + newline.clone(), operator_(" ", "+"), - block_end_("", ""), + block_end_(Code::empty(), Code::empty()), ]), ]); } #[test] fn test_case_block_bad_indents() { + let newline = newline_(Code::empty(), Code::from_str_without_offset("\n")); #[rustfmt::skip] test_lexer_many(vec![ ("\n foo\n bar\nbaz", vec![ - block_start_("", ""), - newline_("", "\n"), ident_(" ", "foo"), - newline_("", "\n"), ident_(" ", "bar"), - block_end_("", ""), - newline_("", "\n"), ident_("", "baz"), + block_start_(Code::empty(), Code::empty()), + newline, ident_(" ", "foo"), + newline, ident_(" ", "bar"), + block_end_(Code::empty(), Code::empty()), + newline, ident_("", "baz"), ]), ("\n foo\n bar\n baz", vec![ - block_start_("", ""), - newline_("", "\n"), ident_(" ", "foo"), - newline_("", "\n"), ident_(" ", "bar"), - newline_("", "\n"), ident_(" ", "baz"), - block_end_("", ""), + block_start_(Code::empty(), Code::empty()), + newline, ident_(" ", "foo"), + newline, ident_(" ", "bar"), + newline, ident_(" ", "baz"), + block_end_(Code::empty(), Code::empty()), ]), ]); } @@ -1497,8 +1514,8 @@ mod tests { fn test_case_whitespace_only_line() { test_lexer_many(vec![("foo\n \nbar", vec![ ident_("", "foo"), - newline_("", "\n"), - newline_(" ", "\n"), + newline_(Code::empty(), Code::from_str_without_offset("\n")), + newline_(" ", Code::from_str_without_offset("\n")), ident_("", "bar"), ])]); } @@ -1523,7 +1540,7 @@ mod tests { #[test] fn test_numeric_literal() { - test_lexer("10", vec![digits_("", "10", None)]); + test_lexer("10", vec![digits_(Code::empty(), Code::from_str_without_offset("10"), None)]); } #[test] @@ -1605,7 +1622,7 @@ mod tests { // 2.2. Last possible sequence of a certain length. /* 2.2.1. 1 byte (U-0000007F): */ "" /* 2.2.2. 2 bytes (U-000007FF): */ "߿" - /* 2.2.3. 3 bytes (U-0000FFFF): */ "￿" + /* 2.2.3. 3 bytes (U-0000FFFF): */ " " /* 2.2.4. 4 bytes (U-001FFFFF): */ "����" /* 2.2.5. 5 bytes (U-03FFFFFF): */ "�����" /* 2.2.6. 6 bytes (U-7FFFFFFF): */ "������" diff --git a/lib/rust/parser/src/macros/built_in.rs b/lib/rust/parser/src/macros/built_in.rs index c749e5678d11..b5ff2abc457b 100644 --- a/lib/rust/parser/src/macros/built_in.rs +++ b/lib/rust/parser/src/macros/built_in.rs @@ -3,6 +3,7 @@ use crate::macros::pattern::*; use crate::macros::*; +use crate::source::Code; use crate::syntax::operator; @@ -437,7 +438,7 @@ fn case_body<'s>( } } if !initial_case.is_empty() { - let newline = syntax::token::newline("", ""); + let newline = syntax::token::newline(Code::empty(), Code::empty()); case_builder.push(syntax::item::Line { newline, items: initial_case }); } block.into_iter().for_each(|line| case_builder.push(line)); @@ -803,6 +804,14 @@ fn expect_qualified(tree: syntax::Tree) -> syntax::Tree { } fn expected_nonempty<'s>() -> syntax::Tree<'s> { - let empty = syntax::Tree::ident(syntax::token::ident("", "", false, 0, false, false, false)); + let empty = syntax::Tree::ident(syntax::token::ident( + Code::empty(), + Code::empty(), + false, + 0, + false, + false, + false, + )); empty.with_error("Expected tokens.") } diff --git a/lib/rust/parser/src/macros/resolver.rs b/lib/rust/parser/src/macros/resolver.rs index a0f944adde2a..26d827ae7ec0 100644 --- a/lib/rust/parser/src/macros/resolver.rs +++ b/lib/rust/parser/src/macros/resolver.rs @@ -26,6 +26,7 @@ use crate::prelude::*; use crate::macros; use crate::macros::pattern; +use crate::source::Code; use crate::syntax; use crate::syntax::token; use crate::syntax::token::Token; @@ -143,7 +144,7 @@ impl<'s> Resolver<'s> { pub fn new_statement() -> Self { let scopes = default(); let open_blocks = - vec![syntax::item::Line { newline: token::newline("", ""), items: default() }]; + vec![syntax::item::Line { newline: token::newline(Code::empty(), Code::empty()), items: default() }]; let macro_stack = default(); let segments = default(); let items = default(); diff --git a/lib/rust/parser/src/source/code.rs b/lib/rust/parser/src/source/code.rs index aba63791abd0..1c64f35d522d 100644 --- a/lib/rust/parser/src/source/code.rs +++ b/lib/rust/parser/src/source/code.rs @@ -18,10 +18,52 @@ pub struct Code<'s> { #[deref] pub repr: Cow<'s, str>, #[reflect(hide)] - pub utf16: usize, + pub offset_utf16: u32, + #[reflect(hide)] + pub utf16: u32, } impl<'s> Code<'s> { + #[inline(always)] + pub fn from_str_at_offset(repr: impl Into>, offset_utf16: u32) -> Self { + let repr = repr.into(); + let utf16 = repr.encode_utf16().count() as u32; + Self { repr, offset_utf16, utf16 } + } + + #[inline(always)] + pub fn from_str_without_offset(repr: impl Into>) -> Self { + Self::from_str_at_offset(repr, 0) + } + + pub fn split_at(&self, offset: usize) -> (Self, Self) { + let (left, right) = match self.repr { + Cow::Borrowed(s) => s.split_at(offset), + Cow::Owned(_) => panic!("Unsupported: Splitting owned cows."), + }; + let left_utf16 = left.encode_utf16().count() as u32; + let right_utf16 = self.utf16 - left_utf16; + (Self { + repr: Cow::Borrowed(left), + offset_utf16: self.offset_utf16, + utf16: left_utf16, + }, + Self { + repr: Cow::Borrowed(right), + offset_utf16: self.offset_utf16 + left_utf16, + utf16: right_utf16, + }, + ) + } + + pub fn empty() -> Self { + Self { + repr: "".into(), + offset_utf16: 0, + utf16: 0, + } + } + /// Length of the code in bytes. #[inline(always)] pub fn len(&self) -> Bytes { @@ -31,7 +73,7 @@ impl<'s> Code<'s> { /// Length of the code. #[inline(always)] pub fn length(&self) -> Length { - Length { utf8: self.repr.len(), utf16: self.utf16 } + Length { utf8: self.repr.len(), utf16: self.utf16 as usize } } /// True if the code is the empty string. @@ -41,23 +83,6 @@ impl<'s> Code<'s> { } } -impl<'a> From> for Code<'a> { - #[inline(always)] - fn from(repr: Cow<'a, str>) -> Self { - let utf16 = repr.encode_utf16().count(); - Self { repr, utf16 } - } -} - -impl<'a> From<&'a str> for Code<'a> { - #[inline(always)] - fn from(str: &'a str) -> Self { - let utf16 = str.encode_utf16().count(); - let repr = str.into(); - Self { repr, utf16 } - } -} - impl<'s> Display for Code<'s> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Display::fmt(&self.repr, f) diff --git a/lib/rust/parser/src/source/span.rs b/lib/rust/parser/src/source/span.rs index eb825432ca84..94b993dd08e6 100644 --- a/lib/rust/parser/src/source/span.rs +++ b/lib/rust/parser/src/source/span.rs @@ -70,8 +70,7 @@ pub struct Offset<'s> { /// Constructor. #[allow(non_snake_case)] -pub fn Offset<'s>(visible: VisibleOffset, code: impl Into>) -> Offset<'s> { - let code = code.into(); +pub fn Offset(visible: VisibleOffset, code: Code) -> Offset { Offset { visible, code } } @@ -95,10 +94,10 @@ impl<'s> AsRef> for Offset<'s> { } } -impl<'s> From<&'s str> for Offset<'s> { +impl<'s> From> for Offset<'s> { #[inline(always)] - fn from(code: &'s str) -> Self { - Offset(code.into(), code) + fn from(code: Code<'s>) -> Self { + Offset(code.repr.as_ref().into(), code) } } diff --git a/lib/rust/parser/src/syntax/token.rs b/lib/rust/parser/src/syntax/token.rs index ef23f7420cfb..a309cff070a0 100644 --- a/lib/rust/parser/src/syntax/token.rs +++ b/lib/rust/parser/src/syntax/token.rs @@ -123,11 +123,10 @@ pub struct Token<'s, T = Variant> { #[allow(non_snake_case)] pub fn Token<'s, T>( left_offset: impl Into>, - code: impl Into>, + code: Code<'s>, variant: T, ) -> Token<'s, T> { let left_offset = left_offset.into(); - let code = code.into(); Token { variant, left_offset, code } } @@ -139,8 +138,9 @@ impl<'s, T> Token<'s, T> { pub fn split_at(self, offset: Bytes) -> (Token<'s, ()>, Token<'s, ()>, T) { let left_lexeme_offset = self.left_offset; let right_lexeme_offset = Offset::default(); - let left = Token(left_lexeme_offset, self.code.slice(Bytes(0)..offset), ()); - let right = Token(right_lexeme_offset, self.code.slice(offset..), ()); + let (left_code, right_code) = self.code.split_at(offset.unchecked_raw()); + let left = Token(left_lexeme_offset, left_code, ()); + let right = Token(right_lexeme_offset, right_code, ()); (left, right, self.variant) } @@ -607,7 +607,7 @@ macro_rules! generate_token_aliases { /// Constructor. pub fn [<$variant:snake:lower>]<'s> ( left_offset: impl Into>, - code: impl Into>, + code: Code<'s>, $($($field : $field_ty),*)? ) -> $variant<'s> { Token(left_offset, code, variant::$variant($($($field),*)?)) @@ -616,7 +616,7 @@ macro_rules! generate_token_aliases { /// Constructor. pub fn [<$variant:snake:lower _>]<'s> ( left_offset: impl Into>, - code: impl Into>, + code: Code<'s>, $($($field : $field_ty),*)? ) -> Token<'s> { Token(left_offset, code, variant::$variant($($($field),*)?)).into() From bfb8e145804becbc5f8ffa20a87217440363281c Mon Sep 17 00:00:00 2001 From: Kaz Wesley Date: Mon, 2 Oct 2023 17:01:32 +0000 Subject: [PATCH 25/44] Abolish cows. --- lib/rust/parser/src/serialization.rs | 20 +++---- lib/rust/parser/src/source/code.rs | 79 +++++++++++++++++----------- lib/rust/parser/src/source/span.rs | 3 +- 3 files changed, 55 insertions(+), 47 deletions(-) diff --git a/lib/rust/parser/src/serialization.rs b/lib/rust/parser/src/serialization.rs index 7b6c73bed343..4bebb3dc9517 100644 --- a/lib/rust/parser/src/serialization.rs +++ b/lib/rust/parser/src/serialization.rs @@ -5,6 +5,8 @@ use crate::prelude::*; +use crate::source::code::StrRef; + // ============ @@ -41,25 +43,17 @@ pub(crate) struct Code { } /// Serde wrapper to serialize a `Cow` as the `Code` representation. -#[allow(clippy::ptr_arg)] // This is the signature required by serde. -pub(crate) fn serialize_cow(cow: &Cow<'_, str>, ser: S) -> Result +pub(crate) fn serialize_cow(s: &StrRef, ser: S) -> Result where S: serde::Serializer { - let s = match cow { - Cow::Borrowed(s) => { - let begin = str::as_ptr(s) as u32; - let len = s.len() as u32; - Code { begin, len } - } - Cow::Owned(s) if s.is_empty() => Code { begin: 0, len: 0 }, - Cow::Owned(_) => panic!(), - }; + let s = s.0; + let s = Code { begin: str::as_ptr(s) as u32, len: s.len() as u32 }; s.serialize(ser) } -pub(crate) fn deserialize_cow<'c, 'de, D>(deserializer: D) -> Result, D::Error> +pub(crate) fn deserialize_cow<'c, 'de, D>(deserializer: D) -> Result, D::Error> where D: serde::Deserializer<'de> { let _ = deserializer.deserialize_u64(DeserializeU64); - Ok(Cow::Owned(String::new())) + Ok(StrRef("")) } diff --git a/lib/rust/parser/src/source/code.rs b/lib/rust/parser/src/source/code.rs index 1c64f35d522d..7817f8d1fd08 100644 --- a/lib/rust/parser/src/source/code.rs +++ b/lib/rust/parser/src/source/code.rs @@ -8,6 +8,11 @@ use crate::prelude::*; // === Code === // ============ +/// Wrap a `&str` that is skipped while deserializing; serde doesn't allow a custom deserializer to +/// produce a `&'s str` without borrowing from the input. +#[derive(Debug, Clone, Default, Eq, PartialEq, Deref)] +pub struct StrRef<'s>(pub &'s str); + /// A code representation. It can either be a borrowed source code or a modified owned one. #[derive(Clone, Default, Eq, PartialEq, Serialize, Reflect, Deserialize, Deref)] #[allow(missing_docs)] @@ -16,52 +21,44 @@ pub struct Code<'s> { #[serde(deserialize_with = "crate::serialization::deserialize_cow")] #[reflect(as = "crate::serialization::Code", flatten, hide)] #[deref] - pub repr: Cow<'s, str>, + pub repr: StrRef<'s>, #[reflect(hide)] pub offset_utf16: u32, #[reflect(hide)] - pub utf16: u32, + pub utf16: u32, } impl<'s> Code<'s> { + /// Return a code reference from the given source and offset within the document. #[inline(always)] - pub fn from_str_at_offset(repr: impl Into>, offset_utf16: u32) -> Self { - let repr = repr.into(); + pub fn from_str_at_offset(repr: &'s str, offset_utf16: u32) -> Self { let utf16 = repr.encode_utf16().count() as u32; + let repr = StrRef(repr); Self { repr, offset_utf16, utf16 } } + /// Return a code reference at the beginning of the document. This can be used in testing, when + /// accurate code references are not needed. #[inline(always)] - pub fn from_str_without_offset(repr: impl Into>) -> Self { + pub fn from_str_without_offset(repr: &'s str) -> Self { Self::from_str_at_offset(repr, 0) } + /// Split the UTF-8 code at the given byte offset. pub fn split_at(&self, offset: usize) -> (Self, Self) { - let (left, right) = match self.repr { - Cow::Borrowed(s) => s.split_at(offset), - Cow::Owned(_) => panic!("Unsupported: Splitting owned cows."), - }; + let (left, right) = self.repr.split_at(offset); let left_utf16 = left.encode_utf16().count() as u32; let right_utf16 = self.utf16 - left_utf16; - (Self { - repr: Cow::Borrowed(left), - offset_utf16: self.offset_utf16, - utf16: left_utf16, - }, - Self { - repr: Cow::Borrowed(right), - offset_utf16: self.offset_utf16 + left_utf16, - utf16: right_utf16, - }, - ) + (Self { repr: StrRef(left), offset_utf16: self.offset_utf16, utf16: left_utf16 }, Self { + repr: StrRef(right), + offset_utf16: self.offset_utf16 + left_utf16, + utf16: right_utf16, + }) } + /// Return a reference to an empty string. pub fn empty() -> Self { - Self { - repr: "".into(), - offset_utf16: 0, - utf16: 0, - } + Self { repr: StrRef(""), offset_utf16: 0, utf16: 0 } } /// Length of the code in bytes. @@ -85,7 +82,7 @@ impl<'s> Code<'s> { impl<'s> Display for Code<'s> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - Display::fmt(&self.repr, f) + Display::fmt(&*self.repr, f) } } @@ -98,14 +95,14 @@ impl<'s> Debug for Code<'s> { impl<'a, 'b> PartialEq<&'b str> for Code<'a> { #[inline(always)] fn eq(&self, other: &&'b str) -> bool { - self.repr.eq(other) + self.repr.0.eq(*other) } } impl AsRef for Code<'_> { #[inline(always)] fn as_ref(&self) -> &str { - &self.repr + &self.repr.0 } } @@ -119,16 +116,34 @@ impl std::borrow::Borrow for Code<'_> { impl<'s> AddAssign> for Code<'s> { #[inline(always)] fn add_assign(&mut self, other: Code<'s>) { - self.repr.add_assign(other.repr); - self.utf16.add_assign(other.utf16); + self.add_assign(&other) } } impl<'s> AddAssign<&Code<'s>> for Code<'s> { #[inline(always)] fn add_assign(&mut self, other: &Code<'s>) { - self.repr.add_assign(other.repr.clone()); - self.utf16.add_assign(other.utf16); + match (self.is_empty(), other.is_empty()) { + (_, true) => (), + (true, _) => { + *self = other.clone(); + } + (false, false) => { + let range = self.repr.as_bytes().as_ptr_range(); + #[allow(unsafe_code)] // See comments in block. + unsafe { + // Combining two slices is sound if the second ends where the first begins. + assert_eq!(range.end, other.repr.as_ptr()); + let joined = slice::from_raw_parts( + range.start, + self.repr.len() + other.repr.len(), + ); + // Concatenating two UTF-8 strings always yields a valid UTF-8 string. + self.repr = StrRef(std::str::from_utf8_unchecked(joined)); + } + self.utf16 += other.utf16; + } + } } } diff --git a/lib/rust/parser/src/source/span.rs b/lib/rust/parser/src/source/span.rs index 94b993dd08e6..058f73ccf728 100644 --- a/lib/rust/parser/src/source/span.rs +++ b/lib/rust/parser/src/source/span.rs @@ -97,7 +97,7 @@ impl<'s> AsRef> for Offset<'s> { impl<'s> From> for Offset<'s> { #[inline(always)] fn from(code: Code<'s>) -> Self { - Offset(code.repr.as_ref().into(), code) + Offset((*code.repr).into(), code) } } @@ -116,7 +116,6 @@ impl<'s> AddAssign<&Offset<'s>> for Offset<'s> { } - // ============ // === Span === // ============ From 0b8d1b06fbd5a9f85a0ca496b2fa6cc07c583922 Mon Sep 17 00:00:00 2001 From: Kaz Wesley Date: Mon, 2 Oct 2023 17:17:51 +0000 Subject: [PATCH 26/44] WIP: More comprehensive test. --- app/gui2/parser-codegen/src/codegen.ts | 22 ++-- app/gui2/src/util/ffi.ts | 67 +++++++--- app/gui2/src/util/parserSupport.ts | 17 +++ lib/rust/parser/debug/src/main.rs | 3 +- lib/rust/parser/src/lexer.rs | 161 +++++++++++++++---------- lib/rust/parser/src/source/code.rs | 39 +++--- 6 files changed, 200 insertions(+), 109 deletions(-) diff --git a/app/gui2/parser-codegen/src/codegen.ts b/app/gui2/parser-codegen/src/codegen.ts index c70f3635551a..95918d8b20dc 100644 --- a/app/gui2/parser-codegen/src/codegen.ts +++ b/app/gui2/parser-codegen/src/codegen.ts @@ -387,17 +387,19 @@ function makeDebugFunction(fields: string[]): ts.MethodDeclaration { tsf.createTypeReferenceNode('any'), tsf.createBlock([ tsf.createReturnStatement( - tsf.createObjectLiteralExpression([ - tsf.createSpreadAssignment( - tsf.createCallExpression( - tsf.createPropertyAccessExpression(tsf.createSuper(), 'debug'), - [], - [], + tsf.createCallExpression(support.debugHelper, [], [ + tsf.createObjectLiteralExpression([ + tsf.createSpreadAssignment( + tsf.createCallExpression( + tsf.createPropertyAccessExpression(tsf.createSuper(), 'debug'), + [], + [], + ), ), - ), - ...fields.map((name: string) => - tsf.createPropertyAssignment(getterIdent(name), debugValue(getterIdent(name))), - ), + ...fields.map((name: string) => + tsf.createPropertyAssignment(getterIdent(name), debugValue(getterIdent(name))), + ), + ]) ]), ), ]), diff --git a/app/gui2/src/util/ffi.ts b/app/gui2/src/util/ffi.ts index f2285d60d13d..281239e25732 100644 --- a/app/gui2/src/util/ffi.ts +++ b/app/gui2/src/util/ffi.ts @@ -537,18 +537,57 @@ export namespace Doc { if (import.meta.vitest) { const { test, expect } = import.meta.vitest test('testParse', () => { - const identInput = 'foo' - const tree0 = parseEnso2(identInput) - expect(Number(tree0.spanLeftOffsetCodeUtf16)).toBe(0) - expect(Number(tree0.spanCodeLengthUtf16)).toBe(identInput.length) - expect(tree0.type).toBe(Ast2.Tree.Type.BodyBlock) - if (tree0.type === Ast2.Tree.Type.BodyBlock) { - const statements = Array.from(tree0.statements) - const tree1 = statements[0]!.expression! - expect(tree1.type).toBe(Ast2.Tree.Type.Ident) - if (tree1.type === Ast2.Tree.Type.Ident) { - expect(Number(tree1.token.codeUtf16)).toBe(identInput.length) - } - } + const identInput = ' foo bar' + const tree = parseEnso2(identInput) + expect(tree.debug()).toBe({ + spanCodeLengthUtf16: 7, + spanLeftOffsetCodeOffsetUtf16: 0, + spanLeftOffsetCodeUtf16: 1, + statements: [ + { + expression: { + arg: { + spanCodeLengthUtf16: 3, + spanLeftOffsetCodeOffsetUtf16: 4, + spanLeftOffsetCodeUtf16: 1, + token: { + codeOffsetUtf16: 4, + codeUtf16: 3, + isFree: false, + isOperatorLexically: false, + isTypeOrConstructor: false, + leftOffsetCodeOffsetUtf16: 0, + leftOffsetCodeUtf16: 0, + liftLevel: 0, + }, + }, + func: { + spanCodeLengthUtf16: 3, + spanLeftOffsetCodeOffsetUtf16: 0, + spanLeftOffsetCodeUtf16: 1, + token: { + codeOffsetUtf16: 1, + codeUtf16: 3, + isFree: false, + isOperatorLexically: false, + isTypeOrConstructor: false, + leftOffsetCodeOffsetUtf16: 0, + leftOffsetCodeUtf16: 0, + liftLevel: 0, + }, + }, + spanCodeLengthUtf16: 7, + spanLeftOffsetCodeOffsetUtf16: 0, + spanLeftOffsetCodeUtf16: 0, + }, + newline: { + codeOffsetUtf16: 0, + codeUtf16: 0, + leftOffsetCodeOffsetUtf16: 0, + leftOffsetCodeUtf16: 0, + }, + }, + ], + }) }) -} \ No newline at end of file +} diff --git a/app/gui2/src/util/parserSupport.ts b/app/gui2/src/util/parserSupport.ts index d326b7411ea2..2447b583e3aa 100644 --- a/app/gui2/src/util/parserSupport.ts +++ b/app/gui2/src/util/parserSupport.ts @@ -125,5 +125,22 @@ export function debugHelper(value: any): object | undefined { if (typeof value[Symbol.iterator] === 'function') { return Array.from(value, debugHelper) } + if (typeof value === 'object') { + // FIXME: Include the `hide` reflect property in the schema, and apply it during code generation to avoid magic + // strings here. + const hide = [ + /* + 'codeReprBegin', + 'codeReprLen', + 'leftOffsetCodeReprBegin', + 'leftOffsetCodeReprLen', + 'leftOffsetVisible', + 'spanLeftOffsetCodeReprBegin', + 'spanLeftOffsetCodeReprLen', + 'spanLeftOffsetVisible', + */ + ] + return Object.fromEntries(Object.entries(value).filter(([key, _val]) => !hide.includes(key))) + } return value } diff --git a/lib/rust/parser/debug/src/main.rs b/lib/rust/parser/debug/src/main.rs index 6828323afd75..71128374b49b 100644 --- a/lib/rust/parser/debug/src/main.rs +++ b/lib/rust/parser/debug/src/main.rs @@ -44,5 +44,6 @@ fn check_file(path: &str, mut code: &str) { assert_eq!(parsed, original, "Bug: dropped tokens, while parsing: {path}"); } let s_expr = enso_parser_debug::to_s_expr(&ast, code); - println!("{s_expr}"); + //println!("{s_expr}"); + println!("{ast:?}"); } diff --git a/lib/rust/parser/src/lexer.rs b/lib/rust/parser/src/lexer.rs index 86689d92bea0..c535f549093e 100644 --- a/lib/rust/parser/src/lexer.rs +++ b/lib/rust/parser/src/lexer.rs @@ -18,7 +18,7 @@ use std::str; /// An optimization constant. Based on it, the estimated memory is allocated on the beginning of /// parsing. -pub const AVERAGE_TOKEN_LEN: usize = 5; +const AVERAGE_TOKEN_LEN: usize = 5; /// Within an indented text block, this sets the minimum whitespace to be trimmed from the start of /// each line. const MIN_TEXT_TRIM: VisibleOffset = VisibleOffset(4); @@ -32,7 +32,7 @@ const MIN_TEXT_TRIM: VisibleOffset = VisibleOffset(4); /// Allows checking if the incoming char matches a predicate. The predicate can be another char /// (then this is simply check for equality), or a function `FnMut(char) -> bool`. This trait allows /// defining parsers which can work with both simple and function-based matchers. -pub trait Pattern { +trait Pattern { /// Check whether [`input`] matches this pattern. fn match_pattern(&mut self, input: char) -> bool; } @@ -81,33 +81,53 @@ pattern_impl_for_char_slice!(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); pub struct Lexer<'s> { #[deref] #[deref_mut] - pub state: LexerState, - pub input: &'s str, - pub iterator: str::CharIndices<'s>, - pub output: Vec>, + state: LexerState, + input: &'s str, + iterator: str::CharIndices<'s>, + output: Vec>, /// Memory for storing tokens, reused as an optimization. - pub token_storage: VecAllocation>, + token_storage: VecAllocation>, +} + +#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +struct StrOffset { + utf8: Bytes, + utf16: u32, +} + +impl Sub for StrOffset { + type Output = Self; + + fn sub(self, rhs: Self) -> Self::Output { + Self { utf8: self.utf8 - rhs.utf8, utf16: self.utf16 - rhs.utf16 } + } +} + +impl Add for StrOffset { + type Output = Self; + + fn add(self, rhs: Self) -> Self::Output { + Self { utf8: self.utf8 + rhs.utf8, utf16: self.utf16 + rhs.utf16 } + } } /// Internal state of the [`Lexer`]. #[derive(Debug, Default)] #[allow(missing_docs)] pub struct LexerState { - pub current_char: Option, - pub current_offset: Bytes, - pub current_offset16: u32, - pub last_spaces_offset: Bytes, - pub last_spaces_offset16: u32, - pub last_spaces_visible_offset: VisibleOffset, - pub current_block_indent: VisibleOffset, - pub block_indent_stack: Vec, - pub internal_error: Option, - pub stack: Vec, + current_char: Option, + current_offset: StrOffset, + last_spaces_offset: StrOffset, + last_spaces_visible_offset: VisibleOffset, + current_block_indent: VisibleOffset, + block_indent_stack: Vec, + internal_error: Option, + stack: Vec, } /// Suspended states. #[derive(Debug, PartialEq, Eq, Copy, Clone)] -pub enum State { +enum State { /// Reading a single-line text literal. InlineText, /// Reading a multi-line text literal. @@ -119,7 +139,7 @@ pub enum State { }, } -type Mark<'s> = (Bytes, u32, Offset<'s>); +type Mark<'s> = (StrOffset, Offset<'s>); impl<'s> Lexer<'s> { /// Constructor. @@ -143,11 +163,18 @@ impl<'s> Lexer<'s> { fn next_input_char(&mut self) -> bool { let next = self.iterator.next(); if let Some((current_offset, current_char)) = next { - self.current_offset = Bytes(current_offset); + self.current_offset = StrOffset { + utf8: Bytes(current_offset), + utf16: self.current_offset.utf16 + + self.current_char.map_or(0, |c| c.len_utf16() as u32), + }; self.current_char = Some(current_char); true - } else if self.current_char.is_some() { - self.current_offset = Bytes(self.input.len()); + } else if let Some(c) = self.current_char { + self.current_offset = StrOffset { + utf8: Bytes(self.input.len()), + utf16: self.current_offset.utf16 + c.len_utf16() as u32, + }; self.current_char = None; true } else { @@ -157,7 +184,7 @@ impl<'s> Lexer<'s> { /// Run the provided function and compute how much input it consumed. #[inline(always)] - pub fn run_and_get_offset(&mut self, f: impl FnOnce(&mut Self) -> T) -> (T, Bytes) { + fn run_and_get_offset(&mut self, f: impl FnOnce(&mut Self) -> T) -> (T, StrOffset) { let start_offset = self.current_offset; let out = f(self); let len = self.current_offset - start_offset; @@ -166,8 +193,8 @@ impl<'s> Lexer<'s> { /// Run the provided function and check if it consumed any input. #[inline(always)] - pub fn run_and_check_if_progressed(&mut self, f: impl FnOnce(&mut Self)) -> bool { - self.run_and_get_offset(f).1.is_positive() + fn run_and_check_if_progressed(&mut self, f: impl FnOnce(&mut Self)) -> bool { + self.run_and_get_offset(f).1.utf8.is_positive() } /// Consume spaces after parsing a [`Token`] and update the internal spacing info. @@ -188,25 +215,30 @@ impl<'s> Lexer<'s> { /// Run the provided function. If it consumed any chars, return the [`Token`] containing the /// provided function output. Returns [`None`] otherwise. #[inline(always)] - pub fn token(&mut self, f: impl FnOnce(&mut Self) -> T) -> Option> { + fn token(&mut self, f: impl FnOnce(&mut Self) -> T) -> Option> { let start = self.current_offset; let (elem, len) = self.run_and_get_offset(f); - len.is_positive().as_some_from(|| { + len.utf8.is_positive().as_some_from(|| { let end = start + len; - let code = self.input.slice(start..end); let left_offset_start = start - self.last_spaces_offset; - let offset_code = self.input.slice(left_offset_start..start); + let (offset_code, code) = self + .input + .slice(left_offset_start.utf8..end.utf8) + .split_at(self.last_spaces_offset.utf8.unchecked_raw()); let visible_offset = self.last_spaces_visible_offset; - let offset = Offset(visible_offset, Code::from_str_at_offset(offset_code, 0)); + let offset = Offset( + visible_offset, + Code::from_str_at_offset(offset_code, left_offset_start.utf16), + ); self.spaces_after_lexeme(); - Token(offset, Code::from_str_at_offset(code, 0), elem) + Token(offset, Code::from_str_at_offset(code, start.utf16), elem) }) } /// A zero-length token which is placed before the last consumed spaces if they were not /// followed by any token. #[inline(always)] - pub fn marker_token(&mut self, elem: T) -> Token<'s, T> { + fn marker_token(&mut self, elem: T) -> Token<'s, T> { let visible_offset = VisibleOffset(0); let offset = Offset(visible_offset, Code::empty()); Token(offset, Code::empty(), elem) @@ -214,13 +246,13 @@ impl<'s> Lexer<'s> { /// Push the [`token`] to the result stream. #[inline(always)] - pub fn submit_token(&mut self, token: Token<'s>) { + fn submit_token(&mut self, token: Token<'s>) { self.output.push(token); } /// Start a new block. #[inline(always)] - pub fn start_block(&mut self, new_indent: VisibleOffset) { + fn start_block(&mut self, new_indent: VisibleOffset) { let current_block_indent = self.current_block_indent; self.block_indent_stack.push(current_block_indent); self.current_block_indent = new_indent; @@ -228,7 +260,7 @@ impl<'s> Lexer<'s> { /// Finish the current block. #[inline(always)] - pub fn end_block(&mut self) -> Option { + fn end_block(&mut self) -> Option { self.block_indent_stack.pop().map(|prev| { let out = self.current_block_indent; self.current_block_indent = prev; @@ -246,13 +278,13 @@ impl<'s> Lexer<'s> { impl<'s> Lexer<'s> { /// Consume the next character, unconditionally. #[inline(always)] - pub fn take_next(&mut self) -> bool { + fn take_next(&mut self) -> bool { self.next_input_char() } /// Consume exactly one character if it matches the pattern. Returns [`true`] if it succeeded. #[inline(always)] - pub fn take_1(&mut self, mut pat: impl Pattern) -> bool { + fn take_1(&mut self, mut pat: impl Pattern) -> bool { match self.current_char.map(|t| pat.match_pattern(t)) { Some(true) => self.next_input_char(), _ => false, @@ -261,13 +293,13 @@ impl<'s> Lexer<'s> { /// Version of [`take_1`] that discards its result. #[inline(always)] - pub fn take_1_(&mut self, pat: impl Pattern) { + fn take_1_(&mut self, pat: impl Pattern) { self.take_1(pat); } /// Consume characters as long as they match the pattern. #[inline(always)] - pub fn take_while(&mut self, mut pat: impl Pattern) { + fn take_while(&mut self, mut pat: impl Pattern) { while let Some(true) = self.current_char.map(|t| pat.match_pattern(t)) { self.next_input_char(); } @@ -276,7 +308,7 @@ impl<'s> Lexer<'s> { /// Consume characters as long as they match the pattern. Returns [`true`] if at least one /// character was consumed. #[inline(always)] - pub fn take_while_1(&mut self, f: impl Copy + Pattern) -> bool { + fn take_while_1(&mut self, f: impl Copy + Pattern) -> bool { let ok = self.take_1(f); if ok { self.take_while(f); @@ -286,7 +318,7 @@ impl<'s> Lexer<'s> { /// Version of [`take_while_1`] that discards its result. #[inline(always)] - pub fn take_while_1_(&mut self, f: impl Copy + Pattern) { + fn take_while_1_(&mut self, f: impl Copy + Pattern) { self.take_while_1(f); } } @@ -380,7 +412,7 @@ impl<'s> Lexer<'s> { /// Check whether the provided character is a newline character. #[inline(always)] -pub fn is_newline_char(t: char) -> bool { +fn is_newline_char(t: char) -> bool { t == '\n' || t == '\r' } @@ -510,7 +542,7 @@ fn is_operator_body_char(t: char) -> bool { /// Info about identifier being parsed. #[derive(Clone, Copy, Debug)] #[allow(missing_docs)] -pub struct IdentInfo { +struct IdentInfo { starts_with_underscore: bool, lift_level: usize, starts_with_uppercase: bool, @@ -520,7 +552,7 @@ pub struct IdentInfo { impl IdentInfo { /// Constructor. #[inline(always)] - pub fn new(repr: &str) -> Self { + fn new(repr: &str) -> Self { let starts_with_underscore = repr.starts_with('_'); let lift_level = repr.chars().rev().take_while(|t| *t == '\'').count(); let starts_with_uppercase = @@ -546,7 +578,7 @@ impl token::Variant { /// Convert the provided string to ident. The provided repr should contain valid identifier /// characters. This condition will not be checked. #[inline(always)] - pub fn new_ident_unchecked(repr: &str) -> token::variant::Ident { + fn new_ident_unchecked(repr: &str) -> token::variant::Ident { let info = IdentInfo::new(repr); let is_operator = false; token::variant::Ident( @@ -561,7 +593,7 @@ impl token::Variant { /// Convert the provided string to ident or wildcard. The provided repr should contain valid /// identifier characters. This condition will not be checked. #[inline(always)] - pub fn new_ident_or_wildcard_unchecked(repr: &str) -> token::Variant { + fn new_ident_or_wildcard_unchecked(repr: &str) -> token::Variant { let info = IdentInfo::new(repr); if info.starts_with_underscore && repr.len() == 1 + info.lift_level { token::Variant::wildcard(info.lift_level) @@ -903,7 +935,7 @@ impl<'s> Lexer<'s> { let indent = self.current_block_indent; let open_quote_start = self.mark(); self.last_spaces_visible_offset = VisibleOffset(0); - self.last_spaces_offset = Bytes(0); + self.last_spaces_offset = default(); self.take_next(); // At least two quote characters. if let Some(char) = self.current_char && char == quote_char { @@ -1048,9 +1080,11 @@ impl<'s> Lexer<'s> { self.end_blocks(indent); self.output.extend(newlines); if self.current_offset == text_start.0 { - self.last_spaces_visible_offset = text_start.2.visible; - self.last_spaces_offset = text_start.2.code.len(); - self.last_spaces_offset16 = text_start.2.code.utf16; + self.last_spaces_visible_offset = text_start.1.visible; + self.last_spaces_offset = StrOffset { + utf8: text_start.1.code.len(), + utf16: text_start.1.code.utf16, + }; } return TextEndedAt::End; } @@ -1187,26 +1221,22 @@ impl<'s> Lexer<'s> { fn mark(&mut self) -> Mark<'s> { let start = self.current_offset; let left_offset_start = start - self.last_spaces_offset; - let start16 = self.current_offset16; - let left_offset_start16 = start16 - self.last_spaces_offset16; - let offset_code = self.input.slice(left_offset_start..start); + let offset_code = self.input.slice(left_offset_start.utf8..start.utf8); let visible_offset = self.last_spaces_visible_offset; self.last_spaces_visible_offset = VisibleOffset(0); - self.last_spaces_offset = Bytes(0); - self.last_spaces_offset16 = 0; + self.last_spaces_offset = default(); ( start, - start16, - Offset(visible_offset, Code::from_str_at_offset(offset_code, left_offset_start16)), + Offset(visible_offset, Code::from_str_at_offset(offset_code, left_offset_start.utf16)), ) } fn make_token(&self, from: Mark<'s>, to: Mark<'s>, variant: token::Variant) -> Token<'s> { - let (start, start16, offset) = from; + let (start, offset) = from; let end = to.0; - let start = start.unchecked_raw(); - let end = end.unchecked_raw(); - Token(offset, Code::from_str_at_offset(&self.input[start..end], start16), variant) + let start8 = start.utf8.unchecked_raw(); + let end8 = end.utf8.unchecked_raw(); + Token(offset, Code::from_str_at_offset(&self.input[start8..end8], start.utf16), variant) } } @@ -1370,11 +1400,12 @@ impl<'s> Lexer<'s> { } if self.last_spaces_visible_offset != VisibleOffset(0) { let left_offset_start = self.current_offset - self.last_spaces_offset; - let left_offset_start16 = self.current_offset16 - self.last_spaces_offset16; - let offset_code = self.input.slice(left_offset_start..self.current_offset); + let offset_code = self.input.slice(left_offset_start.utf8..self.current_offset.utf8); let visible_offset = self.last_spaces_visible_offset; - let offset = - Offset(visible_offset, Code::from_str_at_offset(offset_code, left_offset_start16)); + let offset = Offset( + visible_offset, + Code::from_str_at_offset(offset_code, left_offset_start.utf16), + ); let eof = token::variant::Variant::Newline(token::variant::Newline()); self.submit_token(Token(offset, Code::empty(), eof)); } diff --git a/lib/rust/parser/src/source/code.rs b/lib/rust/parser/src/source/code.rs index 7817f8d1fd08..ef47e08d40ff 100644 --- a/lib/rust/parser/src/source/code.rs +++ b/lib/rust/parser/src/source/code.rs @@ -14,7 +14,7 @@ use crate::prelude::*; pub struct StrRef<'s>(pub &'s str); /// A code representation. It can either be a borrowed source code or a modified owned one. -#[derive(Clone, Default, Eq, PartialEq, Serialize, Reflect, Deserialize, Deref)] +#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Reflect, Deserialize, Deref)] #[allow(missing_docs)] pub struct Code<'s> { #[serde(serialize_with = "crate::serialization::serialize_cow")] @@ -32,7 +32,7 @@ impl<'s> Code<'s> { /// Return a code reference from the given source and offset within the document. #[inline(always)] pub fn from_str_at_offset(repr: &'s str, offset_utf16: u32) -> Self { - let utf16 = repr.encode_utf16().count() as u32; + let utf16 = repr.chars().map(|c| c.len_utf16() as u32).sum(); let repr = StrRef(repr); Self { repr, offset_utf16, utf16 } } @@ -47,13 +47,20 @@ impl<'s> Code<'s> { /// Split the UTF-8 code at the given byte offset. pub fn split_at(&self, offset: usize) -> (Self, Self) { let (left, right) = self.repr.split_at(offset); - let left_utf16 = left.encode_utf16().count() as u32; + let left_utf16 = left.chars().map(|c| c.len_utf16() as u32).sum(); let right_utf16 = self.utf16 - left_utf16; - (Self { repr: StrRef(left), offset_utf16: self.offset_utf16, utf16: left_utf16 }, Self { - repr: StrRef(right), - offset_utf16: self.offset_utf16 + left_utf16, - utf16: right_utf16, - }) + ( + Self { + repr: StrRef(left), + offset_utf16: self.offset_utf16, + utf16: left_utf16, + }, + Self { + repr: StrRef(right), + offset_utf16: self.offset_utf16 + left_utf16, + utf16: right_utf16, + }, + ) } /// Return a reference to an empty string. @@ -86,12 +93,6 @@ impl<'s> Display for Code<'s> { } } -impl<'s> Debug for Code<'s> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - Debug::fmt(&self.repr, f) - } -} - impl<'a, 'b> PartialEq<&'b str> for Code<'a> { #[inline(always)] fn eq(&self, other: &&'b str) -> bool { @@ -132,12 +133,12 @@ impl<'s> AddAssign<&Code<'s>> for Code<'s> { let range = self.repr.as_bytes().as_ptr_range(); #[allow(unsafe_code)] // See comments in block. unsafe { - // Combining two slices is sound if the second ends where the first begins. + // Combining two slices is sound if: + // - They have the same element lifetime (ensured by the type signature). + // - The second ends where the first begins (checked below). assert_eq!(range.end, other.repr.as_ptr()); - let joined = slice::from_raw_parts( - range.start, - self.repr.len() + other.repr.len(), - ); + let joined = + slice::from_raw_parts(range.start, self.repr.len() + other.repr.len()); // Concatenating two UTF-8 strings always yields a valid UTF-8 string. self.repr = StrRef(std::str::from_utf8_unchecked(joined)); } From 2e32656700d00667cf244d6048b5236b60106c0b Mon Sep 17 00:00:00 2001 From: Kaz Wesley Date: Mon, 2 Oct 2023 17:23:05 +0000 Subject: [PATCH 27/44] Use 32-bit numbers in parser. --- lib/rust/parser/src/lexer.rs | 12 ++++++------ lib/rust/parser/src/source/code.rs | 4 ++-- lib/rust/parser/src/source/span.rs | 4 ++-- lib/rust/parser/src/syntax/token.rs | 8 ++++---- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/lib/rust/parser/src/lexer.rs b/lib/rust/parser/src/lexer.rs index c535f549093e..491565fd0520 100644 --- a/lib/rust/parser/src/lexer.rs +++ b/lib/rust/parser/src/lexer.rs @@ -544,7 +544,7 @@ fn is_operator_body_char(t: char) -> bool { #[allow(missing_docs)] struct IdentInfo { starts_with_underscore: bool, - lift_level: usize, + lift_level: u32, starts_with_uppercase: bool, is_default: bool, } @@ -554,7 +554,7 @@ impl IdentInfo { #[inline(always)] fn new(repr: &str) -> Self { let starts_with_underscore = repr.starts_with('_'); - let lift_level = repr.chars().rev().take_while(|t| *t == '\'').count(); + let lift_level = repr.chars().rev().take_while(|t| *t == '\'').count() as u32; let starts_with_uppercase = repr.chars().next().map(|c| c.is_uppercase()).unwrap_or_default(); let is_default = repr == "default"; @@ -595,7 +595,7 @@ impl token::Variant { #[inline(always)] fn new_ident_or_wildcard_unchecked(repr: &str) -> token::Variant { let info = IdentInfo::new(repr); - if info.starts_with_underscore && repr.len() == 1 + info.lift_level { + if info.starts_with_underscore && repr.len() as u32 == 1 + info.lift_level { token::Variant::wildcard(info.lift_level) } else { let is_free = info.starts_with_underscore; @@ -892,7 +892,7 @@ impl<'s> Lexer<'s> { self.token(|this| this.take_while(is_hexadecimal_digit)), }; let joiner = token::OperatorProperties::new() - .with_binary_infix_precedence(usize::MAX) + .with_binary_infix_precedence(u32::MAX) .as_token_joiner(); self.submit_token(Token( Code::empty(), @@ -1440,7 +1440,7 @@ pub mod test { /// Constructor. pub fn ident_<'s>(left_offset: &'s str, code: &'s str) -> Token<'s> { let is_free = code.starts_with('_'); - let lift_level = code.chars().rev().take_while(|t| *t == '\'').count(); + let lift_level = code.chars().rev().take_while(|t| *t == '\'').count() as u32; let is_uppercase = code.chars().next().map(|c| c.is_uppercase()).unwrap_or_default(); let is_operator = false; let left_offset = Code::from_str_without_offset(left_offset); @@ -1450,7 +1450,7 @@ pub mod test { /// Constructor. pub fn wildcard_<'s>(left_offset: &'s str, code: &'s str) -> Token<'s> { - let lift_level = code.chars().rev().take_while(|t| *t == '\'').count(); + let lift_level = code.chars().rev().take_while(|t| *t == '\'').count() as u32; let left_offset = Code::from_str_without_offset(left_offset); let code = Code::from_str_without_offset(code); token::wildcard_(left_offset, code, lift_level) diff --git a/lib/rust/parser/src/source/code.rs b/lib/rust/parser/src/source/code.rs index ef47e08d40ff..5c85863adf9a 100644 --- a/lib/rust/parser/src/source/code.rs +++ b/lib/rust/parser/src/source/code.rs @@ -77,7 +77,7 @@ impl<'s> Code<'s> { /// Length of the code. #[inline(always)] pub fn length(&self) -> Length { - Length { utf8: self.repr.len(), utf16: self.utf16 as usize } + Length { utf8: self.repr.len(), utf16: self.utf16 } } /// True if the code is the empty string. @@ -157,7 +157,7 @@ pub struct Length { #[reflect(skip)] #[serde(skip)] utf8: usize, - utf16: usize, + utf16: u32, } impl Length { diff --git a/lib/rust/parser/src/source/span.rs b/lib/rust/parser/src/source/span.rs index 058f73ccf728..349f7dc0433d 100644 --- a/lib/rust/parser/src/source/span.rs +++ b/lib/rust/parser/src/source/span.rs @@ -28,12 +28,12 @@ pub mod traits { #[allow(missing_docs)] #[reflect(transparent)] pub struct VisibleOffset { - pub width_in_spaces: usize, + pub width_in_spaces: u32, } /// Constructor. #[allow(non_snake_case)] -pub const fn VisibleOffset(width_in_spaces: usize) -> VisibleOffset { +pub const fn VisibleOffset(width_in_spaces: u32) -> VisibleOffset { VisibleOffset { width_in_spaces } } diff --git a/lib/rust/parser/src/syntax/token.rs b/lib/rust/parser/src/syntax/token.rs index a309cff070a0..38f7142ae48c 100644 --- a/lib/rust/parser/src/syntax/token.rs +++ b/lib/rust/parser/src/syntax/token.rs @@ -259,12 +259,12 @@ macro_rules! with_token_definition { ($f:ident ($($args:tt)*)) => { $f! { $($arg BlockStart, BlockEnd, Wildcard { - pub lift_level: usize + pub lift_level: u32 }, AutoScope, Ident { pub is_free: bool, - pub lift_level: usize, + pub lift_level: u32, #[reflect(rename = "is_type_or_constructor")] pub is_type: bool, pub is_operator_lexically: bool, @@ -354,7 +354,7 @@ impl OperatorProperties { } /// Return a copy of this operator, with the given binary infix precedence. - pub fn with_binary_infix_precedence(self, value: usize) -> Self { + pub fn with_binary_infix_precedence(self, value: u32) -> Self { let precedence = Precedence { value }; debug_assert!(precedence > Precedence::min()); Self { binary_infix_precedence: Some(precedence), ..self } @@ -527,7 +527,7 @@ impl OperatorProperties { #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Reflect, Deserialize, PartialOrd, Ord)] pub struct Precedence { /// A numeric value determining precedence order. - value: usize, + value: u32, } impl Precedence { From 8b45146c56de2f5d9b5c2fc5751e823d72a120a0 Mon Sep 17 00:00:00 2001 From: Kaz Wesley Date: Wed, 4 Oct 2023 06:53:29 -0700 Subject: [PATCH 28/44] Fix bug. --- Cargo.lock | 2 + app/gui2/parser-codegen/package.json | 2 +- app/gui2/src/util/ffi.ts | 20 ++- app/gui2/src/util/parserSupport.ts | 27 ++-- lib/rust/parser/debug/Cargo.toml | 1 + lib/rust/parser/debug/src/bin/binary_ast.rs | 24 ++++ lib/rust/parser/debug/src/bin/json_ast.rs | 20 +++ lib/rust/parser/schema/Cargo.toml | 1 + lib/rust/parser/schema/src/lib.rs | 54 ++++---- lib/rust/parser/src/format.rs | 15 ++- lib/rust/parser/src/syntax/token.rs | 9 +- lib/rust/parser/src/syntax/tree.rs | 15 +-- package-lock.json | 131 ++++++++------------ 13 files changed, 170 insertions(+), 151 deletions(-) create mode 100644 lib/rust/parser/debug/src/bin/binary_ast.rs create mode 100644 lib/rust/parser/debug/src/bin/json_ast.rs diff --git a/Cargo.lock b/Cargo.lock index efa8c632ff06..0aedea925e21 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2378,6 +2378,7 @@ dependencies = [ "enso-reflect", "lexpr", "serde", + "serde_json", ] [[package]] @@ -2410,6 +2411,7 @@ dependencies = [ "enso-reflect", "serde", "serde_json", + "serde_yaml", ] [[package]] diff --git a/app/gui2/parser-codegen/package.json b/app/gui2/parser-codegen/package.json index 33e2d098b45c..a36b40f707ac 100644 --- a/app/gui2/parser-codegen/package.json +++ b/app/gui2/parser-codegen/package.json @@ -8,7 +8,7 @@ }, "main": "dist/codegen.js", "scripts": { - "generate-ast-schema": "cargo run -p enso-parser-schema > generated/ast-schema.json", + "generate-ast-schema": "cargo run -p enso-parser-schema --bin enso-parser-schema > generated/ast-schema.json", "preinstall": "npm run generate-ast-schema", "generate-bindings": "tsc --build && node dist/codegen.js generated/ast-schema.json" }, diff --git a/app/gui2/src/util/ffi.ts b/app/gui2/src/util/ffi.ts index 281239e25732..88c930b33102 100644 --- a/app/gui2/src/util/ffi.ts +++ b/app/gui2/src/util/ffi.ts @@ -10,7 +10,6 @@ if (RUNNING_VTEST) { } else { await init() } - export function parseEnso(code: string): Ast.Tree { const json = parse_to_json(code) return JSON.parse(json) @@ -537,10 +536,10 @@ export namespace Doc { if (import.meta.vitest) { const { test, expect } = import.meta.vitest test('testParse', () => { - const identInput = ' foo bar' + const identInput = ' foo bar\n' const tree = parseEnso2(identInput) - expect(tree.debug()).toBe({ - spanCodeLengthUtf16: 7, + expect(tree.debug()).toStrictEqual({ + spanCodeLengthUtf16: 8, spanLeftOffsetCodeOffsetUtf16: 0, spanLeftOffsetCodeUtf16: 1, statements: [ @@ -551,7 +550,7 @@ if (import.meta.vitest) { spanLeftOffsetCodeOffsetUtf16: 4, spanLeftOffsetCodeUtf16: 1, token: { - codeOffsetUtf16: 4, + codeOffsetUtf16: 5, codeUtf16: 3, isFree: false, isOperatorLexically: false, @@ -564,7 +563,7 @@ if (import.meta.vitest) { func: { spanCodeLengthUtf16: 3, spanLeftOffsetCodeOffsetUtf16: 0, - spanLeftOffsetCodeUtf16: 1, + spanLeftOffsetCodeUtf16: 0, token: { codeOffsetUtf16: 1, codeUtf16: 3, @@ -587,6 +586,15 @@ if (import.meta.vitest) { leftOffsetCodeUtf16: 0, }, }, + { + expression: undefined, + newline: { + codeOffsetUtf16: 8, + codeUtf16: 1, + leftOffsetCodeOffsetUtf16: 8, + leftOffsetCodeUtf16: 0, + }, + } ], }) }) diff --git a/app/gui2/src/util/parserSupport.ts b/app/gui2/src/util/parserSupport.ts index 2447b583e3aa..ec4dc3bff61f 100644 --- a/app/gui2/src/util/parserSupport.ts +++ b/app/gui2/src/util/parserSupport.ts @@ -66,7 +66,9 @@ export class Cursor { } readPointer(): Cursor { - return new Cursor(this.blob.buffer, this.readU32()) + const pointee = this.readU32(); + console.log(`readPointer: ${this.address()} -> ${pointee}`) + return new Cursor(this.blob.buffer, pointee) } readU8(): number { @@ -113,23 +115,23 @@ export class Cursor { seek(offset: number): Cursor { return new Cursor(this.blob.buffer, this.blob.byteOffset + offset) } -} -export function debugHelper(value: any): object | undefined { - if (value == null) { - return undefined - } - if (typeof value['debug'] === 'function') { - return value.debug() - } - if (typeof value[Symbol.iterator] === 'function') { - return Array.from(value, debugHelper) + address(): number { + return this.blob.byteOffset } +} + +export function debugHelper(value: any | undefined): any | undefined { if (typeof value === 'object') { + if ('debug' in value && typeof value['debug'] === 'function') { + return value.debug() + } + if (Symbol.iterator in value && typeof value[Symbol.iterator] === 'function') { + return Array.from(value, debugHelper) + } // FIXME: Include the `hide` reflect property in the schema, and apply it during code generation to avoid magic // strings here. const hide = [ - /* 'codeReprBegin', 'codeReprLen', 'leftOffsetCodeReprBegin', @@ -138,7 +140,6 @@ export function debugHelper(value: any): object | undefined { 'spanLeftOffsetCodeReprBegin', 'spanLeftOffsetCodeReprLen', 'spanLeftOffsetVisible', - */ ] return Object.fromEntries(Object.entries(value).filter(([key, _val]) => !hide.includes(key))) } diff --git a/lib/rust/parser/debug/Cargo.toml b/lib/rust/parser/debug/Cargo.toml index ba073126fdba..adb3b586def9 100644 --- a/lib/rust/parser/debug/Cargo.toml +++ b/lib/rust/parser/debug/Cargo.toml @@ -16,3 +16,4 @@ enso-metamodel-lexpr = { path = "../../metamodel/lexpr" } enso-reflect = { path = "../../reflect" } lexpr = "0.2.6" serde = { version = "1.0", features = ["derive"] } +serde_json = { workspace = true } diff --git a/lib/rust/parser/debug/src/bin/binary_ast.rs b/lib/rust/parser/debug/src/bin/binary_ast.rs new file mode 100644 index 000000000000..f41990209c12 --- /dev/null +++ b/lib/rust/parser/debug/src/bin/binary_ast.rs @@ -0,0 +1,24 @@ +//! Run the parser from the command line, and output the raw binary serialization of the AST for +//! debugging. + +// === Features === +// === Standard Linter Configuration === +#![deny(non_ascii_idents)] +#![warn(unsafe_code)] +// === Non-Standard Linter Configuration === + +use std::io::Write; + +fn main() { + use std::io::Read; + let mut input = String::new(); + std::io::stdin().read_to_string(&mut input).unwrap(); + let mut code = input.as_str(); + if let Some((_meta, code_)) = enso_parser::metadata::parse(code) { + code = code_; + } + let ast = enso_parser::Parser::new().run(code); + let data = + enso_parser::format::serialize(&ast).expect("Failed to serialize AST to binary format"); + std::io::stdout().write_all(&data).unwrap(); +} diff --git a/lib/rust/parser/debug/src/bin/json_ast.rs b/lib/rust/parser/debug/src/bin/json_ast.rs new file mode 100644 index 000000000000..4fc7ee2bb8b4 --- /dev/null +++ b/lib/rust/parser/debug/src/bin/json_ast.rs @@ -0,0 +1,20 @@ +//! Run the parser from the command line, and output the a JSON serialization of the AST for +//! debugging. + +// === Features === +// === Standard Linter Configuration === +#![deny(non_ascii_idents)] +#![warn(unsafe_code)] +// === Non-Standard Linter Configuration === + +fn main() { + use std::io::Read; + let mut input = String::new(); + std::io::stdin().read_to_string(&mut input).unwrap(); + let mut code = input.as_str(); + if let Some((_meta, code_)) = enso_parser::metadata::parse(code) { + code = code_; + } + let ast = enso_parser::Parser::new().run(code); + serde_json::to_writer(std::io::stdout(), &ast).unwrap(); +} diff --git a/lib/rust/parser/schema/Cargo.toml b/lib/rust/parser/schema/Cargo.toml index 8c701480873b..8852d9bf4a65 100644 --- a/lib/rust/parser/schema/Cargo.toml +++ b/lib/rust/parser/schema/Cargo.toml @@ -17,3 +17,4 @@ serde = { version = "1", features = ["derive"] } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] serde_json = { workspace = true } +serde_yaml = { workspace = true } diff --git a/lib/rust/parser/schema/src/lib.rs b/lib/rust/parser/schema/src/lib.rs index 7418edb02885..7e7ca608dd87 100644 --- a/lib/rust/parser/schema/src/lib.rs +++ b/lib/rust/parser/schema/src/lib.rs @@ -47,34 +47,34 @@ pub fn schema() -> impl serde::Serialize { // === Schema === // ============== -#[derive(serde::Serialize)] -struct Schema { - types: HashMap, - serialization: HashMap, +#[derive(serde::Serialize, serde::Deserialize)] +pub struct Schema { + pub types: HashMap, + pub serialization: HashMap, } // === Type graph === -#[derive(serde::Serialize)] +#[derive(serde::Serialize, serde::Deserialize)] #[serde(rename_all = "camelCase")] -struct Type { - name: Rc, - fields: HashMap, +pub struct Type { + pub name: Rc, + pub fields: HashMap, #[serde(skip_serializing_if = "Option::is_none")] - parent: Option, + pub parent: Option, } -#[derive(serde::Serialize, Clone, Hash, PartialEq, Eq)] -struct TypeId(Rc); +#[derive(serde::Serialize, serde::Deserialize, Clone, Hash, PartialEq, Eq)] +pub struct TypeId(Rc); -#[derive(serde::Serialize, Clone, Hash, PartialEq, Eq)] -struct FieldName(Rc); +#[derive(serde::Serialize, serde::Deserialize, Clone, Hash, PartialEq, Eq)] +pub struct FieldName(Rc); -#[derive(serde::Serialize, Clone, Hash, PartialEq, Eq)] +#[derive(serde::Serialize, serde::Deserialize, Clone, Hash, PartialEq, Eq)] #[serde(rename_all = "lowercase")] #[serde(tag = "class")] -enum TypeRef { +pub enum TypeRef { Type { id: TypeId }, Primitive { r#type: Primitive }, Sequence { r#type: Box }, @@ -82,9 +82,9 @@ enum TypeRef { Result { r#type0: Box, r#type1: Box }, } -#[derive(serde::Serialize, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(serde::Serialize, serde::Deserialize, Copy, Clone, Hash, PartialEq, Eq)] #[serde(rename_all = "lowercase")] -enum Primitive { +pub enum Primitive { Bool, U32, U64, @@ -97,17 +97,17 @@ enum Primitive { // === Serialization === -#[derive(serde::Serialize)] +#[derive(serde::Serialize, serde::Deserialize)] #[serde(rename_all = "camelCase")] -struct Layout { - fields: Vec<(FieldName, usize)>, +pub struct Layout { + pub fields: Vec<(FieldName, usize)>, #[serde(skip_serializing_if = "Option::is_none")] - discriminants: Option>, - size: usize, + pub discriminants: Option>, + pub size: usize, } -#[derive(serde::Serialize, Clone, PartialEq, Eq, PartialOrd, Ord)] -struct Discriminant(u32); +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, Eq, PartialOrd, Ord, Copy)] +pub struct Discriminant(pub u32); @@ -288,7 +288,11 @@ fn layouts<'g>( .map(|field| { let entry = (FieldName(field.name.to_snake_case().unwrap().into()), offset); - offset += sizes[&field.type_]; + offset += if graph[&field.type_].discriminants.is_empty() { + sizes[&field.type_] + } else { + POINTER + }; entry }) .collect() diff --git a/lib/rust/parser/src/format.rs b/lib/rust/parser/src/format.rs index 0c3ab0dd232b..954722e7e194 100644 --- a/lib/rust/parser/src/format.rs +++ b/lib/rust/parser/src/format.rs @@ -43,6 +43,9 @@ pub fn serialize(value: T) -> Result> { let mut serializer = Serializer::new(); value.serialize(&mut serializer)?; serializer.heap.append(&mut serializer.stack); + debug_assert_eq!(serializer.recursion_depth, 0); + debug_assert_eq!(serializer.object_depth, 0); + debug_assert_eq!(&serializer.parent_structs, &[]); Ok(serializer.heap) } @@ -86,6 +89,7 @@ impl Serializer { self.recursion_depth -= 1; self.object_depth -= 1; let address = self.heap.len(); + eprintln!("-> {address}"); self.heap.extend(self.stack.drain(begin..)); self.serialize_u32(u32::try_from(address).unwrap()) } @@ -111,10 +115,12 @@ impl<'a> ObjectSerializer<'a> { // ==== Parent Struct === /// Information for transforming a struct into a combined parent/child representation. -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] struct ParentStruct { object_depth_inside: usize, begin: usize, + // Useful for debugging. + _name: &'static str, } @@ -243,7 +249,7 @@ impl<'a> ser::Serializer for &'a mut Serializer { self, name: &'static str, variant_index: u32, - _variant: &'static str, + variant: &'static str, value: &T, ) -> Result<()> where @@ -253,12 +259,15 @@ impl<'a> ser::Serializer for &'a mut Serializer { && let Some(ancestor) = self.parent_structs.last() && ancestor.object_depth_inside == self.object_depth { let parent_start = ancestor.begin; + let _ancestor_name = ancestor._name; // Add the child's fields to the stack (following the parent's fields). value.serialize(&mut *self)?; // Build the object on the heap. let address = self.heap.len(); self.heap.extend_from_slice(&variant_index.to_le_bytes()); self.heap.extend(self.stack.drain(parent_start..)); + let end_address = self.heap.len(); + eprintln!(">> {address}-{end_address} [{_ancestor_name}::{variant}]"); self.serialize_u32(u32::try_from(address).unwrap())?; } else { let mut ser = self.object_serializer()?; @@ -311,7 +320,7 @@ impl<'a> ser::Serializer for &'a mut Serializer { if matches!(name, "Tree" | "Token") { let object_depth_inside = self.object_depth; let begin = self.stack.len(); - self.parent_structs.push(ParentStruct { object_depth_inside, begin }); + self.parent_structs.push(ParentStruct { object_depth_inside, begin, _name: name }); } Ok(self) } diff --git a/lib/rust/parser/src/syntax/token.rs b/lib/rust/parser/src/syntax/token.rs index 38f7142ae48c..7f0b4ebc8f1e 100644 --- a/lib/rust/parser/src/syntax/token.rs +++ b/lib/rust/parser/src/syntax/token.rs @@ -105,7 +105,7 @@ use enso_shapely_macros::tagged_enum; // ============= /// The lexical token definition. See the module docs to learn more about its usage scenarios. -#[derive(Clone, Default, Deref, DerefMut, Eq, PartialEq, Serialize, Reflect, Deserialize)] +#[derive(Clone, Debug, Default, Deref, DerefMut, Eq, PartialEq, Serialize, Reflect, Deserialize)] #[allow(missing_docs)] pub struct Token<'s, T = Variant> { #[reflect(flatten, hide)] @@ -170,13 +170,6 @@ impl<'s, T> Token<'s, T> { } } -impl<'s, T: Debug> Debug for Token<'s, T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "[{}:{:?}] ", self.left_offset.visible, self.code)?; - Debug::fmt(&self.variant, f) - } -} - impl<'s, T: PartialEq> PartialEq> for &Token<'s, T> { fn eq(&self, other: &Token<'s, T>) -> bool { as PartialEq>>::eq(*self, other) diff --git a/lib/rust/parser/src/syntax/tree.rs b/lib/rust/parser/src/syntax/tree.rs index 6472453c0c0f..fbd8108ad191 100644 --- a/lib/rust/parser/src/syntax/tree.rs +++ b/lib/rust/parser/src/syntax/tree.rs @@ -23,7 +23,7 @@ pub mod block; // ============ /// The Abstract Syntax Tree of the language. -#[derive(Clone, Deref, DerefMut, Eq, PartialEq, Serialize, Reflect, Deserialize)] +#[derive(Clone, Debug, Deref, DerefMut, Eq, PartialEq, Serialize, Reflect, Deserialize)] #[allow(missing_docs)] pub struct Tree<'s> { #[reflect(flatten, hide)] @@ -41,19 +41,6 @@ pub fn Tree<'s>(span: Span<'s>, variant: impl Into>) -> Tree<'s> { Tree { variant, span } } -impl<'s> Debug for Tree<'s> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let max_code_len = 30; - let ellipsis = "..."; - let mut code = self.code(); - if code.len() > max_code_len { - code = format!("{}{}", &code[..max_code_len - ellipsis.len()], ellipsis); - } - write!(f, "[{}:{}:\"{}\"] ", self.span.left_offset.visible, self.span.code_length, code)?; - Debug::fmt(&self.variant, f) - } -} - impl<'s> AsRef> for Tree<'s> { fn as_ref(&self) -> &Span<'s> { &self.span diff --git a/package-lock.json b/package-lock.json index 0e5f08dcfb8b..6091658ed17b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,7 @@ "lib/rust/ensogl/pack/js" ], "dependencies": { - "chromedriver": "^106.0.1", + "chromedriver": "^117.0.3", "enso-gui2": "^0.1.0", "lint": "^0.8.19", "run": "^1.4.0", @@ -21,7 +21,7 @@ }, "devDependencies": { "npm-run-all": "^4.1.5", - "prettier": "^3.0.0" + "prettier": "^3.0.3" } }, "app/gui2": { @@ -2791,6 +2791,7 @@ }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", + "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", @@ -2802,6 +2803,7 @@ }, "node_modules/@nodelib/fs.stat": { "version": "2.0.5", + "dev": true, "license": "MIT", "engines": { "node": ">= 8" @@ -2809,6 +2811,7 @@ }, "node_modules/@nodelib/fs.walk": { "version": "1.2.8", + "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", @@ -4362,17 +4365,6 @@ "node": ">= 6.0.0" } }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "license": "MIT", - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/ajv": { "version": "6.12.6", "license": "MIT", @@ -4617,6 +4609,7 @@ }, "node_modules/array-union": { "version": "2.1.0", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -4858,11 +4851,13 @@ "license": "MIT" }, "node_modules/axios": { - "version": "0.27.2", - "license": "MIT", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.5.1.tgz", + "integrity": "sha512-Q28iYCWzNHjAm+yEAot5QaAMxhMghWLFVf7rRdwhUI+c2jix2DUXjAHXVi+s1ibs3mjPO/cCgbA++3BjD0vP/A==", "dependencies": { - "follow-redirects": "^1.14.9", - "form-data": "^4.0.0" + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" } }, "node_modules/balanced-match": { @@ -5106,6 +5101,7 @@ }, "node_modules/braces": { "version": "3.0.2", + "dev": true, "license": "MIT", "dependencies": { "fill-range": "^7.0.1" @@ -5553,14 +5549,14 @@ "license": "ISC" }, "node_modules/chromedriver": { - "version": "106.0.1", + "version": "117.0.3", + "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-117.0.3.tgz", + "integrity": "sha512-c2rk2eGK5zZFBJMdviUlAJfQEBuPNIKfal4+rTFVYAmrWbMPYAqPozB+rIkc1lDP/Ryw44lPiqKglrI01ILhTQ==", "hasInstallScript": true, - "license": "Apache-2.0", "dependencies": { "@testim/chrome-version": "^1.1.3", - "axios": "^0.27.2", - "compare-versions": "^5.0.1", - "del": "^6.1.1", + "axios": "^1.4.0", + "compare-versions": "^6.0.0", "extract-zip": "^2.0.1", "https-proxy-agent": "^5.0.1", "proxy-from-env": "^1.1.0", @@ -5570,7 +5566,7 @@ "chromedriver": "bin/chromedriver" }, "engines": { - "node": ">=10" + "node": ">=18" } }, "node_modules/chromium-pickle-js": { @@ -5592,13 +5588,6 @@ "node": ">=8" } }, - "node_modules/clean-stack": { - "version": "2.2.0", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/cli-boxes": { "version": "2.2.1", "dev": true, @@ -5814,8 +5803,9 @@ } }, "node_modules/compare-versions": { - "version": "5.0.3", - "license": "MIT" + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-6.1.0.tgz", + "integrity": "sha512-LNZQXhqUvqUTotpZ00qLSaify3b4VFD588aRr8MKFw4CMUr98ytzCW5wDH5qx/DEY5kCDXcbcRuCqL0szEf2tg==" }, "node_modules/concat-map": { "version": "0.0.1", @@ -6613,26 +6603,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/del": { - "version": "6.1.1", - "license": "MIT", - "dependencies": { - "globby": "^11.0.1", - "graceful-fs": "^4.2.4", - "is-glob": "^4.0.1", - "is-path-cwd": "^2.2.0", - "is-path-inside": "^3.0.2", - "p-map": "^4.0.0", - "rimraf": "^3.0.2", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/delaunator": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.0.tgz", @@ -6723,6 +6693,7 @@ }, "node_modules/dir-glob": { "version": "3.0.1", + "dev": true, "license": "MIT", "dependencies": { "path-type": "^4.0.0" @@ -8284,6 +8255,7 @@ }, "node_modules/fast-glob": { "version": "3.3.1", + "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -8298,6 +8270,7 @@ }, "node_modules/fast-glob/node_modules/glob-parent": { "version": "5.1.2", + "dev": true, "license": "ISC", "dependencies": { "is-glob": "^4.0.1" @@ -8317,6 +8290,7 @@ }, "node_modules/fastq": { "version": "1.15.0", + "dev": true, "license": "ISC", "dependencies": { "reusify": "^1.0.4" @@ -8393,6 +8367,7 @@ }, "node_modules/fill-range": { "version": "7.0.1", + "dev": true, "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" @@ -8435,14 +8410,15 @@ "license": "ISC" }, "node_modules/follow-redirects": { - "version": "1.15.2", + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", + "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", "funding": [ { "type": "individual", "url": "https://github.com/sponsors/RubenVerborgh" } ], - "license": "MIT", "engines": { "node": ">=4.0" }, @@ -8776,6 +8752,7 @@ }, "node_modules/globby": { "version": "11.1.0", + "dev": true, "license": "MIT", "dependencies": { "array-union": "^2.1.0", @@ -8829,6 +8806,7 @@ }, "node_modules/graceful-fs": { "version": "4.2.11", + "dev": true, "license": "ISC" }, "node_modules/graceful-readlink": { @@ -9095,6 +9073,7 @@ }, "node_modules/ignore": { "version": "5.2.4", + "dev": true, "license": "MIT", "engines": { "node": ">= 4" @@ -9192,13 +9171,6 @@ "node": ">= 4.0.0" } }, - "node_modules/indent-string": { - "version": "4.0.0", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/inflight": { "version": "1.0.6", "license": "ISC", @@ -9512,6 +9484,7 @@ }, "node_modules/is-extglob": { "version": "2.1.1", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -9556,6 +9529,7 @@ }, "node_modules/is-glob": { "version": "4.0.3", + "dev": true, "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" @@ -9628,6 +9602,7 @@ }, "node_modules/is-number": { "version": "7.0.0", + "dev": true, "license": "MIT", "engines": { "node": ">=0.12.0" @@ -9655,15 +9630,9 @@ "node": ">=8" } }, - "node_modules/is-path-cwd": { - "version": "2.2.0", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/is-path-inside": { "version": "3.0.3", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -10832,6 +10801,7 @@ }, "node_modules/merge2": { "version": "1.4.1", + "dev": true, "license": "MIT", "engines": { "node": ">= 8" @@ -10839,6 +10809,7 @@ }, "node_modules/micromatch": { "version": "4.0.5", + "dev": true, "license": "MIT", "dependencies": { "braces": "^3.0.2", @@ -11665,19 +11636,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/p-map": { - "version": "4.0.0", - "license": "MIT", - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", @@ -11952,6 +11910,7 @@ }, "node_modules/path-type": { "version": "4.0.0", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -11989,6 +11948,7 @@ }, "node_modules/picomatch": { "version": "2.3.1", + "dev": true, "license": "MIT", "engines": { "node": ">=8.6" @@ -12536,6 +12496,7 @@ }, "node_modules/queue-microtask": { "version": "1.2.3", + "dev": true, "funding": [ { "type": "github", @@ -13270,6 +13231,7 @@ }, "node_modules/reusify": { "version": "1.0.4", + "dev": true, "license": "MIT", "engines": { "iojs": ">=1.0.0", @@ -13278,6 +13240,7 @@ }, "node_modules/rimraf": { "version": "3.0.2", + "dev": true, "license": "ISC", "dependencies": { "glob": "^7.1.3" @@ -13291,6 +13254,7 @@ }, "node_modules/rimraf/node_modules/brace-expansion": { "version": "1.1.11", + "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -13299,6 +13263,7 @@ }, "node_modules/rimraf/node_modules/glob": { "version": "7.2.3", + "dev": true, "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", @@ -13317,6 +13282,7 @@ }, "node_modules/rimraf/node_modules/minimatch": { "version": "3.1.2", + "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -13543,6 +13509,7 @@ }, "node_modules/run-parallel": { "version": "1.2.0", + "dev": true, "funding": [ { "type": "github", @@ -13934,6 +13901,7 @@ }, "node_modules/slash": { "version": "3.0.0", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -14735,6 +14703,7 @@ }, "node_modules/to-regex-range": { "version": "5.0.1", + "dev": true, "license": "MIT", "dependencies": { "is-number": "^7.0.0" From 978fdda80f95fd9c4808a07e09c4a62dd96b448a Mon Sep 17 00:00:00 2001 From: Kaz Wesley Date: Wed, 4 Oct 2023 07:14:22 -0700 Subject: [PATCH 29/44] Cleanup. --- app/gui2/src/util/ffi.ts | 16 +--- app/gui2/src/util/parserSupport.ts | 1 - lib/rust/parser/debug/src/main.rs | 3 +- lib/rust/parser/schema/Cargo.toml | 1 - lib/rust/parser/src/format.rs | 11 ++- package-lock.json | 138 +++++++++++++++++++---------- 6 files changed, 101 insertions(+), 69 deletions(-) diff --git a/app/gui2/src/util/ffi.ts b/app/gui2/src/util/ffi.ts index 88c930b33102..59d40ecfe0a6 100644 --- a/app/gui2/src/util/ffi.ts +++ b/app/gui2/src/util/ffi.ts @@ -538,7 +538,7 @@ if (import.meta.vitest) { test('testParse', () => { const identInput = ' foo bar\n' const tree = parseEnso2(identInput) - expect(tree.debug()).toStrictEqual({ + expect(tree.debug()).toMatchObject({ spanCodeLengthUtf16: 8, spanLeftOffsetCodeOffsetUtf16: 0, spanLeftOffsetCodeUtf16: 1, @@ -552,12 +552,7 @@ if (import.meta.vitest) { token: { codeOffsetUtf16: 5, codeUtf16: 3, - isFree: false, - isOperatorLexically: false, - isTypeOrConstructor: false, - leftOffsetCodeOffsetUtf16: 0, leftOffsetCodeUtf16: 0, - liftLevel: 0, }, }, func: { @@ -567,22 +562,14 @@ if (import.meta.vitest) { token: { codeOffsetUtf16: 1, codeUtf16: 3, - isFree: false, - isOperatorLexically: false, - isTypeOrConstructor: false, - leftOffsetCodeOffsetUtf16: 0, leftOffsetCodeUtf16: 0, - liftLevel: 0, }, }, spanCodeLengthUtf16: 7, - spanLeftOffsetCodeOffsetUtf16: 0, spanLeftOffsetCodeUtf16: 0, }, newline: { - codeOffsetUtf16: 0, codeUtf16: 0, - leftOffsetCodeOffsetUtf16: 0, leftOffsetCodeUtf16: 0, }, }, @@ -591,7 +578,6 @@ if (import.meta.vitest) { newline: { codeOffsetUtf16: 8, codeUtf16: 1, - leftOffsetCodeOffsetUtf16: 8, leftOffsetCodeUtf16: 0, }, } diff --git a/app/gui2/src/util/parserSupport.ts b/app/gui2/src/util/parserSupport.ts index ec4dc3bff61f..ccce9b80d7dd 100644 --- a/app/gui2/src/util/parserSupport.ts +++ b/app/gui2/src/util/parserSupport.ts @@ -67,7 +67,6 @@ export class Cursor { readPointer(): Cursor { const pointee = this.readU32(); - console.log(`readPointer: ${this.address()} -> ${pointee}`) return new Cursor(this.blob.buffer, pointee) } diff --git a/lib/rust/parser/debug/src/main.rs b/lib/rust/parser/debug/src/main.rs index 71128374b49b..6828323afd75 100644 --- a/lib/rust/parser/debug/src/main.rs +++ b/lib/rust/parser/debug/src/main.rs @@ -44,6 +44,5 @@ fn check_file(path: &str, mut code: &str) { assert_eq!(parsed, original, "Bug: dropped tokens, while parsing: {path}"); } let s_expr = enso_parser_debug::to_s_expr(&ast, code); - //println!("{s_expr}"); - println!("{ast:?}"); + println!("{s_expr}"); } diff --git a/lib/rust/parser/schema/Cargo.toml b/lib/rust/parser/schema/Cargo.toml index 8852d9bf4a65..8c701480873b 100644 --- a/lib/rust/parser/schema/Cargo.toml +++ b/lib/rust/parser/schema/Cargo.toml @@ -17,4 +17,3 @@ serde = { version = "1", features = ["derive"] } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] serde_json = { workspace = true } -serde_yaml = { workspace = true } diff --git a/lib/rust/parser/src/format.rs b/lib/rust/parser/src/format.rs index 954722e7e194..fd0c8fd6168e 100644 --- a/lib/rust/parser/src/format.rs +++ b/lib/rust/parser/src/format.rs @@ -32,6 +32,9 @@ use std::fmt::Formatter; /// [`test::wasm::test_infinite_recursion`]). const RECURSION_LIMIT: usize = 1024; +/// If enabled, logs debugging info to stderr. +const DEBUG: bool = false; + // ================= @@ -89,7 +92,9 @@ impl Serializer { self.recursion_depth -= 1; self.object_depth -= 1; let address = self.heap.len(); - eprintln!("-> {address}"); + if DEBUG { + eprintln!("-> {address}"); + } self.heap.extend(self.stack.drain(begin..)); self.serialize_u32(u32::try_from(address).unwrap()) } @@ -267,7 +272,9 @@ impl<'a> ser::Serializer for &'a mut Serializer { self.heap.extend_from_slice(&variant_index.to_le_bytes()); self.heap.extend(self.stack.drain(parent_start..)); let end_address = self.heap.len(); - eprintln!(">> {address}-{end_address} [{_ancestor_name}::{variant}]"); + if DEBUG { + eprintln!(">> {address}-{end_address} [{_ancestor_name}::{variant}]"); + } self.serialize_u32(u32::try_from(address).unwrap())?; } else { let mut ser = self.object_serializer()?; diff --git a/package-lock.json b/package-lock.json index 6091658ed17b..c13837c05d37 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,7 @@ "lib/rust/ensogl/pack/js" ], "dependencies": { - "chromedriver": "^117.0.3", + "chromedriver": "^106.0.1", "enso-gui2": "^0.1.0", "lint": "^0.8.19", "run": "^1.4.0", @@ -21,7 +21,7 @@ }, "devDependencies": { "npm-run-all": "^4.1.5", - "prettier": "^3.0.3" + "prettier": "^3.0.0" } }, "app/gui2": { @@ -2791,7 +2791,6 @@ }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", - "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", @@ -2803,7 +2802,6 @@ }, "node_modules/@nodelib/fs.stat": { "version": "2.0.5", - "dev": true, "license": "MIT", "engines": { "node": ">= 8" @@ -2811,7 +2809,6 @@ }, "node_modules/@nodelib/fs.walk": { "version": "1.2.8", - "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", @@ -4365,6 +4362,18 @@ "node": ">= 6.0.0" } }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/ajv": { "version": "6.12.6", "license": "MIT", @@ -4609,7 +4618,6 @@ }, "node_modules/array-union": { "version": "2.1.0", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -4851,13 +4859,12 @@ "license": "MIT" }, "node_modules/axios": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.5.1.tgz", - "integrity": "sha512-Q28iYCWzNHjAm+yEAot5QaAMxhMghWLFVf7rRdwhUI+c2jix2DUXjAHXVi+s1ibs3mjPO/cCgbA++3BjD0vP/A==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz", + "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==", "dependencies": { - "follow-redirects": "^1.15.0", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.0" + "follow-redirects": "^1.14.9", + "form-data": "^4.0.0" } }, "node_modules/balanced-match": { @@ -5101,7 +5108,6 @@ }, "node_modules/braces": { "version": "3.0.2", - "dev": true, "license": "MIT", "dependencies": { "fill-range": "^7.0.1" @@ -5549,14 +5555,15 @@ "license": "ISC" }, "node_modules/chromedriver": { - "version": "117.0.3", - "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-117.0.3.tgz", - "integrity": "sha512-c2rk2eGK5zZFBJMdviUlAJfQEBuPNIKfal4+rTFVYAmrWbMPYAqPozB+rIkc1lDP/Ryw44lPiqKglrI01ILhTQ==", + "version": "106.0.1", + "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-106.0.1.tgz", + "integrity": "sha512-thaBvbDEPgGocSp4/SBIajQz3G7UQfUqCOHZBp9TVhRJv7c91eZrUGcjeJUaNF4p9CfSjCYNYzs4EVVryqmddA==", "hasInstallScript": true, "dependencies": { "@testim/chrome-version": "^1.1.3", - "axios": "^1.4.0", - "compare-versions": "^6.0.0", + "axios": "^0.27.2", + "compare-versions": "^5.0.1", + "del": "^6.1.1", "extract-zip": "^2.0.1", "https-proxy-agent": "^5.0.1", "proxy-from-env": "^1.1.0", @@ -5566,7 +5573,7 @@ "chromedriver": "bin/chromedriver" }, "engines": { - "node": ">=18" + "node": ">=10" } }, "node_modules/chromium-pickle-js": { @@ -5588,6 +5595,14 @@ "node": ">=8" } }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "engines": { + "node": ">=6" + } + }, "node_modules/cli-boxes": { "version": "2.2.1", "dev": true, @@ -5803,9 +5818,9 @@ } }, "node_modules/compare-versions": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-6.1.0.tgz", - "integrity": "sha512-LNZQXhqUvqUTotpZ00qLSaify3b4VFD588aRr8MKFw4CMUr98ytzCW5wDH5qx/DEY5kCDXcbcRuCqL0szEf2tg==" + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-5.0.3.tgz", + "integrity": "sha512-4UZlZP8Z99MGEY+Ovg/uJxJuvoXuN4M6B3hKaiackiHrgzQFEe3diJi1mf1PNHbFujM7FvLrK2bpgIaImbtZ1A==" }, "node_modules/concat-map": { "version": "0.0.1", @@ -6603,6 +6618,27 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/del": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/del/-/del-6.1.1.tgz", + "integrity": "sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==", + "dependencies": { + "globby": "^11.0.1", + "graceful-fs": "^4.2.4", + "is-glob": "^4.0.1", + "is-path-cwd": "^2.2.0", + "is-path-inside": "^3.0.2", + "p-map": "^4.0.0", + "rimraf": "^3.0.2", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/delaunator": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.0.tgz", @@ -6693,7 +6729,6 @@ }, "node_modules/dir-glob": { "version": "3.0.1", - "dev": true, "license": "MIT", "dependencies": { "path-type": "^4.0.0" @@ -8255,7 +8290,6 @@ }, "node_modules/fast-glob": { "version": "3.3.1", - "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -8270,7 +8304,6 @@ }, "node_modules/fast-glob/node_modules/glob-parent": { "version": "5.1.2", - "dev": true, "license": "ISC", "dependencies": { "is-glob": "^4.0.1" @@ -8290,7 +8323,6 @@ }, "node_modules/fastq": { "version": "1.15.0", - "dev": true, "license": "ISC", "dependencies": { "reusify": "^1.0.4" @@ -8367,7 +8399,6 @@ }, "node_modules/fill-range": { "version": "7.0.1", - "dev": true, "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" @@ -8752,7 +8783,6 @@ }, "node_modules/globby": { "version": "11.1.0", - "dev": true, "license": "MIT", "dependencies": { "array-union": "^2.1.0", @@ -8806,7 +8836,6 @@ }, "node_modules/graceful-fs": { "version": "4.2.11", - "dev": true, "license": "ISC" }, "node_modules/graceful-readlink": { @@ -9073,7 +9102,6 @@ }, "node_modules/ignore": { "version": "5.2.4", - "dev": true, "license": "MIT", "engines": { "node": ">= 4" @@ -9171,6 +9199,14 @@ "node": ">= 4.0.0" } }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "engines": { + "node": ">=8" + } + }, "node_modules/inflight": { "version": "1.0.6", "license": "ISC", @@ -9484,7 +9520,6 @@ }, "node_modules/is-extglob": { "version": "2.1.1", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -9529,7 +9564,6 @@ }, "node_modules/is-glob": { "version": "4.0.3", - "dev": true, "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" @@ -9602,7 +9636,6 @@ }, "node_modules/is-number": { "version": "7.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=0.12.0" @@ -9630,9 +9663,16 @@ "node": ">=8" } }, + "node_modules/is-path-cwd": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", + "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", + "engines": { + "node": ">=6" + } + }, "node_modules/is-path-inside": { "version": "3.0.3", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -10801,7 +10841,6 @@ }, "node_modules/merge2": { "version": "1.4.1", - "dev": true, "license": "MIT", "engines": { "node": ">= 8" @@ -10809,7 +10848,6 @@ }, "node_modules/micromatch": { "version": "4.0.5", - "dev": true, "license": "MIT", "dependencies": { "braces": "^3.0.2", @@ -11636,6 +11674,20 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", @@ -11910,7 +11962,6 @@ }, "node_modules/path-type": { "version": "4.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -11948,7 +11999,6 @@ }, "node_modules/picomatch": { "version": "2.3.1", - "dev": true, "license": "MIT", "engines": { "node": ">=8.6" @@ -12439,7 +12489,8 @@ }, "node_modules/proxy-from-env": { "version": "1.1.0", - "license": "MIT" + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" }, "node_modules/prr": { "version": "1.0.1", @@ -12496,7 +12547,6 @@ }, "node_modules/queue-microtask": { "version": "1.2.3", - "dev": true, "funding": [ { "type": "github", @@ -13231,7 +13281,6 @@ }, "node_modules/reusify": { "version": "1.0.4", - "dev": true, "license": "MIT", "engines": { "iojs": ">=1.0.0", @@ -13240,7 +13289,6 @@ }, "node_modules/rimraf": { "version": "3.0.2", - "dev": true, "license": "ISC", "dependencies": { "glob": "^7.1.3" @@ -13254,7 +13302,6 @@ }, "node_modules/rimraf/node_modules/brace-expansion": { "version": "1.1.11", - "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -13263,7 +13310,6 @@ }, "node_modules/rimraf/node_modules/glob": { "version": "7.2.3", - "dev": true, "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", @@ -13282,7 +13328,6 @@ }, "node_modules/rimraf/node_modules/minimatch": { "version": "3.1.2", - "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -13509,7 +13554,6 @@ }, "node_modules/run-parallel": { "version": "1.2.0", - "dev": true, "funding": [ { "type": "github", @@ -13901,7 +13945,6 @@ }, "node_modules/slash": { "version": "3.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -14703,7 +14746,6 @@ }, "node_modules/to-regex-range": { "version": "5.0.1", - "dev": true, "license": "MIT", "dependencies": { "is-number": "^7.0.0" From e9f64db4fcc52e30e6a81b2b5479e3bde701b5ac Mon Sep 17 00:00:00 2001 From: Kaz Wesley Date: Wed, 4 Oct 2023 07:35:45 -0700 Subject: [PATCH 30/44] Use change-case. --- app/gui2/parser-codegen/package-lock.json | 6 ++++ app/gui2/parser-codegen/package.json | 2 ++ app/gui2/parser-codegen/src/codegen.ts | 36 +++++++---------------- 3 files changed, 19 insertions(+), 25 deletions(-) diff --git a/app/gui2/parser-codegen/package-lock.json b/app/gui2/parser-codegen/package-lock.json index 9755eb259404..9b769df9499e 100644 --- a/app/gui2/parser-codegen/package-lock.json +++ b/app/gui2/parser-codegen/package-lock.json @@ -9,9 +9,15 @@ "version": "1.0.0", "hasInstallScript": true, "dependencies": { + "change-case": "^5.0.2", "typescript": "^5.2.2" } }, + "node_modules/change-case": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/change-case/-/change-case-5.0.2.tgz", + "integrity": "sha512-tH6YZXViaeC2/Mnt8m4gSmbZfNorC2rhwCX2bXw8SYZWr8ljCPB7iA+1TLG9t7yroWBFauc63LlOZ1gucMVCWw==" + }, "node_modules/typescript": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", diff --git a/app/gui2/parser-codegen/package.json b/app/gui2/parser-codegen/package.json index a36b40f707ac..6c8fc2a6757d 100644 --- a/app/gui2/parser-codegen/package.json +++ b/app/gui2/parser-codegen/package.json @@ -2,6 +2,7 @@ "name": "enso-parser-codegen", "version": "1.0.0", "private": true, + "type": "module", "author": { "name": "Enso Team", "email": "contact@enso.org" @@ -14,6 +15,7 @@ }, "keywords": [], "dependencies": { + "change-case": "^5.0.2", "typescript": "^5.2.2" } } diff --git a/app/gui2/parser-codegen/src/codegen.ts b/app/gui2/parser-codegen/src/codegen.ts index 95918d8b20dc..5222dd1b70a2 100644 --- a/app/gui2/parser-codegen/src/codegen.ts +++ b/app/gui2/parser-codegen/src/codegen.ts @@ -1,6 +1,7 @@ import * as fs from 'fs' -import * as ts from 'typescript' -import { factory as tsf } from 'typescript' +import ts from 'typescript' +const { factory: tsf } = ts +import * as changeCase from 'change-case' module Schema { export type TypeId = string @@ -40,29 +41,14 @@ type Schema = { serialization: Schema.Serialization } -function fromSnake(ident: string, to: 'camel' | 'pascal', prefix?: string): string { - const segments = [] - if (prefix != null) { - segments.push(...prefix.split('_')) - } - segments.push(...ident.split('_')) - return segments - .map((seg, i) => { - if (to === 'camel' && i === 0) { - return seg - } else { - return seg.charAt(0).toUpperCase() + seg.slice(1) - } - }) - .join('') -} - -function toPascal(ident: string, prefix?: string): string { - return fromSnake(ident, 'pascal', prefix) +function toPascal(ident: string): string { + if (ident.includes('.')) throw new Error("toPascal cannot be applied to a namespaced name.") + return changeCase.pascalCase(ident) } -function toCamel(ident: string, prefix?: string): string { - return fromSnake(ident, 'camel', prefix) +function toCamel(ident: string): string { + if (ident.includes('.')) throw new Error("toCamel cannot be applied to a namespaced name.") + return changeCase.camelCase(ident) } function legalizeIdent(ident: string): string { @@ -190,7 +176,7 @@ function namespacedName(name: string, namespace?: string): string { function abstractTypeReader(name: string): ExpressionTransformer { return (cursor: ts.Expression) => tsf.createCallExpression( - tsf.createPropertyAccessExpression(tsf.createIdentifier(toPascal(name)), 'read'), + tsf.createPropertyAccessExpression(tsf.createIdentifier(name), 'read'), [], [cursorMethods.readPointer(cursor)], ) @@ -199,7 +185,7 @@ function abstractTypeReader(name: string): ExpressionTransformer { function concreteTypeReader(name: string): ExpressionTransformer { return (cursor: ts.Expression) => tsf.createCallExpression( - tsf.createPropertyAccessExpression(tsf.createIdentifier(toPascal(name)), 'read'), + tsf.createPropertyAccessExpression(tsf.createIdentifier(name), 'read'), [], [cursor], ) From de2a09905d58e16736e7fc74dbcfb5f354fca17c Mon Sep 17 00:00:00 2001 From: Kaz Wesley Date: Wed, 4 Oct 2023 08:23:28 -0700 Subject: [PATCH 31/44] Organize --- Cargo.lock | 1 - app/gui2/parser-codegen/src/codegen.ts | 169 ++++++++----------------- app/gui2/parser-codegen/src/main.ts | 7 + app/gui2/parser-codegen/src/schema.ts | 35 +++++ app/gui2/parser-codegen/src/util.ts | 31 +++++ app/gui2/parser-codegen/tsconfig.json | 12 +- app/gui2/src/util/ffi.ts | 7 + app/gui2/tsconfig.app.json | 1 - 8 files changed, 140 insertions(+), 123 deletions(-) create mode 100644 app/gui2/parser-codegen/src/main.ts create mode 100644 app/gui2/parser-codegen/src/schema.ts create mode 100644 app/gui2/parser-codegen/src/util.ts diff --git a/Cargo.lock b/Cargo.lock index 0aedea925e21..17f1d958945d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2411,7 +2411,6 @@ dependencies = [ "enso-reflect", "serde", "serde_json", - "serde_yaml", ] [[package]] diff --git a/app/gui2/parser-codegen/src/codegen.ts b/app/gui2/parser-codegen/src/codegen.ts index 5222dd1b70a2..3ab519837e94 100644 --- a/app/gui2/parser-codegen/src/codegen.ts +++ b/app/gui2/parser-codegen/src/codegen.ts @@ -1,68 +1,7 @@ -import * as fs from 'fs' import ts from 'typescript' const { factory: tsf } = ts -import * as changeCase from 'change-case' - -module Schema { - export type TypeId = string - export type Types = { - [id: TypeId]: Type - } - export type Type = { - name: string - fields: Fields - parent?: string - } - export type Fields = { - [name: string]: TypeRef - } - export type TypeRef = Class | Primitive | Sequence | Option | Result - export type Class = { class: 'type'; id: TypeId } - export type Primitive = { class: 'primitive'; type: PrimitiveType } - export type Sequence = { class: 'sequence'; type: TypeRef } - export type Option = { class: 'option'; type: TypeRef } - export type Result = { class: 'result'; type0: TypeRef; type1: TypeRef } - export type PrimitiveType = 'bool' | 'u32' | 'u64' | 'i32' | 'i64' | 'char' | 'string' - - export type Serialization = { - [id: TypeId]: Layout - } - export type Layout = { - discriminants?: DiscriminantMap - fields: [name: string, offset: number][] - size: number - } - export type DiscriminantMap = { - [discriminant: number]: TypeId - } -} -type Schema = { - types: Schema.Types - serialization: Schema.Serialization -} - -function toPascal(ident: string): string { - if (ident.includes('.')) throw new Error("toPascal cannot be applied to a namespaced name.") - return changeCase.pascalCase(ident) -} - -function toCamel(ident: string): string { - if (ident.includes('.')) throw new Error("toCamel cannot be applied to a namespaced name.") - return changeCase.camelCase(ident) -} - -function legalizeIdent(ident: string): string { - // FIXME: We should accept a renaming table as an input alongside the schema, then emit an error if a keyword is - // encountered ("constructor") or a field name is duplicated ("type"). - switch (ident) { - case 'constructor': - return 'ident' - case 'type': - return 'typeNode' - default: - return ident - } -} +import * as Schema from '@/schema' +import { toPascal, toCamel, legalizeIdent, namespacedName } from '@/util' type ExpressionTransformer = (expression: ts.Expression) => ts.Expression @@ -165,14 +104,6 @@ function readerTransformerSized( } } -function namespacedName(name: string, namespace?: string): string { - if (namespace == null) { - return toPascal(name) - } else { - return toPascal(namespace) + '.' + toPascal(name) - } -} - function abstractTypeReader(name: string): ExpressionTransformer { return (cursor: ts.Expression) => tsf.createCallExpression( @@ -202,7 +133,7 @@ class Type { this.size = size } - static new(ref: Schema.TypeRef, schema: Schema): Type { + static new(ref: Schema.TypeRef, schema: Schema.Schema): Type { const c = ref.class switch (c) { case 'type': @@ -294,7 +225,7 @@ function makeGetter( fieldName: string, typeRef: Schema.TypeRef, offset: number, - schema: Schema, + schema: Schema.Schema, ): ts.GetAccessorDeclaration { const type = Type.new(typeRef, schema) return tsf.createGetAccessorDeclaration( @@ -322,7 +253,7 @@ function createAssignmentStatement(left: ts.Expression, right: ts.Expression): t ) } -function makeConcreteType(id: string, schema: Schema): ts.ClassDeclaration { +function makeConcreteType(id: string, schema: Schema.Schema): ts.ClassDeclaration { const ident = tsf.createIdentifier(toPascal(schema.types[id].name)) const paramIdent = tsf.createIdentifier('cursor') const cursorParam = tsf.createParameterDeclaration( @@ -392,7 +323,7 @@ function makeDebugFunction(fields: string[]): ts.MethodDeclaration { ) } -function makeGetters(id: string, schema: Schema): ts.ClassElement[] { +function makeGetters(id: string, schema: Schema.Schema): ts.ClassElement[] { return schema.serialization[id].fields.map(([name, offset]: [string, number]) => makeGetter(name, schema.types[id].fields[name], offset, schema)) } @@ -402,7 +333,7 @@ function makeClass( name: ts.Identifier, members: ts.ClassElement[], id: string, - schema: Schema, + schema: Schema.Schema, ): ts.ClassDeclaration { return tsf.createClassDeclaration( modifiers, @@ -432,7 +363,7 @@ function makeChildType( base: ts.Identifier, id: string, discrim: string, - schema: Schema, + schema: Schema.Schema, ): ChildType { const ty: Schema.Type = schema.types[id] const name = toPascal(ty.name) @@ -568,7 +499,7 @@ function abstractTypeDeserializer( ) } -function makeAbstractType(id: string, discriminants: Schema.DiscriminantMap, schema: Schema) { +function makeAbstractType(id: string, discriminants: Schema.DiscriminantMap, schema: Schema.Schema, emit: ((node: ts.Node) => void)) { const ty = schema.types[id] const name = toPascal(ty.name) const ident = tsf.createIdentifier(name) @@ -617,17 +548,51 @@ function makeAbstractType(id: string, discriminants: Schema.DiscriminantMap, sch emit(abstractTypeExport) } -function emit(data: ts.Node) { - output += printer.printNode(ts.EmitHint.Unspecified, data, file) - output += '\n' -} - // ============ // === Main === // ============ -const schema: Schema = JSON.parse(fs.readFileSync(process.argv[2], 'utf8')) -let output = '// *** THIS FILE GENERATED BY `parser-codegen` ***\n' +export function implement(schema: Schema.Schema): string { + let output = '// *** THIS FILE GENERATED BY `parser-codegen` ***\n' + function emit(data: ts.Node) { + output += printer.printNode(ts.EmitHint.Unspecified, data, file) + output += '\n' + } + emit( + tsf.createImportDeclaration( + [], + tsf.createImportClause( + false, + undefined, + tsf.createNamedImports( + Array.from(Object.entries(supportImports), ([name, isTypeOnly]) => + tsf.createImportSpecifier(isTypeOnly, undefined, tsf.createIdentifier(name)), + ), + ), + ), + tsf.createStringLiteral('@/util/parserSupport', true), + undefined, + ), + ) + for (const id in schema.types) { + const ty = schema.types[id] + if (ty.parent == null) { + const discriminants = schema.serialization[id].discriminants + if (discriminants == null) { + emit(makeConcreteType(id, schema)) + } else { + makeAbstractType(id, discriminants, schema, emit) + } + } else { + // Ignore child types; they are generated when `makeAbstractType` processes the parent. + } + } + output += `export function deserializeTree(data: ArrayBuffer): Tree { + const cursor = new Cursor(data, data.byteLength - 4) + return Tree.read(cursor.readPointer()) + }` + return output +} const file = ts.createSourceFile('source.ts', '', ts.ScriptTarget.ESNext, false, ts.ScriptKind.TS) const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed }) const noneType = tsf.createTypeReferenceNode('undefined') @@ -666,37 +631,3 @@ const support = { Result: (t0: ts.TypeNode, t1: ts.TypeNode) => tsf.createTypeReferenceNode(tsf.createIdentifier('Result'), [t0, t1]), } as const -emit( - tsf.createImportDeclaration( - [], - tsf.createImportClause( - false, - undefined, - tsf.createNamedImports( - Array.from(Object.entries(supportImports), ([name, isTypeOnly]) => - tsf.createImportSpecifier(isTypeOnly, undefined, tsf.createIdentifier(name)), - ), - ), - ), - tsf.createStringLiteral('@/util/parserSupport', true), - undefined, - ), -) -for (const id in schema.types) { - const ty = schema.types[id] - if (ty.parent == null) { - const discriminants = schema.serialization[id].discriminants - if (discriminants == null) { - emit(makeConcreteType(id, schema)) - } else { - makeAbstractType(id, discriminants, schema) - } - } else { - // Ignore child types; they are generated when `makeAbstractType` processes the parent. - } -} -output += `export function deserializeTree(data: ArrayBuffer): Tree { - const cursor = new Cursor(data, data.byteLength - 4) - return Tree.read(cursor.readPointer()) -}` -fs.writeFileSync(process.argv[3], output) diff --git a/app/gui2/parser-codegen/src/main.ts b/app/gui2/parser-codegen/src/main.ts new file mode 100644 index 000000000000..94ce182ef13d --- /dev/null +++ b/app/gui2/parser-codegen/src/main.ts @@ -0,0 +1,7 @@ +import fs from "fs"; +import * as Schema from '@/schema' +import * as codegen from "@/codegen"; + +const schema: Schema.Schema = JSON.parse(fs.readFileSync(process.argv[2], 'utf8')) +const code = codegen.implement(schema) +fs.writeFileSync(process.argv[3], code) diff --git a/app/gui2/parser-codegen/src/schema.ts b/app/gui2/parser-codegen/src/schema.ts new file mode 100644 index 000000000000..c2d92c91b4d9 --- /dev/null +++ b/app/gui2/parser-codegen/src/schema.ts @@ -0,0 +1,35 @@ +export type Schema = { + types: Types + serialization: Serialization +} +export type TypeId = string +export type Types = { + [id: TypeId]: Type +} +export type Type = { + name: string + fields: Fields + parent?: string +} +export type Fields = { + [name: string]: TypeRef +} +export type TypeRef = Class | Primitive | Sequence | Option | Result +export type Class = { class: 'type'; id: TypeId } +export type Primitive = { class: 'primitive'; type: PrimitiveType } +export type Sequence = { class: 'sequence'; type: TypeRef } +export type Option = { class: 'option'; type: TypeRef } +export type Result = { class: 'result'; type0: TypeRef; type1: TypeRef } +export type PrimitiveType = 'bool' | 'u32' | 'u64' | 'i32' | 'i64' | 'char' | 'string' + +export type Serialization = { + [id: TypeId]: Layout +} +export type Layout = { + discriminants?: DiscriminantMap + fields: [name: string, offset: number][] + size: number +} +export type DiscriminantMap = { + [discriminant: number]: TypeId +} \ No newline at end of file diff --git a/app/gui2/parser-codegen/src/util.ts b/app/gui2/parser-codegen/src/util.ts new file mode 100644 index 000000000000..a9876e1e6cdf --- /dev/null +++ b/app/gui2/parser-codegen/src/util.ts @@ -0,0 +1,31 @@ +import * as changeCase from 'change-case' + +export function toPascal(ident: string): string { + if (ident.includes('.')) throw new Error("toPascal cannot be applied to a namespaced name.") + return changeCase.pascalCase(ident) +} + +export function toCamel(ident: string): string { + if (ident.includes('.')) throw new Error("toCamel cannot be applied to a namespaced name.") + return changeCase.camelCase(ident) +} + +export function legalizeIdent(ident: string): string { + // FIXME: We should accept a renaming table as an input alongside the schema, then emit an error if a keyword is + // encountered ("constructor") or a field name is duplicated ("type"). + switch (ident) { + case 'constructor': + return 'ident' + case 'type': + return 'typeNode' + default: + return ident + } +} +export function namespacedName(name: string, namespace?: string): string { + if (namespace == null) { + return toPascal(name) + } else { + return toPascal(namespace) + '.' + toPascal(name) + } +} diff --git a/app/gui2/parser-codegen/tsconfig.json b/app/gui2/parser-codegen/tsconfig.json index 14eedeedc478..86b8027a0f9d 100644 --- a/app/gui2/parser-codegen/tsconfig.json +++ b/app/gui2/parser-codegen/tsconfig.json @@ -2,6 +2,14 @@ "extends": "@tsconfig/node18/tsconfig.json", "compilerOptions": { "sourceMap": true, - "outDir": "dist" - } + "composite": true, + "module": "ESNext", + "moduleResolution": "Bundler", + "baseUrl": ".", + "outDir": "dist", + "paths": { + "@/*": ["./src/*"] + } + }, + "include": [ "src/**/*" ] } diff --git a/app/gui2/src/util/ffi.ts b/app/gui2/src/util/ffi.ts index 59d40ecfe0a6..deff574d7b8a 100644 --- a/app/gui2/src/util/ffi.ts +++ b/app/gui2/src/util/ffi.ts @@ -584,4 +584,11 @@ if (import.meta.vitest) { ], }) }) + /* + test('TryParseSmthing', () => { + const smthing = 'Data.read file="name"' + const parsed = parseEnso2(smthing) + Array.from(parsed.statements)[0].expression.name.isTypeOrConstructor + }) + */ } diff --git a/app/gui2/tsconfig.app.json b/app/gui2/tsconfig.app.json index e5a7c92433be..16b57384e950 100644 --- a/app/gui2/tsconfig.app.json +++ b/app/gui2/tsconfig.app.json @@ -16,7 +16,6 @@ "composite": true, "outDir": "../../node_modules/.cache/tsc", "baseUrl": ".", - "noEmit": true, "allowImportingTsExtensions": true, "noEmit": true, "noUncheckedIndexedAccess": true, From a6031e1c1f9f7f86002141d1b179e40ae253f35c Mon Sep 17 00:00:00 2001 From: Kaz Wesley Date: Wed, 4 Oct 2023 08:36:05 -0700 Subject: [PATCH 32/44] Lint --- app/gui/language/parser/src/translation.rs | 4 +- lib/rust/parser/schema/src/lib.rs | 87 +++++++++++++++++----- lib/rust/parser/src/lexer.rs | 14 ++-- lib/rust/parser/src/macros/resolver.rs | 6 +- lib/rust/parser/src/main.rs | 32 ++++---- lib/rust/parser/src/source/code.rs | 2 +- 6 files changed, 95 insertions(+), 50 deletions(-) diff --git a/app/gui/language/parser/src/translation.rs b/app/gui/language/parser/src/translation.rs index 0a891640bb4b..78e1eb77d17c 100644 --- a/app/gui/language/parser/src/translation.rs +++ b/app/gui/language/parser/src/translation.rs @@ -81,7 +81,7 @@ impl Translate { let space = span.left_offset.code.repr.len(); self.space_after.insert(self.offset, space); self.offset += space; - span.left_offset.visible.width_in_spaces + usize::try_from(span.left_offset.visible.width_in_spaces).unwrap() } /// This must be called at the beginning of each [`Token`], as they are processed in depth-first @@ -93,7 +93,7 @@ impl Translate { /// This must be called at the beginning of each [`Token`], as they are processed in depth-first /// order. It updates the internal counter for the token's bytes, and returns its contents. fn visit_token_ref(&mut self, token: syntax::token::Ref) -> WithInitialSpace { - let space = token.left_offset.visible.width_in_spaces; + let space = usize::try_from(token.left_offset.visible.width_in_spaces).unwrap(); let body = token.code.to_string(); self.space_after.insert(self.offset, space); self.offset += token.left_offset.code.repr.len(); diff --git a/lib/rust/parser/schema/src/lib.rs b/lib/rust/parser/schema/src/lib.rs index 7e7ca608dd87..f8edb52d1c92 100644 --- a/lib/rust/parser/schema/src/lib.rs +++ b/lib/rust/parser/schema/src/lib.rs @@ -47,67 +47,114 @@ pub fn schema() -> impl serde::Serialize { // === Schema === // ============== -#[derive(serde::Serialize, serde::Deserialize)] +/// Describes a set of types and their serialization. +#[derive(Debug, serde::Serialize, serde::Deserialize)] pub struct Schema { + /// The type definitions. pub types: HashMap, + /// Serialization information for the types. pub serialization: HashMap, } // === Type graph === -#[derive(serde::Serialize, serde::Deserialize)] +/// Describes a type. +#[derive(Debug, serde::Serialize, serde::Deserialize)] #[serde(rename_all = "camelCase")] pub struct Type { + /// The type's name, in snake case. pub name: Rc, + /// The type's fields. pub fields: HashMap, + /// The type's parent, if any. #[serde(skip_serializing_if = "Option::is_none")] pub parent: Option, } -#[derive(serde::Serialize, serde::Deserialize, Clone, Hash, PartialEq, Eq)] +/// Arbitrary key uniquely identifying a type within the schema. +#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, Hash, PartialEq, Eq)] pub struct TypeId(Rc); -#[derive(serde::Serialize, serde::Deserialize, Clone, Hash, PartialEq, Eq)] +/// The name of a field, in snake case. +#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, Hash, PartialEq, Eq)] pub struct FieldName(Rc); -#[derive(serde::Serialize, serde::Deserialize, Clone, Hash, PartialEq, Eq)] +/// A reference to a type, which may be a [`Type`] defined in the schema, a primitive, or a +/// parameterized generic type. +#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, Hash, PartialEq, Eq)] #[serde(rename_all = "lowercase")] #[serde(tag = "class")] pub enum TypeRef { - Type { id: TypeId }, - Primitive { r#type: Primitive }, - Sequence { r#type: Box }, - Option { r#type: Box }, - Result { r#type0: Box, r#type1: Box }, + /// A type defined in the schema. + Type { + /// Identifies the type. + id: TypeId, + }, + /// A [`Primitive`]. + Primitive { + /// A [`Primitive`]. + r#type: Primitive, + }, + /// A sequence of values of a type. + Sequence { + /// The type of the elements of the sequence. + r#type: Box, + }, + /// An optional value of a type. + Option { + /// The type of the value, if present. + r#type: Box, + }, + /// A value that may indicate success or error. + Result { + /// The type of the value, in case of success. + r#type0: Box, + /// The type of the value, in case of error. + r#type1: Box, + }, } -#[derive(serde::Serialize, serde::Deserialize, Copy, Clone, Hash, PartialEq, Eq)] +/// The base types that all [`Type`]s defined in the schema are ultimately composed of. +#[derive(Debug, serde::Serialize, serde::Deserialize, Copy, Clone, Hash, PartialEq, Eq)] #[serde(rename_all = "lowercase")] pub enum Primitive { + /// A boolean value. Bool, + /// A 32-bit unsigned integer. U32, + /// A 64-bit unsigned integer. U64, + /// A 32-bit signed integer. I32, + /// A 64-bit signed integer. I64, + /// A unicode codepoint, in the range 0x0000..=0x10FFFF. Char, + /// A UTF-8 string. String, } // === Serialization === -#[derive(serde::Serialize, serde::Deserialize)] +/// Describes the serialized layout of a type. +#[derive(Debug, serde::Serialize, serde::Deserialize)] #[serde(rename_all = "camelCase")] pub struct Layout { + /// The fields, in order. Names are references to the fields defined in the [`Type`]. pub fields: Vec<(FieldName, usize)>, + /// Values that encode the possible child types of this type. #[serde(skip_serializing_if = "Option::is_none")] pub discriminants: Option>, + /// The number of bytes this type's encoding takes as a field of a containing struct, element + /// of a sequence, or parent of another type. pub size: usize, } -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, Eq, PartialOrd, Ord, Copy)] -pub struct Discriminant(pub u32); +/// Number distinguishing different possible child types. +#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, PartialEq, Eq, PartialOrd, Ord, Copy)] +pub struct Discriminant(u32); @@ -203,9 +250,9 @@ fn types(graph: &meta::TypeGraph) -> Types { // === Serialization === // ===================== -fn serialization<'g>( - graph: &'g meta::TypeGraph, -) -> impl Iterator)> + 'g + '_ { +fn serialization( + graph: &meta::TypeGraph, +) -> impl Iterator)> + '_ { let sizes = solve_sizes(graph); layouts(graph, sizes) } @@ -272,10 +319,10 @@ fn solve_sizes(graph: &meta::TypeGraph) -> HashMap { /// Given the sizes of all types in the graph, compute the field offsets and return the layouts for /// all the types. -fn layouts<'g>( - graph: &'g meta::TypeGraph, +fn layouts( + graph: &meta::TypeGraph, sizes: HashMap, -) -> impl Iterator)> + 'g + '_ { +) -> impl Iterator)> + '_ { graph.types.iter().map(move |(key, ty)| { (key, { let mut offset = ty.parent.map_or(0, |key| sizes[&key]); diff --git a/lib/rust/parser/src/lexer.rs b/lib/rust/parser/src/lexer.rs index 491565fd0520..b132463b1eab 100644 --- a/lib/rust/parser/src/lexer.rs +++ b/lib/rust/parser/src/lexer.rs @@ -1512,7 +1512,7 @@ mod tests { ("foo\n +", vec![ ident_("", "foo"), block_start_(Code::empty(), Code::empty()), - newline.clone(), + newline, operator_(" ", "+"), block_end_(Code::empty(), Code::empty()), ]), @@ -1526,15 +1526,15 @@ mod tests { test_lexer_many(vec![ ("\n foo\n bar\nbaz", vec![ block_start_(Code::empty(), Code::empty()), - newline, ident_(" ", "foo"), - newline, ident_(" ", "bar"), + newline.clone(), ident_(" ", "foo"), + newline.clone(), ident_(" ", "bar"), block_end_(Code::empty(), Code::empty()), - newline, ident_("", "baz"), + newline.clone(), ident_("", "baz"), ]), ("\n foo\n bar\n baz", vec![ block_start_(Code::empty(), Code::empty()), - newline, ident_(" ", "foo"), - newline, ident_(" ", "bar"), + newline.clone(), ident_(" ", "foo"), + newline.clone(), ident_(" ", "bar"), newline, ident_(" ", "baz"), block_end_(Code::empty(), Code::empty()), ]), @@ -1546,7 +1546,7 @@ mod tests { test_lexer_many(vec![("foo\n \nbar", vec![ ident_("", "foo"), newline_(Code::empty(), Code::from_str_without_offset("\n")), - newline_(" ", Code::from_str_without_offset("\n")), + newline_(Code::from_str_without_offset(" "), Code::from_str_without_offset("\n")), ident_("", "bar"), ])]); } diff --git a/lib/rust/parser/src/macros/resolver.rs b/lib/rust/parser/src/macros/resolver.rs index 26d827ae7ec0..1a840c47687f 100644 --- a/lib/rust/parser/src/macros/resolver.rs +++ b/lib/rust/parser/src/macros/resolver.rs @@ -143,8 +143,10 @@ impl<'s> Resolver<'s> { /// Create a new resolver, in statement context. pub fn new_statement() -> Self { let scopes = default(); - let open_blocks = - vec![syntax::item::Line { newline: token::newline(Code::empty(), Code::empty()), items: default() }]; + let open_blocks = vec![syntax::item::Line { + newline: token::newline(Code::empty(), Code::empty()), + items: default(), + }]; let macro_stack = default(); let segments = default(); let items = default(); diff --git a/lib/rust/parser/src/main.rs b/lib/rust/parser/src/main.rs index 42edc729e2d4..aa7fa97bc8ac 100644 --- a/lib/rust/parser/src/main.rs +++ b/lib/rust/parser/src/main.rs @@ -75,25 +75,21 @@ fn check_file(path: &str, mut code: &str, parser: &mut enso_parser::Parser) { }); for (error, span) in &*errors.borrow() { let whitespace = &span.left_offset.code.repr; - if matches!(whitespace, Cow::Borrowed(_)) { - let start = whitespace.as_ptr() as usize + whitespace.len() - code.as_ptr() as usize; - let mut line = 1; - let mut char = 0; - for (i, c) in code.char_indices() { - if i >= start { - break; - } - if c == '\n' { - line += 1; - char = 0; - } else { - char += 1; - } + let start = whitespace.as_ptr() as usize + whitespace.len() - code.as_ptr() as usize; + let mut line = 1; + let mut char = 0; + for (i, c) in code.char_indices() { + if i >= start { + break; } - eprintln!("{path}:{line}:{char}: {}", &error); - } else { - eprintln!("{path}:?:?: {}", &error); - }; + if c == '\n' { + line += 1; + char = 0; + } else { + char += 1; + } + } + eprintln!("{path}:{line}:{char}: {}", &error); } for (parsed, original) in ast.code().lines().zip(code.lines()) { assert_eq!(parsed, original, "Bug: dropped tokens, while parsing: {path}"); diff --git a/lib/rust/parser/src/source/code.rs b/lib/rust/parser/src/source/code.rs index 5c85863adf9a..8feee8562c90 100644 --- a/lib/rust/parser/src/source/code.rs +++ b/lib/rust/parser/src/source/code.rs @@ -103,7 +103,7 @@ impl<'a, 'b> PartialEq<&'b str> for Code<'a> { impl AsRef for Code<'_> { #[inline(always)] fn as_ref(&self) -> &str { - &self.repr.0 + self.repr.0 } } From 42a484bd5a7128d96ef32aad642fc90e0e08b539 Mon Sep 17 00:00:00 2001 From: Kaz Wesley Date: Wed, 4 Oct 2023 11:14:26 -0700 Subject: [PATCH 33/44] Organize. --- app/gui2/parser-codegen/src/codegen.ts | 873 +++++++------------ app/gui2/parser-codegen/src/serialization.ts | 277 ++++++ app/gui2/parser-codegen/src/util.ts | 50 ++ app/gui2/src/util/parserSupport.ts | 1 + 4 files changed, 630 insertions(+), 571 deletions(-) create mode 100644 app/gui2/parser-codegen/src/serialization.ts diff --git a/app/gui2/parser-codegen/src/codegen.ts b/app/gui2/parser-codegen/src/codegen.ts index 3ab519837e94..485b1fc5b485 100644 --- a/app/gui2/parser-codegen/src/codegen.ts +++ b/app/gui2/parser-codegen/src/codegen.ts @@ -1,633 +1,364 @@ import ts from 'typescript' const { factory: tsf } = ts import * as Schema from '@/schema' -import { toPascal, toCamel, legalizeIdent, namespacedName } from '@/util' +import { + toPascal, + toCamel, + legalizeIdent, + namespacedName, + assignmentStatement, + forwardToSuper, + modifiers +} from '@/util' +import { + Type, + support, + supportImports, + seekCursor, + abstractTypeDeserializer, + fieldDeserializer +} from '@/serialization' -type ExpressionTransformer = (expression: ts.Expression) => ts.Expression -function primitiveReader(name: string): ExpressionTransformer { - return (cursor) => - tsf.createCallExpression(tsf.createPropertyAccessExpression(cursor, name), [], []) -} +// === Public API === -/** - * Given the name of a runtime `Cursor` method that deserializes a derived type given a function to deserialize a - * base type, return a codegen-time function that generates a *reader* for a derived type from a *reader* for the base - * type, where a *reader* is a function producing a deserialization expression from an expression that evaluates to a - * `Cursor`. - */ -function readerTransformer( - name: string, -): (readElement: ExpressionTransformer) => ExpressionTransformer { - const innerParameter = tsf.createIdentifier('element') - return (readElement: ExpressionTransformer) => (cursor: ts.Expression) => { - return tsf.createCallExpression( - tsf.createPropertyAccessExpression(cursor, name), - [], - [ - tsf.createArrowFunction( - [], - [], - [ - tsf.createParameterDeclaration( - [], - undefined, - innerParameter, - undefined, - support.Cursor, - undefined, - ), - ], - undefined, - undefined, - readElement(innerParameter), - ), - ], - ) - } -} +export function implement(schema: Schema.Schema): string { + const file = ts.createSourceFile('source.ts', '', ts.ScriptTarget.ESNext, false, ts.ScriptKind.TS) + const printer = ts.createPrinter({newLine: ts.NewLineKind.LineFeed}) + let output = '// *** THIS FILE GENERATED BY `parser-codegen` ***\n' -function readerTransformerTwoTyped( - name: string, -): (readOk: ExpressionTransformer, readErr: ExpressionTransformer) => ExpressionTransformer { - function makeArrow(reader: ExpressionTransformer, data: ts.Identifier) { - return tsf.createArrowFunction( - [], - [], - [tsf.createParameterDeclaration([], undefined, data, undefined, support.Cursor, undefined)], - undefined, - undefined, - reader(data), - ) - } - const okData = tsf.createIdentifier('okData') - const errData = tsf.createIdentifier('errData') - return (readOk: ExpressionTransformer, readErr: ExpressionTransformer) => - (cursor: ts.Expression) => { - return tsf.createCallExpression( - tsf.createPropertyAccessExpression(cursor, name), - [], - [makeArrow(readOk, okData), makeArrow(readErr, errData)], - ) + function emit(data: ts.Node) { + output += printer.printNode(ts.EmitHint.Unspecified, data, file) + output += '\n' } -} -function readerTransformerSized( - name: string, -): (readElement: ExpressionTransformer, size: number) => ExpressionTransformer { - const innerParameter = tsf.createIdentifier('element') - return (readElement: ExpressionTransformer, size: number) => (cursor: ts.Expression) => { - return tsf.createCallExpression( - tsf.createPropertyAccessExpression(cursor, name), - [], - [ - tsf.createArrowFunction( - [], - [], - [ - tsf.createParameterDeclaration( - [], - undefined, - innerParameter, - undefined, - support.Cursor, - undefined, + emit( + tsf.createImportDeclaration( + [], + tsf.createImportClause( + false, + undefined, + tsf.createNamedImports( + Array.from(Object.entries(supportImports), ([name, isTypeOnly]) => + tsf.createImportSpecifier(isTypeOnly, undefined, tsf.createIdentifier(name)), + ), + ), ), - ], - undefined, - undefined, - readElement(innerParameter), + tsf.createStringLiteral('@/util/parserSupport', true), + undefined, ), - tsf.createNumericLiteral(size), - ], - ) - } -} - -function abstractTypeReader(name: string): ExpressionTransformer { - return (cursor: ts.Expression) => - tsf.createCallExpression( - tsf.createPropertyAccessExpression(tsf.createIdentifier(name), 'read'), - [], - [cursorMethods.readPointer(cursor)], ) -} - -function concreteTypeReader(name: string): ExpressionTransformer { - return (cursor: ts.Expression) => - tsf.createCallExpression( - tsf.createPropertyAccessExpression(tsf.createIdentifier(name), 'read'), - [], - [cursor], - ) -} - -class Type { - readonly type: ts.TypeNode - readonly reader: ExpressionTransformer - readonly size: number - - constructor(type: ts.TypeNode, reader: ExpressionTransformer, size: number) { - this.type = type - this.reader = reader - this.size = size - } - - static new(ref: Schema.TypeRef, schema: Schema.Schema): Type { - const c = ref.class - switch (c) { - case 'type': - const ty = schema.types[ref.id] - const parent = ty.parent != null ? schema.types[ty.parent] : undefined - const typeName = namespacedName(ty.name, parent?.name) - const type = tsf.createTypeReferenceNode(typeName) - const layout = schema.serialization[ref.id] - if (layout.discriminants != null) { - return new Type(type, abstractTypeReader(typeName), POINTER_SIZE) + for (const id in schema.types) { + const ty = schema.types[id] + if (ty.parent == null) { + const discriminants = schema.serialization[id].discriminants + if (discriminants == null) { + emit(makeConcreteType(id, schema)) + } else { + const ty = makeAbstractType(id, discriminants, schema) + emit(ty.module) + emit(ty.export) + } } else { - return new Type(type, concreteTypeReader(typeName), layout.size) + // Ignore child types; they are generated when `makeAbstractType` processes the parent. } - case 'primitive': - const p = ref.type - switch (p) { - case 'bool': - return new Type(tsf.createTypeReferenceNode('boolean'), cursorMethods.readBool, 1) - case 'u32': - return new Type(tsf.createTypeReferenceNode('number'), cursorMethods.readU32, 4) - case 'i32': - return new Type(tsf.createTypeReferenceNode('number'), cursorMethods.readI32, 4) - case 'u64': - return new Type(tsf.createTypeReferenceNode('bigint'), cursorMethods.readU64, 8) - case 'i64': - return new Type(tsf.createTypeReferenceNode('bigint'), cursorMethods.readI64, 8) - case 'char': - return new Type(tsf.createTypeReferenceNode('number'), cursorMethods.readU32, 4) - case 'string': - return new Type( - tsf.createTypeReferenceNode('string'), - cursorMethods.readString, - POINTER_SIZE, - ) - default: - const _ = p satisfies never - throw new Error("unreachable: PrimitiveType.type='" + p + "'") - } - case 'sequence': - return Type.sequence(Type.new(ref.type, schema)) - case 'option': - return Type.option(Type.new(ref.type, schema)) - case 'result': - return Type.result(Type.new(ref.type0, schema), Type.new(ref.type1, schema)) - default: - const _ = c satisfies never - throw new Error("unreachable: TypeRef.class='" + c + "' in " + JSON.stringify(ref)) } - } - - static sequence(element: Type): Type { - return new Type( - tsf.createTypeReferenceNode('Iterable', [element.type]), - cursorMethods.readSequence(element.reader, element.size), - POINTER_SIZE, - ) - } + output += `export function deserializeTree(data: ArrayBuffer): Tree { + const cursor = new Cursor(data, data.byteLength - 4) + return Tree.read(cursor.readPointer()) + }` + return output +} - static option(element: Type): Type { - return new Type( - tsf.createUnionTypeNode([element.type, noneType]), - cursorMethods.readOption(element.reader), - POINTER_SIZE + 1, - ) - } - static result(ok: Type, err: Type): Type { - return new Type( - support.Result(ok.type, err.type), - cursorMethods.readResult(ok.reader, err.reader), - POINTER_SIZE, - ) - } -} +// === Implementation === -function seekCursor(cursor: ts.Expression, offset: number): ts.Expression { - if (offset === 0) { - return cursor - } else { - return tsf.createCallExpression( - tsf.createPropertyAccessExpression(cursor, 'seek'), - [], - [tsf.createNumericLiteral(offset)], - ) +function makeType(ref: Schema.TypeRef, schema: Schema.Schema): Type { + const c = ref.class + switch (c) { + case 'type': + const ty = schema.types[ref.id] + const parent = ty.parent != null ? schema.types[ty.parent] : undefined + const typeName = namespacedName(ty.name, parent?.name) + const layout = schema.serialization[ref.id] + if (layout.discriminants != null) { + return Type.Abstract(typeName) + } else { + return Type.Concrete(typeName, layout.size) + } + case 'primitive': + const p = ref.type + switch (p) { + case 'bool': return Type.Boolean + case 'u32': return Type.UInt32 + case 'i32': return Type.Int32 + case 'u64': return Type.UInt64 + case 'i64': return Type.Int64 + case 'char': return Type.Char + case 'string': return Type.String + default: + const _ = p satisfies never + throw new Error("unreachable: PrimitiveType.type='" + p + "'") + } + case 'sequence': + return Type.Sequence(makeType(ref.type, schema)) + case 'option': + return Type.Option(makeType(ref.type, schema)) + case 'result': + return Type.Result(makeType(ref.type0, schema), makeType(ref.type1, schema)) + default: + const _ = c satisfies never + throw new Error("unreachable: TypeRef.class='" + c + "' in " + JSON.stringify(ref)) } } function makeGetter( - fieldName: string, - typeRef: Schema.TypeRef, - offset: number, - schema: Schema.Schema, + fieldName: string, + typeRef: Schema.TypeRef, + offset: number, + schema: Schema.Schema, ): ts.GetAccessorDeclaration { - const type = Type.new(typeRef, schema) - return tsf.createGetAccessorDeclaration( - [], - tsf.createIdentifier(legalizeIdent(toCamel(fieldName))), - [], - type.type, - tsf.createBlock([ - tsf.createReturnStatement( - type.reader( - seekCursor( - tsf.createPropertyAccessExpression(tsf.createThis(), cursorFieldIdent), - offset, - ), - ), - ), - ]), - ) -} - -// Helper for a common case of constructing an assignment. -function createAssignmentStatement(left: ts.Expression, right: ts.Expression): ts.Statement { - return tsf.createExpressionStatement( - tsf.createBinaryExpression(left, ts.SyntaxKind.EqualsToken, right), - ) + return fieldDeserializer(tsf.createIdentifier(legalizeIdent(toCamel(fieldName))), makeType(typeRef, schema), offset) } function makeConcreteType(id: string, schema: Schema.Schema): ts.ClassDeclaration { - const ident = tsf.createIdentifier(toPascal(schema.types[id].name)) - const paramIdent = tsf.createIdentifier('cursor') - const cursorParam = tsf.createParameterDeclaration( - [], - undefined, - paramIdent, - undefined, - support.Cursor, - undefined, - ) - return makeClass( - [modifiers.export], - ident, - [ - forwardToSuper(paramIdent, support.Cursor), - tsf.createMethodDeclaration( - [modifiers.static], + const ident = tsf.createIdentifier(toPascal(schema.types[id].name)) + const paramIdent = tsf.createIdentifier('cursor') + const cursorParam = tsf.createParameterDeclaration( + [], undefined, - 'read', + paramIdent, undefined, - [], - [cursorParam], - tsf.createTypeReferenceNode(ident), - tsf.createBlock([ - tsf.createReturnStatement(tsf.createNewExpression(ident, [], [paramIdent])), - ]), - ), - ], - id, - schema, - ) + support.Cursor, + undefined, + ) + return makeClass( + [modifiers.export], + ident, + [ + forwardToSuper(paramIdent, support.Cursor), + tsf.createMethodDeclaration( + [modifiers.static], + undefined, + 'read', + undefined, + [], + [cursorParam], + tsf.createTypeReferenceNode(ident), + tsf.createBlock([ + tsf.createReturnStatement(tsf.createNewExpression(ident, [], [paramIdent])), + ]), + ), + ], + id, + schema, + ) } function debugValue(ident: ts.Identifier): ts.Expression { - const value = tsf.createPropertyAccessExpression(tsf.createThis(), ident) - return tsf.createCallExpression(support.debugHelper, [], [value]) + const value = tsf.createPropertyAccessExpression(tsf.createThis(), ident) + return tsf.createCallExpression(support.debugHelper, [], [value]) } function makeDebugFunction(fields: string[]): ts.MethodDeclaration { - const getterIdent = (fieldName: string) => tsf.createIdentifier(legalizeIdent(toCamel(fieldName))) - return tsf.createMethodDeclaration( - [], - undefined, - 'debug', - undefined, - [], - [], - tsf.createTypeReferenceNode('any'), - tsf.createBlock([ - tsf.createReturnStatement( - tsf.createCallExpression(support.debugHelper, [], [ - tsf.createObjectLiteralExpression([ - tsf.createSpreadAssignment( - tsf.createCallExpression( - tsf.createPropertyAccessExpression(tsf.createSuper(), 'debug'), - [], - [], - ), - ), - ...fields.map((name: string) => - tsf.createPropertyAssignment(getterIdent(name), debugValue(getterIdent(name))), + const getterIdent = (fieldName: string) => tsf.createIdentifier(legalizeIdent(toCamel(fieldName))) + return tsf.createMethodDeclaration( + [], + undefined, + 'debug', + undefined, + [], + [], + tsf.createTypeReferenceNode('any'), + tsf.createBlock([ + tsf.createReturnStatement( + tsf.createCallExpression(support.debugHelper, [], [ + tsf.createObjectLiteralExpression([ + tsf.createSpreadAssignment( + tsf.createCallExpression( + tsf.createPropertyAccessExpression(tsf.createSuper(), 'debug'), + [], + [], + ), + ), + ...fields.map((name: string) => + tsf.createPropertyAssignment(getterIdent(name), debugValue(getterIdent(name))), + ), + ]) + ]), ), - ]) ]), - ), - ]), - ) + ) } function makeGetters(id: string, schema: Schema.Schema): ts.ClassElement[] { - return schema.serialization[id].fields.map(([name, offset]: [string, number]) => - makeGetter(name, schema.types[id].fields[name], offset, schema)) + return schema.serialization[id].fields.map(([name, offset]: [string, number]) => + makeGetter(name, schema.types[id].fields[name], offset, schema)) } function makeClass( - modifiers: ts.Modifier[], - name: ts.Identifier, - members: ts.ClassElement[], - id: string, - schema: Schema.Schema, + modifiers: ts.Modifier[], + name: ts.Identifier, + members: ts.ClassElement[], + id: string, + schema: Schema.Schema, ): ts.ClassDeclaration { - return tsf.createClassDeclaration( - modifiers, - name, - undefined, - [ - tsf.createHeritageClause(ts.SyntaxKind.ExtendsKeyword, [ - tsf.createExpressionWithTypeArguments(support.LazyObject, []), - ]), - ], - [ - ...members, - ...makeGetters(id, schema), - makeDebugFunction(Object.getOwnPropertyNames(schema.types[id].fields)), - ], - ) + return tsf.createClassDeclaration( + modifiers, + name, + undefined, + [ + tsf.createHeritageClause(ts.SyntaxKind.ExtendsKeyword, [ + tsf.createExpressionWithTypeArguments(support.LazyObject, []), + ]), + ], + [ + ...members, + ...makeGetters(id, schema), + makeDebugFunction(Object.getOwnPropertyNames(schema.types[id].fields)), + ], + ) } type ChildType = { - definition: ts.ClassDeclaration - reference: ts.TypeNode - enumMember: ts.EnumMember - case: ts.CaseClause + definition: ts.ClassDeclaration + reference: ts.TypeNode + enumMember: ts.EnumMember + case: ts.CaseClause } function makeChildType( - base: ts.Identifier, - id: string, - discrim: string, - schema: Schema.Schema, + base: ts.Identifier, + id: string, + discrim: string, + schema: Schema.Schema, ): ChildType { - const ty: Schema.Type = schema.types[id] - const name = toPascal(ty.name) - const ident = tsf.createIdentifier(name) - const cursorIdent = tsf.createIdentifier('cursor') - const cursorParam = tsf.createParameterDeclaration( - [], - undefined, - cursorIdent, - undefined, - support.Cursor, - undefined, - ) - const discrimInt = tsf.createNumericLiteral(parseInt(discrim, 10)) - return { - definition: tsf.createClassDeclaration( - [modifiers.export], - name, - undefined, - [ - tsf.createHeritageClause(ts.SyntaxKind.ExtendsKeyword, [ - tsf.createExpressionWithTypeArguments(base, []), - ]), - ], - [ - tsf.createPropertyDeclaration( - [modifiers.readonly], - 'type', - undefined, - tsf.createTypeReferenceNode('Type.' + name), - undefined, - ), - tsf.createConstructorDeclaration( - [], - [ - tsf.createParameterDeclaration( - [], - undefined, - cursorIdent, - undefined, - support.Cursor, - undefined, - ), - ], - tsf.createBlock([ - tsf.createExpressionStatement( - tsf.createCallExpression(tsf.createIdentifier('super'), [], [cursorIdent]), - ), - createAssignmentStatement( - tsf.createPropertyAccessExpression(tsf.createIdentifier('this'), 'type'), - tsf.createPropertyAccessExpression(tsf.createIdentifier('Type'), name), - ), - ]), - ), - tsf.createMethodDeclaration( - [modifiers.static], - undefined, - 'read', - undefined, - [], - [cursorParam], - tsf.createTypeReferenceNode(ident), - tsf.createBlock([ - tsf.createReturnStatement(tsf.createNewExpression(ident, [], [cursorIdent])), - ]), - ), - ...makeGetters(id, schema), - makeDebugFunction(Object.getOwnPropertyNames(ty.fields)), - ], - ), - reference: tsf.createTypeReferenceNode(name), - enumMember: tsf.createEnumMember(toPascal(schema.types[id].name), discrimInt), - case: tsf.createCaseClause(discrimInt, [ - tsf.createReturnStatement(tsf.createNewExpression(ident, [], [seekCursor(cursorIdent, 4)])), - ]), - } -} - -function forwardToSuper(ident: ts.Identifier, type: ts.TypeNode) { - return tsf.createConstructorDeclaration( - [], - [tsf.createParameterDeclaration([], undefined, ident, undefined, type, undefined)], - tsf.createBlock([ - tsf.createExpressionStatement( - tsf.createCallExpression(tsf.createIdentifier('super'), [], [ident]), - ), - ]), - ) -} - -function casesOrThrow(cases: ts.CaseClause[], error: string): ts.CaseBlock { - return tsf.createCaseBlock([ - ...cases, - tsf.createDefaultClause([ - tsf.createThrowStatement( - tsf.createNewExpression( - tsf.createIdentifier('Error'), - [], - [tsf.createStringLiteral(error)], - ), - ), - ]), - ]) -} - -function abstractTypeDeserializer( - ident: ts.Identifier, - cases: ts.CaseClause[], -): ts.FunctionDeclaration { - const cursorIdent = tsf.createIdentifier('cursor') - return tsf.createFunctionDeclaration( - [modifiers.export], - undefined, - 'read', - [], - [ - tsf.createParameterDeclaration( + const ty: Schema.Type = schema.types[id] + const name = toPascal(ty.name) + const ident = tsf.createIdentifier(name) + const cursorIdent = tsf.createIdentifier('cursor') + const cursorParam = tsf.createParameterDeclaration( [], undefined, cursorIdent, undefined, support.Cursor, undefined, - ), - ], - tsf.createTypeReferenceNode(ident), - tsf.createBlock([ - tsf.createSwitchStatement( - cursorMethods.readU32(cursorIdent), - casesOrThrow(cases, 'Unexpected discriminant while deserializing.'), - ), - ]), - ) + ) + const discrimInt = tsf.createNumericLiteral(parseInt(discrim, 10)) + return { + definition: tsf.createClassDeclaration( + [modifiers.export], + name, + undefined, + [ + tsf.createHeritageClause(ts.SyntaxKind.ExtendsKeyword, [ + tsf.createExpressionWithTypeArguments(base, []), + ]), + ], + [ + tsf.createPropertyDeclaration( + [modifiers.readonly], + 'type', + undefined, + tsf.createTypeReferenceNode('Type.' + name), + undefined, + ), + tsf.createConstructorDeclaration( + [], + [ + tsf.createParameterDeclaration( + [], + undefined, + cursorIdent, + undefined, + support.Cursor, + undefined, + ), + ], + tsf.createBlock([ + tsf.createExpressionStatement( + tsf.createCallExpression(tsf.createIdentifier('super'), [], [cursorIdent]), + ), + assignmentStatement( + tsf.createPropertyAccessExpression(tsf.createIdentifier('this'), 'type'), + tsf.createPropertyAccessExpression(tsf.createIdentifier('Type'), name), + ), + ]), + ), + tsf.createMethodDeclaration( + [modifiers.static], + undefined, + 'read', + undefined, + [], + [cursorParam], + tsf.createTypeReferenceNode(ident), + tsf.createBlock([ + tsf.createReturnStatement(tsf.createNewExpression(ident, [], [cursorIdent])), + ]), + ), + ...makeGetters(id, schema), + makeDebugFunction(Object.getOwnPropertyNames(ty.fields)), + ], + ), + reference: tsf.createTypeReferenceNode(name), + enumMember: tsf.createEnumMember(toPascal(schema.types[id].name), discrimInt), + case: tsf.createCaseClause(discrimInt, [ + tsf.createReturnStatement(tsf.createNewExpression(ident, [], [seekCursor(cursorIdent, 4)])), + ]), + } } -function makeAbstractType(id: string, discriminants: Schema.DiscriminantMap, schema: Schema.Schema, emit: ((node: ts.Node) => void)) { - const ty = schema.types[id] - const name = toPascal(ty.name) - const ident = tsf.createIdentifier(name) - const baseIdent = tsf.createIdentifier('AbstractBase') - const childTypes = Array.from( - Object.entries(discriminants), - ([discrim, id]: [string, string]) => makeChildType(baseIdent, id, discrim, schema), - ) - const cursorIdent = tsf.createIdentifier('cursor') - const moduleDecl = tsf.createModuleDeclaration( - [modifiers.export], - ident, - tsf.createModuleBlock([ - makeClass( - [modifiers.abstract], - baseIdent, - [forwardToSuper(cursorIdent, support.Cursor)], - id, - schema, - ), - tsf.createEnumDeclaration( - [modifiers.export, modifiers.const], - 'Type', - childTypes.map((child) => child.enumMember), - ), - ...childTypes.map((child) => child.definition), - tsf.createTypeAliasDeclaration( - [modifiers.export], - ident, - undefined, - tsf.createUnionTypeNode(childTypes.map((child) => child.reference)), - ), - abstractTypeDeserializer( - ident, - childTypes.map((child) => child.case), - ), - ]), - ) - const abstractTypeExport = tsf.createTypeAliasDeclaration( - [modifiers.export], - ident, - undefined, - tsf.createTypeReferenceNode(name + '.' + name), - ) - emit(moduleDecl) - emit(abstractTypeExport) +type AbstractType = { + module: ts.ModuleDeclaration, + export: ts.TypeAliasDeclaration, } -// ============ -// === Main === -// ============ - -export function implement(schema: Schema.Schema): string { - let output = '// *** THIS FILE GENERATED BY `parser-codegen` ***\n' - function emit(data: ts.Node) { - output += printer.printNode(ts.EmitHint.Unspecified, data, file) - output += '\n' - } - emit( - tsf.createImportDeclaration( - [], - tsf.createImportClause( - false, - undefined, - tsf.createNamedImports( - Array.from(Object.entries(supportImports), ([name, isTypeOnly]) => - tsf.createImportSpecifier(isTypeOnly, undefined, tsf.createIdentifier(name)), - ), - ), - ), - tsf.createStringLiteral('@/util/parserSupport', true), - undefined, - ), - ) - for (const id in schema.types) { +function makeAbstractType(id: string, discriminants: Schema.DiscriminantMap, schema: Schema.Schema): AbstractType { const ty = schema.types[id] - if (ty.parent == null) { - const discriminants = schema.serialization[id].discriminants - if (discriminants == null) { - emit(makeConcreteType(id, schema)) - } else { - makeAbstractType(id, discriminants, schema, emit) - } - } else { - // Ignore child types; they are generated when `makeAbstractType` processes the parent. - } - } - output += `export function deserializeTree(data: ArrayBuffer): Tree { - const cursor = new Cursor(data, data.byteLength - 4) - return Tree.read(cursor.readPointer()) - }` - return output + const name = toPascal(ty.name) + const ident = tsf.createIdentifier(name) + const baseIdent = tsf.createIdentifier('AbstractBase') + const childTypes = Array.from( + Object.entries(discriminants), + ([discrim, id]: [string, string]) => makeChildType(baseIdent, id, discrim, schema), + ) + const cursorIdent = tsf.createIdentifier('cursor') + const moduleDecl = tsf.createModuleDeclaration( + [modifiers.export], + ident, + tsf.createModuleBlock([ + makeClass( + [modifiers.abstract], + baseIdent, + [forwardToSuper(cursorIdent, support.Cursor, [modifiers.protected])], + id, + schema, + ), + tsf.createEnumDeclaration( + [modifiers.export, modifiers.const], + 'Type', + childTypes.map((child) => child.enumMember), + ), + ...childTypes.map((child) => child.definition), + tsf.createTypeAliasDeclaration( + [modifiers.export], + ident, + undefined, + tsf.createUnionTypeNode(childTypes.map((child) => child.reference)), + ), + abstractTypeDeserializer( + ident, + childTypes.map((child) => child.case), + ), + ]), + ) + const abstractTypeExport = tsf.createTypeAliasDeclaration( + [modifiers.export], + ident, + undefined, + tsf.createTypeReferenceNode(name + '.' + name), + ) + return { module: moduleDecl, export: abstractTypeExport } } -const file = ts.createSourceFile('source.ts', '', ts.ScriptTarget.ESNext, false, ts.ScriptKind.TS) -const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed }) -const noneType = tsf.createTypeReferenceNode('undefined') -const cursorFieldIdent = tsf.createIdentifier('lazyObjectData') -const modifiers = { - export: tsf.createModifier(ts.SyntaxKind.ExportKeyword), - const: tsf.createModifier(ts.SyntaxKind.ConstKeyword), - readonly: tsf.createModifier(ts.SyntaxKind.ReadonlyKeyword), - abstract: tsf.createModifier(ts.SyntaxKind.AbstractKeyword), - static: tsf.createModifier(ts.SyntaxKind.StaticKeyword), -} as const -const cursorMethods = { - readString: primitiveReader('readString'), - readBool: primitiveReader('readBool'), - readU32: primitiveReader('readU32'), - readI32: primitiveReader('readI32'), - readU64: primitiveReader('readU64'), - readI64: primitiveReader('readI64'), - readPointer: primitiveReader('readPointer'), - readSequence: readerTransformerSized('readSequence'), - readOption: readerTransformer('readOption'), - readResult: readerTransformerTwoTyped('readResult'), -} as const -const POINTER_SIZE: number = 4 -// Symbols exported by the `parserSupport` module. -const supportImports = { - LazyObject: false, - Cursor: false, - debugHelper: false, - Result: true, -} as const -const support = { - LazyObject: tsf.createIdentifier('LazyObject'), - Cursor: tsf.createTypeReferenceNode(tsf.createIdentifier('Cursor')), - debugHelper: tsf.createIdentifier('debugHelper'), - Result: (t0: ts.TypeNode, t1: ts.TypeNode) => - tsf.createTypeReferenceNode(tsf.createIdentifier('Result'), [t0, t1]), -} as const diff --git a/app/gui2/parser-codegen/src/serialization.ts b/app/gui2/parser-codegen/src/serialization.ts new file mode 100644 index 000000000000..58ea6749f31b --- /dev/null +++ b/app/gui2/parser-codegen/src/serialization.ts @@ -0,0 +1,277 @@ +import ts from "typescript"; + +const {factory: tsf} = ts +import {casesOrThrow, modifiers} from "@/util"; + + +// === Definitions === + +const noneType = tsf.createTypeReferenceNode('undefined') +const cursorFieldIdent = tsf.createIdentifier('lazyObjectData') +const POINTER_SIZE: number = 4 +// Symbols exported by the `parserSupport` module. +export const supportImports = { + LazyObject: false, + Cursor: false, + debugHelper: false, + Result: true, +} as const +export const support = { + LazyObject: tsf.createIdentifier('LazyObject'), + Cursor: tsf.createTypeReferenceNode(tsf.createIdentifier('Cursor')), + debugHelper: tsf.createIdentifier('debugHelper'), + Result: (t0: ts.TypeNode, t1: ts.TypeNode) => + tsf.createTypeReferenceNode(tsf.createIdentifier('Result'), [t0, t1]), +} as const + +const cursorMethods = { + readString: primitiveReader('readString'), + readBool: primitiveReader('readBool'), + readU32: primitiveReader('readU32'), + readI32: primitiveReader('readI32'), + readU64: primitiveReader('readU64'), + readI64: primitiveReader('readI64'), + readPointer: primitiveReader('readPointer'), + readSequence: readerTransformerSized('readSequence'), + readOption: readerTransformer('readOption'), + readResult: readerTransformerTwoTyped('readResult'), +} as const + +type ExpressionTransformer = (expression: ts.Expression) => ts.Expression + + +// === Public API === + +export class Type { + readonly type: ts.TypeNode + readonly reader: ExpressionTransformer + readonly size: number + + private constructor(type: ts.TypeNode, reader: ExpressionTransformer, size: number) { + this.type = type + this.reader = reader + this.size = size + } + + static Abstract(name: string): Type { + return new Type(tsf.createTypeReferenceNode(name), abstractTypeReader(name), POINTER_SIZE) + } + + static Concrete(name: string, size: number): Type { + return new Type(tsf.createTypeReferenceNode(name), concreteTypeReader(name), size) + } + + static Sequence(element: Type): Type { + return new Type( + tsf.createTypeReferenceNode('Iterable', [element.type]), + cursorMethods.readSequence(element.reader, element.size), + POINTER_SIZE, + ) + } + + static Option(element: Type): Type { + return new Type( + tsf.createUnionTypeNode([element.type, noneType]), + cursorMethods.readOption(element.reader), + POINTER_SIZE + 1, + ) + } + + static Result(ok: Type, err: Type): Type { + return new Type( + support.Result(ok.type, err.type), + cursorMethods.readResult(ok.reader, err.reader), + POINTER_SIZE, + ) + } + + static Boolean: Type = new Type(tsf.createTypeReferenceNode('boolean'), cursorMethods.readBool, 1) + static UInt32: Type = new Type(tsf.createTypeReferenceNode('number'), cursorMethods.readU32, 4) + static Int32: Type = new Type(tsf.createTypeReferenceNode('number'), cursorMethods.readI32, 4) + static UInt64: Type = new Type(tsf.createTypeReferenceNode('bigint'), cursorMethods.readU64, 8) + static Int64: Type = new Type(tsf.createTypeReferenceNode('bigint'), cursorMethods.readI64, 8) + static Char: Type = new Type(tsf.createTypeReferenceNode('number'), cursorMethods.readU32, 4) + static String: Type = new Type(tsf.createTypeReferenceNode('string'), cursorMethods.readString, POINTER_SIZE) +} + +export function seekCursor(cursor: ts.Expression, offset: number): ts.Expression { + if (offset === 0) { + return cursor + } else { + return tsf.createCallExpression( + tsf.createPropertyAccessExpression(cursor, 'seek'), + [], + [tsf.createNumericLiteral(offset)], + ) + } +} + +export function abstractTypeDeserializer( + ident: ts.Identifier, + cases: ts.CaseClause[], +): ts.FunctionDeclaration { + const cursorIdent = tsf.createIdentifier('cursor') + return tsf.createFunctionDeclaration( + [modifiers.export], + undefined, + 'read', + [], + [ + tsf.createParameterDeclaration( + [], + undefined, + cursorIdent, + undefined, + support.Cursor, + undefined, + ), + ], + tsf.createTypeReferenceNode(ident), + tsf.createBlock([ + tsf.createSwitchStatement( + cursorMethods.readU32(cursorIdent), + casesOrThrow(cases, 'Unexpected discriminant while deserializing.'), + ), + ]), + ) +} + +export function fieldDeserializer(ident: ts.Identifier, type: Type, offset: number): ts.GetAccessorDeclaration { + return tsf.createGetAccessorDeclaration( + [], + ident, + [], + type.type, + tsf.createBlock([ + tsf.createReturnStatement( + type.reader( + seekCursor( + tsf.createPropertyAccessExpression(tsf.createThis(), cursorFieldIdent), + offset, + ), + ), + ), + ]), + ) +} + + +// === Implementation === + +function primitiveReader(name: string): ExpressionTransformer { + return (cursor) => + tsf.createCallExpression(tsf.createPropertyAccessExpression(cursor, name), [], []) +} + +/** + * Given the name of a runtime `Cursor` method that deserializes a derived type given a function to deserialize a + * base type, return a codegen-time function that generates a *reader* for a derived type from a *reader* for the base + * type, where a *reader* is a function producing a deserialization expression from an expression that evaluates to a + * `Cursor`. + */ +function readerTransformer( + name: string, +): (readElement: ExpressionTransformer) => ExpressionTransformer { + const innerParameter = tsf.createIdentifier('element') + return (readElement: ExpressionTransformer) => (cursor: ts.Expression) => { + return tsf.createCallExpression( + tsf.createPropertyAccessExpression(cursor, name), + [], + [ + tsf.createArrowFunction( + [], + [], + [ + tsf.createParameterDeclaration( + [], + undefined, + innerParameter, + undefined, + support.Cursor, + undefined, + ), + ], + undefined, + undefined, + readElement(innerParameter), + ), + ], + ) + } +} + +function readerTransformerTwoTyped( + name: string, +): (readOk: ExpressionTransformer, readErr: ExpressionTransformer) => ExpressionTransformer { + function makeArrow(reader: ExpressionTransformer, data: ts.Identifier) { + return tsf.createArrowFunction( + [], + [], + [tsf.createParameterDeclaration([], undefined, data, undefined, support.Cursor, undefined)], + undefined, + undefined, + reader(data), + ) + } + + const okData = tsf.createIdentifier('okData') + const errData = tsf.createIdentifier('errData') + return (readOk: ExpressionTransformer, readErr: ExpressionTransformer) => + (cursor: ts.Expression) => { + return tsf.createCallExpression( + tsf.createPropertyAccessExpression(cursor, name), + [], + [makeArrow(readOk, okData), makeArrow(readErr, errData)], + ) + } +} + +function readerTransformerSized( + name: string, +): (readElement: ExpressionTransformer, size: number) => ExpressionTransformer { + const innerParameter = tsf.createIdentifier('element') + return (readElement: ExpressionTransformer, size: number) => (cursor: ts.Expression) => { + return tsf.createCallExpression( + tsf.createPropertyAccessExpression(cursor, name), + [], + [ + tsf.createArrowFunction( + [], + [], + [ + tsf.createParameterDeclaration( + [], + undefined, + innerParameter, + undefined, + support.Cursor, + undefined, + ), + ], + undefined, + undefined, + readElement(innerParameter), + ), + tsf.createNumericLiteral(size), + ], + ) + } +} + +function abstractTypeReader(name: string): ExpressionTransformer { + return (cursor: ts.Expression) => + tsf.createCallExpression( + tsf.createPropertyAccessExpression(tsf.createIdentifier(name), 'read'), + [], + [cursorMethods.readPointer(cursor)], + ) +} + +function concreteTypeReader(name: string): ExpressionTransformer { + return (cursor: ts.Expression) => + tsf.createCallExpression( + tsf.createPropertyAccessExpression(tsf.createIdentifier(name), 'read'), + [], + [cursor], + ) +} diff --git a/app/gui2/parser-codegen/src/util.ts b/app/gui2/parser-codegen/src/util.ts index a9876e1e6cdf..9618a473670b 100644 --- a/app/gui2/parser-codegen/src/util.ts +++ b/app/gui2/parser-codegen/src/util.ts @@ -1,4 +1,9 @@ import * as changeCase from 'change-case' +import ts from "typescript"; +const { factory: tsf } = ts + + +// === Identifier utilities === export function toPascal(ident: string): string { if (ident.includes('.')) throw new Error("toPascal cannot be applied to a namespaced name.") @@ -29,3 +34,48 @@ export function namespacedName(name: string, namespace?: string): string { return toPascal(namespace) + '.' + toPascal(name) } } + + +// === AST utilities === + +export const modifiers = { + export: tsf.createModifier(ts.SyntaxKind.ExportKeyword), + const: tsf.createModifier(ts.SyntaxKind.ConstKeyword), + readonly: tsf.createModifier(ts.SyntaxKind.ReadonlyKeyword), + abstract: tsf.createModifier(ts.SyntaxKind.AbstractKeyword), + static: tsf.createModifier(ts.SyntaxKind.StaticKeyword), + protected: tsf.createModifier(ts.SyntaxKind.ProtectedKeyword), +} as const + +export function assignmentStatement(left: ts.Expression, right: ts.Expression): ts.Statement { + return tsf.createExpressionStatement( + tsf.createBinaryExpression(left, ts.SyntaxKind.EqualsToken, right), + ) +} + +export function forwardToSuper(ident: ts.Identifier, type: ts.TypeNode, modifiers?: ts.ModifierLike[]) { + return tsf.createConstructorDeclaration( + modifiers, + [tsf.createParameterDeclaration([], undefined, ident, undefined, type, undefined)], + tsf.createBlock([ + tsf.createExpressionStatement( + tsf.createCallExpression(tsf.createIdentifier('super'), [], [ident]), + ), + ]), + ) +} + +export function casesOrThrow(cases: ts.CaseClause[], error: string): ts.CaseBlock { + return tsf.createCaseBlock([ + ...cases, + tsf.createDefaultClause([ + tsf.createThrowStatement( + tsf.createNewExpression( + tsf.createIdentifier('Error'), + [], + [tsf.createStringLiteral(error)], + ), + ), + ]), + ]) +} diff --git a/app/gui2/src/util/parserSupport.ts b/app/gui2/src/util/parserSupport.ts index ccce9b80d7dd..7b6ea6f75f89 100644 --- a/app/gui2/src/util/parserSupport.ts +++ b/app/gui2/src/util/parserSupport.ts @@ -1,5 +1,6 @@ /** This file supports the module in `../generated/ast.ts` that is produced by `parser-codegen`. */ +export { type Result } from '@/util/result' import { Err, Ok, type Result } from '@/util/result' /** Base class for objects that lazily deserialize fields when accessed. */ From a2f9af877857c2779894c86079fdc3e05cd32f01 Mon Sep 17 00:00:00 2001 From: Kaz Wesley Date: Wed, 4 Oct 2023 12:09:42 -0700 Subject: [PATCH 34/44] Docs. --- app/gui2/parser-codegen/src/codegen.ts | 9 +++++++++ app/gui2/parser-codegen/src/serialization.ts | 10 ++++++++++ lib/rust/parser/schema/src/main.rs | 2 +- lib/rust/parser/src/format.rs | 11 +++++++++-- 4 files changed, 29 insertions(+), 3 deletions(-) diff --git a/app/gui2/parser-codegen/src/codegen.ts b/app/gui2/parser-codegen/src/codegen.ts index 485b1fc5b485..3590497f4226 100644 --- a/app/gui2/parser-codegen/src/codegen.ts +++ b/app/gui2/parser-codegen/src/codegen.ts @@ -1,3 +1,12 @@ +/** + * Generates TypeScript bindings from a schema describing types and their serialization. + * + * Internally, the generated types deserialize their data on demand. This benefits performance: If we eagerly + * deserialized a serialized tree to a tree of objects in memory, creating the tree would produce many heap-allocated + * objects, and visiting the tree would require dereferencing chains of heap pointers. Deserializing while traversing + * allows the optimizer to stack-allocate the temporary objects, saving time and reducing GC pressure. + */ + import ts from 'typescript' const { factory: tsf } = ts import * as Schema from '@/schema' diff --git a/app/gui2/parser-codegen/src/serialization.ts b/app/gui2/parser-codegen/src/serialization.ts index 58ea6749f31b..e41ad2012699 100644 --- a/app/gui2/parser-codegen/src/serialization.ts +++ b/app/gui2/parser-codegen/src/serialization.ts @@ -158,6 +158,8 @@ export function fieldDeserializer(ident: ts.Identifier, type: Type, offset: numb // === Implementation === +/** Returns a function that, given an expression evaluating to a [`Cursor`], returns an expression applying a + * deserialization method with the given name to the cursor. */ function primitiveReader(name: string): ExpressionTransformer { return (cursor) => tsf.createCallExpression(tsf.createPropertyAccessExpression(cursor, name), [], []) @@ -168,6 +170,10 @@ function primitiveReader(name: string): ExpressionTransformer { * base type, return a codegen-time function that generates a *reader* for a derived type from a *reader* for the base * type, where a *reader* is a function producing a deserialization expression from an expression that evaluates to a * `Cursor`. + * + * For example, if we have a reader produced by `primitiveReader('readU32')`, we can use it to create an expression + * representing the deserialization of a number from an expression that will evaluate to a location in the input. If we + * create a `readerTransformer('readOption')`, we can apply it to the number reader to yield an optional-number reader. */ function readerTransformer( name: string, @@ -200,6 +206,8 @@ function readerTransformer( } } +/** Similar to [`readerTransformer`], but for deserialization-transformers that produce a reader by combining two input + * readers. */ function readerTransformerTwoTyped( name: string, ): (readOk: ExpressionTransformer, readErr: ExpressionTransformer) => ExpressionTransformer { @@ -226,6 +234,8 @@ function readerTransformerTwoTyped( } } +/** Similar to [`readerTransformer`], but for deserialization-transformers are parameterized by the size of their + * element. */ function readerTransformerSized( name: string, ): (readElement: ExpressionTransformer, size: number) => ExpressionTransformer { diff --git a/lib/rust/parser/schema/src/main.rs b/lib/rust/parser/schema/src/main.rs index 7870e06a47c4..f7d76ec050c4 100644 --- a/lib/rust/parser/schema/src/main.rs +++ b/lib/rust/parser/schema/src/main.rs @@ -1,5 +1,5 @@ //! Generate a schema representing `enso-parser`'s AST types. This schema can be used to generate -//! AST representations and (de)serialization. +//! AST representations and deserialization in other languages, such as TypeScript. //! //! The JSON schema data will be emitted to standard output. diff --git a/lib/rust/parser/src/format.rs b/lib/rust/parser/src/format.rs index fd0c8fd6168e..c3e633aadaef 100644 --- a/lib/rust/parser/src/format.rs +++ b/lib/rust/parser/src/format.rs @@ -1,7 +1,14 @@ +//! Serializer for a binary format compatible with a lazy deserialization strategy. +//! //! # Design //! -//! The format produced by this module is not actually "serial", as such there is a bit of an -//! impedance mismatch using the `Serializer` trait: `serde` presents each field to the +//! In order to support lazy deserialization, fields of each object are located at fixed offsets +//! from the object; variable-sized objects (sequences, optional values, and discriminated unions) +//! are stored out of band, with a reference in the owning object identifying the location of the +//! data. +//! +//! Consequently, the format produced by this module is not actually "serial". This results in a bit +//! of an impedance mismatch using the `Serializer` trait: `serde` presents each field to the //! serializer once, but we ultimately need to write to two different places in the output for //! each "boxed" field (the data, and the reference to it). //! From 95a4059fad1c4dfd4cd087bed03356e7b04c2a97 Mon Sep 17 00:00:00 2001 From: Kaz Wesley Date: Thu, 5 Oct 2023 07:06:30 -0700 Subject: [PATCH 35/44] Span testing. --- app/gui2/parser-codegen/package-lock.json | 9 ++ app/gui2/parser-codegen/package.json | 6 +- app/gui2/parser-codegen/src/codegen.ts | 101 ++++++++----- app/gui2/parser-codegen/src/main.ts | 4 +- app/gui2/parser-codegen/src/serialization.ts | 63 ++++++-- app/gui2/parser-codegen/src/util.ts | 26 ++-- app/gui2/parser-codegen/tsconfig.json | 9 +- app/gui2/src/util/ffi.ts | 57 +++++--- app/gui2/src/util/parserSupport.ts | 145 +++++++++++++++---- lib/rust/parser/src/lexer.rs | 5 +- lib/rust/parser/src/source/code.rs | 7 +- 11 files changed, 308 insertions(+), 124 deletions(-) diff --git a/app/gui2/parser-codegen/package-lock.json b/app/gui2/parser-codegen/package-lock.json index 9b769df9499e..4933cdeeadf4 100644 --- a/app/gui2/parser-codegen/package-lock.json +++ b/app/gui2/parser-codegen/package-lock.json @@ -11,8 +11,17 @@ "dependencies": { "change-case": "^5.0.2", "typescript": "^5.2.2" + }, + "devDependencies": { + "@types/node": "^20.8.2" } }, + "node_modules/@types/node": { + "version": "20.8.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.2.tgz", + "integrity": "sha512-Vvycsc9FQdwhxE3y3DzeIxuEJbWGDsnrxvMADzTDF/lcdR9/K+AQIeAghTQsHtotg/q0j3WEOYS/jQgSdWue3w==", + "dev": true + }, "node_modules/change-case": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/change-case/-/change-case-5.0.2.tgz", diff --git a/app/gui2/parser-codegen/package.json b/app/gui2/parser-codegen/package.json index 6c8fc2a6757d..df6d7aae87c9 100644 --- a/app/gui2/parser-codegen/package.json +++ b/app/gui2/parser-codegen/package.json @@ -7,15 +7,17 @@ "name": "Enso Team", "email": "contact@enso.org" }, - "main": "dist/codegen.js", "scripts": { "generate-ast-schema": "cargo run -p enso-parser-schema --bin enso-parser-schema > generated/ast-schema.json", "preinstall": "npm run generate-ast-schema", - "generate-bindings": "tsc --build && node dist/codegen.js generated/ast-schema.json" + "generate-bindings": "tsc --build && node dist/main.js generated/ast-schema.json" }, "keywords": [], "dependencies": { "change-case": "^5.0.2", "typescript": "^5.2.2" + }, + "devDependencies": { + "@types/node": "^20.8.2" } } diff --git a/app/gui2/parser-codegen/src/codegen.ts b/app/gui2/parser-codegen/src/codegen.ts index 3590497f4226..5ac226023630 100644 --- a/app/gui2/parser-codegen/src/codegen.ts +++ b/app/gui2/parser-codegen/src/codegen.ts @@ -9,24 +9,25 @@ import ts from 'typescript' const { factory: tsf } = ts -import * as Schema from '@/schema' +import * as Schema from './schema.js' import { toPascal, toCamel, - legalizeIdent, + mapIdent, namespacedName, assignmentStatement, forwardToSuper, modifiers -} from '@/util' +} from './util.js' import { Type, support, supportImports, seekCursor, abstractTypeDeserializer, - fieldDeserializer -} from '@/serialization' + fieldDeserializer, + fieldDynValue +} from './serialization.js' // === Public API === @@ -121,13 +122,27 @@ function makeType(ref: Schema.TypeRef, schema: Schema.Schema): Type { } } -function makeGetter( - fieldName: string, +type Field = { + name: string, + type: Type, + offset: number, +} + +function makeField( + name: string, typeRef: Schema.TypeRef, offset: number, schema: Schema.Schema, -): ts.GetAccessorDeclaration { - return fieldDeserializer(tsf.createIdentifier(legalizeIdent(toCamel(fieldName))), makeType(typeRef, schema), offset) +): Field { + return { + name: mapIdent(toCamel(name)), + type: makeType(typeRef, schema), + offset: offset, + } +} + +function makeGetter(field: Field): ts.GetAccessorDeclaration { + return fieldDeserializer(tsf.createIdentifier(field.name), field.type, field.offset) } function makeConcreteType(id: string, schema: Schema.Schema): ts.ClassDeclaration { @@ -164,45 +179,57 @@ function makeConcreteType(id: string, schema: Schema.Schema): ts.ClassDeclaratio ) } -function debugValue(ident: ts.Identifier): ts.Expression { - const value = tsf.createPropertyAccessExpression(tsf.createThis(), ident) - return tsf.createCallExpression(support.debugHelper, [], [value]) -} - -function makeDebugFunction(fields: string[]): ts.MethodDeclaration { - const getterIdent = (fieldName: string) => tsf.createIdentifier(legalizeIdent(toCamel(fieldName))) +function makeDebugFunction(fields: Field[], typeName?: string): ts.MethodDeclaration { + const ident = tsf.createIdentifier('fields') + const fieldAssignments = fields.map(field => + tsf.createArrayLiteralExpression([ + tsf.createStringLiteral(field.name), + fieldDynValue(field.type, field.offset) + ]) + ) + if (typeName != null) { + fieldAssignments.push( + tsf.createArrayLiteralExpression([ + tsf.createStringLiteral('type'), + tsf.createObjectLiteralExpression([ + tsf.createPropertyAssignment('type', tsf.createStringLiteral('primitive')), + tsf.createPropertyAssignment('value', tsf.createStringLiteral(typeName)), + ]) + ]) + ) + } return tsf.createMethodDeclaration( [], undefined, - 'debug', + ident, undefined, [], [], - tsf.createTypeReferenceNode('any'), + tsf.createTypeReferenceNode(`[string, ${support.DynValue}][]`), tsf.createBlock([ tsf.createReturnStatement( - tsf.createCallExpression(support.debugHelper, [], [ - tsf.createObjectLiteralExpression([ - tsf.createSpreadAssignment( - tsf.createCallExpression( - tsf.createPropertyAccessExpression(tsf.createSuper(), 'debug'), - [], - [], - ), - ), - ...fields.map((name: string) => - tsf.createPropertyAssignment(getterIdent(name), debugValue(getterIdent(name))), - ), - ]) - ]), + tsf.createArrayLiteralExpression([ + tsf.createSpreadElement( + tsf.createCallExpression( + tsf.createPropertyAccessExpression(tsf.createSuper(), ident), + undefined, + undefined, + ) + ), + ...fieldAssignments + ]) ), ]), ) } -function makeGetters(id: string, schema: Schema.Schema): ts.ClassElement[] { - return schema.serialization[id].fields.map(([name, offset]: [string, number]) => - makeGetter(name, schema.types[id].fields[name], offset, schema)) +function makeGetters(id: string, schema: Schema.Schema, typeName?: string): ts.ClassElement[] { + const fields = schema.serialization[id].fields.map(([name, offset]: [string, number]) => + makeField(name, schema.types[id].fields[name], offset, schema)) + return [ + ...fields.map(makeGetter), + makeDebugFunction(fields, typeName), + ] } function makeClass( @@ -224,7 +251,6 @@ function makeClass( [ ...members, ...makeGetters(id, schema), - makeDebugFunction(Object.getOwnPropertyNames(schema.types[id].fields)), ], ) } @@ -307,8 +333,7 @@ function makeChildType( tsf.createReturnStatement(tsf.createNewExpression(ident, [], [cursorIdent])), ]), ), - ...makeGetters(id, schema), - makeDebugFunction(Object.getOwnPropertyNames(ty.fields)), + ...makeGetters(id, schema, name), ], ), reference: tsf.createTypeReferenceNode(name), diff --git a/app/gui2/parser-codegen/src/main.ts b/app/gui2/parser-codegen/src/main.ts index 94ce182ef13d..f5d2af9cad3b 100644 --- a/app/gui2/parser-codegen/src/main.ts +++ b/app/gui2/parser-codegen/src/main.ts @@ -1,6 +1,6 @@ import fs from "fs"; -import * as Schema from '@/schema' -import * as codegen from "@/codegen"; +import * as Schema from './schema.js' +import * as codegen from "./codegen.js"; const schema: Schema.Schema = JSON.parse(fs.readFileSync(process.argv[2], 'utf8')) const code = codegen.implement(schema) diff --git a/app/gui2/parser-codegen/src/serialization.ts b/app/gui2/parser-codegen/src/serialization.ts index e41ad2012699..15aa46183bd2 100644 --- a/app/gui2/parser-codegen/src/serialization.ts +++ b/app/gui2/parser-codegen/src/serialization.ts @@ -1,7 +1,9 @@ +/** Generates code lazily deserializing from an application-specific binary format. */ + import ts from "typescript"; const {factory: tsf} = ts -import {casesOrThrow, modifiers} from "@/util"; +import {casesOrThrow, modifiers} from "./util.js"; // === Definitions === @@ -13,15 +15,17 @@ const POINTER_SIZE: number = 4 export const supportImports = { LazyObject: false, Cursor: false, - debugHelper: false, Result: true, + DynValue: true, + Dyn: false, } as const export const support = { LazyObject: tsf.createIdentifier('LazyObject'), Cursor: tsf.createTypeReferenceNode(tsf.createIdentifier('Cursor')), - debugHelper: tsf.createIdentifier('debugHelper'), Result: (t0: ts.TypeNode, t1: ts.TypeNode) => tsf.createTypeReferenceNode(tsf.createIdentifier('Result'), [t0, t1]), + DynValue: 'DynValue', + Dyn: tsf.createIdentifier('Dyn'), } as const const cursorMethods = { @@ -36,6 +40,13 @@ const cursorMethods = { readOption: readerTransformer('readOption'), readResult: readerTransformerTwoTyped('readResult'), } as const +const dynBuilders = { + Primitive: dynReader('Primitive'), + Result: dynReader('Result'), + Sequence: dynReader('Sequence'), + Option: dynReader('Option'), + Object: dynReader('Object'), +} as const type ExpressionTransformer = (expression: ts.Expression) => ts.Expression @@ -45,26 +56,31 @@ type ExpressionTransformer = (expression: ts.Expression) => ts.Expression export class Type { readonly type: ts.TypeNode readonly reader: ExpressionTransformer + readonly dynReader: ExpressionTransformer readonly size: number - private constructor(type: ts.TypeNode, reader: ExpressionTransformer, size: number) { + private constructor(type: ts.TypeNode, reader: ExpressionTransformer, dynReader: ExpressionTransformer, size: number) { this.type = type this.reader = reader + this.dynReader = dynReader this.size = size } static Abstract(name: string): Type { - return new Type(tsf.createTypeReferenceNode(name), abstractTypeReader(name), POINTER_SIZE) + const valueReader = abstractTypeReader(name) + return new Type(tsf.createTypeReferenceNode(name), valueReader, dynBuilders.Object(valueReader), POINTER_SIZE) } static Concrete(name: string, size: number): Type { - return new Type(tsf.createTypeReferenceNode(name), concreteTypeReader(name), size) + const valueReader = concreteTypeReader(name) + return new Type(tsf.createTypeReferenceNode(name), valueReader, dynBuilders.Object(valueReader), size) } static Sequence(element: Type): Type { return new Type( tsf.createTypeReferenceNode('Iterable', [element.type]), cursorMethods.readSequence(element.reader, element.size), + dynBuilders.Sequence(cursorMethods.readSequence(element.dynReader, element.size)), POINTER_SIZE, ) } @@ -73,6 +89,7 @@ export class Type { return new Type( tsf.createUnionTypeNode([element.type, noneType]), cursorMethods.readOption(element.reader), + dynBuilders.Option(cursorMethods.readOption(element.dynReader)), POINTER_SIZE + 1, ) } @@ -81,17 +98,18 @@ export class Type { return new Type( support.Result(ok.type, err.type), cursorMethods.readResult(ok.reader, err.reader), + dynBuilders.Result(cursorMethods.readResult(ok.dynReader, err.dynReader)), POINTER_SIZE, ) } - static Boolean: Type = new Type(tsf.createTypeReferenceNode('boolean'), cursorMethods.readBool, 1) - static UInt32: Type = new Type(tsf.createTypeReferenceNode('number'), cursorMethods.readU32, 4) - static Int32: Type = new Type(tsf.createTypeReferenceNode('number'), cursorMethods.readI32, 4) - static UInt64: Type = new Type(tsf.createTypeReferenceNode('bigint'), cursorMethods.readU64, 8) - static Int64: Type = new Type(tsf.createTypeReferenceNode('bigint'), cursorMethods.readI64, 8) - static Char: Type = new Type(tsf.createTypeReferenceNode('number'), cursorMethods.readU32, 4) - static String: Type = new Type(tsf.createTypeReferenceNode('string'), cursorMethods.readString, POINTER_SIZE) + static Boolean: Type = new Type(tsf.createTypeReferenceNode('boolean'), cursorMethods.readBool, dynBuilders.Primitive(cursorMethods.readBool), 1) + static UInt32: Type = new Type(tsf.createTypeReferenceNode('number'), cursorMethods.readU32, dynBuilders.Primitive(cursorMethods.readU32), 4) + static Int32: Type = new Type(tsf.createTypeReferenceNode('number'), cursorMethods.readI32, dynBuilders.Primitive(cursorMethods.readI32), 4) + static UInt64: Type = new Type(tsf.createTypeReferenceNode('bigint'), cursorMethods.readU64, dynBuilders.Primitive(cursorMethods.readU64), 8) + static Int64: Type = new Type(tsf.createTypeReferenceNode('bigint'), cursorMethods.readI64, dynBuilders.Primitive(cursorMethods.readI64), 8) + static Char: Type = new Type(tsf.createTypeReferenceNode('number'), cursorMethods.readU32, dynBuilders.Primitive(cursorMethods.readU32), 4) + static String: Type = new Type(tsf.createTypeReferenceNode('string'), cursorMethods.readString, dynBuilders.Primitive(cursorMethods.readString), POINTER_SIZE) } export function seekCursor(cursor: ts.Expression, offset: number): ts.Expression { @@ -155,6 +173,15 @@ export function fieldDeserializer(ident: ts.Identifier, type: Type, offset: numb ) } +export function fieldDynValue(type: Type, offset: number): ts.Expression { + return type.dynReader( + seekCursor( + tsf.createPropertyAccessExpression(tsf.createThis(), cursorFieldIdent), + offset, + ), + ) +} + // === Implementation === @@ -268,6 +295,16 @@ function readerTransformerSized( } } +function dynReader(name: string): (readValue: ExpressionTransformer) => ExpressionTransformer { + return (readValue: ExpressionTransformer) => (cursor: ts.Expression) => { + return tsf.createCallExpression( + tsf.createPropertyAccessExpression(support.Dyn, name), + [], + [readValue(cursor)] + ) + } +} + function abstractTypeReader(name: string): ExpressionTransformer { return (cursor: ts.Expression) => tsf.createCallExpression( diff --git a/app/gui2/parser-codegen/src/util.ts b/app/gui2/parser-codegen/src/util.ts index 9618a473670b..3576278d095b 100644 --- a/app/gui2/parser-codegen/src/util.ts +++ b/app/gui2/parser-codegen/src/util.ts @@ -15,18 +15,22 @@ export function toCamel(ident: string): string { return changeCase.camelCase(ident) } -export function legalizeIdent(ident: string): string { - // FIXME: We should accept a renaming table as an input alongside the schema, then emit an error if a keyword is - // encountered ("constructor") or a field name is duplicated ("type"). - switch (ident) { - case 'constructor': - return 'ident' - case 'type': - return 'typeNode' - default: - return ident - } +const RENAME = new Map([ + ['constructor', 'ident'], + ['type', 'typeNode'], + ['spanLeftOffsetCodeOffsetUtf16', 'whitespaceStart'], + ['spanLeftOffsetCodeUtf16', 'whitespaceLength'], + ['leftOffsetCodeOffsetUtf16', 'whitespaceStart'], + ['leftOffsetCodeUtf16', 'whitespaceLength'], + ['spanCodeLengthUtf16', 'childrenCodeLength'], + ['codeUtf16', 'codeLength'], + ['codeOffsetUtf16', 'codeStart'], +]) + +export function mapIdent(ident: string): string { + return RENAME.get(ident) ?? ident } + export function namespacedName(name: string, namespace?: string): string { if (namespace == null) { return toPascal(name) diff --git a/app/gui2/parser-codegen/tsconfig.json b/app/gui2/parser-codegen/tsconfig.json index 86b8027a0f9d..5fb0258ccea2 100644 --- a/app/gui2/parser-codegen/tsconfig.json +++ b/app/gui2/parser-codegen/tsconfig.json @@ -2,14 +2,11 @@ "extends": "@tsconfig/node18/tsconfig.json", "compilerOptions": { "sourceMap": true, - "composite": true, - "module": "ESNext", - "moduleResolution": "Bundler", + "module": "NodeNext", + "moduleResolution": "NodeNext", "baseUrl": ".", "outDir": "dist", - "paths": { - "@/*": ["./src/*"] - } + "types": ["node"] }, "include": [ "src/**/*" ] } diff --git a/app/gui2/src/util/ffi.ts b/app/gui2/src/util/ffi.ts index deff574d7b8a..400eb3c69073 100644 --- a/app/gui2/src/util/ffi.ts +++ b/app/gui2/src/util/ffi.ts @@ -1,5 +1,6 @@ import type { NonEmptyArray } from '@/util/array' import type { Opt } from '@/util/opt' +import {debug, validateSpans} from '@/util/parserSupport' import init, { parse, parse_doc_to_json, parse_to_json } from '../../rust-ffi/pkg/rust_ffi' import * as Ast2 from '../generated/ast' @@ -538,50 +539,54 @@ if (import.meta.vitest) { test('testParse', () => { const identInput = ' foo bar\n' const tree = parseEnso2(identInput) - expect(tree.debug()).toMatchObject({ - spanCodeLengthUtf16: 8, - spanLeftOffsetCodeOffsetUtf16: 0, - spanLeftOffsetCodeUtf16: 1, + expect(debug(tree)).toMatchObject({ + childrenCodeLength: 8, + whitespaceStart: 0, + whitespaceLength: 1, statements: [ { expression: { arg: { - spanCodeLengthUtf16: 3, - spanLeftOffsetCodeOffsetUtf16: 4, - spanLeftOffsetCodeUtf16: 1, + childrenCodeLength: 3, + whitespaceStart: 4, + whitespaceLength: 1, token: { - codeOffsetUtf16: 5, - codeUtf16: 3, - leftOffsetCodeUtf16: 0, + codeStart: 5, + codeLength: 3, + whitespaceLength: 0, }, + type: 'Ident', }, func: { - spanCodeLengthUtf16: 3, - spanLeftOffsetCodeOffsetUtf16: 0, - spanLeftOffsetCodeUtf16: 0, + childrenCodeLength: 3, + whitespaceStart: 0, + whitespaceLength: 0, token: { - codeOffsetUtf16: 1, - codeUtf16: 3, - leftOffsetCodeUtf16: 0, + codeStart: 1, + codeLength: 3, + whitespaceLength: 0, }, + type: 'Ident', }, - spanCodeLengthUtf16: 7, - spanLeftOffsetCodeUtf16: 0, + childrenCodeLength: 7, + whitespaceLength: 0, + type: 'App', }, newline: { - codeUtf16: 0, - leftOffsetCodeUtf16: 0, + codeLength: 0, + whitespaceLength: 0, }, }, { expression: undefined, newline: { - codeOffsetUtf16: 8, - codeUtf16: 1, - leftOffsetCodeUtf16: 0, + codeStart: 8, + codeLength: 1, + whitespaceLength: 0, }, } ], + type: 'BodyBlock', }) }) /* @@ -591,4 +596,10 @@ if (import.meta.vitest) { Array.from(parsed.statements)[0].expression.name.isTypeOrConstructor }) */ + test('testSpans', () => { + const identInput = ' foo bar\n' + const tree = parseEnso2(identInput) + const endPos = validateSpans(tree) + expect(endPos).toStrictEqual(identInput.length) + }) } diff --git a/app/gui2/src/util/parserSupport.ts b/app/gui2/src/util/parserSupport.ts index 7b6ea6f75f89..0c03c40c7d00 100644 --- a/app/gui2/src/util/parserSupport.ts +++ b/app/gui2/src/util/parserSupport.ts @@ -1,7 +1,36 @@ /** This file supports the module in `../generated/ast.ts` that is produced by `parser-codegen`. */ export { type Result } from '@/util/result' -import { Err, Ok, type Result } from '@/util/result' +import {Err, Error, Ok, type Result} from '@/util/result' + +export type Primitive = { + type: 'primitive', + value: boolean | number | bigint | string +} +export type DynValue = Primitive | DynSequence | DynResult | DynOption | DynObject +export type DynResult = { + type: 'result', + value: Result, +} +export type DynSequence = { + type: 'sequence', + value: Iterable, +} +export type DynOption = { + type: 'option', + value: DynValue | undefined, +} +export type DynObject = { + type: 'object', + getFields: () => [string, DynValue][], +} +export const Dyn = { + Primitive: (value: boolean | number | bigint | string): DynValue => ({ type: 'primitive', value: value }), + Result: (value: Result): DynValue => ({ type: 'result', value: value }), + Sequence: (value: Iterable): DynValue => ({ type: 'sequence', value: value }), + Option: (value: DynValue | undefined): DynValue => ({ type: 'option', value: value }), + Object: (value: LazyObject): DynValue => ({ type: 'object', getFields: value.fields.bind(value) }), +} as const /** Base class for objects that lazily deserialize fields when accessed. */ export abstract class LazyObject { @@ -11,8 +40,8 @@ export abstract class LazyObject { this.lazyObjectData = data } - debug(): {} { - return {} + fields(): [string, DynValue][] { + return [] } } @@ -121,27 +150,91 @@ export class Cursor { } } -export function debugHelper(value: any | undefined): any | undefined { - if (typeof value === 'object') { - if ('debug' in value && typeof value['debug'] === 'function') { - return value.debug() - } - if (Symbol.iterator in value && typeof value[Symbol.iterator] === 'function') { - return Array.from(value, debugHelper) - } - // FIXME: Include the `hide` reflect property in the schema, and apply it during code generation to avoid magic - // strings here. - const hide = [ - 'codeReprBegin', - 'codeReprLen', - 'leftOffsetCodeReprBegin', - 'leftOffsetCodeReprLen', - 'leftOffsetVisible', - 'spanLeftOffsetCodeReprBegin', - 'spanLeftOffsetCodeReprLen', - 'spanLeftOffsetVisible', - ] - return Object.fromEntries(Object.entries(value).filter(([key, _val]) => !hide.includes(key))) - } - return value +export function debug(obj: LazyObject): any { + return debug_(Dyn.Object(obj)) +} + +function debug_(value: DynValue): any { + switch (value.type) { + case 'sequence': + return Array.from(value.value, debug_) + case 'result': + if (value.value.ok) + return Ok(debug_(value.value.value)) + else + return Err(debug_(value.value.error.payload)) + case 'option': + if (value.value != null) + return debug_(value.value) + else + return undefined + case 'object': + // FIXME: Include the `hide` reflect property in the schema, and apply it during code generation to avoid magic + // strings here. + const hide = [ + 'codeReprBegin', + 'codeReprLen', + 'leftOffsetCodeReprBegin', + 'leftOffsetCodeReprLen', + 'leftOffsetVisible', + 'spanLeftOffsetCodeReprBegin', + 'spanLeftOffsetCodeReprLen', + 'spanLeftOffsetVisible', + ] + return Object.fromEntries(value.getFields().filter(([name, _]) => !hide.includes(name)).map(([name, value]) => [name, debug_(value)])) + case 'primitive': + return value.value + } +} + +export function validateSpans(obj: LazyObject, initialPos?: number): number { + const state = { pos: initialPos ?? 0 } + validateSpans_(Dyn.Object(obj), state) + return state.pos +} + +function validateSpans_(value: DynValue, state: { pos: number }) { + switch (value.type) { + case 'sequence': + for (const elem of value.value) + validateSpans_(elem, state) + break + case 'result': + if (value.value.ok) + validateSpans_(value.value.value, state) + else + validateSpans_(value.value.error.payload, state) + break + case 'option': + if (value.value != null) + validateSpans_(value.value, state) + break + case 'object': + const fields = new Map(value.getFields()) + const whitespaceStart = fields.get('whitespaceLength') + const whitespaceLength = fields.get('whitespaceLength') + const codeStart = fields.get('codeStart') + const codeLength = fields.get('codeLength') + const childrenCodeLength = fields.get('childrenCodeLength') + if (whitespaceStart?.type === 'primitive' && whitespaceStart.value !== state.pos) + throw new Error('Span error (whitespace).') + if (whitespaceLength?.type === 'primitive') + state.pos += whitespaceLength.value as number + if (codeStart?.type === 'primitive' && codeStart.value !== state.pos) + throw new Error('Span error (code).') + if (codeLength?.type === 'primitive') + state.pos += codeLength.value as number + let endPos: number | undefined + if (childrenCodeLength?.type === 'primitive') + endPos = state.pos + (childrenCodeLength.value as number) + for (const entry of fields) { + const [_name, value] = entry + validateSpans_(value, state) + } + if (endPos != null && state.pos !== endPos) + throw new Error('Span error (children).') + break + case 'primitive': + break + } } diff --git a/lib/rust/parser/src/lexer.rs b/lib/rust/parser/src/lexer.rs index b132463b1eab..ad6ea49f3ac7 100644 --- a/lib/rust/parser/src/lexer.rs +++ b/lib/rust/parser/src/lexer.rs @@ -240,8 +240,9 @@ impl<'s> Lexer<'s> { #[inline(always)] fn marker_token(&mut self, elem: T) -> Token<'s, T> { let visible_offset = VisibleOffset(0); - let offset = Offset(visible_offset, Code::empty()); - Token(offset, Code::empty(), elem) + let start = self.current_offset - self.last_spaces_offset; + let offset = Offset(visible_offset, Code::empty_at(start.utf16)); + Token(offset, Code::empty_at(start.utf16), elem) } /// Push the [`token`] to the result stream. diff --git a/lib/rust/parser/src/source/code.rs b/lib/rust/parser/src/source/code.rs index 8feee8562c90..3355163ffd8d 100644 --- a/lib/rust/parser/src/source/code.rs +++ b/lib/rust/parser/src/source/code.rs @@ -63,11 +63,16 @@ impl<'s> Code<'s> { ) } - /// Return a reference to an empty string. + /// Return a reference to an empty string, without any location in the document. pub fn empty() -> Self { Self { repr: StrRef(""), offset_utf16: 0, utf16: 0 } } + /// Return a reference to an empty string. + pub fn empty_at(offset: u32) -> Self { + Self { repr: StrRef(""), offset_utf16: offset, utf16: 0 } + } + /// Length of the code in bytes. #[inline(always)] pub fn len(&self) -> Bytes { From 8353dca861eb875c086df39c767f7fbf063069b4 Mon Sep 17 00:00:00 2001 From: Kaz Wesley Date: Thu, 5 Oct 2023 22:41:42 -0700 Subject: [PATCH 36/44] Fix most spans... --- app/gui2/src/util/ffi.ts | 8 ------ app/gui2/src/util/parserSupport.ts | 21 ++++++++------ lib/rust/parser/src/lexer.rs | 40 +++++++++++++------------- lib/rust/parser/src/macros/built_in.rs | 6 ++-- lib/rust/parser/src/macros/resolver.rs | 2 +- lib/rust/parser/src/source/code.rs | 6 ++-- lib/rust/parser/src/source/span.rs | 1 + lib/rust/parser/src/syntax/token.rs | 1 + 8 files changed, 41 insertions(+), 44 deletions(-) diff --git a/app/gui2/src/util/ffi.ts b/app/gui2/src/util/ffi.ts index 400eb3c69073..99afcdefc814 100644 --- a/app/gui2/src/util/ffi.ts +++ b/app/gui2/src/util/ffi.ts @@ -559,7 +559,6 @@ if (import.meta.vitest) { }, func: { childrenCodeLength: 3, - whitespaceStart: 0, whitespaceLength: 0, token: { codeStart: 1, @@ -589,13 +588,6 @@ if (import.meta.vitest) { type: 'BodyBlock', }) }) - /* - test('TryParseSmthing', () => { - const smthing = 'Data.read file="name"' - const parsed = parseEnso2(smthing) - Array.from(parsed.statements)[0].expression.name.isTypeOrConstructor - }) - */ test('testSpans', () => { const identInput = ' foo bar\n' const tree = parseEnso2(identInput) diff --git a/app/gui2/src/util/parserSupport.ts b/app/gui2/src/util/parserSupport.ts index 0c03c40c7d00..15eddf913df9 100644 --- a/app/gui2/src/util/parserSupport.ts +++ b/app/gui2/src/util/parserSupport.ts @@ -211,19 +211,22 @@ function validateSpans_(value: DynValue, state: { pos: number }) { break case 'object': const fields = new Map(value.getFields()) - const whitespaceStart = fields.get('whitespaceLength') + const whitespaceStart = fields.get('whitespaceStart') const whitespaceLength = fields.get('whitespaceLength') const codeStart = fields.get('codeStart') const codeLength = fields.get('codeLength') const childrenCodeLength = fields.get('childrenCodeLength') - if (whitespaceStart?.type === 'primitive' && whitespaceStart.value !== state.pos) - throw new Error('Span error (whitespace).') - if (whitespaceLength?.type === 'primitive') - state.pos += whitespaceLength.value as number - if (codeStart?.type === 'primitive' && codeStart.value !== state.pos) - throw new Error('Span error (code).') - if (codeLength?.type === 'primitive') - state.pos += codeLength.value as number + if (!(whitespaceLength?.type === 'primitive' && whitespaceLength.value === 0 + && codeLength?.type === 'primitive' && codeLength?.value === 0)) { + if (whitespaceStart?.type === 'primitive' && whitespaceStart.value !== state.pos) + throw new Error('Span error (whitespace).') + if (whitespaceLength?.type === 'primitive') + state.pos += whitespaceLength.value as number + if (codeStart?.type === 'primitive' && codeStart.value !== state.pos) + throw new Error('Span error (code).') + if (codeLength?.type === 'primitive') + state.pos += codeLength.value as number + } let endPos: number | undefined if (childrenCodeLength?.type === 'primitive') endPos = state.pos + (childrenCodeLength.value as number) diff --git a/lib/rust/parser/src/lexer.rs b/lib/rust/parser/src/lexer.rs index ad6ea49f3ac7..91aa8a84c373 100644 --- a/lib/rust/parser/src/lexer.rs +++ b/lib/rust/parser/src/lexer.rs @@ -241,8 +241,8 @@ impl<'s> Lexer<'s> { fn marker_token(&mut self, elem: T) -> Token<'s, T> { let visible_offset = VisibleOffset(0); let start = self.current_offset - self.last_spaces_offset; - let offset = Offset(visible_offset, Code::empty_at(start.utf16)); - Token(offset, Code::empty_at(start.utf16), elem) + let offset = Offset(visible_offset, Code::empty(start.utf16)); + Token(offset, Code::empty(start.utf16), elem) } /// Push the [`token`] to the result stream. @@ -896,8 +896,8 @@ impl<'s> Lexer<'s> { .with_binary_infix_precedence(u32::MAX) .as_token_joiner(); self.submit_token(Token( - Code::empty(), - Code::empty(), + Code::empty_without_offset(), + Code::empty_without_offset(), token::Variant::operator(joiner), )); // Every number has a digits-token, even if it's zero-length. @@ -1077,7 +1077,7 @@ impl<'s> Lexer<'s> { if let Some(indent) = new_indent { if indent <= *block_indent { self.output - .push(Token::from(token::text_end(Code::empty(), Code::empty()))); + .push(Token::from(token::text_end(Code::empty_without_offset(), Code::empty_without_offset()))); self.end_blocks(indent); self.output.extend(newlines); if self.current_offset == text_start.0 { @@ -1150,7 +1150,7 @@ impl<'s> Lexer<'s> { let close_quote_end = self.mark(); self.make_token(text_end, close_quote_end, token::Variant::text_end()) } else { - Token::from(token::text_end(Code::empty(), Code::empty())) + Token::from(token::text_end(Code::empty_without_offset(), Code::empty_without_offset())) }; self.output.push(end_token); TextEndedAt::End @@ -1408,7 +1408,7 @@ impl<'s> Lexer<'s> { Code::from_str_at_offset(offset_code, left_offset_start.utf16), ); let eof = token::variant::Variant::Newline(token::variant::Newline()); - self.submit_token(Token(offset, Code::empty(), eof)); + self.submit_token(Token(offset, Code::empty(self.current_offset.utf16), eof)); } let mut internal_error = self.internal_error.take(); if self.current_char.is_some() { @@ -1499,45 +1499,45 @@ mod tests { #[test] fn test_case_block() { - let newline = newline_(Code::empty(), Code::from_str_without_offset("\n")); + let newline = newline_(Code::empty_without_offset(), Code::from_str_without_offset("\n")); test_lexer_many(vec![ - ("\n", vec![newline_(Code::empty(), Code::from_str_without_offset("\n"))]), + ("\n", vec![newline_(Code::empty_without_offset(), Code::from_str_without_offset("\n"))]), ("\n foo\n bar", vec![ - block_start_(Code::empty(), Code::empty()), + block_start_(Code::empty_without_offset(), Code::empty_without_offset()), newline.clone(), ident_(" ", "foo"), newline.clone(), ident_(" ", "bar"), - block_end_(Code::empty(), Code::empty()), + block_end_(Code::empty_without_offset(), Code::empty_without_offset()), ]), ("foo\n +", vec![ ident_("", "foo"), - block_start_(Code::empty(), Code::empty()), + block_start_(Code::empty_without_offset(), Code::empty_without_offset()), newline, operator_(" ", "+"), - block_end_(Code::empty(), Code::empty()), + block_end_(Code::empty_without_offset(), Code::empty_without_offset()), ]), ]); } #[test] fn test_case_block_bad_indents() { - let newline = newline_(Code::empty(), Code::from_str_without_offset("\n")); + let newline = newline_(Code::empty_without_offset(), Code::from_str_without_offset("\n")); #[rustfmt::skip] test_lexer_many(vec![ ("\n foo\n bar\nbaz", vec![ - block_start_(Code::empty(), Code::empty()), + block_start_(Code::empty_without_offset(), Code::empty_without_offset()), newline.clone(), ident_(" ", "foo"), newline.clone(), ident_(" ", "bar"), - block_end_(Code::empty(), Code::empty()), + block_end_(Code::empty_without_offset(), Code::empty_without_offset()), newline.clone(), ident_("", "baz"), ]), ("\n foo\n bar\n baz", vec![ - block_start_(Code::empty(), Code::empty()), + block_start_(Code::empty_without_offset(), Code::empty_without_offset()), newline.clone(), ident_(" ", "foo"), newline.clone(), ident_(" ", "bar"), newline, ident_(" ", "baz"), - block_end_(Code::empty(), Code::empty()), + block_end_(Code::empty_without_offset(), Code::empty_without_offset()), ]), ]); } @@ -1546,7 +1546,7 @@ mod tests { fn test_case_whitespace_only_line() { test_lexer_many(vec![("foo\n \nbar", vec![ ident_("", "foo"), - newline_(Code::empty(), Code::from_str_without_offset("\n")), + newline_(Code::empty_without_offset(), Code::from_str_without_offset("\n")), newline_(Code::from_str_without_offset(" "), Code::from_str_without_offset("\n")), ident_("", "bar"), ])]); @@ -1572,7 +1572,7 @@ mod tests { #[test] fn test_numeric_literal() { - test_lexer("10", vec![digits_(Code::empty(), Code::from_str_without_offset("10"), None)]); + test_lexer("10", vec![digits_(Code::empty_without_offset(), Code::from_str_without_offset("10"), None)]); } #[test] diff --git a/lib/rust/parser/src/macros/built_in.rs b/lib/rust/parser/src/macros/built_in.rs index b5ff2abc457b..2509c617468c 100644 --- a/lib/rust/parser/src/macros/built_in.rs +++ b/lib/rust/parser/src/macros/built_in.rs @@ -438,7 +438,7 @@ fn case_body<'s>( } } if !initial_case.is_empty() { - let newline = syntax::token::newline(Code::empty(), Code::empty()); + let newline = syntax::token::newline(Code::empty_without_offset(), Code::empty_without_offset()); case_builder.push(syntax::item::Line { newline, items: initial_case }); } block.into_iter().for_each(|line| case_builder.push(line)); @@ -805,8 +805,8 @@ fn expect_qualified(tree: syntax::Tree) -> syntax::Tree { fn expected_nonempty<'s>() -> syntax::Tree<'s> { let empty = syntax::Tree::ident(syntax::token::ident( - Code::empty(), - Code::empty(), + Code::empty_without_offset(), + Code::empty_without_offset(), false, 0, false, diff --git a/lib/rust/parser/src/macros/resolver.rs b/lib/rust/parser/src/macros/resolver.rs index 1a840c47687f..1bde8d372bd1 100644 --- a/lib/rust/parser/src/macros/resolver.rs +++ b/lib/rust/parser/src/macros/resolver.rs @@ -144,7 +144,7 @@ impl<'s> Resolver<'s> { pub fn new_statement() -> Self { let scopes = default(); let open_blocks = vec![syntax::item::Line { - newline: token::newline(Code::empty(), Code::empty()), + newline: token::newline(Code::empty_without_offset(), Code::empty_without_offset()), items: default(), }]; let macro_stack = default(); diff --git a/lib/rust/parser/src/source/code.rs b/lib/rust/parser/src/source/code.rs index 3355163ffd8d..af6339d2f52a 100644 --- a/lib/rust/parser/src/source/code.rs +++ b/lib/rust/parser/src/source/code.rs @@ -63,13 +63,13 @@ impl<'s> Code<'s> { ) } - /// Return a reference to an empty string, without any location in the document. - pub fn empty() -> Self { + /// Return a reference to an empty string, not associated with any location in the document. + pub fn empty_without_offset() -> Self { Self { repr: StrRef(""), offset_utf16: 0, utf16: 0 } } /// Return a reference to an empty string. - pub fn empty_at(offset: u32) -> Self { + pub fn empty(offset: u32) -> Self { Self { repr: StrRef(""), offset_utf16: offset, utf16: 0 } } diff --git a/lib/rust/parser/src/source/span.rs b/lib/rust/parser/src/source/span.rs index 349f7dc0433d..1bc1f8a69efc 100644 --- a/lib/rust/parser/src/source/span.rs +++ b/lib/rust/parser/src/source/span.rs @@ -257,6 +257,7 @@ impl<'s> FirstChildTrim<'s> for Span<'s> { #[inline(always)] fn trim_as_first_child(&mut self) -> Span<'s> { let left_offset = mem::take(&mut self.left_offset); + self.left_offset.code.offset_utf16 = left_offset.code.offset_utf16 + left_offset.code.utf16; let code_length = self.code_length; Span { left_offset, code_length } } diff --git a/lib/rust/parser/src/syntax/token.rs b/lib/rust/parser/src/syntax/token.rs index 7f0b4ebc8f1e..4c6ad5d4809c 100644 --- a/lib/rust/parser/src/syntax/token.rs +++ b/lib/rust/parser/src/syntax/token.rs @@ -180,6 +180,7 @@ impl<'s, T> FirstChildTrim<'s> for Token<'s, T> { #[inline(always)] fn trim_as_first_child(&mut self) -> Span<'s> { let left_offset = mem::take(&mut self.left_offset); + self.left_offset.code.offset_utf16 = left_offset.code.offset_utf16 + left_offset.code.utf16; let code_length = self.code.length(); Span { left_offset, code_length } } From 5e21a4873c9bb57a9f545855333c45ecc358e462 Mon Sep 17 00:00:00 2001 From: Kaz Wesley Date: Fri, 6 Oct 2023 08:38:08 -0700 Subject: [PATCH 37/44] Fix spans --- app/gui2/src/util/ffi.ts | 12 ++++-- app/gui2/src/util/parserSupport.ts | 2 +- lib/rust/parser/debug/src/lib.rs | 1 + lib/rust/parser/src/lexer.rs | 60 ++++++++++++++++---------- lib/rust/parser/src/lib.rs | 8 ++-- lib/rust/parser/src/macros/built_in.rs | 7 +-- lib/rust/parser/src/macros/resolver.rs | 2 +- lib/rust/parser/src/source/code.rs | 43 +++++++++++++++--- lib/rust/parser/src/source/span.rs | 23 ++++++++-- lib/rust/parser/src/syntax/token.rs | 5 +-- lib/rust/parser/src/syntax/tree.rs | 8 ++-- 11 files changed, 120 insertions(+), 51 deletions(-) diff --git a/app/gui2/src/util/ffi.ts b/app/gui2/src/util/ffi.ts index 99afcdefc814..5aed49d3a8f6 100644 --- a/app/gui2/src/util/ffi.ts +++ b/app/gui2/src/util/ffi.ts @@ -588,10 +588,16 @@ if (import.meta.vitest) { type: 'BodyBlock', }) }) + test('testCase', () => { + const input = 'Data.read\n2 + 2' + const tree = parseEnso2(input) + const endPos = validateSpans(tree) + expect(endPos).toStrictEqual(input.length) + }) test('testSpans', () => { - const identInput = ' foo bar\n' - const tree = parseEnso2(identInput) + const input = ' foo bar\n' + const tree = parseEnso2(input) const endPos = validateSpans(tree) - expect(endPos).toStrictEqual(identInput.length) + expect(endPos).toStrictEqual(input.length) }) } diff --git a/app/gui2/src/util/parserSupport.ts b/app/gui2/src/util/parserSupport.ts index 15eddf913df9..3294030fd401 100644 --- a/app/gui2/src/util/parserSupport.ts +++ b/app/gui2/src/util/parserSupport.ts @@ -219,7 +219,7 @@ function validateSpans_(value: DynValue, state: { pos: number }) { if (!(whitespaceLength?.type === 'primitive' && whitespaceLength.value === 0 && codeLength?.type === 'primitive' && codeLength?.value === 0)) { if (whitespaceStart?.type === 'primitive' && whitespaceStart.value !== state.pos) - throw new Error('Span error (whitespace).') + throw new Error(`Span error (whitespace) in: ${JSON.stringify(debug_(value))}.`) if (whitespaceLength?.type === 'primitive') state.pos += whitespaceLength.value as number if (codeStart?.type === 'primitive' && codeStart.value !== state.pos) diff --git a/lib/rust/parser/debug/src/lib.rs b/lib/rust/parser/debug/src/lib.rs index 0213380eddec..e60d956885f4 100644 --- a/lib/rust/parser/debug/src/lib.rs +++ b/lib/rust/parser/debug/src/lib.rs @@ -122,6 +122,7 @@ fn strip_hidden_fields(tree: Value) -> Value { ":spanLeftOffsetCodeReprBegin", ":spanLeftOffsetCodeReprLen", ":spanLeftOffsetCodeUtf16", + ":spanLeftOffsetCodeOffsetUtf16", ":spanCodeLengthUtf8", ":spanCodeLengthUtf16", ]; diff --git a/lib/rust/parser/src/lexer.rs b/lib/rust/parser/src/lexer.rs index 91aa8a84c373..6a2ccccfcbaa 100644 --- a/lib/rust/parser/src/lexer.rs +++ b/lib/rust/parser/src/lexer.rs @@ -1076,15 +1076,17 @@ impl<'s> Lexer<'s> { } if let Some(indent) = new_indent { if indent <= *block_indent { - self.output - .push(Token::from(token::text_end(Code::empty_without_offset(), Code::empty_without_offset()))); + self.output.push(Token::from(token::text_end( + Code::empty_without_offset(), + Code::empty_without_offset(), + ))); self.end_blocks(indent); self.output.extend(newlines); if self.current_offset == text_start.0 { self.last_spaces_visible_offset = text_start.1.visible; self.last_spaces_offset = StrOffset { utf8: text_start.1.code.len(), - utf16: text_start.1.code.utf16, + utf16: text_start.1.code.len_utf16(), }; } return TextEndedAt::End; @@ -1438,30 +1440,34 @@ pub mod test { use super::*; pub use token::*; + fn test_code(code: &str) -> Code { + Code::from_str_without_offset(code) + } + /// Constructor. pub fn ident_<'s>(left_offset: &'s str, code: &'s str) -> Token<'s> { let is_free = code.starts_with('_'); let lift_level = code.chars().rev().take_while(|t| *t == '\'').count() as u32; let is_uppercase = code.chars().next().map(|c| c.is_uppercase()).unwrap_or_default(); let is_operator = false; - let left_offset = Code::from_str_without_offset(left_offset); - let code = Code::from_str_without_offset(code); + let left_offset = test_code(left_offset); + let code = test_code(code); token::ident_(left_offset, code, is_free, lift_level, is_uppercase, is_operator, false) } /// Constructor. pub fn wildcard_<'s>(left_offset: &'s str, code: &'s str) -> Token<'s> { let lift_level = code.chars().rev().take_while(|t| *t == '\'').count() as u32; - let left_offset = Code::from_str_without_offset(left_offset); - let code = Code::from_str_without_offset(code); + let left_offset = test_code(left_offset); + let code = test_code(code); token::wildcard_(left_offset, code, lift_level) } /// Constructor. pub fn operator_<'s>(left_offset: &'s str, code: &'s str) -> Token<'s> { let variant = token::Variant::operator(analyze_operator(code)); - let left_offset = Code::from_str_without_offset(left_offset); - let code = Code::from_str_without_offset(code); + let left_offset = test_code(left_offset); + let code = test_code(code); Token(left_offset, code, variant) } } @@ -1471,6 +1477,14 @@ mod tests { use super::test::*; use super::*; + fn empty() -> Code { + Code::empty_without_offset() + } + + fn test_code(code: &str) -> Code { + Code::from_str_without_offset(code) + } + fn test_lexer_many<'s>(inputs: Vec<(&'s str, Vec>)>) { for (input, output) in inputs { test_lexer(input, output) @@ -1499,45 +1513,45 @@ mod tests { #[test] fn test_case_block() { - let newline = newline_(Code::empty_without_offset(), Code::from_str_without_offset("\n")); + let newline = newline_(empty(), test_code("\n")); test_lexer_many(vec![ - ("\n", vec![newline_(Code::empty_without_offset(), Code::from_str_without_offset("\n"))]), + ("\n", vec![newline_(empty(), test_code("\n"))]), ("\n foo\n bar", vec![ - block_start_(Code::empty_without_offset(), Code::empty_without_offset()), + block_start_(empty(), empty()), newline.clone(), ident_(" ", "foo"), newline.clone(), ident_(" ", "bar"), - block_end_(Code::empty_without_offset(), Code::empty_without_offset()), + block_end_(empty(), empty()), ]), ("foo\n +", vec![ ident_("", "foo"), - block_start_(Code::empty_without_offset(), Code::empty_without_offset()), + block_start_(empty(), empty()), newline, operator_(" ", "+"), - block_end_(Code::empty_without_offset(), Code::empty_without_offset()), + block_end_(empty(), empty()), ]), ]); } #[test] fn test_case_block_bad_indents() { - let newline = newline_(Code::empty_without_offset(), Code::from_str_without_offset("\n")); + let newline = newline_(empty(), test_code("\n")); #[rustfmt::skip] test_lexer_many(vec![ ("\n foo\n bar\nbaz", vec![ - block_start_(Code::empty_without_offset(), Code::empty_without_offset()), + block_start_(empty(), empty()), newline.clone(), ident_(" ", "foo"), newline.clone(), ident_(" ", "bar"), - block_end_(Code::empty_without_offset(), Code::empty_without_offset()), + block_end_(empty(), empty()), newline.clone(), ident_("", "baz"), ]), ("\n foo\n bar\n baz", vec![ - block_start_(Code::empty_without_offset(), Code::empty_without_offset()), + block_start_(empty(), empty()), newline.clone(), ident_(" ", "foo"), newline.clone(), ident_(" ", "bar"), newline, ident_(" ", "baz"), - block_end_(Code::empty_without_offset(), Code::empty_without_offset()), + block_end_(empty(), empty()), ]), ]); } @@ -1546,8 +1560,8 @@ mod tests { fn test_case_whitespace_only_line() { test_lexer_many(vec![("foo\n \nbar", vec![ ident_("", "foo"), - newline_(Code::empty_without_offset(), Code::from_str_without_offset("\n")), - newline_(Code::from_str_without_offset(" "), Code::from_str_without_offset("\n")), + newline_(empty(), test_code("\n")), + newline_(test_code(" "), test_code("\n")), ident_("", "bar"), ])]); } @@ -1572,7 +1586,7 @@ mod tests { #[test] fn test_numeric_literal() { - test_lexer("10", vec![digits_(Code::empty_without_offset(), Code::from_str_without_offset("10"), None)]); + test_lexer("10", vec![digits_(empty(), test_code("10"), None)]); } #[test] diff --git a/lib/rust/parser/src/lib.rs b/lib/rust/parser/src/lib.rs index 28ddea679210..7b7e3546c73f 100644 --- a/lib/rust/parser/src/lib.rs +++ b/lib/rust/parser/src/lib.rs @@ -201,7 +201,7 @@ impl Default for Parser { /// interpreted as a variable assignment or method definition. fn expression_to_statement(mut tree: syntax::Tree<'_>) -> syntax::Tree<'_> { use syntax::tree::*; - let mut left_offset = source::span::Offset::default(); + let mut left_offset = tree.span.left_offset.position_before(); if let Tree { variant: box Variant::Annotated(annotated), .. } = &mut tree { annotated.expression = annotated.expression.take().map(expression_to_statement); return tree; @@ -344,7 +344,7 @@ pub fn parse_argument_application<'s>( match &mut expression.variant { box Variant::App(App { func, arg }) => { let arg = parse_argument_definition(arg.clone()); - func.span.left_offset += mem::take(&mut expression.span.left_offset); + func.span.left_offset += expression.span.left_offset.take(); *expression = func.clone(); Some(arg) } @@ -358,7 +358,7 @@ pub fn parse_argument_application<'s>( let close2 = default(); let type_ = default(); let default = Some(ArgumentDefault { equals, expression: arg.clone() }); - func.span.left_offset += mem::take(&mut expression.span.left_offset); + func.span.left_offset += expression.span.left_offset.take(); *expression = func.clone(); Some(ArgumentDefinition { open, @@ -373,7 +373,7 @@ pub fn parse_argument_application<'s>( } box Variant::DefaultApp(DefaultApp { func, default: default_ }) => { let pattern = Tree::ident(default_.clone()); - func.span.left_offset += mem::take(&mut expression.span.left_offset); + func.span.left_offset += expression.span.left_offset.take(); *expression = func.clone(); Some(ArgumentDefinition { open: default(), diff --git a/lib/rust/parser/src/macros/built_in.rs b/lib/rust/parser/src/macros/built_in.rs index 2509c617468c..64ef482b6e16 100644 --- a/lib/rust/parser/src/macros/built_in.rs +++ b/lib/rust/parser/src/macros/built_in.rs @@ -339,7 +339,7 @@ fn to_body_statement(mut line_expression: syntax::Tree<'_>) -> syntax::Tree<'_> return line_expression; } let mut last_argument_default = default(); - let mut left_offset = crate::source::Offset::default(); + let mut left_offset = line_expression.span.left_offset.position_before(); let lhs = match &line_expression { Tree { variant: box Variant::OprApp(OprApp { lhs: Some(lhs), opr: Ok(opr), rhs: Some(rhs) }), @@ -437,8 +437,9 @@ fn case_body<'s>( _ => initial_case.push(item), } } - if !initial_case.is_empty() { - let newline = syntax::token::newline(Code::empty_without_offset(), Code::empty_without_offset()); + if let Some(first) = initial_case.first() { + let newline = + syntax::token::newline(Code::empty_without_offset(), Code::empty_without_offset()); case_builder.push(syntax::item::Line { newline, items: initial_case }); } block.into_iter().for_each(|line| case_builder.push(line)); diff --git a/lib/rust/parser/src/macros/resolver.rs b/lib/rust/parser/src/macros/resolver.rs index 1bde8d372bd1..3e8c85060e70 100644 --- a/lib/rust/parser/src/macros/resolver.rs +++ b/lib/rust/parser/src/macros/resolver.rs @@ -144,7 +144,7 @@ impl<'s> Resolver<'s> { pub fn new_statement() -> Self { let scopes = default(); let open_blocks = vec![syntax::item::Line { - newline: token::newline(Code::empty_without_offset(), Code::empty_without_offset()), + newline: token::newline(Code::empty(0), Code::empty(0)), items: default(), }]; let macro_stack = default(); diff --git a/lib/rust/parser/src/source/code.rs b/lib/rust/parser/src/source/code.rs index af6339d2f52a..8a1b7377c257 100644 --- a/lib/rust/parser/src/source/code.rs +++ b/lib/rust/parser/src/source/code.rs @@ -21,11 +21,11 @@ pub struct Code<'s> { #[serde(deserialize_with = "crate::serialization::deserialize_cow")] #[reflect(as = "crate::serialization::Code", flatten, hide)] #[deref] - pub repr: StrRef<'s>, + pub repr: StrRef<'s>, #[reflect(hide)] - pub offset_utf16: u32, + offset_utf16: u32, #[reflect(hide)] - pub utf16: u32, + utf16: u32, } impl<'s> Code<'s> { @@ -44,6 +44,32 @@ impl<'s> Code<'s> { Self::from_str_at_offset(repr, 0) } + #[inline(always)] + pub fn take(&mut self) -> Self { + let end = self.offset_utf16 + self.utf16; + Self { + repr: mem::take(&mut self.repr), + offset_utf16: mem::replace(&mut self.offset_utf16, end), + utf16: mem::take(&mut self.utf16), + } + } + + pub fn position_before(&self) -> Self { + Self { repr: default(), offset_utf16: self.offset_utf16, utf16: default() } + } + + pub fn position_after(&self) -> Self { + Self { + repr: default(), + offset_utf16: self.offset_utf16 + self.utf16, + utf16: default(), + } + } + + pub fn len_utf16(&self) -> u32 { + self.utf16 + } + /// Split the UTF-8 code at the given byte offset. pub fn split_at(&self, offset: usize) -> (Self, Self) { let (left, right) = self.repr.split_at(offset); @@ -130,8 +156,15 @@ impl<'s> AddAssign<&Code<'s>> for Code<'s> { #[inline(always)] fn add_assign(&mut self, other: &Code<'s>) { match (self.is_empty(), other.is_empty()) { - (_, true) => (), - (true, _) => { + (false, true) => (), + (true, true) => { + // The span builder works by starting with `Span::new()` (producing a span with no + // location in the document), and appending to the right side. In order to ensure + // every span has a location: When the LHS is empty, take the location from the RHS + // even if the RHS is also empty. + self.offset_utf16 = other.offset_utf16; + } + (true, false) => { *self = other.clone(); } (false, false) => { diff --git a/lib/rust/parser/src/source/span.rs b/lib/rust/parser/src/source/span.rs index 1bc1f8a69efc..909493b79981 100644 --- a/lib/rust/parser/src/source/span.rs +++ b/lib/rust/parser/src/source/span.rs @@ -86,6 +86,19 @@ impl<'s> Offset<'s> { pub fn exists(&self) -> bool { !self.is_empty() } + + #[inline(always)] + pub fn take(&mut self) -> Self { + Self { visible: mem::take(&mut self.visible), code: self.code.take() } + } + + pub fn position_before(&self) -> Self { + Self { visible: default(), code: self.code.position_before() } + } + + pub fn position_after(&self) -> Self { + Self { visible: default(), code: self.code.position_before() } + } } impl<'s> AsRef> for Offset<'s> { @@ -125,7 +138,7 @@ impl<'s> AddAssign<&Offset<'s>> for Offset<'s> { /// element. This is done in order to not duplicate the data. For example, some AST nodes contain a /// lot of tokens. They need to remember their span, but they do not need to remember their code, /// because it is already stored in the tokens. -#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Reflect, Deserialize)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Reflect, Deserialize)] #[allow(missing_docs)] pub struct Span<'s> { #[reflect(hide, flatten)] @@ -138,7 +151,10 @@ pub struct Span<'s> { impl<'s> Span<'s> { /// Constructor. pub fn new() -> Self { - default() + Self { + left_offset: Code::empty_without_offset().into(), + code_length: default(), + } } /// Check whether the span is empty. @@ -256,8 +272,7 @@ pub trait FirstChildTrim<'s> { impl<'s> FirstChildTrim<'s> for Span<'s> { #[inline(always)] fn trim_as_first_child(&mut self) -> Span<'s> { - let left_offset = mem::take(&mut self.left_offset); - self.left_offset.code.offset_utf16 = left_offset.code.offset_utf16 + left_offset.code.utf16; + let left_offset = self.left_offset.take(); let code_length = self.code_length; Span { left_offset, code_length } } diff --git a/lib/rust/parser/src/syntax/token.rs b/lib/rust/parser/src/syntax/token.rs index 4c6ad5d4809c..3362d5142903 100644 --- a/lib/rust/parser/src/syntax/token.rs +++ b/lib/rust/parser/src/syntax/token.rs @@ -137,7 +137,7 @@ impl<'s, T> Token<'s, T> { #[inline(always)] pub fn split_at(self, offset: Bytes) -> (Token<'s, ()>, Token<'s, ()>, T) { let left_lexeme_offset = self.left_offset; - let right_lexeme_offset = Offset::default(); + let right_lexeme_offset = self.code.position_after(); let (left_code, right_code) = self.code.split_at(offset.unchecked_raw()); let left = Token(left_lexeme_offset, left_code, ()); let right = Token(right_lexeme_offset, right_code, ()); @@ -179,8 +179,7 @@ impl<'s, T: PartialEq> PartialEq> for &Token<'s, T> { impl<'s, T> FirstChildTrim<'s> for Token<'s, T> { #[inline(always)] fn trim_as_first_child(&mut self) -> Span<'s> { - let left_offset = mem::take(&mut self.left_offset); - self.left_offset.code.offset_utf16 = left_offset.code.offset_utf16 + left_offset.code.utf16; + let left_offset = self.left_offset.take(); let code_length = self.code.length(); Span { left_offset, code_length } } diff --git a/lib/rust/parser/src/syntax/tree.rs b/lib/rust/parser/src/syntax/tree.rs index fbd8108ad191..8e9404fbefd5 100644 --- a/lib/rust/parser/src/syntax/tree.rs +++ b/lib/rust/parser/src/syntax/tree.rs @@ -51,7 +51,7 @@ impl<'s> Default for Tree<'s> { fn default() -> Self { Self { variant: Box::new(Variant::Ident(Ident { token: Default::default() })), - span: Default::default(), + span: Span::new(), } } } @@ -764,7 +764,7 @@ pub fn apply<'s>(mut func: Tree<'s>, mut arg: Tree<'s>) -> Tree<'s> { func } (_, Variant::ArgumentBlockApplication(block)) if block.lhs.is_none() => { - let func_left_offset = mem::take(&mut func.span.left_offset); + let func_left_offset = func.span.left_offset.take(); let arg_left_offset = mem::replace(&mut arg.span.left_offset, func_left_offset); if let Some(first) = block.arguments.first_mut() { first.newline.left_offset += arg_left_offset; @@ -773,7 +773,7 @@ pub fn apply<'s>(mut func: Tree<'s>, mut arg: Tree<'s>) -> Tree<'s> { arg } (_, Variant::OperatorBlockApplication(block)) if block.lhs.is_none() => { - let func_left_offset = mem::take(&mut func.span.left_offset); + let func_left_offset = func.span.left_offset.take(); let arg_left_offset = mem::replace(&mut arg.span.left_offset, func_left_offset); if let Some(first) = block.expressions.first_mut() { first.newline.left_offset += arg_left_offset; @@ -903,7 +903,7 @@ pub fn apply_operator<'s>( if let Variant::ArgumentBlockApplication(block) = &mut *rhs_.variant { if block.lhs.is_none() { if let Some(first) = block.arguments.first_mut() { - first.newline.left_offset += mem::take(&mut rhs_.span.left_offset); + first.newline.left_offset += rhs_.span.left_offset.take(); } let ArgumentBlockApplication { lhs: _, arguments } = block; let arguments = mem::take(arguments); From 1388d0201c99da708f58f6e6d50112409eba7a17 Mon Sep 17 00:00:00 2001 From: Kaz Wesley Date: Tue, 10 Oct 2023 06:46:14 -0700 Subject: [PATCH 38/44] Clean up. --- lib/rust/parser/src/lexer.rs | 9 ++++++--- lib/rust/parser/src/source/code.rs | 15 +++++++++++---- lib/rust/parser/src/source/span.rs | 8 ++++++-- lib/rust/parser/src/syntax/token.rs | 10 ++++++++++ lib/rust/parser/src/syntax/tree.rs | 2 +- 5 files changed, 34 insertions(+), 10 deletions(-) diff --git a/lib/rust/parser/src/lexer.rs b/lib/rust/parser/src/lexer.rs index 6a2ccccfcbaa..029e2d1e81cc 100644 --- a/lib/rust/parser/src/lexer.rs +++ b/lib/rust/parser/src/lexer.rs @@ -1477,7 +1477,7 @@ mod tests { use super::test::*; use super::*; - fn empty() -> Code { + fn empty<'a>() -> Code<'a> { Code::empty_without_offset() } @@ -1492,7 +1492,10 @@ mod tests { } fn test_lexer<'s>(input: &'s str, expected: Vec>) { - assert_eq!(run(input).unwrap(), expected); + let result: Vec<_> = + run(input).unwrap().into_iter().map(|token| token.without_offsets()).collect(); + let expected: Vec<_> = expected.into_iter().map(|token| token.without_offsets()).collect(); + assert_eq!(result, expected); } fn lexer_case_idents<'s>(idents: &[&'s str]) -> Vec<(&'s str, Vec>)> { @@ -1668,7 +1671,7 @@ mod tests { // 2.2. Last possible sequence of a certain length. /* 2.2.1. 1 byte (U-0000007F): */ "" /* 2.2.2. 2 bytes (U-000007FF): */ "߿" - /* 2.2.3. 3 bytes (U-0000FFFF): */ " " + /* 2.2.3. 3 bytes (U-0000FFFF): */ "￿" /* 2.2.4. 4 bytes (U-001FFFFF): */ "����" /* 2.2.5. 5 bytes (U-03FFFFFF): */ "�����" /* 2.2.6. 6 bytes (U-7FFFFFFF): */ "������" diff --git a/lib/rust/parser/src/source/code.rs b/lib/rust/parser/src/source/code.rs index 8a1b7377c257..f0364fc3e522 100644 --- a/lib/rust/parser/src/source/code.rs +++ b/lib/rust/parser/src/source/code.rs @@ -116,6 +116,14 @@ impl<'s> Code<'s> { pub fn is_empty(&self) -> bool { self.repr.is_empty() } + + pub fn without_offset(&self) -> Self { + Self { + repr: self.repr.clone(), + offset_utf16: default(), + utf16: self.utf16, + } + } } impl<'s> Display for Code<'s> { @@ -158,10 +166,9 @@ impl<'s> AddAssign<&Code<'s>> for Code<'s> { match (self.is_empty(), other.is_empty()) { (false, true) => (), (true, true) => { - // The span builder works by starting with `Span::new()` (producing a span with no - // location in the document), and appending to the right side. In order to ensure - // every span has a location: When the LHS is empty, take the location from the RHS - // even if the RHS is also empty. + // The span builder works by starting with `Span::empty_without_offset()`, and + // appending to the right side. In order to ensure every span has an offset: When + // the LHS is empty, take the location from the RHS even if the RHS is also empty. self.offset_utf16 = other.offset_utf16; } (true, false) => { diff --git a/lib/rust/parser/src/source/span.rs b/lib/rust/parser/src/source/span.rs index 909493b79981..24256c11d9ad 100644 --- a/lib/rust/parser/src/source/span.rs +++ b/lib/rust/parser/src/source/span.rs @@ -99,6 +99,10 @@ impl<'s> Offset<'s> { pub fn position_after(&self) -> Self { Self { visible: default(), code: self.code.position_before() } } + + pub fn without_offset(&self) -> Self { + Self { visible: self.visible, code: self.code.without_offset() } + } } impl<'s> AsRef> for Offset<'s> { @@ -150,7 +154,7 @@ pub struct Span<'s> { impl<'s> Span<'s> { /// Constructor. - pub fn new() -> Self { + pub fn empty_without_offset() -> Self { Self { left_offset: Code::empty_without_offset().into(), code_length: default(), @@ -289,7 +293,7 @@ impl<'s> FirstChildTrim<'s> for Span<'s> { #[macro_export] macro_rules! span_builder { ($($arg:ident),* $(,)?) => { - $crate::source::span::Span::new() $(.add(&mut $arg))* + $crate::source::span::Span::empty_without_offset() $(.add(&mut $arg))* }; } diff --git a/lib/rust/parser/src/syntax/token.rs b/lib/rust/parser/src/syntax/token.rs index 3362d5142903..a219e24f382d 100644 --- a/lib/rust/parser/src/syntax/token.rs +++ b/lib/rust/parser/src/syntax/token.rs @@ -170,6 +170,16 @@ impl<'s, T> Token<'s, T> { } } +impl<'s, V: Clone> Token<'s, V> { + pub fn without_offsets(&self) -> Self { + Self { + left_offset: self.left_offset.without_offset(), + code: self.code.without_offset(), + variant: self.variant.clone(), + } + } +} + impl<'s, T: PartialEq> PartialEq> for &Token<'s, T> { fn eq(&self, other: &Token<'s, T>) -> bool { as PartialEq>>::eq(*self, other) diff --git a/lib/rust/parser/src/syntax/tree.rs b/lib/rust/parser/src/syntax/tree.rs index 8e9404fbefd5..3120bee71c98 100644 --- a/lib/rust/parser/src/syntax/tree.rs +++ b/lib/rust/parser/src/syntax/tree.rs @@ -51,7 +51,7 @@ impl<'s> Default for Tree<'s> { fn default() -> Self { Self { variant: Box::new(Variant::Ident(Ident { token: Default::default() })), - span: Span::new(), + span: Span::empty_without_offset(), } } } From 82ec438935c60c398b923c28817603dcb96626da Mon Sep 17 00:00:00 2001 From: Kaz Wesley Date: Tue, 10 Oct 2023 08:26:31 -0700 Subject: [PATCH 39/44] Prettier. --- app/gui2/parser-codegen/src/codegen.ts | 593 ++++++++++--------- app/gui2/parser-codegen/src/main.ts | 4 +- app/gui2/parser-codegen/src/schema.ts | 6 +- app/gui2/parser-codegen/src/serialization.ts | 516 ++++++++-------- app/gui2/parser-codegen/src/util.ts | 108 ++-- app/gui2/parser-codegen/tsconfig.json | 2 +- app/gui2/src/util/ffi.ts | 6 +- app/gui2/src/util/parserSupport.ts | 82 +-- 8 files changed, 688 insertions(+), 629 deletions(-) diff --git a/app/gui2/parser-codegen/src/codegen.ts b/app/gui2/parser-codegen/src/codegen.ts index 5ac226023630..dc17c3d506e2 100644 --- a/app/gui2/parser-codegen/src/codegen.ts +++ b/app/gui2/parser-codegen/src/codegen.ts @@ -8,79 +8,77 @@ */ import ts from 'typescript' -const { factory: tsf } = ts import * as Schema from './schema.js' import { - toPascal, - toCamel, - mapIdent, - namespacedName, - assignmentStatement, - forwardToSuper, - modifiers -} from './util.js' -import { - Type, - support, - supportImports, - seekCursor, - abstractTypeDeserializer, - fieldDeserializer, - fieldDynValue + Type, + abstractTypeDeserializer, + fieldDeserializer, + fieldDynValue, + seekCursor, + support, + supportImports, } from './serialization.js' - +import { + assignmentStatement, + forwardToSuper, + mapIdent, + modifiers, + namespacedName, + toCamel, + toPascal, +} from './util.js' +const { factory: tsf } = ts // === Public API === export function implement(schema: Schema.Schema): string { - const file = ts.createSourceFile('source.ts', '', ts.ScriptTarget.ESNext, false, ts.ScriptKind.TS) - const printer = ts.createPrinter({newLine: ts.NewLineKind.LineFeed}) - let output = '// *** THIS FILE GENERATED BY `parser-codegen` ***\n' + const file = ts.createSourceFile('source.ts', '', ts.ScriptTarget.ESNext, false, ts.ScriptKind.TS) + const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed }) + let output = '// *** THIS FILE GENERATED BY `parser-codegen` ***\n' - function emit(data: ts.Node) { - output += printer.printNode(ts.EmitHint.Unspecified, data, file) - output += '\n' - } + function emit(data: ts.Node) { + output += printer.printNode(ts.EmitHint.Unspecified, data, file) + output += '\n' + } - emit( - tsf.createImportDeclaration( - [], - tsf.createImportClause( - false, - undefined, - tsf.createNamedImports( - Array.from(Object.entries(supportImports), ([name, isTypeOnly]) => - tsf.createImportSpecifier(isTypeOnly, undefined, tsf.createIdentifier(name)), - ), - ), - ), - tsf.createStringLiteral('@/util/parserSupport', true), - undefined, + emit( + tsf.createImportDeclaration( + [], + tsf.createImportClause( + false, + undefined, + tsf.createNamedImports( + Array.from(Object.entries(supportImports), ([name, isTypeOnly]) => + tsf.createImportSpecifier(isTypeOnly, undefined, tsf.createIdentifier(name)), + ), ), - ) - for (const id in schema.types) { - const ty = schema.types[id] - if (ty.parent == null) { - const discriminants = schema.serialization[id].discriminants - if (discriminants == null) { - emit(makeConcreteType(id, schema)) - } else { - const ty = makeAbstractType(id, discriminants, schema) - emit(ty.module) - emit(ty.export) - } - } else { - // Ignore child types; they are generated when `makeAbstractType` processes the parent. - } + ), + tsf.createStringLiteral('@/util/parserSupport', true), + undefined, + ), + ) + for (const id in schema.types) { + const ty = schema.types[id] + if (ty.parent == null) { + const discriminants = schema.serialization[id].discriminants + if (discriminants == null) { + emit(makeConcreteType(id, schema)) + } else { + const ty = makeAbstractType(id, discriminants, schema) + emit(ty.module) + emit(ty.export) + } + } else { + // Ignore child types; they are generated when `makeAbstractType` processes the parent. } - output += `export function deserializeTree(data: ArrayBuffer): Tree { + } + output += `export function deserializeTree(data: ArrayBuffer): Tree { const cursor = new Cursor(data, data.byteLength - 4) return Tree.read(cursor.readPointer()) }` - return output + return output } - // === Implementation === function makeType(ref: Schema.TypeRef, schema: Schema.Schema): Type { @@ -99,13 +97,20 @@ function makeType(ref: Schema.TypeRef, schema: Schema.Schema): Type { case 'primitive': const p = ref.type switch (p) { - case 'bool': return Type.Boolean - case 'u32': return Type.UInt32 - case 'i32': return Type.Int32 - case 'u64': return Type.UInt64 - case 'i64': return Type.Int64 - case 'char': return Type.Char - case 'string': return Type.String + case 'bool': + return Type.Boolean + case 'u32': + return Type.UInt32 + case 'i32': + return Type.Int32 + case 'u64': + return Type.UInt64 + case 'i64': + return Type.Int64 + case 'char': + return Type.Char + case 'string': + return Type.String default: const _ = p satisfies never throw new Error("unreachable: PrimitiveType.type='" + p + "'") @@ -123,276 +128,274 @@ function makeType(ref: Schema.TypeRef, schema: Schema.Schema): Type { } type Field = { - name: string, - type: Type, - offset: number, + name: string + type: Type + offset: number } function makeField( - name: string, - typeRef: Schema.TypeRef, - offset: number, - schema: Schema.Schema, + name: string, + typeRef: Schema.TypeRef, + offset: number, + schema: Schema.Schema, ): Field { - return { - name: mapIdent(toCamel(name)), - type: makeType(typeRef, schema), - offset: offset, - } + return { + name: mapIdent(toCamel(name)), + type: makeType(typeRef, schema), + offset: offset, + } } function makeGetter(field: Field): ts.GetAccessorDeclaration { - return fieldDeserializer(tsf.createIdentifier(field.name), field.type, field.offset) + return fieldDeserializer(tsf.createIdentifier(field.name), field.type, field.offset) } function makeConcreteType(id: string, schema: Schema.Schema): ts.ClassDeclaration { - const ident = tsf.createIdentifier(toPascal(schema.types[id].name)) - const paramIdent = tsf.createIdentifier('cursor') - const cursorParam = tsf.createParameterDeclaration( - [], - undefined, - paramIdent, + const ident = tsf.createIdentifier(toPascal(schema.types[id].name)) + const paramIdent = tsf.createIdentifier('cursor') + const cursorParam = tsf.createParameterDeclaration( + [], + undefined, + paramIdent, + undefined, + support.Cursor, + undefined, + ) + return makeClass( + [modifiers.export], + ident, + [ + forwardToSuper(paramIdent, support.Cursor), + tsf.createMethodDeclaration( + [modifiers.static], undefined, - support.Cursor, + 'read', undefined, - ) - return makeClass( - [modifiers.export], - ident, - [ - forwardToSuper(paramIdent, support.Cursor), - tsf.createMethodDeclaration( - [modifiers.static], - undefined, - 'read', - undefined, - [], - [cursorParam], - tsf.createTypeReferenceNode(ident), - tsf.createBlock([ - tsf.createReturnStatement(tsf.createNewExpression(ident, [], [paramIdent])), - ]), - ), - ], - id, - schema, - ) + [], + [cursorParam], + tsf.createTypeReferenceNode(ident), + tsf.createBlock([ + tsf.createReturnStatement(tsf.createNewExpression(ident, [], [paramIdent])), + ]), + ), + ], + id, + schema, + ) } function makeDebugFunction(fields: Field[], typeName?: string): ts.MethodDeclaration { - const ident = tsf.createIdentifier('fields') - const fieldAssignments = fields.map(field => - tsf.createArrayLiteralExpression([ - tsf.createStringLiteral(field.name), - fieldDynValue(field.type, field.offset) - ]) + const ident = tsf.createIdentifier('fields') + const fieldAssignments = fields.map((field) => + tsf.createArrayLiteralExpression([ + tsf.createStringLiteral(field.name), + fieldDynValue(field.type, field.offset), + ]), + ) + if (typeName != null) { + fieldAssignments.push( + tsf.createArrayLiteralExpression([ + tsf.createStringLiteral('type'), + tsf.createObjectLiteralExpression([ + tsf.createPropertyAssignment('type', tsf.createStringLiteral('primitive')), + tsf.createPropertyAssignment('value', tsf.createStringLiteral(typeName)), + ]), + ]), ) - if (typeName != null) { - fieldAssignments.push( - tsf.createArrayLiteralExpression([ - tsf.createStringLiteral('type'), - tsf.createObjectLiteralExpression([ - tsf.createPropertyAssignment('type', tsf.createStringLiteral('primitive')), - tsf.createPropertyAssignment('value', tsf.createStringLiteral(typeName)), - ]) - ]) - ) - } - return tsf.createMethodDeclaration( - [], - undefined, - ident, - undefined, - [], - [], - tsf.createTypeReferenceNode(`[string, ${support.DynValue}][]`), - tsf.createBlock([ - tsf.createReturnStatement( - tsf.createArrayLiteralExpression([ - tsf.createSpreadElement( - tsf.createCallExpression( - tsf.createPropertyAccessExpression(tsf.createSuper(), ident), - undefined, - undefined, - ) - ), - ...fieldAssignments - ]) + } + return tsf.createMethodDeclaration( + [], + undefined, + ident, + undefined, + [], + [], + tsf.createTypeReferenceNode(`[string, ${support.DynValue}][]`), + tsf.createBlock([ + tsf.createReturnStatement( + tsf.createArrayLiteralExpression([ + tsf.createSpreadElement( + tsf.createCallExpression( + tsf.createPropertyAccessExpression(tsf.createSuper(), ident), + undefined, + undefined, ), + ), + ...fieldAssignments, ]), - ) + ), + ]), + ) } function makeGetters(id: string, schema: Schema.Schema, typeName?: string): ts.ClassElement[] { - const fields = schema.serialization[id].fields.map(([name, offset]: [string, number]) => - makeField(name, schema.types[id].fields[name], offset, schema)) - return [ - ...fields.map(makeGetter), - makeDebugFunction(fields, typeName), - ] + const fields = schema.serialization[id].fields.map(([name, offset]: [string, number]) => + makeField(name, schema.types[id].fields[name], offset, schema), + ) + return [...fields.map(makeGetter), makeDebugFunction(fields, typeName)] } function makeClass( - modifiers: ts.Modifier[], - name: ts.Identifier, - members: ts.ClassElement[], - id: string, - schema: Schema.Schema, + modifiers: ts.Modifier[], + name: ts.Identifier, + members: ts.ClassElement[], + id: string, + schema: Schema.Schema, ): ts.ClassDeclaration { - return tsf.createClassDeclaration( - modifiers, - name, - undefined, - [ - tsf.createHeritageClause(ts.SyntaxKind.ExtendsKeyword, [ - tsf.createExpressionWithTypeArguments(support.LazyObject, []), - ]), - ], - [ - ...members, - ...makeGetters(id, schema), - ], - ) + return tsf.createClassDeclaration( + modifiers, + name, + undefined, + [ + tsf.createHeritageClause(ts.SyntaxKind.ExtendsKeyword, [ + tsf.createExpressionWithTypeArguments(support.LazyObject, []), + ]), + ], + [...members, ...makeGetters(id, schema)], + ) } type ChildType = { - definition: ts.ClassDeclaration - reference: ts.TypeNode - enumMember: ts.EnumMember - case: ts.CaseClause + definition: ts.ClassDeclaration + reference: ts.TypeNode + enumMember: ts.EnumMember + case: ts.CaseClause } function makeChildType( - base: ts.Identifier, - id: string, - discrim: string, - schema: Schema.Schema, + base: ts.Identifier, + id: string, + discrim: string, + schema: Schema.Schema, ): ChildType { - const ty: Schema.Type = schema.types[id] - const name = toPascal(ty.name) - const ident = tsf.createIdentifier(name) - const cursorIdent = tsf.createIdentifier('cursor') - const cursorParam = tsf.createParameterDeclaration( - [], - undefined, - cursorIdent, - undefined, - support.Cursor, - undefined, - ) - const discrimInt = tsf.createNumericLiteral(parseInt(discrim, 10)) - return { - definition: tsf.createClassDeclaration( - [modifiers.export], - name, - undefined, - [ - tsf.createHeritageClause(ts.SyntaxKind.ExtendsKeyword, [ - tsf.createExpressionWithTypeArguments(base, []), - ]), - ], - [ - tsf.createPropertyDeclaration( - [modifiers.readonly], - 'type', - undefined, - tsf.createTypeReferenceNode('Type.' + name), - undefined, - ), - tsf.createConstructorDeclaration( - [], - [ - tsf.createParameterDeclaration( - [], - undefined, - cursorIdent, - undefined, - support.Cursor, - undefined, - ), - ], - tsf.createBlock([ - tsf.createExpressionStatement( - tsf.createCallExpression(tsf.createIdentifier('super'), [], [cursorIdent]), - ), - assignmentStatement( - tsf.createPropertyAccessExpression(tsf.createIdentifier('this'), 'type'), - tsf.createPropertyAccessExpression(tsf.createIdentifier('Type'), name), - ), - ]), - ), - tsf.createMethodDeclaration( - [modifiers.static], - undefined, - 'read', - undefined, - [], - [cursorParam], - tsf.createTypeReferenceNode(ident), - tsf.createBlock([ - tsf.createReturnStatement(tsf.createNewExpression(ident, [], [cursorIdent])), - ]), - ), - ...makeGetters(id, schema, name), - ], - ), - reference: tsf.createTypeReferenceNode(name), - enumMember: tsf.createEnumMember(toPascal(schema.types[id].name), discrimInt), - case: tsf.createCaseClause(discrimInt, [ - tsf.createReturnStatement(tsf.createNewExpression(ident, [], [seekCursor(cursorIdent, 4)])), + const ty: Schema.Type = schema.types[id] + const name = toPascal(ty.name) + const ident = tsf.createIdentifier(name) + const cursorIdent = tsf.createIdentifier('cursor') + const cursorParam = tsf.createParameterDeclaration( + [], + undefined, + cursorIdent, + undefined, + support.Cursor, + undefined, + ) + const discrimInt = tsf.createNumericLiteral(parseInt(discrim, 10)) + return { + definition: tsf.createClassDeclaration( + [modifiers.export], + name, + undefined, + [ + tsf.createHeritageClause(ts.SyntaxKind.ExtendsKeyword, [ + tsf.createExpressionWithTypeArguments(base, []), ]), - } + ], + [ + tsf.createPropertyDeclaration( + [modifiers.readonly], + 'type', + undefined, + tsf.createTypeReferenceNode('Type.' + name), + undefined, + ), + tsf.createConstructorDeclaration( + [], + [ + tsf.createParameterDeclaration( + [], + undefined, + cursorIdent, + undefined, + support.Cursor, + undefined, + ), + ], + tsf.createBlock([ + tsf.createExpressionStatement( + tsf.createCallExpression(tsf.createIdentifier('super'), [], [cursorIdent]), + ), + assignmentStatement( + tsf.createPropertyAccessExpression(tsf.createIdentifier('this'), 'type'), + tsf.createPropertyAccessExpression(tsf.createIdentifier('Type'), name), + ), + ]), + ), + tsf.createMethodDeclaration( + [modifiers.static], + undefined, + 'read', + undefined, + [], + [cursorParam], + tsf.createTypeReferenceNode(ident), + tsf.createBlock([ + tsf.createReturnStatement(tsf.createNewExpression(ident, [], [cursorIdent])), + ]), + ), + ...makeGetters(id, schema, name), + ], + ), + reference: tsf.createTypeReferenceNode(name), + enumMember: tsf.createEnumMember(toPascal(schema.types[id].name), discrimInt), + case: tsf.createCaseClause(discrimInt, [ + tsf.createReturnStatement(tsf.createNewExpression(ident, [], [seekCursor(cursorIdent, 4)])), + ]), + } } type AbstractType = { - module: ts.ModuleDeclaration, - export: ts.TypeAliasDeclaration, + module: ts.ModuleDeclaration + export: ts.TypeAliasDeclaration } -function makeAbstractType(id: string, discriminants: Schema.DiscriminantMap, schema: Schema.Schema): AbstractType { - const ty = schema.types[id] - const name = toPascal(ty.name) - const ident = tsf.createIdentifier(name) - const baseIdent = tsf.createIdentifier('AbstractBase') - const childTypes = Array.from( - Object.entries(discriminants), - ([discrim, id]: [string, string]) => makeChildType(baseIdent, id, discrim, schema), - ) - const cursorIdent = tsf.createIdentifier('cursor') - const moduleDecl = tsf.createModuleDeclaration( - [modifiers.export], - ident, - tsf.createModuleBlock([ - makeClass( - [modifiers.abstract], - baseIdent, - [forwardToSuper(cursorIdent, support.Cursor, [modifiers.protected])], - id, - schema, - ), - tsf.createEnumDeclaration( - [modifiers.export, modifiers.const], - 'Type', - childTypes.map((child) => child.enumMember), - ), - ...childTypes.map((child) => child.definition), - tsf.createTypeAliasDeclaration( - [modifiers.export], - ident, - undefined, - tsf.createUnionTypeNode(childTypes.map((child) => child.reference)), - ), - abstractTypeDeserializer( - ident, - childTypes.map((child) => child.case), - ), - ]), - ) - const abstractTypeExport = tsf.createTypeAliasDeclaration( +function makeAbstractType( + id: string, + discriminants: Schema.DiscriminantMap, + schema: Schema.Schema, +): AbstractType { + const ty = schema.types[id] + const name = toPascal(ty.name) + const ident = tsf.createIdentifier(name) + const baseIdent = tsf.createIdentifier('AbstractBase') + const childTypes = Array.from(Object.entries(discriminants), ([discrim, id]: [string, string]) => + makeChildType(baseIdent, id, discrim, schema), + ) + const cursorIdent = tsf.createIdentifier('cursor') + const moduleDecl = tsf.createModuleDeclaration( + [modifiers.export], + ident, + tsf.createModuleBlock([ + makeClass( + [modifiers.abstract], + baseIdent, + [forwardToSuper(cursorIdent, support.Cursor, [modifiers.protected])], + id, + schema, + ), + tsf.createEnumDeclaration( + [modifiers.export, modifiers.const], + 'Type', + childTypes.map((child) => child.enumMember), + ), + ...childTypes.map((child) => child.definition), + tsf.createTypeAliasDeclaration( [modifiers.export], ident, undefined, - tsf.createTypeReferenceNode(name + '.' + name), - ) - return { module: moduleDecl, export: abstractTypeExport } + tsf.createUnionTypeNode(childTypes.map((child) => child.reference)), + ), + abstractTypeDeserializer( + ident, + childTypes.map((child) => child.case), + ), + ]), + ) + const abstractTypeExport = tsf.createTypeAliasDeclaration( + [modifiers.export], + ident, + undefined, + tsf.createTypeReferenceNode(name + '.' + name), + ) + return { module: moduleDecl, export: abstractTypeExport } } diff --git a/app/gui2/parser-codegen/src/main.ts b/app/gui2/parser-codegen/src/main.ts index f5d2af9cad3b..30d88d284103 100644 --- a/app/gui2/parser-codegen/src/main.ts +++ b/app/gui2/parser-codegen/src/main.ts @@ -1,6 +1,6 @@ -import fs from "fs"; +import fs from 'fs' +import * as codegen from './codegen.js' import * as Schema from './schema.js' -import * as codegen from "./codegen.js"; const schema: Schema.Schema = JSON.parse(fs.readFileSync(process.argv[2], 'utf8')) const code = codegen.implement(schema) diff --git a/app/gui2/parser-codegen/src/schema.ts b/app/gui2/parser-codegen/src/schema.ts index c2d92c91b4d9..85ebea74a23f 100644 --- a/app/gui2/parser-codegen/src/schema.ts +++ b/app/gui2/parser-codegen/src/schema.ts @@ -1,6 +1,6 @@ export type Schema = { - types: Types - serialization: Serialization + types: Types + serialization: Serialization } export type TypeId = string export type Types = { @@ -32,4 +32,4 @@ export type Layout = { } export type DiscriminantMap = { [discriminant: number]: TypeId -} \ No newline at end of file +} diff --git a/app/gui2/parser-codegen/src/serialization.ts b/app/gui2/parser-codegen/src/serialization.ts index 15aa46183bd2..add65487dce0 100644 --- a/app/gui2/parser-codegen/src/serialization.ts +++ b/app/gui2/parser-codegen/src/serialization.ts @@ -1,10 +1,9 @@ /** Generates code lazily deserializing from an application-specific binary format. */ -import ts from "typescript"; - -const {factory: tsf} = ts -import {casesOrThrow, modifiers} from "./util.js"; +import ts from 'typescript' +import { casesOrThrow, modifiers } from './util.js' +const { factory: tsf } = ts // === Definitions === @@ -13,183 +12,232 @@ const cursorFieldIdent = tsf.createIdentifier('lazyObjectData') const POINTER_SIZE: number = 4 // Symbols exported by the `parserSupport` module. export const supportImports = { - LazyObject: false, - Cursor: false, - Result: true, - DynValue: true, - Dyn: false, + LazyObject: false, + Cursor: false, + Result: true, + DynValue: true, + Dyn: false, } as const export const support = { - LazyObject: tsf.createIdentifier('LazyObject'), - Cursor: tsf.createTypeReferenceNode(tsf.createIdentifier('Cursor')), - Result: (t0: ts.TypeNode, t1: ts.TypeNode) => - tsf.createTypeReferenceNode(tsf.createIdentifier('Result'), [t0, t1]), - DynValue: 'DynValue', - Dyn: tsf.createIdentifier('Dyn'), + LazyObject: tsf.createIdentifier('LazyObject'), + Cursor: tsf.createTypeReferenceNode(tsf.createIdentifier('Cursor')), + Result: (t0: ts.TypeNode, t1: ts.TypeNode) => + tsf.createTypeReferenceNode(tsf.createIdentifier('Result'), [t0, t1]), + DynValue: 'DynValue', + Dyn: tsf.createIdentifier('Dyn'), } as const const cursorMethods = { - readString: primitiveReader('readString'), - readBool: primitiveReader('readBool'), - readU32: primitiveReader('readU32'), - readI32: primitiveReader('readI32'), - readU64: primitiveReader('readU64'), - readI64: primitiveReader('readI64'), - readPointer: primitiveReader('readPointer'), - readSequence: readerTransformerSized('readSequence'), - readOption: readerTransformer('readOption'), - readResult: readerTransformerTwoTyped('readResult'), + readString: primitiveReader('readString'), + readBool: primitiveReader('readBool'), + readU32: primitiveReader('readU32'), + readI32: primitiveReader('readI32'), + readU64: primitiveReader('readU64'), + readI64: primitiveReader('readI64'), + readPointer: primitiveReader('readPointer'), + readSequence: readerTransformerSized('readSequence'), + readOption: readerTransformer('readOption'), + readResult: readerTransformerTwoTyped('readResult'), } as const const dynBuilders = { - Primitive: dynReader('Primitive'), - Result: dynReader('Result'), - Sequence: dynReader('Sequence'), - Option: dynReader('Option'), - Object: dynReader('Object'), + Primitive: dynReader('Primitive'), + Result: dynReader('Result'), + Sequence: dynReader('Sequence'), + Option: dynReader('Option'), + Object: dynReader('Object'), } as const type ExpressionTransformer = (expression: ts.Expression) => ts.Expression - // === Public API === export class Type { - readonly type: ts.TypeNode - readonly reader: ExpressionTransformer - readonly dynReader: ExpressionTransformer - readonly size: number + readonly type: ts.TypeNode + readonly reader: ExpressionTransformer + readonly dynReader: ExpressionTransformer + readonly size: number - private constructor(type: ts.TypeNode, reader: ExpressionTransformer, dynReader: ExpressionTransformer, size: number) { - this.type = type - this.reader = reader - this.dynReader = dynReader - this.size = size - } + private constructor( + type: ts.TypeNode, + reader: ExpressionTransformer, + dynReader: ExpressionTransformer, + size: number, + ) { + this.type = type + this.reader = reader + this.dynReader = dynReader + this.size = size + } - static Abstract(name: string): Type { - const valueReader = abstractTypeReader(name) - return new Type(tsf.createTypeReferenceNode(name), valueReader, dynBuilders.Object(valueReader), POINTER_SIZE) - } + static Abstract(name: string): Type { + const valueReader = abstractTypeReader(name) + return new Type( + tsf.createTypeReferenceNode(name), + valueReader, + dynBuilders.Object(valueReader), + POINTER_SIZE, + ) + } - static Concrete(name: string, size: number): Type { - const valueReader = concreteTypeReader(name) - return new Type(tsf.createTypeReferenceNode(name), valueReader, dynBuilders.Object(valueReader), size) - } + static Concrete(name: string, size: number): Type { + const valueReader = concreteTypeReader(name) + return new Type( + tsf.createTypeReferenceNode(name), + valueReader, + dynBuilders.Object(valueReader), + size, + ) + } - static Sequence(element: Type): Type { - return new Type( - tsf.createTypeReferenceNode('Iterable', [element.type]), - cursorMethods.readSequence(element.reader, element.size), - dynBuilders.Sequence(cursorMethods.readSequence(element.dynReader, element.size)), - POINTER_SIZE, - ) - } + static Sequence(element: Type): Type { + return new Type( + tsf.createTypeReferenceNode('Iterable', [element.type]), + cursorMethods.readSequence(element.reader, element.size), + dynBuilders.Sequence(cursorMethods.readSequence(element.dynReader, element.size)), + POINTER_SIZE, + ) + } - static Option(element: Type): Type { - return new Type( - tsf.createUnionTypeNode([element.type, noneType]), - cursorMethods.readOption(element.reader), - dynBuilders.Option(cursorMethods.readOption(element.dynReader)), - POINTER_SIZE + 1, - ) - } + static Option(element: Type): Type { + return new Type( + tsf.createUnionTypeNode([element.type, noneType]), + cursorMethods.readOption(element.reader), + dynBuilders.Option(cursorMethods.readOption(element.dynReader)), + POINTER_SIZE + 1, + ) + } - static Result(ok: Type, err: Type): Type { - return new Type( - support.Result(ok.type, err.type), - cursorMethods.readResult(ok.reader, err.reader), - dynBuilders.Result(cursorMethods.readResult(ok.dynReader, err.dynReader)), - POINTER_SIZE, - ) - } + static Result(ok: Type, err: Type): Type { + return new Type( + support.Result(ok.type, err.type), + cursorMethods.readResult(ok.reader, err.reader), + dynBuilders.Result(cursorMethods.readResult(ok.dynReader, err.dynReader)), + POINTER_SIZE, + ) + } - static Boolean: Type = new Type(tsf.createTypeReferenceNode('boolean'), cursorMethods.readBool, dynBuilders.Primitive(cursorMethods.readBool), 1) - static UInt32: Type = new Type(tsf.createTypeReferenceNode('number'), cursorMethods.readU32, dynBuilders.Primitive(cursorMethods.readU32), 4) - static Int32: Type = new Type(tsf.createTypeReferenceNode('number'), cursorMethods.readI32, dynBuilders.Primitive(cursorMethods.readI32), 4) - static UInt64: Type = new Type(tsf.createTypeReferenceNode('bigint'), cursorMethods.readU64, dynBuilders.Primitive(cursorMethods.readU64), 8) - static Int64: Type = new Type(tsf.createTypeReferenceNode('bigint'), cursorMethods.readI64, dynBuilders.Primitive(cursorMethods.readI64), 8) - static Char: Type = new Type(tsf.createTypeReferenceNode('number'), cursorMethods.readU32, dynBuilders.Primitive(cursorMethods.readU32), 4) - static String: Type = new Type(tsf.createTypeReferenceNode('string'), cursorMethods.readString, dynBuilders.Primitive(cursorMethods.readString), POINTER_SIZE) + static Boolean: Type = new Type( + tsf.createTypeReferenceNode('boolean'), + cursorMethods.readBool, + dynBuilders.Primitive(cursorMethods.readBool), + 1, + ) + static UInt32: Type = new Type( + tsf.createTypeReferenceNode('number'), + cursorMethods.readU32, + dynBuilders.Primitive(cursorMethods.readU32), + 4, + ) + static Int32: Type = new Type( + tsf.createTypeReferenceNode('number'), + cursorMethods.readI32, + dynBuilders.Primitive(cursorMethods.readI32), + 4, + ) + static UInt64: Type = new Type( + tsf.createTypeReferenceNode('bigint'), + cursorMethods.readU64, + dynBuilders.Primitive(cursorMethods.readU64), + 8, + ) + static Int64: Type = new Type( + tsf.createTypeReferenceNode('bigint'), + cursorMethods.readI64, + dynBuilders.Primitive(cursorMethods.readI64), + 8, + ) + static Char: Type = new Type( + tsf.createTypeReferenceNode('number'), + cursorMethods.readU32, + dynBuilders.Primitive(cursorMethods.readU32), + 4, + ) + static String: Type = new Type( + tsf.createTypeReferenceNode('string'), + cursorMethods.readString, + dynBuilders.Primitive(cursorMethods.readString), + POINTER_SIZE, + ) } export function seekCursor(cursor: ts.Expression, offset: number): ts.Expression { - if (offset === 0) { - return cursor - } else { - return tsf.createCallExpression( - tsf.createPropertyAccessExpression(cursor, 'seek'), - [], - [tsf.createNumericLiteral(offset)], - ) - } + if (offset === 0) { + return cursor + } else { + return tsf.createCallExpression( + tsf.createPropertyAccessExpression(cursor, 'seek'), + [], + [tsf.createNumericLiteral(offset)], + ) + } } export function abstractTypeDeserializer( - ident: ts.Identifier, - cases: ts.CaseClause[], + ident: ts.Identifier, + cases: ts.CaseClause[], ): ts.FunctionDeclaration { - const cursorIdent = tsf.createIdentifier('cursor') - return tsf.createFunctionDeclaration( - [modifiers.export], - undefined, - 'read', + const cursorIdent = tsf.createIdentifier('cursor') + return tsf.createFunctionDeclaration( + [modifiers.export], + undefined, + 'read', + [], + [ + tsf.createParameterDeclaration( [], - [ - tsf.createParameterDeclaration( - [], - undefined, - cursorIdent, - undefined, - support.Cursor, - undefined, - ), - ], - tsf.createTypeReferenceNode(ident), - tsf.createBlock([ - tsf.createSwitchStatement( - cursorMethods.readU32(cursorIdent), - casesOrThrow(cases, 'Unexpected discriminant while deserializing.'), - ), - ]), - ) -} - -export function fieldDeserializer(ident: ts.Identifier, type: Type, offset: number): ts.GetAccessorDeclaration { - return tsf.createGetAccessorDeclaration( - [], - ident, - [], - type.type, - tsf.createBlock([ - tsf.createReturnStatement( - type.reader( - seekCursor( - tsf.createPropertyAccessExpression(tsf.createThis(), cursorFieldIdent), - offset, - ), - ), - ), - ]), - ) + undefined, + cursorIdent, + undefined, + support.Cursor, + undefined, + ), + ], + tsf.createTypeReferenceNode(ident), + tsf.createBlock([ + tsf.createSwitchStatement( + cursorMethods.readU32(cursorIdent), + casesOrThrow(cases, 'Unexpected discriminant while deserializing.'), + ), + ]), + ) } -export function fieldDynValue(type: Type, offset: number): ts.Expression { - return type.dynReader( - seekCursor( +export function fieldDeserializer( + ident: ts.Identifier, + type: Type, + offset: number, +): ts.GetAccessorDeclaration { + return tsf.createGetAccessorDeclaration( + [], + ident, + [], + type.type, + tsf.createBlock([ + tsf.createReturnStatement( + type.reader( + seekCursor( tsf.createPropertyAccessExpression(tsf.createThis(), cursorFieldIdent), offset, + ), ), - ) + ), + ]), + ) } +export function fieldDynValue(type: Type, offset: number): ts.Expression { + return type.dynReader( + seekCursor(tsf.createPropertyAccessExpression(tsf.createThis(), cursorFieldIdent), offset), + ) +} // === Implementation === /** Returns a function that, given an expression evaluating to a [`Cursor`], returns an expression applying a * deserialization method with the given name to the cursor. */ function primitiveReader(name: string): ExpressionTransformer { - return (cursor) => - tsf.createCallExpression(tsf.createPropertyAccessExpression(cursor, name), [], []) + return (cursor) => + tsf.createCallExpression(tsf.createPropertyAccessExpression(cursor, name), [], []) } /** @@ -203,122 +251,122 @@ function primitiveReader(name: string): ExpressionTransformer { * create a `readerTransformer('readOption')`, we can apply it to the number reader to yield an optional-number reader. */ function readerTransformer( - name: string, + name: string, ): (readElement: ExpressionTransformer) => ExpressionTransformer { - const innerParameter = tsf.createIdentifier('element') - return (readElement: ExpressionTransformer) => (cursor: ts.Expression) => { - return tsf.createCallExpression( - tsf.createPropertyAccessExpression(cursor, name), - [], - [ - tsf.createArrowFunction( - [], - [], - [ - tsf.createParameterDeclaration( - [], - undefined, - innerParameter, - undefined, - support.Cursor, - undefined, - ), - ], - undefined, - undefined, - readElement(innerParameter), - ), - ], - ) - } + const innerParameter = tsf.createIdentifier('element') + return (readElement: ExpressionTransformer) => (cursor: ts.Expression) => { + return tsf.createCallExpression( + tsf.createPropertyAccessExpression(cursor, name), + [], + [ + tsf.createArrowFunction( + [], + [], + [ + tsf.createParameterDeclaration( + [], + undefined, + innerParameter, + undefined, + support.Cursor, + undefined, + ), + ], + undefined, + undefined, + readElement(innerParameter), + ), + ], + ) + } } /** Similar to [`readerTransformer`], but for deserialization-transformers that produce a reader by combining two input * readers. */ function readerTransformerTwoTyped( - name: string, + name: string, ): (readOk: ExpressionTransformer, readErr: ExpressionTransformer) => ExpressionTransformer { - function makeArrow(reader: ExpressionTransformer, data: ts.Identifier) { - return tsf.createArrowFunction( - [], - [], - [tsf.createParameterDeclaration([], undefined, data, undefined, support.Cursor, undefined)], - undefined, - undefined, - reader(data), - ) - } + function makeArrow(reader: ExpressionTransformer, data: ts.Identifier) { + return tsf.createArrowFunction( + [], + [], + [tsf.createParameterDeclaration([], undefined, data, undefined, support.Cursor, undefined)], + undefined, + undefined, + reader(data), + ) + } - const okData = tsf.createIdentifier('okData') - const errData = tsf.createIdentifier('errData') - return (readOk: ExpressionTransformer, readErr: ExpressionTransformer) => - (cursor: ts.Expression) => { - return tsf.createCallExpression( - tsf.createPropertyAccessExpression(cursor, name), - [], - [makeArrow(readOk, okData), makeArrow(readErr, errData)], - ) - } + const okData = tsf.createIdentifier('okData') + const errData = tsf.createIdentifier('errData') + return (readOk: ExpressionTransformer, readErr: ExpressionTransformer) => + (cursor: ts.Expression) => { + return tsf.createCallExpression( + tsf.createPropertyAccessExpression(cursor, name), + [], + [makeArrow(readOk, okData), makeArrow(readErr, errData)], + ) + } } /** Similar to [`readerTransformer`], but for deserialization-transformers are parameterized by the size of their * element. */ function readerTransformerSized( - name: string, + name: string, ): (readElement: ExpressionTransformer, size: number) => ExpressionTransformer { - const innerParameter = tsf.createIdentifier('element') - return (readElement: ExpressionTransformer, size: number) => (cursor: ts.Expression) => { - return tsf.createCallExpression( - tsf.createPropertyAccessExpression(cursor, name), - [], - [ - tsf.createArrowFunction( - [], - [], - [ - tsf.createParameterDeclaration( - [], - undefined, - innerParameter, - undefined, - support.Cursor, - undefined, - ), - ], - undefined, - undefined, - readElement(innerParameter), - ), - tsf.createNumericLiteral(size), - ], - ) - } + const innerParameter = tsf.createIdentifier('element') + return (readElement: ExpressionTransformer, size: number) => (cursor: ts.Expression) => { + return tsf.createCallExpression( + tsf.createPropertyAccessExpression(cursor, name), + [], + [ + tsf.createArrowFunction( + [], + [], + [ + tsf.createParameterDeclaration( + [], + undefined, + innerParameter, + undefined, + support.Cursor, + undefined, + ), + ], + undefined, + undefined, + readElement(innerParameter), + ), + tsf.createNumericLiteral(size), + ], + ) + } } function dynReader(name: string): (readValue: ExpressionTransformer) => ExpressionTransformer { - return (readValue: ExpressionTransformer) => (cursor: ts.Expression) => { - return tsf.createCallExpression( - tsf.createPropertyAccessExpression(support.Dyn, name), - [], - [readValue(cursor)] - ) - } + return (readValue: ExpressionTransformer) => (cursor: ts.Expression) => { + return tsf.createCallExpression( + tsf.createPropertyAccessExpression(support.Dyn, name), + [], + [readValue(cursor)], + ) + } } function abstractTypeReader(name: string): ExpressionTransformer { - return (cursor: ts.Expression) => - tsf.createCallExpression( - tsf.createPropertyAccessExpression(tsf.createIdentifier(name), 'read'), - [], - [cursorMethods.readPointer(cursor)], - ) + return (cursor: ts.Expression) => + tsf.createCallExpression( + tsf.createPropertyAccessExpression(tsf.createIdentifier(name), 'read'), + [], + [cursorMethods.readPointer(cursor)], + ) } function concreteTypeReader(name: string): ExpressionTransformer { - return (cursor: ts.Expression) => - tsf.createCallExpression( - tsf.createPropertyAccessExpression(tsf.createIdentifier(name), 'read'), - [], - [cursor], - ) + return (cursor: ts.Expression) => + tsf.createCallExpression( + tsf.createPropertyAccessExpression(tsf.createIdentifier(name), 'read'), + [], + [cursor], + ) } diff --git a/app/gui2/parser-codegen/src/util.ts b/app/gui2/parser-codegen/src/util.ts index 3576278d095b..d3cf29f4dcde 100644 --- a/app/gui2/parser-codegen/src/util.ts +++ b/app/gui2/parser-codegen/src/util.ts @@ -1,85 +1,87 @@ import * as changeCase from 'change-case' -import ts from "typescript"; +import ts from 'typescript' const { factory: tsf } = ts - // === Identifier utilities === export function toPascal(ident: string): string { - if (ident.includes('.')) throw new Error("toPascal cannot be applied to a namespaced name.") - return changeCase.pascalCase(ident) + if (ident.includes('.')) throw new Error('toPascal cannot be applied to a namespaced name.') + return changeCase.pascalCase(ident) } export function toCamel(ident: string): string { - if (ident.includes('.')) throw new Error("toCamel cannot be applied to a namespaced name.") - return changeCase.camelCase(ident) + if (ident.includes('.')) throw new Error('toCamel cannot be applied to a namespaced name.') + return changeCase.camelCase(ident) } const RENAME = new Map([ - ['constructor', 'ident'], - ['type', 'typeNode'], - ['spanLeftOffsetCodeOffsetUtf16', 'whitespaceStart'], - ['spanLeftOffsetCodeUtf16', 'whitespaceLength'], - ['leftOffsetCodeOffsetUtf16', 'whitespaceStart'], - ['leftOffsetCodeUtf16', 'whitespaceLength'], - ['spanCodeLengthUtf16', 'childrenCodeLength'], - ['codeUtf16', 'codeLength'], - ['codeOffsetUtf16', 'codeStart'], + ['constructor', 'ident'], + ['type', 'typeNode'], + ['spanLeftOffsetCodeOffsetUtf16', 'whitespaceStart'], + ['spanLeftOffsetCodeUtf16', 'whitespaceLength'], + ['leftOffsetCodeOffsetUtf16', 'whitespaceStart'], + ['leftOffsetCodeUtf16', 'whitespaceLength'], + ['spanCodeLengthUtf16', 'childrenCodeLength'], + ['codeUtf16', 'codeLength'], + ['codeOffsetUtf16', 'codeStart'], ]) export function mapIdent(ident: string): string { - return RENAME.get(ident) ?? ident + return RENAME.get(ident) ?? ident } export function namespacedName(name: string, namespace?: string): string { - if (namespace == null) { - return toPascal(name) - } else { - return toPascal(namespace) + '.' + toPascal(name) - } + if (namespace == null) { + return toPascal(name) + } else { + return toPascal(namespace) + '.' + toPascal(name) + } } - // === AST utilities === export const modifiers = { - export: tsf.createModifier(ts.SyntaxKind.ExportKeyword), - const: tsf.createModifier(ts.SyntaxKind.ConstKeyword), - readonly: tsf.createModifier(ts.SyntaxKind.ReadonlyKeyword), - abstract: tsf.createModifier(ts.SyntaxKind.AbstractKeyword), - static: tsf.createModifier(ts.SyntaxKind.StaticKeyword), - protected: tsf.createModifier(ts.SyntaxKind.ProtectedKeyword), + export: tsf.createModifier(ts.SyntaxKind.ExportKeyword), + const: tsf.createModifier(ts.SyntaxKind.ConstKeyword), + readonly: tsf.createModifier(ts.SyntaxKind.ReadonlyKeyword), + abstract: tsf.createModifier(ts.SyntaxKind.AbstractKeyword), + static: tsf.createModifier(ts.SyntaxKind.StaticKeyword), + protected: tsf.createModifier(ts.SyntaxKind.ProtectedKeyword), } as const export function assignmentStatement(left: ts.Expression, right: ts.Expression): ts.Statement { - return tsf.createExpressionStatement( - tsf.createBinaryExpression(left, ts.SyntaxKind.EqualsToken, right), - ) + return tsf.createExpressionStatement( + tsf.createBinaryExpression(left, ts.SyntaxKind.EqualsToken, right), + ) } -export function forwardToSuper(ident: ts.Identifier, type: ts.TypeNode, modifiers?: ts.ModifierLike[]) { - return tsf.createConstructorDeclaration( - modifiers, - [tsf.createParameterDeclaration([], undefined, ident, undefined, type, undefined)], - tsf.createBlock([ - tsf.createExpressionStatement( - tsf.createCallExpression(tsf.createIdentifier('super'), [], [ident]), - ), - ]), - ) +export function forwardToSuper( + ident: ts.Identifier, + type: ts.TypeNode, + modifiers?: ts.ModifierLike[], +) { + return tsf.createConstructorDeclaration( + modifiers, + [tsf.createParameterDeclaration([], undefined, ident, undefined, type, undefined)], + tsf.createBlock([ + tsf.createExpressionStatement( + tsf.createCallExpression(tsf.createIdentifier('super'), [], [ident]), + ), + ]), + ) } export function casesOrThrow(cases: ts.CaseClause[], error: string): ts.CaseBlock { - return tsf.createCaseBlock([ - ...cases, - tsf.createDefaultClause([ - tsf.createThrowStatement( - tsf.createNewExpression( - tsf.createIdentifier('Error'), - [], - [tsf.createStringLiteral(error)], - ), - ), - ]), - ]) + return tsf.createCaseBlock([ + ...cases, + tsf.createDefaultClause([ + tsf.createThrowStatement( + tsf.createNewExpression( + tsf.createIdentifier('Error'), + [], + [tsf.createStringLiteral(error)], + ), + ), + ]), + ]) } diff --git a/app/gui2/parser-codegen/tsconfig.json b/app/gui2/parser-codegen/tsconfig.json index 5fb0258ccea2..091490356cfd 100644 --- a/app/gui2/parser-codegen/tsconfig.json +++ b/app/gui2/parser-codegen/tsconfig.json @@ -8,5 +8,5 @@ "outDir": "dist", "types": ["node"] }, - "include": [ "src/**/*" ] + "include": ["src/**/*"] } diff --git a/app/gui2/src/util/ffi.ts b/app/gui2/src/util/ffi.ts index 5aed49d3a8f6..666efa5d3bd8 100644 --- a/app/gui2/src/util/ffi.ts +++ b/app/gui2/src/util/ffi.ts @@ -1,6 +1,6 @@ import type { NonEmptyArray } from '@/util/array' import type { Opt } from '@/util/opt' -import {debug, validateSpans} from '@/util/parserSupport' +import { debug, validateSpans } from '@/util/parserSupport' import init, { parse, parse_doc_to_json, parse_to_json } from '../../rust-ffi/pkg/rust_ffi' import * as Ast2 from '../generated/ast' @@ -530,7 +530,7 @@ export namespace Doc { mark: Mark header?: string body: HtmlString - } + } } } @@ -583,7 +583,7 @@ if (import.meta.vitest) { codeLength: 1, whitespaceLength: 0, }, - } + }, ], type: 'BodyBlock', }) diff --git a/app/gui2/src/util/parserSupport.ts b/app/gui2/src/util/parserSupport.ts index 3294030fd401..477e3b0de8f9 100644 --- a/app/gui2/src/util/parserSupport.ts +++ b/app/gui2/src/util/parserSupport.ts @@ -1,35 +1,41 @@ /** This file supports the module in `../generated/ast.ts` that is produced by `parser-codegen`. */ export { type Result } from '@/util/result' -import {Err, Error, Ok, type Result} from '@/util/result' +import { Err, Error, Ok, type Result } from '@/util/result' export type Primitive = { - type: 'primitive', + type: 'primitive' value: boolean | number | bigint | string } export type DynValue = Primitive | DynSequence | DynResult | DynOption | DynObject export type DynResult = { - type: 'result', - value: Result, + type: 'result' + value: Result } export type DynSequence = { - type: 'sequence', - value: Iterable, + type: 'sequence' + value: Iterable } export type DynOption = { - type: 'option', - value: DynValue | undefined, + type: 'option' + value: DynValue | undefined } export type DynObject = { - type: 'object', - getFields: () => [string, DynValue][], + type: 'object' + getFields: () => [string, DynValue][] } export const Dyn = { - Primitive: (value: boolean | number | bigint | string): DynValue => ({ type: 'primitive', value: value }), + Primitive: (value: boolean | number | bigint | string): DynValue => ({ + type: 'primitive', + value: value, + }), Result: (value: Result): DynValue => ({ type: 'result', value: value }), Sequence: (value: Iterable): DynValue => ({ type: 'sequence', value: value }), Option: (value: DynValue | undefined): DynValue => ({ type: 'option', value: value }), - Object: (value: LazyObject): DynValue => ({ type: 'object', getFields: value.fields.bind(value) }), + Object: (value: LazyObject): DynValue => ({ + type: 'object', + getFields: value.fields.bind(value), + }), } as const /** Base class for objects that lazily deserialize fields when accessed. */ @@ -96,7 +102,7 @@ export class Cursor { } readPointer(): Cursor { - const pointee = this.readU32(); + const pointee = this.readU32() return new Cursor(this.blob.buffer, pointee) } @@ -159,15 +165,11 @@ function debug_(value: DynValue): any { case 'sequence': return Array.from(value.value, debug_) case 'result': - if (value.value.ok) - return Ok(debug_(value.value.value)) - else - return Err(debug_(value.value.error.payload)) + if (value.value.ok) return Ok(debug_(value.value.value)) + else return Err(debug_(value.value.error.payload)) case 'option': - if (value.value != null) - return debug_(value.value) - else - return undefined + if (value.value != null) return debug_(value.value) + else return undefined case 'object': // FIXME: Include the `hide` reflect property in the schema, and apply it during code generation to avoid magic // strings here. @@ -181,7 +183,12 @@ function debug_(value: DynValue): any { 'spanLeftOffsetCodeReprLen', 'spanLeftOffsetVisible', ] - return Object.fromEntries(value.getFields().filter(([name, _]) => !hide.includes(name)).map(([name, value]) => [name, debug_(value)])) + return Object.fromEntries( + value + .getFields() + .filter(([name, _]) => !hide.includes(name)) + .map(([name, value]) => [name, debug_(value)]), + ) case 'primitive': return value.value } @@ -196,18 +203,14 @@ export function validateSpans(obj: LazyObject, initialPos?: number): number { function validateSpans_(value: DynValue, state: { pos: number }) { switch (value.type) { case 'sequence': - for (const elem of value.value) - validateSpans_(elem, state) + for (const elem of value.value) validateSpans_(elem, state) break case 'result': - if (value.value.ok) - validateSpans_(value.value.value, state) - else - validateSpans_(value.value.error.payload, state) + if (value.value.ok) validateSpans_(value.value.value, state) + else validateSpans_(value.value.error.payload, state) break case 'option': - if (value.value != null) - validateSpans_(value.value, state) + if (value.value != null) validateSpans_(value.value, state) break case 'object': const fields = new Map(value.getFields()) @@ -216,16 +219,20 @@ function validateSpans_(value: DynValue, state: { pos: number }) { const codeStart = fields.get('codeStart') const codeLength = fields.get('codeLength') const childrenCodeLength = fields.get('childrenCodeLength') - if (!(whitespaceLength?.type === 'primitive' && whitespaceLength.value === 0 - && codeLength?.type === 'primitive' && codeLength?.value === 0)) { + if ( + !( + whitespaceLength?.type === 'primitive' && + whitespaceLength.value === 0 && + codeLength?.type === 'primitive' && + codeLength?.value === 0 + ) + ) { if (whitespaceStart?.type === 'primitive' && whitespaceStart.value !== state.pos) throw new Error(`Span error (whitespace) in: ${JSON.stringify(debug_(value))}.`) - if (whitespaceLength?.type === 'primitive') - state.pos += whitespaceLength.value as number + if (whitespaceLength?.type === 'primitive') state.pos += whitespaceLength.value as number if (codeStart?.type === 'primitive' && codeStart.value !== state.pos) throw new Error('Span error (code).') - if (codeLength?.type === 'primitive') - state.pos += codeLength.value as number + if (codeLength?.type === 'primitive') state.pos += codeLength.value as number } let endPos: number | undefined if (childrenCodeLength?.type === 'primitive') @@ -234,8 +241,7 @@ function validateSpans_(value: DynValue, state: { pos: number }) { const [_name, value] = entry validateSpans_(value, state) } - if (endPos != null && state.pos !== endPos) - throw new Error('Span error (children).') + if (endPos != null && state.pos !== endPos) throw new Error('Span error (children).') break case 'primitive': break From 73963b19acf45cff37116c8894243943328f7e60 Mon Sep 17 00:00:00 2001 From: Kaz Wesley Date: Tue, 10 Oct 2023 08:39:13 -0700 Subject: [PATCH 40/44] Docs. --- lib/rust/parser/src/lib.rs | 6 +++--- lib/rust/parser/src/macros/built_in.rs | 3 ++- lib/rust/parser/src/source/code.rs | 15 +++++++++------ lib/rust/parser/src/source/span.rs | 17 ++++++++++------- lib/rust/parser/src/syntax/token.rs | 8 +++++--- lib/rust/parser/src/syntax/tree.rs | 6 +++--- 6 files changed, 32 insertions(+), 23 deletions(-) diff --git a/lib/rust/parser/src/lib.rs b/lib/rust/parser/src/lib.rs index 7b7e3546c73f..6a01af76f865 100644 --- a/lib/rust/parser/src/lib.rs +++ b/lib/rust/parser/src/lib.rs @@ -344,7 +344,7 @@ pub fn parse_argument_application<'s>( match &mut expression.variant { box Variant::App(App { func, arg }) => { let arg = parse_argument_definition(arg.clone()); - func.span.left_offset += expression.span.left_offset.take(); + func.span.left_offset += expression.span.left_offset.take_as_prefix(); *expression = func.clone(); Some(arg) } @@ -358,7 +358,7 @@ pub fn parse_argument_application<'s>( let close2 = default(); let type_ = default(); let default = Some(ArgumentDefault { equals, expression: arg.clone() }); - func.span.left_offset += expression.span.left_offset.take(); + func.span.left_offset += expression.span.left_offset.take_as_prefix(); *expression = func.clone(); Some(ArgumentDefinition { open, @@ -373,7 +373,7 @@ pub fn parse_argument_application<'s>( } box Variant::DefaultApp(DefaultApp { func, default: default_ }) => { let pattern = Tree::ident(default_.clone()); - func.span.left_offset += expression.span.left_offset.take(); + func.span.left_offset += expression.span.left_offset.take_as_prefix(); *expression = func.clone(); Some(ArgumentDefinition { open: default(), diff --git a/lib/rust/parser/src/macros/built_in.rs b/lib/rust/parser/src/macros/built_in.rs index 64ef482b6e16..8dbad9925cdb 100644 --- a/lib/rust/parser/src/macros/built_in.rs +++ b/lib/rust/parser/src/macros/built_in.rs @@ -437,7 +437,8 @@ fn case_body<'s>( _ => initial_case.push(item), } } - if let Some(first) = initial_case.first() { + if let Some(_first) = initial_case.first() { + // FIXME: Create 0-length span at offset preceding `_first`. let newline = syntax::token::newline(Code::empty_without_offset(), Code::empty_without_offset()); case_builder.push(syntax::item::Line { newline, items: initial_case }); diff --git a/lib/rust/parser/src/source/code.rs b/lib/rust/parser/src/source/code.rs index f0364fc3e522..7be3332fd7b2 100644 --- a/lib/rust/parser/src/source/code.rs +++ b/lib/rust/parser/src/source/code.rs @@ -44,8 +44,10 @@ impl<'s> Code<'s> { Self::from_str_at_offset(repr, 0) } + /// Return a copy of this value, and set this value to a 0-length value following the returned + /// value. #[inline(always)] - pub fn take(&mut self) -> Self { + pub fn take_as_prefix(&mut self) -> Self { let end = self.offset_utf16 + self.utf16; Self { repr: mem::take(&mut self.repr), @@ -54,10 +56,12 @@ impl<'s> Code<'s> { } } + /// Return a 0-length `Code` located immediately before the start of this `Code`. pub fn position_before(&self) -> Self { Self { repr: default(), offset_utf16: self.offset_utf16, utf16: default() } } + /// Return a 0-length `Code` located immediately after the end of this `Code`. pub fn position_after(&self) -> Self { Self { repr: default(), @@ -66,6 +70,7 @@ impl<'s> Code<'s> { } } + /// Return the length in UTF-16 code units. pub fn len_utf16(&self) -> u32 { self.utf16 } @@ -117,12 +122,10 @@ impl<'s> Code<'s> { self.repr.is_empty() } + /// Return this value with its start position removed (set to 0). This can be used to compare + /// values ignoring offsets. pub fn without_offset(&self) -> Self { - Self { - repr: self.repr.clone(), - offset_utf16: default(), - utf16: self.utf16, - } + Self { repr: self.repr.clone(), offset_utf16: default(), utf16: self.utf16 } } } diff --git a/lib/rust/parser/src/source/span.rs b/lib/rust/parser/src/source/span.rs index 24256c11d9ad..cd243c348a2e 100644 --- a/lib/rust/parser/src/source/span.rs +++ b/lib/rust/parser/src/source/span.rs @@ -87,19 +87,25 @@ impl<'s> Offset<'s> { !self.is_empty() } + /// Return a copy of this value, and set this value to a 0-length offset following the returned + /// value. #[inline(always)] - pub fn take(&mut self) -> Self { - Self { visible: mem::take(&mut self.visible), code: self.code.take() } + pub fn take_as_prefix(&mut self) -> Self { + Self { visible: mem::take(&mut self.visible), code: self.code.take_as_prefix() } } + /// Return a 0-length `Span` representing the position before the start of this `Span`. pub fn position_before(&self) -> Self { Self { visible: default(), code: self.code.position_before() } } + /// Return a 0-length `Span` representing the position after the end of this `Span`. pub fn position_after(&self) -> Self { Self { visible: default(), code: self.code.position_before() } } + /// Return this value with its start position removed (set to 0). This can be used to compare + /// spans ignoring offsets. pub fn without_offset(&self) -> Self { Self { visible: self.visible, code: self.code.without_offset() } } @@ -155,10 +161,7 @@ pub struct Span<'s> { impl<'s> Span<'s> { /// Constructor. pub fn empty_without_offset() -> Self { - Self { - left_offset: Code::empty_without_offset().into(), - code_length: default(), - } + Self { left_offset: Code::empty_without_offset().into(), code_length: default() } } /// Check whether the span is empty. @@ -276,7 +279,7 @@ pub trait FirstChildTrim<'s> { impl<'s> FirstChildTrim<'s> for Span<'s> { #[inline(always)] fn trim_as_first_child(&mut self) -> Span<'s> { - let left_offset = self.left_offset.take(); + let left_offset = self.left_offset.take_as_prefix(); let code_length = self.code_length; Span { left_offset, code_length } } diff --git a/lib/rust/parser/src/syntax/token.rs b/lib/rust/parser/src/syntax/token.rs index a219e24f382d..640934f3ddf5 100644 --- a/lib/rust/parser/src/syntax/token.rs +++ b/lib/rust/parser/src/syntax/token.rs @@ -171,11 +171,13 @@ impl<'s, T> Token<'s, T> { } impl<'s, V: Clone> Token<'s, V> { + /// Return this value with all source references stripped of positions. This supports comparing + /// tokens irrespective of their locations in the source. pub fn without_offsets(&self) -> Self { Self { left_offset: self.left_offset.without_offset(), - code: self.code.without_offset(), - variant: self.variant.clone(), + code: self.code.without_offset(), + variant: self.variant.clone(), } } } @@ -189,7 +191,7 @@ impl<'s, T: PartialEq> PartialEq> for &Token<'s, T> { impl<'s, T> FirstChildTrim<'s> for Token<'s, T> { #[inline(always)] fn trim_as_first_child(&mut self) -> Span<'s> { - let left_offset = self.left_offset.take(); + let left_offset = self.left_offset.take_as_prefix(); let code_length = self.code.length(); Span { left_offset, code_length } } diff --git a/lib/rust/parser/src/syntax/tree.rs b/lib/rust/parser/src/syntax/tree.rs index 3120bee71c98..6b0341e361e8 100644 --- a/lib/rust/parser/src/syntax/tree.rs +++ b/lib/rust/parser/src/syntax/tree.rs @@ -764,7 +764,7 @@ pub fn apply<'s>(mut func: Tree<'s>, mut arg: Tree<'s>) -> Tree<'s> { func } (_, Variant::ArgumentBlockApplication(block)) if block.lhs.is_none() => { - let func_left_offset = func.span.left_offset.take(); + let func_left_offset = func.span.left_offset.take_as_prefix(); let arg_left_offset = mem::replace(&mut arg.span.left_offset, func_left_offset); if let Some(first) = block.arguments.first_mut() { first.newline.left_offset += arg_left_offset; @@ -773,7 +773,7 @@ pub fn apply<'s>(mut func: Tree<'s>, mut arg: Tree<'s>) -> Tree<'s> { arg } (_, Variant::OperatorBlockApplication(block)) if block.lhs.is_none() => { - let func_left_offset = func.span.left_offset.take(); + let func_left_offset = func.span.left_offset.take_as_prefix(); let arg_left_offset = mem::replace(&mut arg.span.left_offset, func_left_offset); if let Some(first) = block.expressions.first_mut() { first.newline.left_offset += arg_left_offset; @@ -903,7 +903,7 @@ pub fn apply_operator<'s>( if let Variant::ArgumentBlockApplication(block) = &mut *rhs_.variant { if block.lhs.is_none() { if let Some(first) = block.arguments.first_mut() { - first.newline.left_offset += rhs_.span.left_offset.take(); + first.newline.left_offset += rhs_.span.left_offset.take_as_prefix(); } let ArgumentBlockApplication { lhs: _, arguments } = block; let arguments = mem::take(arguments); From d7dd38e437c76587ab0ae331b55680753b86f715 Mon Sep 17 00:00:00 2001 From: Kaz Wesley Date: Tue, 10 Oct 2023 08:54:36 -0700 Subject: [PATCH 41/44] Change field names --- app/gui2/parser-codegen/src/util.ts | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/app/gui2/parser-codegen/src/util.ts b/app/gui2/parser-codegen/src/util.ts index d3cf29f4dcde..2f530ede12ca 100644 --- a/app/gui2/parser-codegen/src/util.ts +++ b/app/gui2/parser-codegen/src/util.ts @@ -15,15 +15,19 @@ export function toCamel(ident: string): string { } const RENAME = new Map([ + // TS reserved words. ['constructor', 'ident'], ['type', 'typeNode'], - ['spanLeftOffsetCodeOffsetUtf16', 'whitespaceStart'], - ['spanLeftOffsetCodeUtf16', 'whitespaceLength'], - ['leftOffsetCodeOffsetUtf16', 'whitespaceStart'], - ['leftOffsetCodeUtf16', 'whitespaceLength'], - ['spanCodeLengthUtf16', 'childrenCodeLength'], - ['codeUtf16', 'codeLength'], - ['codeOffsetUtf16', 'codeStart'], + // Rename source references to reflect our usage: + // - In `Tree`s: + ['spanLeftOffsetCodeOffsetUtf16', 'whitespaceStartInCodeParsed'], + ['spanLeftOffsetCodeUtf16', 'whitespaceLengthInCodeParsed'], + ['spanCodeLengthUtf16', 'childrenCodeLengthInCodeParsed'], + // - In `Tokens`s: + ['leftOffsetCodeOffsetUtf16', 'whitespaceStartInCodeBuffer'], + ['leftOffsetCodeUtf16', 'whitespaceLengthInCodeBuffer'], + ['codeUtf16', 'lengthInCodeBuffer'], + ['codeOffsetUtf16', 'startInCodeBuffer'], ]) export function mapIdent(ident: string): string { From d048e1d5d4c21dc1c6c8af85bb804604cb158e7f Mon Sep 17 00:00:00 2001 From: Kaz Wesley Date: Tue, 10 Oct 2023 09:50:54 -0700 Subject: [PATCH 42/44] Update tests for new field names --- app/gui2/parser-codegen/src/util.ts | 2 +- app/gui2/src/util/ffi.ts | 42 ++++++++-------- app/gui2/src/util/parserSupport.ts | 12 +++-- package-lock.json | 74 +---------------------------- 4 files changed, 31 insertions(+), 99 deletions(-) diff --git a/app/gui2/parser-codegen/src/util.ts b/app/gui2/parser-codegen/src/util.ts index 2f530ede12ca..ea80e5b25ba1 100644 --- a/app/gui2/parser-codegen/src/util.ts +++ b/app/gui2/parser-codegen/src/util.ts @@ -22,7 +22,7 @@ const RENAME = new Map([ // - In `Tree`s: ['spanLeftOffsetCodeOffsetUtf16', 'whitespaceStartInCodeParsed'], ['spanLeftOffsetCodeUtf16', 'whitespaceLengthInCodeParsed'], - ['spanCodeLengthUtf16', 'childrenCodeLengthInCodeParsed'], + ['spanCodeLengthUtf16', 'childrenLengthInCodeParsed'], // - In `Tokens`s: ['leftOffsetCodeOffsetUtf16', 'whitespaceStartInCodeBuffer'], ['leftOffsetCodeUtf16', 'whitespaceLengthInCodeBuffer'], diff --git a/app/gui2/src/util/ffi.ts b/app/gui2/src/util/ffi.ts index 666efa5d3bd8..f00c364729cd 100644 --- a/app/gui2/src/util/ffi.ts +++ b/app/gui2/src/util/ffi.ts @@ -540,48 +540,48 @@ if (import.meta.vitest) { const identInput = ' foo bar\n' const tree = parseEnso2(identInput) expect(debug(tree)).toMatchObject({ - childrenCodeLength: 8, - whitespaceStart: 0, - whitespaceLength: 1, + childrenLengthInCodeParsed: 8, + whitespaceStartInCodeParsed: 0, + whitespaceLengthInCodeParsed: 1, statements: [ { expression: { arg: { - childrenCodeLength: 3, - whitespaceStart: 4, - whitespaceLength: 1, + childrenLengthInCodeParsed: 3, + whitespaceStartInCodeParsed: 4, + whitespaceLengthInCodeParsed: 1, token: { - codeStart: 5, - codeLength: 3, - whitespaceLength: 0, + startInCodeBuffer: 5, + lengthInCodeBuffer: 3, + whitespaceLengthInCodeBuffer: 0, }, type: 'Ident', }, func: { - childrenCodeLength: 3, - whitespaceLength: 0, + childrenLengthInCodeParsed: 3, + whitespaceLengthInCodeParsed: 0, token: { - codeStart: 1, - codeLength: 3, - whitespaceLength: 0, + startInCodeBuffer: 1, + lengthInCodeBuffer: 3, + whitespaceLengthInCodeBuffer: 0, }, type: 'Ident', }, - childrenCodeLength: 7, - whitespaceLength: 0, + childrenLengthInCodeParsed: 7, + whitespaceLengthInCodeParsed: 0, type: 'App', }, newline: { - codeLength: 0, - whitespaceLength: 0, + lengthInCodeBuffer: 0, + whitespaceLengthInCodeBuffer: 0, }, }, { expression: undefined, newline: { - codeStart: 8, - codeLength: 1, - whitespaceLength: 0, + startInCodeBuffer: 8, + lengthInCodeBuffer: 1, + whitespaceLengthInCodeBuffer: 0, }, }, ], diff --git a/app/gui2/src/util/parserSupport.ts b/app/gui2/src/util/parserSupport.ts index 477e3b0de8f9..69e57ce0197a 100644 --- a/app/gui2/src/util/parserSupport.ts +++ b/app/gui2/src/util/parserSupport.ts @@ -214,11 +214,13 @@ function validateSpans_(value: DynValue, state: { pos: number }) { break case 'object': const fields = new Map(value.getFields()) - const whitespaceStart = fields.get('whitespaceStart') - const whitespaceLength = fields.get('whitespaceLength') - const codeStart = fields.get('codeStart') - const codeLength = fields.get('codeLength') - const childrenCodeLength = fields.get('childrenCodeLength') + const whitespaceStart = + fields.get('whitespaceStartInCodeParsed') ?? fields.get('whitespaceStartInCodeBuffer') + const whitespaceLength = + fields.get('whitespaceLengthInCodeParsed') ?? fields.get('whitespaceLengthInCodeBuffer') + const codeStart = fields.get('startInCodeBuffer') + const codeLength = fields.get('lengthInCodeBuffer') + const childrenCodeLength = fields.get('childrenLengthInCodeParsed') if ( !( whitespaceLength?.type === 'primitive' && diff --git a/package-lock.json b/package-lock.json index 7459dda93d50..3b59f77d53b0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -46,7 +46,6 @@ "pinia": "^2.1.6", "postcss-inline-svg": "^6.0.0", "postcss-nesting": "^12.0.1", - "rollup-plugin-visualizer": "^5.9.2", "sha3": "^2.1.4", "sucrase": "^3.34.0", "vue": "^3.3.4", @@ -9916,6 +9915,7 @@ }, "node_modules/is-wsl": { "version": "2.2.0", + "dev": true, "license": "MIT", "dependencies": { "is-docker": "^2.0.0" @@ -9926,6 +9926,7 @@ }, "node_modules/is-wsl/node_modules/is-docker": { "version": "2.2.1", + "dev": true, "license": "MIT", "bin": { "is-docker": "cli.js" @@ -13528,77 +13529,6 @@ "rollup-plugin-inject": "^3.0.0" } }, - "node_modules/rollup-plugin-visualizer": { - "version": "5.9.2", - "resolved": "https://registry.npmjs.org/rollup-plugin-visualizer/-/rollup-plugin-visualizer-5.9.2.tgz", - "integrity": "sha512-waHktD5mlWrYFrhOLbti4YgQCn1uR24nYsNuXxg7LkPH8KdTXVWR9DNY1WU0QqokyMixVXJS4J04HNrVTMP01A==", - "dependencies": { - "open": "^8.4.0", - "picomatch": "^2.3.1", - "source-map": "^0.7.4", - "yargs": "^17.5.1" - }, - "bin": { - "rollup-plugin-visualizer": "dist/bin/cli.js" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "rollup": "2.x || 3.x" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, - "node_modules/rollup-plugin-visualizer/node_modules/define-lazy-prop": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", - "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", - "engines": { - "node": ">=8" - } - }, - "node_modules/rollup-plugin-visualizer/node_modules/is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/rollup-plugin-visualizer/node_modules/open": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", - "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", - "dependencies": { - "define-lazy-prop": "^2.0.0", - "is-docker": "^2.1.1", - "is-wsl": "^2.2.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/rollup-plugin-visualizer/node_modules/source-map": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", - "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", - "engines": { - "node": ">= 8" - } - }, "node_modules/rollup-pluginutils": { "version": "2.8.2", "dev": true, From 88d0fa1e3badbd66e4acd8da2029eafa2eb315c0 Mon Sep 17 00:00:00 2001 From: Kaz Wesley Date: Tue, 10 Oct 2023 13:47:11 -0700 Subject: [PATCH 43/44] Make prettier happier --- app/gui2/eslint.config.js | 3 +- app/gui2/parser-codegen/src/codegen.ts | 12 +++-- app/gui2/src/util/parserSupport.ts | 70 ++++++++++++++------------ 3 files changed, 47 insertions(+), 38 deletions(-) diff --git a/app/gui2/eslint.config.js b/app/gui2/eslint.config.js index a282d3d43b2c..1005e92a1dcd 100644 --- a/app/gui2/eslint.config.js +++ b/app/gui2/eslint.config.js @@ -9,7 +9,7 @@ const DIR_NAME = path.dirname(url.fileURLToPath(import.meta.url)) const conf = [ { - ignores: ['rust-ffi/pkg', 'dist'], + ignores: ['rust-ffi/pkg', 'dist', 'parser-codegen/dist', 'src/generated'], }, ...compat.extends('plugin:vue/vue3-recommended'), eslintJs.configs.recommended, @@ -26,6 +26,7 @@ const conf = [ './tsconfig.server.json', './tsconfig.app.vitest.json', './tsconfig.server.vitest.json', + './parser-codegen/tsconfig.json', ], }, }, diff --git a/app/gui2/parser-codegen/src/codegen.ts b/app/gui2/parser-codegen/src/codegen.ts index dc17c3d506e2..b0d9c036bfd8 100644 --- a/app/gui2/parser-codegen/src/codegen.ts +++ b/app/gui2/parser-codegen/src/codegen.ts @@ -84,7 +84,7 @@ export function implement(schema: Schema.Schema): string { function makeType(ref: Schema.TypeRef, schema: Schema.Schema): Type { const c = ref.class switch (c) { - case 'type': + case 'type': { const ty = schema.types[ref.id] const parent = ty.parent != null ? schema.types[ty.parent] : undefined const typeName = namespacedName(ty.name, parent?.name) @@ -94,7 +94,8 @@ function makeType(ref: Schema.TypeRef, schema: Schema.Schema): Type { } else { return Type.Concrete(typeName, layout.size) } - case 'primitive': + } + case 'primitive': { const p = ref.type switch (p) { case 'bool': @@ -111,19 +112,22 @@ function makeType(ref: Schema.TypeRef, schema: Schema.Schema): Type { return Type.Char case 'string': return Type.String - default: + default: { const _ = p satisfies never throw new Error("unreachable: PrimitiveType.type='" + p + "'") + } } + } case 'sequence': return Type.Sequence(makeType(ref.type, schema)) case 'option': return Type.Option(makeType(ref.type, schema)) case 'result': return Type.Result(makeType(ref.type0, schema), makeType(ref.type1, schema)) - default: + default: { const _ = c satisfies never throw new Error("unreachable: TypeRef.class='" + c + "' in " + JSON.stringify(ref)) + } } } diff --git a/app/gui2/src/util/parserSupport.ts b/app/gui2/src/util/parserSupport.ts index 69e57ce0197a..5db57a9f1a6d 100644 --- a/app/gui2/src/util/parserSupport.ts +++ b/app/gui2/src/util/parserSupport.ts @@ -170,7 +170,7 @@ function debug_(value: DynValue): any { case 'option': if (value.value != null) return debug_(value.value) else return undefined - case 'object': + case 'object': { // FIXME: Include the `hide` reflect property in the schema, and apply it during code generation to avoid magic // strings here. const hide = [ @@ -189,6 +189,7 @@ function debug_(value: DynValue): any { .filter(([name, _]) => !hide.includes(name)) .map(([name, value]) => [name, debug_(value)]), ) + } case 'primitive': return value.value } @@ -213,39 +214,42 @@ function validateSpans_(value: DynValue, state: { pos: number }) { if (value.value != null) validateSpans_(value.value, state) break case 'object': - const fields = new Map(value.getFields()) - const whitespaceStart = - fields.get('whitespaceStartInCodeParsed') ?? fields.get('whitespaceStartInCodeBuffer') - const whitespaceLength = - fields.get('whitespaceLengthInCodeParsed') ?? fields.get('whitespaceLengthInCodeBuffer') - const codeStart = fields.get('startInCodeBuffer') - const codeLength = fields.get('lengthInCodeBuffer') - const childrenCodeLength = fields.get('childrenLengthInCodeParsed') - if ( - !( - whitespaceLength?.type === 'primitive' && - whitespaceLength.value === 0 && - codeLength?.type === 'primitive' && - codeLength?.value === 0 - ) - ) { - if (whitespaceStart?.type === 'primitive' && whitespaceStart.value !== state.pos) - throw new Error(`Span error (whitespace) in: ${JSON.stringify(debug_(value))}.`) - if (whitespaceLength?.type === 'primitive') state.pos += whitespaceLength.value as number - if (codeStart?.type === 'primitive' && codeStart.value !== state.pos) - throw new Error('Span error (code).') - if (codeLength?.type === 'primitive') state.pos += codeLength.value as number - } - let endPos: number | undefined - if (childrenCodeLength?.type === 'primitive') - endPos = state.pos + (childrenCodeLength.value as number) - for (const entry of fields) { - const [_name, value] = entry - validateSpans_(value, state) - } - if (endPos != null && state.pos !== endPos) throw new Error('Span error (children).') - break + return validateObjectSpans(value, state) case 'primitive': break } } + +function validateObjectSpans(value: DynObject, state: { pos: number }) { + const fields = new Map(value.getFields()) + const whitespaceStart = + fields.get('whitespaceStartInCodeParsed') ?? fields.get('whitespaceStartInCodeBuffer') + const whitespaceLength = + fields.get('whitespaceLengthInCodeParsed') ?? fields.get('whitespaceLengthInCodeBuffer') + const codeStart = fields.get('startInCodeBuffer') + const codeLength = fields.get('lengthInCodeBuffer') + const childrenCodeLength = fields.get('childrenLengthInCodeParsed') + if ( + !( + whitespaceLength?.type === 'primitive' && + whitespaceLength.value === 0 && + codeLength?.type === 'primitive' && + codeLength?.value === 0 + ) + ) { + if (whitespaceStart?.type === 'primitive' && whitespaceStart.value !== state.pos) + throw new Error(`Span error (whitespace) in: ${JSON.stringify(debug_(value))}.`) + if (whitespaceLength?.type === 'primitive') state.pos += whitespaceLength.value as number + if (codeStart?.type === 'primitive' && codeStart.value !== state.pos) + throw new Error('Span error (code).') + if (codeLength?.type === 'primitive') state.pos += codeLength.value as number + } + let endPos: number | undefined + if (childrenCodeLength?.type === 'primitive') + endPos = state.pos + (childrenCodeLength.value as number) + for (const entry of fields) { + const [_name, value] = entry + validateSpans_(value, state) + } + if (endPos != null && state.pos !== endPos) throw new Error('Span error (children).') +} From c6a4f53d58f42f45223e2d1acc47292a77215963 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Grabarz?= Date: Wed, 11 Oct 2023 00:57:35 +0200 Subject: [PATCH 44/44] remove old Ast, simplify codegen build sequence --- app/gui2/env.d.ts | 2 +- app/gui2/eslint.config.js | 2 +- app/gui2/package.json | 9 +- app/gui2/parser-codegen/{src => }/codegen.ts | 38 +- app/gui2/parser-codegen/generated/.gitkeep | 0 app/gui2/parser-codegen/index.ts | 17 + app/gui2/parser-codegen/package-lock.json | 43 -- app/gui2/parser-codegen/package.json | 23 - app/gui2/parser-codegen/{src => }/schema.ts | 0 .../parser-codegen/{src => }/serialization.ts | 0 app/gui2/parser-codegen/src/main.ts | 7 - app/gui2/parser-codegen/tsconfig.json | 12 - app/gui2/parser-codegen/tslint.json | 7 - app/gui2/parser-codegen/{src => }/util.ts | 2 +- app/gui2/rust-ffi/src/lib.rs | 6 - app/gui2/src/stores/graph.ts | 2 +- .../__tests__/lsUpdate.test.ts | 2 +- .../suggestionDatabase/documentation.ts | 2 +- .../src/stores/suggestionDatabase/entry.ts | 3 +- .../src/stores/suggestionDatabase/lsUpdate.ts | 2 +- app/gui2/src/util/ast.ts | 78 +++ app/gui2/src/util/docParser.ts | 72 +++ app/gui2/src/util/ffi.ts | 599 +----------------- app/gui2/src/util/parserSupport.ts | 10 +- app/gui2/tsconfig.node.json | 1 + app/gui2/vite.config.ts | 2 +- app/gui2/vitest.config.ts | 2 +- lib/rust/parser/schema/src/main.rs | 2 +- package-lock.json | 8 + 29 files changed, 225 insertions(+), 728 deletions(-) rename app/gui2/parser-codegen/{src => }/codegen.ts (89%) delete mode 100644 app/gui2/parser-codegen/generated/.gitkeep create mode 100644 app/gui2/parser-codegen/index.ts delete mode 100644 app/gui2/parser-codegen/package-lock.json delete mode 100644 app/gui2/parser-codegen/package.json rename app/gui2/parser-codegen/{src => }/schema.ts (100%) rename app/gui2/parser-codegen/{src => }/serialization.ts (100%) delete mode 100644 app/gui2/parser-codegen/src/main.ts delete mode 100644 app/gui2/parser-codegen/tsconfig.json delete mode 100644 app/gui2/parser-codegen/tslint.json rename app/gui2/parser-codegen/{src => }/util.ts (99%) create mode 100644 app/gui2/src/util/ast.ts create mode 100644 app/gui2/src/util/docParser.ts diff --git a/app/gui2/env.d.ts b/app/gui2/env.d.ts index 3ae511733df5..814a0e7e22f2 100644 --- a/app/gui2/env.d.ts +++ b/app/gui2/env.d.ts @@ -1,7 +1,7 @@ /// declare const PROJECT_MANAGER_URL: string -declare const RUNNING_VTEST: boolean +declare const RUNNING_VITEST: boolean // This is an augmentation to the built-in `ImportMeta` interface. // This file MUST NOT contain any top-level imports. diff --git a/app/gui2/eslint.config.js b/app/gui2/eslint.config.js index 1005e92a1dcd..220caf4e65b4 100644 --- a/app/gui2/eslint.config.js +++ b/app/gui2/eslint.config.js @@ -9,7 +9,7 @@ const DIR_NAME = path.dirname(url.fileURLToPath(import.meta.url)) const conf = [ { - ignores: ['rust-ffi/pkg', 'dist', 'parser-codegen/dist', 'src/generated'], + ignores: ['rust-ffi/pkg', 'dist', 'src/generated'], }, ...compat.extends('plugin:vue/vue3-recommended'), eslintJs.configs.recommended, diff --git a/app/gui2/package.json b/app/gui2/package.json index e01603be183a..86d3cb5f5d32 100644 --- a/app/gui2/package.json +++ b/app/gui2/package.json @@ -19,9 +19,10 @@ "typecheck": "vue-tsc --noEmit -p tsconfig.app.json --composite false", "lint": "eslint .", "format": "prettier --write src/ && eslint . --fix", - "build-rust-ffi": "cd rust-ffi && wasm-pack build --release --target web", - "generate-parser-bindings": "cd parser-codegen && npm install && npm run generate-bindings ../src/generated/ast.ts", - "preinstall": "npm run build-rust-ffi && npm run generate-parser-bindings" + "build-rust-ffi": "wasm-pack build ./rust-ffi --release --target web", + "generate-ast-schema": "cargo run -p enso-parser-schema > src/generated/ast-schema.json", + "generate-ast-types": "tsx ./parser-codegen/index.ts src/generated/ast-schema.json src/generated/ast.ts", + "preinstall": "npm run build-rust-ffi && npm run generate-ast-schema && npm run generate-ast-types" }, "dependencies": { "@babel/parser": "^7.22.16", @@ -76,6 +77,7 @@ "@vue/tsconfig": "^0.4.0", "ag-grid-community": "^30.1.0", "ag-grid-enterprise": "^30.1.0", + "change-case": "^5.0.2", "d3": "^7.4.0", "esbuild": "^0.19.3", "eslint": "^8.49.0", @@ -87,6 +89,7 @@ "shuffle-seed": "^1.1.6", "sql-formatter": "^13.0.0", "tailwindcss": "^3.2.7", + "tsx": "^3.12.6", "typescript": "~5.2.2", "vite": "^4.4.9", "vite-plugin-inspect": "^0.7.38", diff --git a/app/gui2/parser-codegen/src/codegen.ts b/app/gui2/parser-codegen/codegen.ts similarity index 89% rename from app/gui2/parser-codegen/src/codegen.ts rename to app/gui2/parser-codegen/codegen.ts index b0d9c036bfd8..a60f7dac04e3 100644 --- a/app/gui2/parser-codegen/src/codegen.ts +++ b/app/gui2/parser-codegen/codegen.ts @@ -27,7 +27,7 @@ import { toCamel, toPascal, } from './util.js' -const { factory: tsf } = ts +const tsf = ts.factory // === Public API === @@ -59,8 +59,8 @@ export function implement(schema: Schema.Schema): string { ) for (const id in schema.types) { const ty = schema.types[id] - if (ty.parent == null) { - const discriminants = schema.serialization[id].discriminants + if (ty?.parent == null) { + const discriminants = schema.serialization[id]?.discriminants if (discriminants == null) { emit(makeConcreteType(id, schema)) } else { @@ -86,9 +86,11 @@ function makeType(ref: Schema.TypeRef, schema: Schema.Schema): Type { switch (c) { case 'type': { const ty = schema.types[ref.id] + if (!ty) throw new Error(`Invalid type ref: ${ref.id}`) const parent = ty.parent != null ? schema.types[ty.parent] : undefined const typeName = namespacedName(ty.name, parent?.name) const layout = schema.serialization[ref.id] + if (!layout) throw new Error(`Invalid serialization ref: ${ref.id}`) if (layout.discriminants != null) { return Type.Abstract(typeName) } else { @@ -114,7 +116,7 @@ function makeType(ref: Schema.TypeRef, schema: Schema.Schema): Type { return Type.String default: { const _ = p satisfies never - throw new Error("unreachable: PrimitiveType.type='" + p + "'") + throw new Error(`unreachable: PrimitiveType.type='${p}'`) } } } @@ -126,7 +128,7 @@ function makeType(ref: Schema.TypeRef, schema: Schema.Schema): Type { return Type.Result(makeType(ref.type0, schema), makeType(ref.type1, schema)) default: { const _ = c satisfies never - throw new Error("unreachable: TypeRef.class='" + c + "' in " + JSON.stringify(ref)) + throw new Error(`unreachable: TypeRef.class='${c}' in ${JSON.stringify(ref)}`) } } } @@ -155,7 +157,7 @@ function makeGetter(field: Field): ts.GetAccessorDeclaration { } function makeConcreteType(id: string, schema: Schema.Schema): ts.ClassDeclaration { - const ident = tsf.createIdentifier(toPascal(schema.types[id].name)) + const ident = tsf.createIdentifier(toPascal(schema.types[id]!.name)) const paramIdent = tsf.createIdentifier('cursor') const cursorParam = tsf.createParameterDeclaration( [], @@ -233,9 +235,14 @@ function makeDebugFunction(fields: Field[], typeName?: string): ts.MethodDeclara } function makeGetters(id: string, schema: Schema.Schema, typeName?: string): ts.ClassElement[] { - const fields = schema.serialization[id].fields.map(([name, offset]: [string, number]) => - makeField(name, schema.types[id].fields[name], offset, schema), - ) + const serialization = schema.serialization[id] + const type = schema.types[id] + if (serialization == null || type == null) throw new Error(`Invalid type id: ${id}`) + const fields = serialization.fields.map(([name, offset]: [string, number]) => { + const field = type.fields[name] + if (field == null) throw new Error(`Invalid field name '${name}' for type '${type.name}'`) + return makeField(name, field, offset, schema) + }) return [...fields.map(makeGetter), makeDebugFunction(fields, typeName)] } @@ -269,10 +276,11 @@ type ChildType = { function makeChildType( base: ts.Identifier, id: string, - discrim: string, + discriminant: string, schema: Schema.Schema, ): ChildType { - const ty: Schema.Type = schema.types[id] + const ty = schema.types[id] + if (ty == null) throw new Error(`Invalid type id: ${id}`) const name = toPascal(ty.name) const ident = tsf.createIdentifier(name) const cursorIdent = tsf.createIdentifier('cursor') @@ -284,7 +292,7 @@ function makeChildType( support.Cursor, undefined, ) - const discrimInt = tsf.createNumericLiteral(parseInt(discrim, 10)) + const discriminantInt = tsf.createNumericLiteral(parseInt(discriminant, 10)) return { definition: tsf.createClassDeclaration( [modifiers.export], @@ -341,8 +349,8 @@ function makeChildType( ], ), reference: tsf.createTypeReferenceNode(name), - enumMember: tsf.createEnumMember(toPascal(schema.types[id].name), discrimInt), - case: tsf.createCaseClause(discrimInt, [ + enumMember: tsf.createEnumMember(toPascal(ty.name), discriminantInt), + case: tsf.createCaseClause(discriminantInt, [ tsf.createReturnStatement(tsf.createNewExpression(ident, [], [seekCursor(cursorIdent, 4)])), ]), } @@ -358,7 +366,7 @@ function makeAbstractType( discriminants: Schema.DiscriminantMap, schema: Schema.Schema, ): AbstractType { - const ty = schema.types[id] + const ty = schema.types[id]! const name = toPascal(ty.name) const ident = tsf.createIdentifier(name) const baseIdent = tsf.createIdentifier('AbstractBase') diff --git a/app/gui2/parser-codegen/generated/.gitkeep b/app/gui2/parser-codegen/generated/.gitkeep deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/app/gui2/parser-codegen/index.ts b/app/gui2/parser-codegen/index.ts new file mode 100644 index 000000000000..ab06131db292 --- /dev/null +++ b/app/gui2/parser-codegen/index.ts @@ -0,0 +1,17 @@ +import * as fs from 'node:fs' +import * as process from 'node:process' +import * as codegen from './codegen.js' +import * as Schema from './schema.js' + +const schemaPath = process.argv[2] +const outputPath = process.argv[3] + +if (!schemaPath || !outputPath) { + console.error('Usage: parser-codegen ') + process.exit(1) +} + +console.log(`Generating ${outputPath} from ${schemaPath}.`) +const schema: Schema.Schema = JSON.parse(fs.readFileSync(schemaPath, 'utf8')) +const code = codegen.implement(schema) +fs.writeFileSync(outputPath, code) diff --git a/app/gui2/parser-codegen/package-lock.json b/app/gui2/parser-codegen/package-lock.json deleted file mode 100644 index 4933cdeeadf4..000000000000 --- a/app/gui2/parser-codegen/package-lock.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "name": "enso-parser-codegen", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "enso-parser-codegen", - "version": "1.0.0", - "hasInstallScript": true, - "dependencies": { - "change-case": "^5.0.2", - "typescript": "^5.2.2" - }, - "devDependencies": { - "@types/node": "^20.8.2" - } - }, - "node_modules/@types/node": { - "version": "20.8.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.2.tgz", - "integrity": "sha512-Vvycsc9FQdwhxE3y3DzeIxuEJbWGDsnrxvMADzTDF/lcdR9/K+AQIeAghTQsHtotg/q0j3WEOYS/jQgSdWue3w==", - "dev": true - }, - "node_modules/change-case": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/change-case/-/change-case-5.0.2.tgz", - "integrity": "sha512-tH6YZXViaeC2/Mnt8m4gSmbZfNorC2rhwCX2bXw8SYZWr8ljCPB7iA+1TLG9t7yroWBFauc63LlOZ1gucMVCWw==" - }, - "node_modules/typescript": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", - "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - } - } -} diff --git a/app/gui2/parser-codegen/package.json b/app/gui2/parser-codegen/package.json deleted file mode 100644 index df6d7aae87c9..000000000000 --- a/app/gui2/parser-codegen/package.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "enso-parser-codegen", - "version": "1.0.0", - "private": true, - "type": "module", - "author": { - "name": "Enso Team", - "email": "contact@enso.org" - }, - "scripts": { - "generate-ast-schema": "cargo run -p enso-parser-schema --bin enso-parser-schema > generated/ast-schema.json", - "preinstall": "npm run generate-ast-schema", - "generate-bindings": "tsc --build && node dist/main.js generated/ast-schema.json" - }, - "keywords": [], - "dependencies": { - "change-case": "^5.0.2", - "typescript": "^5.2.2" - }, - "devDependencies": { - "@types/node": "^20.8.2" - } -} diff --git a/app/gui2/parser-codegen/src/schema.ts b/app/gui2/parser-codegen/schema.ts similarity index 100% rename from app/gui2/parser-codegen/src/schema.ts rename to app/gui2/parser-codegen/schema.ts diff --git a/app/gui2/parser-codegen/src/serialization.ts b/app/gui2/parser-codegen/serialization.ts similarity index 100% rename from app/gui2/parser-codegen/src/serialization.ts rename to app/gui2/parser-codegen/serialization.ts diff --git a/app/gui2/parser-codegen/src/main.ts b/app/gui2/parser-codegen/src/main.ts deleted file mode 100644 index 30d88d284103..000000000000 --- a/app/gui2/parser-codegen/src/main.ts +++ /dev/null @@ -1,7 +0,0 @@ -import fs from 'fs' -import * as codegen from './codegen.js' -import * as Schema from './schema.js' - -const schema: Schema.Schema = JSON.parse(fs.readFileSync(process.argv[2], 'utf8')) -const code = codegen.implement(schema) -fs.writeFileSync(process.argv[3], code) diff --git a/app/gui2/parser-codegen/tsconfig.json b/app/gui2/parser-codegen/tsconfig.json deleted file mode 100644 index 091490356cfd..000000000000 --- a/app/gui2/parser-codegen/tsconfig.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "extends": "@tsconfig/node18/tsconfig.json", - "compilerOptions": { - "sourceMap": true, - "module": "NodeNext", - "moduleResolution": "NodeNext", - "baseUrl": ".", - "outDir": "dist", - "types": ["node"] - }, - "include": ["src/**/*"] -} diff --git a/app/gui2/parser-codegen/tslint.json b/app/gui2/parser-codegen/tslint.json deleted file mode 100644 index 9e97bd249e15..000000000000 --- a/app/gui2/parser-codegen/tslint.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "defaultSeverity": "error", - "extends": ["tslint:recommended"], - "jsRules": {}, - "rules": {}, - "rulesDirectory": [] -} diff --git a/app/gui2/parser-codegen/src/util.ts b/app/gui2/parser-codegen/util.ts similarity index 99% rename from app/gui2/parser-codegen/src/util.ts rename to app/gui2/parser-codegen/util.ts index ea80e5b25ba1..11ea74b4db8e 100644 --- a/app/gui2/parser-codegen/src/util.ts +++ b/app/gui2/parser-codegen/util.ts @@ -1,6 +1,6 @@ import * as changeCase from 'change-case' import ts from 'typescript' -const { factory: tsf } = ts +const tsf = ts.factory // === Identifier utilities === diff --git a/app/gui2/rust-ffi/src/lib.rs b/app/gui2/rust-ffi/src/lib.rs index ee85221e66eb..bf7d75703615 100644 --- a/app/gui2/rust-ffi/src/lib.rs +++ b/app/gui2/rust-ffi/src/lib.rs @@ -14,12 +14,6 @@ thread_local! { pub static PARSER: Parser = Parser::new(); } -#[wasm_bindgen] -pub fn parse_to_json(code: &str) -> String { - let ast = PARSER.with(|parser| parser.run(code)); - serde_json::to_string(&ast).expect("Failed to serialize AST to JSON") -} - #[wasm_bindgen] pub fn parse_doc_to_json(docs: &str) -> String { let docs = enso_doc_parser::parse(docs); diff --git a/app/gui2/src/stores/graph.ts b/app/gui2/src/stores/graph.ts index edbd675c1532..e991cfc706c6 100644 --- a/app/gui2/src/stores/graph.ts +++ b/app/gui2/src/stores/graph.ts @@ -1,6 +1,6 @@ import { assert, assertNever } from '@/util/assert' +import { Ast, parseEnso } from '@/util/ast' import { useObserveYjs } from '@/util/crdt' -import { parseEnso, type Ast } from '@/util/ffi' import type { Opt } from '@/util/opt' import { Vec2 } from '@/util/vec2' import * as map from 'lib0/map' diff --git a/app/gui2/src/stores/suggestionDatabase/__tests__/lsUpdate.test.ts b/app/gui2/src/stores/suggestionDatabase/__tests__/lsUpdate.test.ts index 89105a8ab4ba..cc1fab58ff23 100644 --- a/app/gui2/src/stores/suggestionDatabase/__tests__/lsUpdate.test.ts +++ b/app/gui2/src/stores/suggestionDatabase/__tests__/lsUpdate.test.ts @@ -1,4 +1,4 @@ -import { parseDocs } from '@/util/ffi' +import { parseDocs } from '@/util/docParser' import { tryIdentifier, tryQualifiedName } from '@/util/qualifiedName' import { unwrap } from '@/util/result' import * as lsTypes from 'shared/languageServerTypes/suggestions' diff --git a/app/gui2/src/stores/suggestionDatabase/documentation.ts b/app/gui2/src/stores/suggestionDatabase/documentation.ts index 05e98bff300e..29b2b9ad1bca 100644 --- a/app/gui2/src/stores/suggestionDatabase/documentation.ts +++ b/app/gui2/src/stores/suggestionDatabase/documentation.ts @@ -1,6 +1,6 @@ import type { Group } from '@/stores/suggestionDatabase' import { findIndexOpt } from '@/util/array' -import { parseDocs, type Doc } from '@/util/ffi' +import { parseDocs, type Doc } from '@/util/docParser' import { isSome, type Opt } from '@/util/opt' import { tryQualifiedName, type QualifiedName } from '@/util/qualifiedName' import { unwrap } from '@/util/result' diff --git a/app/gui2/src/stores/suggestionDatabase/entry.ts b/app/gui2/src/stores/suggestionDatabase/entry.ts index 51a063e597cd..d1bedeaf02b3 100644 --- a/app/gui2/src/stores/suggestionDatabase/entry.ts +++ b/app/gui2/src/stores/suggestionDatabase/entry.ts @@ -1,5 +1,5 @@ import { assert } from '@/util/assert' -import type { Doc } from '@/util/ffi' +import type { Doc } from '@/util/docParser' import { isIdentifier, isQualifiedName, @@ -13,7 +13,6 @@ import type { SuggestionEntryArgument, SuggestionEntryScope, } from 'shared/languageServerTypes/suggestions' -export type { Doc } from '@/util/ffi' export type { SuggestionEntryArgument, SuggestionEntryScope, diff --git a/app/gui2/src/stores/suggestionDatabase/lsUpdate.ts b/app/gui2/src/stores/suggestionDatabase/lsUpdate.ts index e4a6f27960ee..5925bcf927be 100644 --- a/app/gui2/src/stores/suggestionDatabase/lsUpdate.ts +++ b/app/gui2/src/stores/suggestionDatabase/lsUpdate.ts @@ -1,13 +1,13 @@ import { SuggestionDb, type Group } from '@/stores/suggestionDatabase' import { SuggestionKind, - type Doc, type SuggestionEntry, type SuggestionEntryArgument, type SuggestionEntryScope, type Typename, } from '@/stores/suggestionDatabase/entry' import { assert } from '@/util/assert' +import type { Doc } from '@/util/docParser' import { type Opt } from '@/util/opt' import { qnJoin, diff --git a/app/gui2/src/util/ast.ts b/app/gui2/src/util/ast.ts new file mode 100644 index 000000000000..c096a8bf5113 --- /dev/null +++ b/app/gui2/src/util/ast.ts @@ -0,0 +1,78 @@ +import * as Ast from '@/generated/ast' +import { debug, validateSpans } from '@/util/parserSupport' +import { parse } from './ffi' + +export { Ast } + +export function parseEnso(code: string): Ast.Tree { + const blob = parse(code) + return Ast.deserializeTree(blob.buffer) +} + +if (import.meta.vitest) { + const { test, expect } = import.meta.vitest + test('testParse', () => { + const identInput = ' foo bar\n' + const tree = parseEnso(identInput) + expect(debug(tree)).toMatchObject({ + childrenLengthInCodeParsed: 8, + whitespaceStartInCodeParsed: 0, + whitespaceLengthInCodeParsed: 1, + statements: [ + { + expression: { + arg: { + childrenLengthInCodeParsed: 3, + whitespaceStartInCodeParsed: 4, + whitespaceLengthInCodeParsed: 1, + token: { + startInCodeBuffer: 5, + lengthInCodeBuffer: 3, + whitespaceLengthInCodeBuffer: 0, + }, + type: 'Ident', + }, + func: { + childrenLengthInCodeParsed: 3, + whitespaceLengthInCodeParsed: 0, + token: { + startInCodeBuffer: 1, + lengthInCodeBuffer: 3, + whitespaceLengthInCodeBuffer: 0, + }, + type: 'Ident', + }, + childrenLengthInCodeParsed: 7, + whitespaceLengthInCodeParsed: 0, + type: 'App', + }, + newline: { + lengthInCodeBuffer: 0, + whitespaceLengthInCodeBuffer: 0, + }, + }, + { + expression: undefined, + newline: { + startInCodeBuffer: 8, + lengthInCodeBuffer: 1, + whitespaceLengthInCodeBuffer: 0, + }, + }, + ], + type: 'BodyBlock', + }) + }) + test('testCase', () => { + const input = 'Data.read\n2 + 2' + const tree = parseEnso(input) + const endPos = validateSpans(tree) + expect(endPos).toStrictEqual(input.length) + }) + test('testSpans', () => { + const input = ' foo bar\n' + const tree = parseEnso(input) + const endPos = validateSpans(tree) + expect(endPos).toStrictEqual(input.length) + }) +} diff --git a/app/gui2/src/util/docParser.ts b/app/gui2/src/util/docParser.ts new file mode 100644 index 000000000000..20641718191e --- /dev/null +++ b/app/gui2/src/util/docParser.ts @@ -0,0 +1,72 @@ +import { parse_doc_to_json } from './ffi' + +export function parseDocs(docs: string): Doc.Section[] { + const json = parse_doc_to_json(docs) + return JSON.parse(json) +} + +export namespace Doc { + export type HtmlString = string + export type Tag = + | 'Added' + | 'Advanced' + | 'Alias' + | 'Deprecated' + | 'Icon' + | 'Group' + | 'Modified' + | 'Private' + | 'Removed' + | 'TextOnly' + | 'Unstable' + | 'Upcoming' + export type Mark = 'Important' | 'Info' | 'Example' + + export interface Argument { + name: string + description: HtmlString + } + + export type Section = + | { Tag: Section.Tag } + | { Paragraph: Section.Paragraph } + | { List: Section.List } + | { Arguments: Section.Arguments } + | { Keyed: Section.Keyed } + | { Marked: Section.Marked } + + export namespace Section { + /** The documentation tag. */ + export interface Tag { + tag: Doc.Tag + body: HtmlString + } + + /** The paragraph of the text. */ + export interface Paragraph { + body: HtmlString + } + + /** A list of items. Each item starts with a dash (`-`). */ + export interface List { + items: HtmlString[] + } + + /** A list of items, but each item is an [`Argument`]. Starts with `Arguments:` keyword. */ + export interface Arguments { + args: Argument[] + } + + /** The section that starts with the key followed by the colon and the body. */ + export interface Keyed { + key: String + body: HtmlString + } + /** The section that starts with the mark followed by the header and the body. */ + export interface Marked { + mark: Mark + header?: string + body: HtmlString + } + } +} diff --git a/app/gui2/src/util/ffi.ts b/app/gui2/src/util/ffi.ts index f00c364729cd..1bc80d6773e6 100644 --- a/app/gui2/src/util/ffi.ts +++ b/app/gui2/src/util/ffi.ts @@ -1,603 +1,12 @@ -import type { NonEmptyArray } from '@/util/array' -import type { Opt } from '@/util/opt' -import { debug, validateSpans } from '@/util/parserSupport' -import init, { parse, parse_doc_to_json, parse_to_json } from '../../rust-ffi/pkg/rust_ffi' -import * as Ast2 from '../generated/ast' +import init, { parse, parse_doc_to_json } from '../../rust-ffi/pkg/rust_ffi' -if (RUNNING_VTEST) { +if (RUNNING_VITEST) { const fs = await import('node:fs/promises') const buffer = await fs.readFile('./rust-ffi/pkg/rust_ffi_bg.wasm') await init(buffer) } else { await init() } -export function parseEnso(code: string): Ast.Tree { - const json = parse_to_json(code) - return JSON.parse(json) -} - -// TODO (#7791): Replace `parseEnso` with this. -export function parseEnso2(code: string): Ast2.Tree { - const blob = parse(code) - return Ast2.deserializeTree(blob.buffer) -} - -export namespace Ast { - export interface Tree { - span: Span - variant: Variant - } - - export type Token = - | Token.AutoScope - | Token.CloseSymbol - | Token.Digits - | Token.Ident - | Token.Newline - | Token.NumberBase - | Token.OpenSymbol - | Token.Operator - | Token.TextEnd - | Token.TextEscape - | Token.TextSection - | Token.TextStart - | Token.Wildcard - - namespace Token { - declare const Brand: unique symbol - - interface TokenBase { - left_offset: Offset - code: Code - variant: T & { [Brand]: B } - } - - export type AutoScope = TokenBase<'AutoScope'> - export type CloseSymbol = TokenBase<'CloseSymbol'> - export type Digits = TokenBase<'Digits', { base: Opt<'Binary' | 'Octal' | 'Hexadecimal'> }> - export type Ident = TokenBase< - 'Ident', - { - is_free: boolean - lift_level: number - is_type: boolean - is_operator_lexically: boolean - } - > - export type Newline = TokenBase<'Newline'> - export type NumberBase = TokenBase<'NumberBase'> - export type OpenSymbol = TokenBase<'OpenSymbol'> - export type Operator = TokenBase<'Operator'> - export type TextEnd = TokenBase<'TextEnd'> - export type TextEscape = TokenBase< - 'TextEscape', - { - /** - * Escaped character Unicode scalar value, Serialized from Rust's `char`. - * https://doc.rust-lang.org/std/primitive.char.html - */ - value: Opt - } - > - export type TextSection = TokenBase<'TextSection'> - export type TextStart = TokenBase<'TextStart'> - export type Wildcard = TokenBase<'Wildcard', { lift_level: number }> - } - - export interface Span { - code_length: Length - left_offset: Offset - } - - export interface Code { - repr: CowStrPtr - utf16: number - } - - export interface Length { - utf8: number - utf16: number - } - - export interface Offset { - visible: VisibleOffset - code: Code - } - - export interface CowStrPtr { - begin: number - len: number - } - - export interface VisibleOffset { - width_in_spaces: number - } - - export type Variant = - | { Invalid: Variant.Invalid } - | { BodyBlock: Variant.BodyBlock } - | { ArgumentBlockApplication: Variant.ArgumentBlockApplication } - | { OperatorBlockApplication: Variant.OperatorBlockApplication } - | { Ident: Variant.Ident } - | { Number: Variant.Number } - | { Wildcard: Variant.Wildcard } - | { AutoScope: Variant.AutoScope } - | { TextLiteral: Variant.TextLiteral } - | { App: Variant.App } - | { NamedApp: Variant.NamedApp } - | { DefaultApp: Variant.DefaultApp } - | { OprApp: Variant.OprApp } - | { UnaryOprApp: Variant.UnaryOprApp } - | { OprSectionBoundary: Variant.OprSectionBoundary } - | { TemplateFunction: Variant.TemplateFunction } - | { MultiSegmentApp: Variant.MultiSegmentApp } - | { TypeDef: Variant.TypeDef } - | { Assignment: Variant.Assignment } - | { Function: Variant.Function } - | { ForeignFunction: Variant.ForeignFunction } - | { Import: Variant.Import } - | { Export: Variant.Export } - | { Group: Variant.Group } - | { TypeSignature: Variant.TypeSignature } - | { TypeAnnotated: Variant.TypeAnnotated } - | { CaseOf: Variant.CaseOf } - | { Lambda: Variant.Lambda } - | { Array: Variant.Array } - | { Tuple: Variant.Tuple } - | { Annotated: Variant.Annotated } - | { AnnotatedBuiltin: Variant.AnnotatedBuiltin } - | { Documented: Variant.Documented } - | { ConstructorDefinition: Variant.ConstructorDefinition } - - export namespace Variant { - export interface Invalid { - error: Error - ast: Tree - } - - export interface BlockLine { - newline: Token.Newline - expression: Opt - } - - export interface BlockOperatorLine {} - - export interface BodyBlock { - statements: BlockLine[] - } - - export interface ArgumentBlockApplication { - lhs: Opt - arguments: BlockLine[] - } - - export interface OperatorBlockApplication { - lhs: Opt - expressions: BlockOperatorLine[] - excess: BlockLine[] - } - export interface Ident { - token: Token.Ident - } - - export interface FractionalDigits { - dot: Token.Operator - digits: Token.Digits - } - - export interface Number { - base: Opt - integer: Opt - fractional_digits: Opt - } - export interface Wildcard { - token: Token.Wildcard - de_bruijn_index: Opt - } - - export interface AutoScope { - token: Token.AutoScope - } - - export interface TextLiteral { - open: Opt - newline: Opt - elements: TextElement[] - close: Opt - } - - export interface App { - func: Tree - arg: Tree - } - - export interface NamedApp { - func: Tree - open: Opt - name: Token.Ident - equals: Token.Operator - arg: Tree - close: Opt - } - - export interface DefaultApp { - func: Tree - default: Token.Ident - } - - type Result = { Ok: T } | { Err: E } - - export interface OprApp { - lhs: Opt - opr: Result - rhs: Opt - } - - export interface UnaryOprApp { - opr: Token.Operator - rhs: Opt - } - - export interface OprSectionBoundary { - arguments: number - ast: Tree - } - - export interface TemplateFunction { - arguments: number - ast: Tree - } - - export interface MultiSegmentApp { - segments: NonEmptyArray - } - - export interface MultiSegmentAppSegment { - header: Token - body: Opt - } - - export interface ArgumentType { - operator: Token.Operator - type: Tree - } - - export interface ArgumentDefault { - equals: Token.Operator - expression: Tree - } - - /** A function argument definition. */ - export interface ArgumentDefinition { - /** Opening parenthesis (outer). */ - open: Opt - /** Opening parenthesis (inner). */ - open2: Opt - /** An optional execution-suspension unary operator (~). */ - suspension: Opt - /** The pattern being bound to an argument. */ - pattern: Tree - /** An optional type ascribed to an argument. */ - type: Opt - /** Closing parenthesis (inner). */ - close2: Opt - /** An optional default value for an argument. */ - default: Opt - /** Closing parenthesis (outer). */ - close: Opt - } - - export interface ArgumentDefinitionLine { - newline: Token.Newline - argument: Opt - } - - export interface TypeDef { - keyword: Token.Ident - name: Token.Ident - params: ArgumentDefinition[] - body: BlockLine[] - } - export interface Assignment { - pattern: Tree - equals: Token.Operator - expr: Tree - } - - export interface Function { - name: Tree - args: ArgumentDefinition[] - equals: Token.Operator - body: Opt - } - - export interface ForeignFunction { - foreign: Token.Ident - language: Token.Ident - name: Token.Ident - args: ArgumentDefinition[] - equals: Token.Operator - body: Tree - } - - export interface Import { - polyglot: Opt - from: Opt - import: MultiSegmentAppSegment - all: Opt - as_: Opt - hiding: Opt - } - - export interface Export { - from: Opt - export: MultiSegmentAppSegment - all: Opt - as_: Opt - hiding: Opt - } - - export interface Group { - open: Opt - body: Opt - close: Opt - } - - export interface TypeSignature { - variable: Tree - operator: Token.Operator - type_: Tree - } - - export interface TypeAnnotated { - expression: Tree - operator: Token.Operator - type_: Tree - } - - export interface CaseLine { - newline: Opt - case: Opt - } - - export interface Case { - documentation: Opt - pattern: Opt - arrow: Opt - expression: Opt - } - - export interface CaseOf { - case: Token.Ident - expression: Opt - of: Token.Ident - cases: CaseLine[] - } - - export interface Lambda { - operator: Token.Operator - arrow: Opt - } - - export interface OperatorDelimitedTree { - operator: Token.Operator - body: Opt - } - - export interface Array { - left: Token.OpenSymbol - first: Opt - rest: OperatorDelimitedTree[] - right: Token.CloseSymbol - } - - export interface Tuple { - left: Token.OpenSymbol - first: Opt - rest: OperatorDelimitedTree[] - right: Token.CloseSymbol - } - - export interface Annotated { - token: Token.Operator - annotation: Token.Ident - argument: Opt - newlines: Token.Newline[] - expression: Opt - } - - export interface AnnotatedBuiltin { - token: Token.Operator - annotation: Token.Ident - newlines: Token.Newline[] - expression: Opt - } - - export interface Documented { - documentation: DocComment - expression: Opt - } - - export interface ConstructorDefinition { - constructor: Token.Ident - arguments: ArgumentDefinition[] - block: ArgumentDefinitionLine[] - } - } - - export interface DocComment { - open: Token.TextStart - elements: TextElement[] - newlines: Token.Newline[] - } - - export type TextElement = - | { Section: TextElement.Section } - | { Escape: TextElement.Escape } - | { Newline: TextElement.Newline } - | { Splice: TextElement.Splice } - - export namespace TextElement { - export interface Section { - text: Token.TextSection - } - - export interface Escape { - token: Token.TextEscape - } - - export interface Newline { - newline: Token.Newline - } - - export interface Splice { - open: Token.OpenSymbol - expression: Opt - close: Token.CloseSymbol - } - } - - export interface Error { - message: string - } -} - -export function parseDocs(docs: string): Doc.Section[] { - const json = parse_doc_to_json(docs) - return JSON.parse(json) -} - -export namespace Doc { - export type HtmlString = string - export type Tag = - | 'Added' - | 'Advanced' - | 'Alias' - | 'Deprecated' - | 'Icon' - | 'Group' - | 'Modified' - | 'Private' - | 'Removed' - | 'TextOnly' - | 'Unstable' - | 'Upcoming' - export type Mark = 'Important' | 'Info' | 'Example' - - export interface Argument { - name: string - description: HtmlString - } - - export type Section = - | { Tag: Section.Tag } - | { Paragraph: Section.Paragraph } - | { List: Section.List } - | { Arguments: Section.Arguments } - | { Keyed: Section.Keyed } - | { Marked: Section.Marked } - - export namespace Section { - /** The documentation tag. */ - export interface Tag { - tag: Doc.Tag - body: HtmlString - } - - /** The paragraph of the text. */ - export interface Paragraph { - body: HtmlString - } - - /** A list of items. Each item starts with a dash (`-`). */ - export interface List { - items: HtmlString[] - } - - /** A list of items, but each item is an [`Argument`]. Starts with `Arguments:` keyword. */ - export interface Arguments { - args: Argument[] - } - - /** The section that starts with the key followed by the colon and the body. */ - export interface Keyed { - key: String - body: HtmlString - } - /** The section that starts with the mark followed by the header and the body. */ - export interface Marked { - mark: Mark - header?: string - body: HtmlString - } - } -} - -if (import.meta.vitest) { - const { test, expect } = import.meta.vitest - test('testParse', () => { - const identInput = ' foo bar\n' - const tree = parseEnso2(identInput) - expect(debug(tree)).toMatchObject({ - childrenLengthInCodeParsed: 8, - whitespaceStartInCodeParsed: 0, - whitespaceLengthInCodeParsed: 1, - statements: [ - { - expression: { - arg: { - childrenLengthInCodeParsed: 3, - whitespaceStartInCodeParsed: 4, - whitespaceLengthInCodeParsed: 1, - token: { - startInCodeBuffer: 5, - lengthInCodeBuffer: 3, - whitespaceLengthInCodeBuffer: 0, - }, - type: 'Ident', - }, - func: { - childrenLengthInCodeParsed: 3, - whitespaceLengthInCodeParsed: 0, - token: { - startInCodeBuffer: 1, - lengthInCodeBuffer: 3, - whitespaceLengthInCodeBuffer: 0, - }, - type: 'Ident', - }, - childrenLengthInCodeParsed: 7, - whitespaceLengthInCodeParsed: 0, - type: 'App', - }, - newline: { - lengthInCodeBuffer: 0, - whitespaceLengthInCodeBuffer: 0, - }, - }, - { - expression: undefined, - newline: { - startInCodeBuffer: 8, - lengthInCodeBuffer: 1, - whitespaceLengthInCodeBuffer: 0, - }, - }, - ], - type: 'BodyBlock', - }) - }) - test('testCase', () => { - const input = 'Data.read\n2 + 2' - const tree = parseEnso2(input) - const endPos = validateSpans(tree) - expect(endPos).toStrictEqual(input.length) - }) - test('testSpans', () => { - const input = ' foo bar\n' - const tree = parseEnso2(input) - const endPos = validateSpans(tree) - expect(endPos).toStrictEqual(input.length) - }) -} +// eslint-disable-next-line camelcase +export { parse, parse_doc_to_json } diff --git a/app/gui2/src/util/parserSupport.ts b/app/gui2/src/util/parserSupport.ts index 5db57a9f1a6d..72f47b5305ad 100644 --- a/app/gui2/src/util/parserSupport.ts +++ b/app/gui2/src/util/parserSupport.ts @@ -107,23 +107,23 @@ export class Cursor { } readU8(): number { - return this.blob.getUint8(0)! + return this.blob.getUint8(0) } readU32(): number { - return this.blob.getUint32(0, true)! + return this.blob.getUint32(0, true) } readI32(): number { - return this.blob.getInt32(0, true)! + return this.blob.getInt32(0, true) } readU64(): bigint { - return this.blob.getBigUint64(0, true)! + return this.blob.getBigUint64(0, true) } readI64(): bigint { - return this.blob.getBigInt64(0, true)! + return this.blob.getBigInt64(0, true) } readBool(): boolean { diff --git a/app/gui2/tsconfig.node.json b/app/gui2/tsconfig.node.json index cc1982ee8cbd..c333414101e9 100644 --- a/app/gui2/tsconfig.node.json +++ b/app/gui2/tsconfig.node.json @@ -6,6 +6,7 @@ "playwright.config.*", "eslint.config.js", "e2e/**/*", + "parser-codegen/**/*", "node.env.d.ts" ], "compilerOptions": { diff --git a/app/gui2/vite.config.ts b/app/gui2/vite.config.ts index 6a3cd2c1abac..8a3814761963 100644 --- a/app/gui2/vite.config.ts +++ b/app/gui2/vite.config.ts @@ -29,7 +29,7 @@ export default defineConfig({ IS_DEV_MODE: JSON.stringify(process.env.NODE_ENV !== 'production'), CLOUD_ENV: process.env.ENSO_CLOUD_ENV != null ? JSON.stringify(process.env.ENSO_CLOUD_ENV) : 'undefined', - RUNNING_VTEST: false, + RUNNING_VITEST: false, 'import.meta.vitest': false, // Single hardcoded usage of `global` in by aws-amplify. 'global.TYPED_ARRAY_SUPPORT': true, diff --git a/app/gui2/vitest.config.ts b/app/gui2/vitest.config.ts index 2bf6a232ed23..c7ff56109912 100644 --- a/app/gui2/vitest.config.ts +++ b/app/gui2/vitest.config.ts @@ -12,7 +12,7 @@ export default mergeConfig( root: fileURLToPath(new URL('./', import.meta.url)), }, define: { - RUNNING_VTEST: true, + RUNNING_VITEST: true, }, }), ) diff --git a/lib/rust/parser/schema/src/main.rs b/lib/rust/parser/schema/src/main.rs index f7d76ec050c4..c0b1502bbb9d 100644 --- a/lib/rust/parser/schema/src/main.rs +++ b/lib/rust/parser/schema/src/main.rs @@ -23,5 +23,5 @@ // ========================= fn main() { - serde_json::to_writer(std::io::stdout(), &enso_parser_schema::schema()).unwrap() + serde_json::to_writer_pretty(std::io::stdout(), &enso_parser_schema::schema()).unwrap() } diff --git a/package-lock.json b/package-lock.json index 3b59f77d53b0..4fd34a595079 100644 --- a/package-lock.json +++ b/package-lock.json @@ -81,6 +81,7 @@ "@vue/tsconfig": "^0.4.0", "ag-grid-community": "^30.1.0", "ag-grid-enterprise": "^30.1.0", + "change-case": "^5.0.2", "d3": "^7.4.0", "esbuild": "^0.19.3", "eslint": "^8.49.0", @@ -92,6 +93,7 @@ "shuffle-seed": "^1.1.6", "sql-formatter": "^13.0.0", "tailwindcss": "^3.2.7", + "tsx": "^3.12.6", "typescript": "~5.2.2", "vite": "^4.4.9", "vite-plugin-inspect": "^0.7.38", @@ -5567,6 +5569,12 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/change-case": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/change-case/-/change-case-5.0.2.tgz", + "integrity": "sha512-tH6YZXViaeC2/Mnt8m4gSmbZfNorC2rhwCX2bXw8SYZWr8ljCPB7iA+1TLG9t7yroWBFauc63LlOZ1gucMVCWw==", + "dev": true + }, "node_modules/char-regex": { "version": "2.0.1", "license": "MIT",