nested constructors, shallow enums
This commit is contained in:
parent
07737d23c2
commit
99383fd9c1
73
ast.out.ts
73
ast.out.ts
@ -1,53 +1,61 @@
|
||||
// Generated file by ast_generator
|
||||
export type EnumStatement = {
|
||||
kind: "Enum";
|
||||
[0]: Enum;
|
||||
export type Statement_Enum = {
|
||||
kind: "Enum",
|
||||
[0]: Enum,
|
||||
};
|
||||
export const EnumStatement = (v0: Enum): EnumStatement => ({ kind: "Enum", [0]: v0 });
|
||||
export type NodeStatement = {
|
||||
kind: "Node";
|
||||
[0]: Node;
|
||||
export const Statement_Enum = (v0: Enum): Statement_Enum => ({ kind: "Enum", [0]: v0 });
|
||||
export type Statement_Node = {
|
||||
kind: "Node",
|
||||
[0]: Node,
|
||||
};
|
||||
export const NodeStatement = (v0: Node): NodeStatement => ({ kind: "Node", [0]: v0 });
|
||||
export type Statement = EnumStatement | NodeStatement;
|
||||
export const Statement_Node = (v0: Node): Statement_Node => ({ kind: "Node", [0]: v0 });
|
||||
export type Statement = Statement_Enum | Statement_Node;
|
||||
export const Statement = { Enum: Statement_Enum, Node: Statement_Node } as const;
|
||||
|
||||
export type Enum = {
|
||||
name: Name;
|
||||
nodes: Node[];
|
||||
};
|
||||
export const Enum = (name: Name, nodes: Node[]): Enum => ({ name, nodes });
|
||||
|
||||
export type Node = {
|
||||
name: Name;
|
||||
params: Param[];
|
||||
};
|
||||
export const Node = (name: Name, params: Param[]): Node => ({ name, params });
|
||||
export type NamedParam = {
|
||||
kind: "Named";
|
||||
name: Name;
|
||||
type_: Type;
|
||||
|
||||
export type Param_Named = {
|
||||
kind: "Named",
|
||||
name: Name,
|
||||
type_: Type,
|
||||
};
|
||||
export const NamedParam = (name: Name, type_: Type): NamedParam => ({ kind: "Named", name, type_ });
|
||||
export type UnnamedParam = {
|
||||
kind: "Unnamed";
|
||||
[0]: Type;
|
||||
export const Param_Named = (name: Name, type_: Type): Param_Named => ({ kind: "Named", name, type_ });
|
||||
export type Param_Unnamed = {
|
||||
kind: "Unnamed",
|
||||
[0]: Type,
|
||||
};
|
||||
export const UnnamedParam = (v0: Type): UnnamedParam => ({ kind: "Unnamed", [0]: v0 });
|
||||
export type Param = NamedParam | UnnamedParam;
|
||||
export type NameType = {
|
||||
kind: "Name";
|
||||
[0]: Name;
|
||||
export const Param_Unnamed = (v0: Type): Param_Unnamed => ({ kind: "Unnamed", [0]: v0 });
|
||||
export type Param = Param_Named | Param_Unnamed;
|
||||
export const Param = { Named: Param_Named, Unnamed: Param_Unnamed } as const;
|
||||
|
||||
export type Type_Name = {
|
||||
kind: "Name",
|
||||
[0]: Name,
|
||||
};
|
||||
export const NameType = (v0: Name): NameType => ({ kind: "Name", [0]: v0 });
|
||||
export type OptionalType = {
|
||||
kind: "Optional";
|
||||
[0]: Type;
|
||||
export const Type_Name = (v0: Name): Type_Name => ({ kind: "Name", [0]: v0 });
|
||||
export type Type_Optional = {
|
||||
kind: "Optional",
|
||||
[0]: Type,
|
||||
};
|
||||
export const OptionalType = (v0: Type): OptionalType => ({ kind: "Optional", [0]: v0 });
|
||||
export type MultipleType = {
|
||||
kind: "Multiple";
|
||||
[0]: Type;
|
||||
export const Type_Optional = (v0: Type): Type_Optional => ({ kind: "Optional", [0]: v0 });
|
||||
export type Type_Multiple = {
|
||||
kind: "Multiple",
|
||||
[0]: Type,
|
||||
};
|
||||
export const MultipleType = (v0: Type): MultipleType => ({ kind: "Multiple", [0]: v0 });
|
||||
export type Type = NameType | OptionalType | MultipleType;
|
||||
export const Type_Multiple = (v0: Type): Type_Multiple => ({ kind: "Multiple", [0]: v0 });
|
||||
export type Type = Type_Name | Type_Optional | Type_Multiple;
|
||||
export const Type = { Name: Type_Name, Optional: Type_Optional, Multiple: Type_Multiple } as const;
|
||||
|
||||
export type Name = {
|
||||
[0]: string;
|
||||
line: number;
|
||||
@ -55,3 +63,4 @@ export type Name = {
|
||||
};
|
||||
export const Name = (v0: string, line: number, col: number): Name => ({ [0]: v0, line, col });
|
||||
|
||||
|
||||
|
124
ast_generator.ts
124
ast_generator.ts
@ -4,7 +4,15 @@ import {
|
||||
} from "https://deno.land/x/nearley@2.19.7-deno/mod.ts";
|
||||
|
||||
import compiledParserGrammar from "./parser.out.ts";
|
||||
import { Enum, Name, NamedParam, Node, Statement, Type } from "./ast.out.ts";
|
||||
import {
|
||||
Enum,
|
||||
Name,
|
||||
Node,
|
||||
Param,
|
||||
Param_Named,
|
||||
Statement,
|
||||
Type,
|
||||
} from "./ast.out.ts";
|
||||
|
||||
class TypescriptGenerator {
|
||||
private result = "";
|
||||
@ -20,35 +28,75 @@ class TypescriptGenerator {
|
||||
this.generateNode(statement[0]);
|
||||
break;
|
||||
}
|
||||
this.result += "\n";
|
||||
}
|
||||
return this.result;
|
||||
}
|
||||
|
||||
private generateEnum(enum_: Enum) {
|
||||
if (this.isShallowEnum(enum_)) {
|
||||
return this.generateShallowEnumBody(enum_);
|
||||
} else {
|
||||
return this.generateEnumBody(enum_);
|
||||
}
|
||||
}
|
||||
|
||||
private isShallowEnum(enum_: Enum): boolean {
|
||||
return !enum_.nodes.some((node) => node.params.length > 0);
|
||||
}
|
||||
|
||||
private generateShallowEnumBody(enum_: Enum) {
|
||||
const name = this.makeName(enum_.name);
|
||||
const fields = enum_.nodes.map((node) => this.makeName(node.name)).map(
|
||||
(name) => `${name}: "${name}"`,
|
||||
).join(", ");
|
||||
this.result += `export const ${name} = { ${fields} } as const;\n`;
|
||||
this.result += `export type ${name} = keyof typeof ${name};\n`;
|
||||
}
|
||||
|
||||
private generateEnumBody(enum_: Enum) {
|
||||
const enumName = this.makeName(enum_.name);
|
||||
const nodeNames: string[] = [];
|
||||
const nodeNames: [string, string][] = [];
|
||||
for (const node of enum_.nodes) {
|
||||
const kind = this.makeName(node.name);
|
||||
const name = `${kind}${enumName}`;
|
||||
this.generateNodeBody(node, name, kind);
|
||||
nodeNames.push(name);
|
||||
const name = this.makeName(node.name);
|
||||
const fullName = `${enumName}_${name}`;
|
||||
nodeNames.push([name, fullName]);
|
||||
this.result += `export type ${fullName} = {\n`;
|
||||
this.result += ` kind: "${name}",\n`;
|
||||
this.result += node.params.map((p, i) => this.makeParamField(p, i))
|
||||
.map((field) => ` ${field},\n`).join("");
|
||||
this.result += `};\n`;
|
||||
const fnParams = this.makeFnParams(node.params);
|
||||
const fields = this.makeFnFields(node.params);
|
||||
this.result += `export const ${fullName}` +
|
||||
` = (${fnParams}): ${fullName}` +
|
||||
` => ({ kind: "${name}", ${fields} });\n`;
|
||||
}
|
||||
this.result += `export type ${enumName} = ${nodeNames.join(" | ")};\n`;
|
||||
const typeList = nodeNames
|
||||
.map(([_, fullName]) => fullName)
|
||||
.join(" | ");
|
||||
this.result += `export type ${enumName} = ${typeList};\n`;
|
||||
const enumFieldFns = nodeNames
|
||||
.map(([name, fullName]) => `${name}: ${fullName}`)
|
||||
.join(", ");
|
||||
this.result +=
|
||||
`export const ${enumName} = { ${enumFieldFns} } as const;\n`;
|
||||
}
|
||||
|
||||
private generateNode(node: Node) {
|
||||
this.generateNodeBody(node);
|
||||
private makeParamField(param: Param, index: number): string {
|
||||
switch (param.kind) {
|
||||
case "Named":
|
||||
return this.makeNamedParam(param);
|
||||
case "Unnamed":
|
||||
return `[${index}]: ${this.makeType(param[0])}`;
|
||||
}
|
||||
}
|
||||
|
||||
private generateNodeBody(
|
||||
private generateNode(
|
||||
node: Node,
|
||||
name = this.makeName(node.name),
|
||||
kind?: string,
|
||||
) {
|
||||
const name = this.makeName(node.name);
|
||||
this.result += `export type ${name} = {\n`;
|
||||
if (kind) {
|
||||
this.result += ` kind: "${kind}";\n`;
|
||||
}
|
||||
for (
|
||||
const [param, index] of node.params
|
||||
.map((v, i) => [v, i] as const)
|
||||
@ -57,14 +105,23 @@ class TypescriptGenerator {
|
||||
case "Named":
|
||||
this.result += ` ${this.makeNamedParam(param)};\n`;
|
||||
break;
|
||||
case "Unnamed":
|
||||
this.result += ` [${index}]: ${
|
||||
this.makeType(param[0])
|
||||
};\n`;
|
||||
case "Unnamed": {
|
||||
const type_ = this.makeType(param[0]);
|
||||
this.result += ` [${index}]: ${type_};\n`;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.result += "};\n";
|
||||
const fnParams = node.params
|
||||
const fnParams = this.makeFnParams(node.params);
|
||||
const fields = this.makeFnFields(node.params);
|
||||
this.result += `export const ${name}` +
|
||||
` = (${fnParams}): ${name}` +
|
||||
` => ({ ${fields} });\n`;
|
||||
}
|
||||
|
||||
private makeFnParams(params: Param[]): string {
|
||||
return params
|
||||
.map((param, index) => {
|
||||
switch (param.kind) {
|
||||
case "Named":
|
||||
@ -74,22 +131,21 @@ class TypescriptGenerator {
|
||||
}
|
||||
})
|
||||
.join(", ");
|
||||
const fields = [
|
||||
...(kind ? [`kind: "${kind}"`] : []),
|
||||
...node.params.map((param, index) => {
|
||||
switch (param.kind) {
|
||||
case "Named":
|
||||
return this.makeName(param.name);
|
||||
case "Unnamed":
|
||||
return `[${index}]: v${index}`;
|
||||
}
|
||||
}),
|
||||
].join(", ");
|
||||
this.result +=
|
||||
`export const ${name} = (${fnParams}): ${name} => ({ ${fields} });\n`;
|
||||
}
|
||||
|
||||
private makeNamedParam(param: NamedParam): string {
|
||||
private makeFnFields(params: Param[]): string {
|
||||
return params.map((param, index) => {
|
||||
switch (param.kind) {
|
||||
case "Named":
|
||||
return this.makeName(param.name);
|
||||
case "Unnamed":
|
||||
return `[${index}]: v${index}`;
|
||||
}
|
||||
})
|
||||
.join(", ");
|
||||
}
|
||||
|
||||
private makeNamedParam(param: Param_Named): string {
|
||||
const name = this.makeName(param.name);
|
||||
const type_ = this.makeType(param.type_);
|
||||
return `${name}: ${type_}`;
|
||||
|
20
parser.ne
20
parser.ne
@ -40,8 +40,8 @@ elements -> _ (element elementTail _):? {% v => v[1] ? [v[1][0], ...v[1][1]] : [
|
||||
|
||||
elementTail -> (nl__ element):* {% v => v[0].map(w => w[1]) %}
|
||||
|
||||
element -> enum {% v => ast.EnumStatement(v[0]) %}
|
||||
| node {% v => ast.NodeStatement(v[0]) %}
|
||||
element -> enum {% v => ast.Statement.Enum(v[0]) %}
|
||||
| node {% v => ast.Statement.Node(v[0]) %}
|
||||
|
||||
enum -> name _ "{" nodes "}" {% v => ast.Enum(v[0], v[3]) %}
|
||||
|
||||
@ -49,7 +49,9 @@ nodes -> _ (node nodeTail _):? {% v => v[1] ? [v[1][0], ...v[1][1]] : [] %}
|
||||
|
||||
nodeTail -> (nl__ node):* {% v => v[0].map(w => w[1]) %}
|
||||
|
||||
node -> name _ "(" params ")" {% v => ast.Node(v[0], v[3]) %}
|
||||
node -> name (_ paramList):? {% v => ast.Node(v[0], v[1] ? v[1][1] : []) %}
|
||||
|
||||
paramList -> "(" params ")" {% v => v[1] %}
|
||||
|
||||
params -> _ (param paramTail (_ ","):? _):? {% v => v[1] ? [v[1][0], ...v[1][1]] : [] %}
|
||||
|
||||
@ -58,22 +60,22 @@ paramTail -> ("," _ param):* {% v => v[0].map(w => w[2]) %}
|
||||
param -> namedParam {% id %}
|
||||
| unnamedParam {% id %}
|
||||
|
||||
namedParam -> name _ ":" _ type {% v => ast.NamedParam(v[0], v[4]) %}
|
||||
namedParam -> name _ ":" _ type {% v => ast.Param.Named(v[0], v[4]) %}
|
||||
|
||||
unnamedParam -> type {% v => ast.UnnamedParam(v[0]) %}
|
||||
unnamedParam -> type {% v => ast.Param.Unnamed(v[0]) %}
|
||||
|
||||
type -> optional {% id %}
|
||||
| multiple {% id %}
|
||||
| name {% v => ast.NameType(v[0]) %}
|
||||
| name {% v => ast.Type.Name(v[0]) %}
|
||||
|
||||
optional -> type "?" {% v => ast.OptionalType(v[0]) %}
|
||||
optional -> type "?" {% v => ast.Type.Optional(v[0]) %}
|
||||
|
||||
multiple -> type "[" "]" {% v => ast.MultipleType(v[0]) %}
|
||||
multiple -> type "[" "]" {% v => ast.Type.Multiple(v[0]) %}
|
||||
|
||||
name -> %name {% v => ast.Name(v[0].value, v[0].line, v[0].col) %}
|
||||
|
||||
_ -> __:?
|
||||
__ -> (%whitespace|%newline|%singeLineComment|%multiLineComment):+
|
||||
__ -> (%whitespace|%newline|%singleLineComment|%multiLineComment):+
|
||||
|
||||
nl__ -> sl_ (%newline sl_):+
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user