enso/app/gui2/parser-codegen/util.ts
Paweł Grabarz bf76be6e6b
[GUI2] use DataView directly in generated parser code (#8028)
- Removed `Cursor` and moved all accessors to standalone functions, reducing the generated code size significantly (especially after minification).
- Removed unnecessary `seek`s from everywhere. Now the offseting is part of each `read` implementation.
- Removed unnecessary differences between `read`s on abstract and concrete types. Now abstract types do the pointer access internally in their `read`.
2023-10-11 21:28:29 +00:00

98 lines
3.0 KiB
TypeScript

import * as changeCase from 'change-case'
import ts from 'typescript'
const tsf = ts.factory
// === 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)
}
export function toCamel(ident: string): string {
if (ident.includes('.')) throw new Error('toCamel cannot be applied to a namespaced name.')
return changeCase.camelCase(ident)
}
const RENAME = new Map([
// TS reserved words.
['constructor', 'ident'],
['type', 'typeNode'],
// Rename source references to reflect our usage:
// - In `Tree`s:
['spanLeftOffsetCodeOffsetUtf16', 'whitespaceStartInCodeParsed'],
['spanLeftOffsetCodeUtf16', 'whitespaceLengthInCodeParsed'],
['spanCodeLengthUtf16', 'childrenLengthInCodeParsed'],
// - In `Tokens`s:
['leftOffsetCodeOffsetUtf16', 'whitespaceStartInCodeBuffer'],
['leftOffsetCodeUtf16', 'whitespaceLengthInCodeBuffer'],
['codeUtf16', 'lengthInCodeBuffer'],
['codeOffsetUtf16', 'startInCodeBuffer'],
])
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)
} 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),
} 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([throwError(error)])])
}
export function throwError(error: string): ts.Statement {
return tsf.createThrowStatement(
tsf.createNewExpression(tsf.createIdentifier('Error'), [], [tsf.createStringLiteral(error)]),
)
}
export function makeArrow(params: ts.BindingName[], expr: ts.Expression) {
return tsf.createArrowFunction(
[],
[],
params.map((ident) => tsf.createParameterDeclaration([], undefined, ident)),
undefined,
undefined,
expr,
)
}