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
|
// Generated file by ast_generator
|
||||||
export type EnumStatement = {
|
export type Statement_Enum = {
|
||||||
kind: "Enum";
|
kind: "Enum",
|
||||||
[0]: Enum;
|
[0]: Enum,
|
||||||
};
|
};
|
||||||
export const EnumStatement = (v0: Enum): EnumStatement => ({ kind: "Enum", [0]: v0 });
|
export const Statement_Enum = (v0: Enum): Statement_Enum => ({ kind: "Enum", [0]: v0 });
|
||||||
export type NodeStatement = {
|
export type Statement_Node = {
|
||||||
kind: "Node";
|
kind: "Node",
|
||||||
[0]: Node;
|
[0]: Node,
|
||||||
};
|
};
|
||||||
export const NodeStatement = (v0: Node): NodeStatement => ({ kind: "Node", [0]: v0 });
|
export const Statement_Node = (v0: Node): Statement_Node => ({ kind: "Node", [0]: v0 });
|
||||||
export type Statement = EnumStatement | NodeStatement;
|
export type Statement = Statement_Enum | Statement_Node;
|
||||||
|
export const Statement = { Enum: Statement_Enum, Node: Statement_Node } as const;
|
||||||
|
|
||||||
export type Enum = {
|
export type Enum = {
|
||||||
name: Name;
|
name: Name;
|
||||||
nodes: Node[];
|
nodes: Node[];
|
||||||
};
|
};
|
||||||
export const Enum = (name: Name, nodes: Node[]): Enum => ({ name, nodes });
|
export const Enum = (name: Name, nodes: Node[]): Enum => ({ name, nodes });
|
||||||
|
|
||||||
export type Node = {
|
export type Node = {
|
||||||
name: Name;
|
name: Name;
|
||||||
params: Param[];
|
params: Param[];
|
||||||
};
|
};
|
||||||
export const Node = (name: Name, params: Param[]): Node => ({ name, params });
|
export const Node = (name: Name, params: Param[]): Node => ({ name, params });
|
||||||
export type NamedParam = {
|
|
||||||
kind: "Named";
|
export type Param_Named = {
|
||||||
name: Name;
|
kind: "Named",
|
||||||
type_: Type;
|
name: Name,
|
||||||
|
type_: Type,
|
||||||
};
|
};
|
||||||
export const NamedParam = (name: Name, type_: Type): NamedParam => ({ kind: "Named", name, type_ });
|
export const Param_Named = (name: Name, type_: Type): Param_Named => ({ kind: "Named", name, type_ });
|
||||||
export type UnnamedParam = {
|
export type Param_Unnamed = {
|
||||||
kind: "Unnamed";
|
kind: "Unnamed",
|
||||||
[0]: Type;
|
[0]: Type,
|
||||||
};
|
};
|
||||||
export const UnnamedParam = (v0: Type): UnnamedParam => ({ kind: "Unnamed", [0]: v0 });
|
export const Param_Unnamed = (v0: Type): Param_Unnamed => ({ kind: "Unnamed", [0]: v0 });
|
||||||
export type Param = NamedParam | UnnamedParam;
|
export type Param = Param_Named | Param_Unnamed;
|
||||||
export type NameType = {
|
export const Param = { Named: Param_Named, Unnamed: Param_Unnamed } as const;
|
||||||
kind: "Name";
|
|
||||||
[0]: Name;
|
export type Type_Name = {
|
||||||
|
kind: "Name",
|
||||||
|
[0]: Name,
|
||||||
};
|
};
|
||||||
export const NameType = (v0: Name): NameType => ({ kind: "Name", [0]: v0 });
|
export const Type_Name = (v0: Name): Type_Name => ({ kind: "Name", [0]: v0 });
|
||||||
export type OptionalType = {
|
export type Type_Optional = {
|
||||||
kind: "Optional";
|
kind: "Optional",
|
||||||
[0]: Type;
|
[0]: Type,
|
||||||
};
|
};
|
||||||
export const OptionalType = (v0: Type): OptionalType => ({ kind: "Optional", [0]: v0 });
|
export const Type_Optional = (v0: Type): Type_Optional => ({ kind: "Optional", [0]: v0 });
|
||||||
export type MultipleType = {
|
export type Type_Multiple = {
|
||||||
kind: "Multiple";
|
kind: "Multiple",
|
||||||
[0]: Type;
|
[0]: Type,
|
||||||
};
|
};
|
||||||
export const MultipleType = (v0: Type): MultipleType => ({ kind: "Multiple", [0]: v0 });
|
export const Type_Multiple = (v0: Type): Type_Multiple => ({ kind: "Multiple", [0]: v0 });
|
||||||
export type Type = NameType | OptionalType | MultipleType;
|
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 = {
|
export type Name = {
|
||||||
[0]: string;
|
[0]: string;
|
||||||
line: number;
|
line: number;
|
||||||
@ -55,3 +63,4 @@ export type Name = {
|
|||||||
};
|
};
|
||||||
export const Name = (v0: string, line: number, col: number): Name => ({ [0]: v0, line, col });
|
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";
|
} from "https://deno.land/x/nearley@2.19.7-deno/mod.ts";
|
||||||
|
|
||||||
import compiledParserGrammar from "./parser.out.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 {
|
class TypescriptGenerator {
|
||||||
private result = "";
|
private result = "";
|
||||||
@ -20,35 +28,75 @@ class TypescriptGenerator {
|
|||||||
this.generateNode(statement[0]);
|
this.generateNode(statement[0]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
this.result += "\n";
|
||||||
}
|
}
|
||||||
return this.result;
|
return this.result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private generateEnum(enum_: Enum) {
|
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 enumName = this.makeName(enum_.name);
|
||||||
const nodeNames: string[] = [];
|
const nodeNames: [string, string][] = [];
|
||||||
for (const node of enum_.nodes) {
|
for (const node of enum_.nodes) {
|
||||||
const kind = this.makeName(node.name);
|
const name = this.makeName(node.name);
|
||||||
const name = `${kind}${enumName}`;
|
const fullName = `${enumName}_${name}`;
|
||||||
this.generateNodeBody(node, name, kind);
|
nodeNames.push([name, fullName]);
|
||||||
nodeNames.push(name);
|
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) {
|
private makeParamField(param: Param, index: number): string {
|
||||||
this.generateNodeBody(node);
|
switch (param.kind) {
|
||||||
|
case "Named":
|
||||||
|
return this.makeNamedParam(param);
|
||||||
|
case "Unnamed":
|
||||||
|
return `[${index}]: ${this.makeType(param[0])}`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private generateNodeBody(
|
private generateNode(
|
||||||
node: Node,
|
node: Node,
|
||||||
name = this.makeName(node.name),
|
|
||||||
kind?: string,
|
|
||||||
) {
|
) {
|
||||||
|
const name = this.makeName(node.name);
|
||||||
this.result += `export type ${name} = {\n`;
|
this.result += `export type ${name} = {\n`;
|
||||||
if (kind) {
|
|
||||||
this.result += ` kind: "${kind}";\n`;
|
|
||||||
}
|
|
||||||
for (
|
for (
|
||||||
const [param, index] of node.params
|
const [param, index] of node.params
|
||||||
.map((v, i) => [v, i] as const)
|
.map((v, i) => [v, i] as const)
|
||||||
@ -57,14 +105,23 @@ class TypescriptGenerator {
|
|||||||
case "Named":
|
case "Named":
|
||||||
this.result += ` ${this.makeNamedParam(param)};\n`;
|
this.result += ` ${this.makeNamedParam(param)};\n`;
|
||||||
break;
|
break;
|
||||||
case "Unnamed":
|
case "Unnamed": {
|
||||||
this.result += ` [${index}]: ${
|
const type_ = this.makeType(param[0]);
|
||||||
this.makeType(param[0])
|
this.result += ` [${index}]: ${type_};\n`;
|
||||||
};\n`;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.result += "};\n";
|
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) => {
|
.map((param, index) => {
|
||||||
switch (param.kind) {
|
switch (param.kind) {
|
||||||
case "Named":
|
case "Named":
|
||||||
@ -74,22 +131,21 @@ class TypescriptGenerator {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.join(", ");
|
.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 name = this.makeName(param.name);
|
||||||
const type_ = this.makeType(param.type_);
|
const type_ = this.makeType(param.type_);
|
||||||
return `${name}: ${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]) %}
|
elementTail -> (nl__ element):* {% v => v[0].map(w => w[1]) %}
|
||||||
|
|
||||||
element -> enum {% v => ast.EnumStatement(v[0]) %}
|
element -> enum {% v => ast.Statement.Enum(v[0]) %}
|
||||||
| node {% v => ast.NodeStatement(v[0]) %}
|
| node {% v => ast.Statement.Node(v[0]) %}
|
||||||
|
|
||||||
enum -> name _ "{" nodes "}" {% v => ast.Enum(v[0], v[3]) %}
|
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]) %}
|
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]] : [] %}
|
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 %}
|
param -> namedParam {% id %}
|
||||||
| unnamedParam {% 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 %}
|
type -> optional {% id %}
|
||||||
| multiple {% 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) %}
|
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_):+
|
nl__ -> sl_ (%newline sl_):+
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user