Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/1-framework/2-authoring/psl-parser/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
"exports": {
".": "./dist/index.mjs",
"./parser": "./dist/parser.mjs",
"./tokenizer": "./dist/tokenizer.mjs",
"./syntax": "./dist/syntax.mjs",
"./types": "./dist/types.mjs",
"./package.json": "./package.json"
},
Expand Down
38 changes: 38 additions & 0 deletions packages/1-framework/2-authoring/psl-parser/src/exports/syntax.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
export {
AttributeArgListAst,
FieldAttributeAst,
ModelAttributeAst,
} from '../syntax/ast/attributes';
export {
BlockDeclarationAst,
DocumentAst,
EnumDeclarationAst,
EnumValueDeclarationAst,
FieldDeclarationAst,
KeyValuePairAst,
ModelDeclarationAst,
NamedTypeDeclarationAst,
TypesBlockAst,
} from '../syntax/ast/declarations';
export type { ExpressionAst } from '../syntax/ast/expressions';
export {
ArrayLiteralAst,
AttributeArgAst,
BooleanLiteralExprAst,
castExpression,
FunctionCallAst,
NumberLiteralExprAst,
StringLiteralExprAst,
} from '../syntax/ast/expressions';
// AST wrappers
export { IdentifierAst } from '../syntax/ast/identifier';
export { TypeAnnotationAst } from '../syntax/ast/type-annotation';
export type { AstNode } from '../syntax/ast-helpers';
export { filterChildren, findChildToken, findFirstChild } from '../syntax/ast-helpers';
export type { GreenElement, GreenNode, GreenToken } from '../syntax/green';
export { greenNode, greenToken } from '../syntax/green';
export { GreenNodeBuilder } from '../syntax/green-builder';
// Red layer
export type { SyntaxElement } from '../syntax/red';
export { createSyntaxTree, SyntaxNode } from '../syntax/red';
export type { SyntaxKind } from '../syntax/syntax-kind';
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export type { Token, TokenKind } from '../tokenizer';
export { Tokenizer } from '../tokenizer';
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import type { Token, TokenKind } from '../tokenizer';
import { SyntaxNode } from './red';

export interface AstNode {
readonly syntax: SyntaxNode;
}

export function findChildToken(node: SyntaxNode, kind: TokenKind): Token | undefined {
for (const child of node.children()) {
if (!(child instanceof SyntaxNode) && child.kind === kind) {
return child;
}
}
return undefined;
}

export function findFirstChild<T>(
node: SyntaxNode,
cast: (node: SyntaxNode) => T | undefined,
): T | undefined {
for (const child of node.childNodes()) {
const result = cast(child);
if (result !== undefined) return result;
}
return undefined;
}

export function* filterChildren<T>(
node: SyntaxNode,
cast: (node: SyntaxNode) => T | undefined,
): Iterable<T> {
for (const child of node.childNodes()) {
const result = cast(child);
if (result !== undefined) yield result;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import type { Token } from '../../tokenizer';
import type { AstNode } from '../ast-helpers';
import { filterChildren, findChildToken, findFirstChild } from '../ast-helpers';
import type { SyntaxNode } from '../red';
import { AttributeArgAst } from './expressions';
import { IdentifierAst } from './identifier';

export class AttributeArgListAst implements AstNode {
readonly syntax: SyntaxNode;

constructor(syntax: SyntaxNode) {
this.syntax = syntax;
}

lparen(): Token | undefined {
return findChildToken(this.syntax, 'LParen');
}

rparen(): Token | undefined {
return findChildToken(this.syntax, 'RParen');
}

*args(): Iterable<AttributeArgAst> {
yield* filterChildren(this.syntax, AttributeArgAst.cast);
}

static cast(node: SyntaxNode): AttributeArgListAst | undefined {
return node.kind === 'AttributeArgList' ? new AttributeArgListAst(node) : undefined;
}
}

export class FieldAttributeAst implements AstNode {
readonly syntax: SyntaxNode;

constructor(syntax: SyntaxNode) {
this.syntax = syntax;
}

at(): Token | undefined {
return findChildToken(this.syntax, 'At');
}

name(): IdentifierAst | undefined {
if (this.dot()) {
let count = 0;
for (const child of this.syntax.childNodes()) {
if (child.kind === 'Identifier') {
count++;
if (count === 2) return new IdentifierAst(child);
}
}
return undefined;
}
return findFirstChild(this.syntax, IdentifierAst.cast);
}

dot(): Token | undefined {
return findChildToken(this.syntax, 'Dot');
}

namespaceName(): IdentifierAst | undefined {
if (!this.dot()) return undefined;
return findFirstChild(this.syntax, IdentifierAst.cast);
}

argList(): AttributeArgListAst | undefined {
return findFirstChild(this.syntax, AttributeArgListAst.cast);
}

static cast(node: SyntaxNode): FieldAttributeAst | undefined {
return node.kind === 'FieldAttribute' ? new FieldAttributeAst(node) : undefined;
}
}

export class ModelAttributeAst implements AstNode {
readonly syntax: SyntaxNode;

constructor(syntax: SyntaxNode) {
this.syntax = syntax;
}

doubleAt(): Token | undefined {
return findChildToken(this.syntax, 'DoubleAt');
}

name(): IdentifierAst | undefined {
return findFirstChild(this.syntax, IdentifierAst.cast);
}

argList(): AttributeArgListAst | undefined {
return findFirstChild(this.syntax, AttributeArgListAst.cast);
}

static cast(node: SyntaxNode): ModelAttributeAst | undefined {
return node.kind === 'ModelAttribute' ? new ModelAttributeAst(node) : undefined;
}
}
Loading
Loading