Fix some issues in treegen

This commit is contained in:
Sam Vervaeck 2020-05-26 20:59:44 +02:00
parent 4197fe21dc
commit ae41362367
3 changed files with 48 additions and 20 deletions

View file

@ -36,6 +36,22 @@ const nodeProto = {
} }
}, },
visit(visitors) {
const stack = [this];
while (stack.length > 0) {
const node = stack.pop();
const key = `visit${kindToString(node.kind)}`
for (const visitor of visitors) {
if (visitor[key] !== undefined) {
visitor[key](node);
}
}
for (const childNode of node.getChildNodes()) {
stack.push(childNode);
}
}
},
*preorder() { *preorder() {
const stack = [this]; const stack = [this];
while (stack.length > 0) { while (stack.length > 0) {
@ -52,6 +68,17 @@ const nodeProto = {
return true; return true;
}, },
getParentOfKind(kind) {
let currNode = this.parentNode;
while (currNode !== null) {
if (currNode.kind === kind) {
return currNode;
}
currNode = currNode.parentNode;
}
return null;
},
*findAllChildrenOfKind(kind) { *findAllChildrenOfKind(kind) {
for (const node of this.preorder()) { for (const node of this.preorder()) {
if (!node.mayContainKind(kind)) { if (!node.mayContainKind(kind)) {

View file

@ -9,13 +9,15 @@ export type SyntaxRange = [Syntax, Syntax];
export function isSyntax(value: any): value is Syntax; export function isSyntax(value: any): value is Syntax;
interface SyntaxBase<K extends SyntaxKind> { interface SyntaxBase {
id: number; id: number;
kind: K kind: SyntaxKind;
_typeInfo: TypeInfo; _typeInfo: TypeInfo;
parentNode: Syntax | null; parentNode: Syntax | null;
span: TextSpan | null; span: TextSpan | null;
visit(visitors: NodeVisitor[]): void;
preorder(): IterableIterator<Syntax>; preorder(): IterableIterator<Syntax>;
getParentOfKind<K1 extends SyntaxKind>(kind: K1): ResolveSyntaxKind<K1> | null;
getChildNodes(): IterableIterator<Syntax>, getChildNodes(): IterableIterator<Syntax>,
findAllChildrenOfKind<K1 extends SyntaxKind>(kind: K1): IterableIterator<ResolveSyntaxKind<K1>>; findAllChildrenOfKind<K1 extends SyntaxKind>(kind: K1): IterableIterator<ResolveSyntaxKind<K1>>;
} }

View file

@ -46,14 +46,14 @@ export function generateAST(decls: Declaration[]) {
// After we're done mappping parents to children, we can use isLeafNode() // After we're done mappping parents to children, we can use isLeafNode()
// to store the nodes we will be iterating most frequently on. // to store the nodes we will be iterating most frequently on.
const finalNodes: NodeDeclaration[] = nodeDecls.filter(decl => isLeafNode(decl.name)); const finalNodes: NodeDeclaration[] = nodeDecls.filter(decl => isFinalNode(decl.name));
// Write a JavaScript file that contains all AST definitions. // Write a JavaScript file that contains all AST definitions.
jsFile.write(`\nconst NODE_TYPES = {\n`); jsFile.write(`\nconst NODE_TYPES = {\n`);
jsFile.indent(); jsFile.indent();
for (const decl of finalNodes) { for (const decl of finalNodes) {
if (decl.type === 'NodeDeclaration' && isLeafNode(decl.name)) { if (decl.type === 'NodeDeclaration' && isFinalNode(decl.name)) {
jsFile.write(`'${decl.name}': {\n`); jsFile.write(`'${decl.name}': {\n`);
jsFile.indent(); jsFile.indent();
jsFile.write(`index: ${decl.index},\n`); jsFile.write(`index: ${decl.index},\n`);
@ -86,7 +86,7 @@ export function generateAST(decls: Declaration[]) {
jsFile.write(`exported.is${decl.name} = function (value) {\n`); jsFile.write(`exported.is${decl.name} = function (value) {\n`);
jsFile.indent(); jsFile.indent();
jsFile.write(`if (!isSyntax(value)) {\n return false;\n}\n`); jsFile.write(`if (!isSyntax(value)) {\n return false;\n}\n`);
if (isLeafNode(decl.name)) { if (isFinalNode(decl.name)) {
jsFile.write(` return value.kind === ${decl.index};\n`); jsFile.write(` return value.kind === ${decl.index};\n`);
} else { } else {
jsFile.write('return ' + [...getFinalNodes(decl.name)].map(d => `value.kind === ${getDeclarationNamed(d).index}`).join(' || ') + '\n'); jsFile.write('return ' + [...getFinalNodes(decl.name)].map(d => `value.kind === ${getDeclarationNamed(d).index}`).join(' || ') + '\n');
@ -104,7 +104,7 @@ export function generateAST(decls: Declaration[]) {
dtsFile.write('export class NodeVisitor {\n'); dtsFile.write('export class NodeVisitor {\n');
dtsFile.write(' public visit(node: Syntax): void;\n'); dtsFile.write(' public visit(node: Syntax): void;\n');
for (const decl of finalNodes) { for (const decl of finalNodes) {
dtsFile.write(` protected visit${decl.name}(node: ${decl.name}): void;\n`); dtsFile.write(` protected visit${decl.name}?(node: ${decl.name}): void;\n`);
} }
dtsFile.write('}\n\n'); dtsFile.write('}\n\n');
@ -116,15 +116,14 @@ export function generateAST(decls: Declaration[]) {
for (const decl of decls) { for (const decl of decls) {
if (decl.type === 'NodeDeclaration') { if (decl.type === 'NodeDeclaration') {
if (isLeafNode(decl.name)) { if (isFinalNode(decl.name)) {
dtsFile.write(`export interface ${decl.name} extends SyntaxBase<SyntaxKind.${decl.name}> {\n`) dtsFile.write(`export interface ${decl.name} extends SyntaxBase {\n`)
dtsFile.indent() dtsFile.indent()
dtsFile.write(`kind: SyntaxKind.${decl.name};\n`); dtsFile.write(`kind: SyntaxKind.${decl.name};\n`);
for (const field of getAllFields(decl)) { for (const field of getAllFields(decl)) {
dtsFile.write(`${field.name}: ${emitTypeScriptType(field.typeNode)};\n`); dtsFile.write(`${field.name}: ${emitTypeScriptType(field.typeNode)};\n`);
} }
dtsFile.write(`parentNode: ${decl.name}Parent;\n`); dtsFile.write(`parentNode: ${decl.name}Parent;\n`);
dtsFile.write(`getParentOfKind(kind: SyntaxKind): ${decl.name}AnyParent;\n`)
dtsFile.write(`getChildNodes(): IterableIterator<${decl.name}Child>\n`) dtsFile.write(`getChildNodes(): IterableIterator<${decl.name}Child>\n`)
dtsFile.dedent(); dtsFile.dedent();
dtsFile.write(`}\n\n`); dtsFile.write(`}\n\n`);
@ -373,14 +372,13 @@ export function generateAST(decls: Declaration[]) {
function* getFinalNodes(declName: string): IterableIterator<string> { function* getFinalNodes(declName: string): IterableIterator<string> {
const stack = [ declName ]; const stack = [ declName ];
while (stack.length > 0) { while (stack.length > 0) {
console.log("HE")
const nodeName = stack.pop()!; const nodeName = stack.pop()!;
for (const childName of getNodesDirectlyInheritingFrom(nodeName)) { for (const childName of getNodesDirectlyInheritingFrom(nodeName)) {
//const childDecl = getDeclarationNamed(childName) //const childDecl = getDeclarationNamed(childName)
//if (childDecl.type !== 'NodeDeclaration') { //if (childDecl.type !== 'NodeDeclaration') {
// throw new Error(`Node ${declName} has a child named '${childDecl.name}' that is not a node.`); // throw new Error(`Node ${declName} has a child named '${childDecl.name}' that is not a node.`);
//} //}
if (isLeafNode(childName)) { if (isFinalNode(childName)) {
yield childName; yield childName;
} else { } else {
stack.push(childName); stack.push(childName);
@ -390,14 +388,15 @@ export function generateAST(decls: Declaration[]) {
} }
function* getAllFields(nodeDecl: NodeDeclaration): IterableIterator<NodeField> { function* getAllFields(nodeDecl: NodeDeclaration): IterableIterator<NodeField> {
if (isLeafNode(nodeDecl.name)) { yield* nodeDecl.fields;
yield* nodeDecl.fields; if (isFinalNode(nodeDecl.name)) {
//for (const parentName of nodeDecl.parents) { for (const parentName of nodeDecl.parents) {
// const parentDecl = getDeclarationNamed(parentName); const parentDecl = getDeclarationNamed(parentName);
// if (parentDecl.type !== 'NodeDeclaration') { if (parentDecl.type !== 'NodeDeclaration') {
// throw new Error(`Parent declaration '${parentName}' of '${nodeDecl.name}' must be a node declaration.`); throw new Error(`Parent declaration '${parentName}' of '${nodeDecl.name}' must be a node declaration.`);
// } }
//} yield* parentDecl.fields;
}
} else { } else {
for (const nodeName of getFinalNodes(nodeDecl.name)) { for (const nodeName of getFinalNodes(nodeDecl.name)) {
yield* getAllFields(getDeclarationNamed(nodeName) as NodeDeclaration); yield* getAllFields(getDeclarationNamed(nodeName) as NodeDeclaration);
@ -417,7 +416,7 @@ export function generateAST(decls: Declaration[]) {
return childrenOf[name] !== undefined && childrenOf[name].length !== 0; return childrenOf[name] !== undefined && childrenOf[name].length !== 0;
} }
function isLeafNode(name: string): boolean { function isFinalNode(name: string): boolean {
const decl = getDeclarationNamed(name); const decl = getDeclarationNamed(name);
if (decl.type !== 'NodeDeclaration') { if (decl.type !== 'NodeDeclaration') {
return false; return false;