The GenericVisitor class contains methods for extracting specific information from the abstract syntax tree (AST) of a programming language, such as identifiers, properties, types, and binary expressions, but three of the methods are currently empty and unused.
// TODO: move this in to CPP visitor above is our GenericVisitor
GenericVisitor.prototype.visitIdexpression = function (ctx) {
// var id = getGenericContext.apply(this, [ctx])
return {
type: 'Identifier',
name: this.visitChildren(ctx).flat().pop()
}
}
GenericVisitor.prototype.visitMemberdeclaration = function (ctx) {
var obj = getGenericContext.apply(this, [ctx])
return {
type: 'Property',
kind: obj.declspecifierseq.accept(this).flat(4).pop(), // get, set, init
key: obj.memberdeclaratorlist.accept(this).flat(6).pop(),
// computed: boolean,
value: null, // TODO: default value
method: false,
// shorthand: boolean,
}
}
GenericVisitor.prototype.visitTrailingtypespecifier = function (ctx) {
return {
type: 'Type',
name: this.visitChildren(ctx).flat(4).pop()
}
}
GenericVisitor.prototype.visitTypespecifier = function (ctx) {
return this.visitChildren(ctx).flat().pop()
}
GenericVisitor.prototype.visitEqualityexpression = function (ctx) {
var obj = getGenericContext.apply(this, [ctx])
if(!obj.NotEqual && !obj.Equal) return this.visitChildren(ctx)
return {
type: 'BinaryExpression',
operator: (obj.NotEqual || obj.Equal).accept(this),
left: obj.equalityexpression.accept(this),
right: obj.relationalexpression.accept(this),
}
}
GenericVisitor.prototype.visitClassspecifier = function (ctx) {
var obj = getGenericContext.apply(this, [ctx])
return {
type: 'ClassExpression',
id: null,
superClass: obj.classhead.accept(this).flat(3).pop(),
body: obj.memberspecification.accept(this),
}
}
GenericVisitor.prototype.visitPtrdeclarator = function (ctx) {
var obj = getGenericContext.apply(this, [ctx])
return
}
GenericVisitor.prototype.visitSimpledeclaration = function (ctx) {
var obj = getGenericContext.apply(this, [ctx])
}
GenericVisitor.prototype.visitFunctiondefinition = function (ctx) {
var obj = getGenericContext.apply(this, [ctx])
var kind = getGenericContext.apply(this, [obj.declspecifierseq])
console.log(kind)
var declarator = obj.declarator.accept(this)
return {
type: 'Function',
// id: ,
// params: ,
body: obj.functionbody.accept(this),
kind: ,
// generator: boolean,
// async: boolean,
// expression: boolean,
static: kind[0].flat(3).pop() === 'static',
// returnType: returnType ? returnType.accept(this) : returnType,
// void: ctx.declspecifierseq().accept(this) === 'void',
}
}
GenericVisitor.prototype.visitParameterdeclaration = function (ctx) {
}
GenericVisitor.prototype.visitDeclspecifierseq = function (ctx) {
}
GenericVisitor.prototype.visit = function (ctx) {
console.log(Object.getPrototypeOf(ctx))
var visit = Object.getPrototypeOf(ctx).constructor.name
.replace(/Context$/, '')
if(typeof this['visit' + visit] === 'function') {
return this['visit' + visit](ctx)
}
var obj = getGenericContext.apply(this, [ctx])
return Object.keys(obj).reduce((ret, cur) => {
ret[cur] = obj ? obj.accept(this) : obj
}, {})
}
GenericVisitor.prototype.visitTranslationunit = function (ctx) {
var obj = getGenericContext.apply(this, [ctx])
return {
type: 'Program',
body: obj.declarationseq.accept(this)
}
}
GenericVisitor.prototype.visitDeclarationseq = function (ctx) {
var obj = getGenericContext.apply(this, [ctx])
if(!obj.declarationseq) return obj.declaration.accept(this)
return [...obj.declarationseq.accept(this), ...obj.declaration.accept(this)]
}
GenericVisitor.prototype.visitFunctiondefinition = function (ctx) {
var obj = getGenericContext.apply(this, [ctx])
var decl = getGenericContext.apply(this, [obj.declarator])
var ptr = getGenericContext.apply(this, [decl.ptrdeclarator])
var noptr = getGenericContext.apply(this, [ptr.noptrdeclarator])
return {
type: 'Function',
id: getGenericContext.apply(this, [noptr.noptrdeclarator]).declaratorid.accept(this),
params: noptr.parametersandqualifiers.accept(this),
body: obj.functionbody.accept(this),
// returnType: returnType ? returnType.accept(this) : returnType,
// void: ctx.declspecifierseq().accept(this) === 'void',
}
}
GenericVisitor.prototype.visitDeclaratorid = function (ctx) {
return getGenericContext.apply(this, [ctx]).idexpression.accept(this)
}
GenericVisitor.prototype.visitFunctionbody = function (ctx) {
return getGenericContext.apply(this, [ctx]).compoundstatement.accept(this)
}
GenericVisitor.prototype.visitCompoundstatement = function (ctx) {
return {
type: 'BlockStatement',
body: getGenericContext.apply(this, [ctx]).statementseq.accept(this)
}
}
GenericVisitor.prototype.visitStatementseq = function (ctx) {
var obj = getGenericContext.apply(this, [ctx])
if(!obj.statementseq) return obj.statement.accept(this)
return [...obj.statementseq.accept(this), ...obj.statement.accept(this)]
}
GenericVisitor.prototype.visitStatement = function (ctx) {
return this.visitChildren(ctx)
}
GenericVisitor.prototype.visitExpressionstatement = function (ctx) {
var obj = getGenericContext.apply(this, [ctx])
return obj.expression.accept(this)
}
GenericVisitor.prototype.visitExpression = function (ctx) {
var obj = getGenericContext.apply(this, [ctx])
return this.visitChildren(ctx)[0]
}
GenericVisitor.prototype.visitAssignmentexpression = function (ctx) {
// var obj = getGenericContext.apply(this, [ctx])
return {
type: 'AssignmentExpression',
operator: '=' | '*=' | '**=' | '/=' | '%=' | '+=' | '-=' |
'<<=' | '>>=' | '>>>=' | '&=' | '^=' | '|=',
left: 0,
right: this.visitChildren(ctx)[0],
}
}
GenericVisitor.prototype.visitConditionalexpression = function (ctx) {
// var obj = getGenericContext.apply(this, [ctx])
return {
type: 'ConditionalExpression',
test: this.visitChildren(ctx)[0],
consequent: 0,
alternate: 0,
}
}
GenericVisitor.prototype.visitInclusiveorexpression = function (ctx) {
// var obj = getGenericContext.apply(this, [ctx])
return {
type: 'LogicalExpression',
operator: '||',
left: this.visitChildren(ctx),
right: 0,
}
}
GenericVisitor.prototype.visitExclusiveorexpression = function (ctx) {
return {
type: 'LogicalExpression',
operator: '||',
left: this.visitChildren(ctx),
right: 0,
}
}
GenericVisitor.prototype.visitRelationalexpression = function (ctx) {
return this.visitChildren(ctx)[0]
}
GenericVisitor.prototype.visitAdditiveexpression = function (ctx) {
return this.visitChildren(ctx)[0]
}
GenericVisitor.prototype.visitDeclarator = function (ctx) {
var params = ctx.parametersandqualifiers()
if(params) return params.accept(this)
return {
type: 'Identifier',
name: getGenericToken(parser, ctx._start).value,
body: this.visitChildren(ctx)
}
}
GenericVisitor.prototype.visitDeclspecifierseq = function (ctx) {
// console.log(ctx.attributespecifierseq())
// console.log(ctx.declspecifierseq())
// console.log(ctx.declspecifier())
var seq = ctx.declspecifierseq()
if(!seq) return ctx.declspecifier().accept(this)
return [ctx.declspecifier().accept(this), seq.accept(this)]
}
GenericVisitor.prototype.visitDeclspecifier = function (ctx) {
return {
storage: ctx.storageclassspecifier(),
type: ctx.typespecifier(),
function: ctx.functionspecifier(),
typedef: getGenericToken(ctx.Typedef()),
friend: getGenericToken(ctx.Friend()),
const: getGenericToken(ctx.Constexpr())
}
}
GenericVisitor.prototype.visitPseudodestructorname = function (ctx) {
//console.log('hit')
return {
id: ctx.decltypespecifier().accept(this)
}
}
GenericVisitor.prototype.visitSimpledeclaration = function (ctx) {
return {
type: 'Declarator',
value: getGenericToken(parser, ctx._start).value,
body: this.visitChildren(ctx)
}
}
var types = selectDom(['//SimpletypespecifierContext'], dom)
types.forEach(t => {
var node = selectDom(['.//TerminalNode'], t)
assert(node.length === 1)
t.replaceWith(selectDom('./*', treeToHtml([{
type: 'Type',
id: node[0].getAttribute('value')
}])))
})
var ids = selectDom(['//IdexpressionContext'], dom)
ids.forEach(i => {
var node = selectDom(['.//TerminalNode'], i)
// unary operator parses incorrectly
var ctx = selectDom(['.//ClassnameContext'], i)
if(ctx.length > 0 && node[0].getAttribute('value') === '~') {
i.replaceWith(selectDom('./*', treeToHtml([{
type: 'UnaryExpression',
operator: '~',
argument: {
type: 'Identifier',
name: node[1].getAttribute('value')
},
prefix: true
}])))
} else {
assert(node.length === 1)
i.replaceWith(selectDom('./*', treeToHtml([{
type: 'Identifier',
name: node[0].getAttribute('value')
}])))
}
})
// TODO: use transpile to get even more succinct
selectDom([
'//MemberdeclarationContext',
replace(ctx => selectDom('./*', treeToHtml([{
type: 'Property',
kind: htmlToTree(selectDom('.//Type', ctx)),
key: htmlToTree(selectDom('.//Identifier', ctx)),
method: false,
computed: false,
value: null,
shorthand: false,
}])))
], dom)
selectDom([
// TODO: use parent:: method instead especially since it supports it
'//ClassspecifierContext',
replace(ctx => selectDom('./*', treeToHtml([{
type: 'ClassExpression',
id: null,
superClass: selectDom('.//ClasskeyContext//@value', ctx),
body: {
type: 'ClassBody',
body: htmlToTree(selectDom('.//Property', ctx))
}
}])))
], dom)
selectDom([
'//DeclspecifierseqContext[not(.//DeclspecifierseqContext)]',
replace(ctx => {
var result = selectDom([
`.//Type[not(.//parent::Identifier)]
|.//Identifier[not(.//parent::ClassExpression)]
|.//ClassExpression`
], ctx)
console.log(result)
return result
})
], dom)
selectDom([
'//SimpledeclarationContext',
replace(ctx => selectDom('./*', treeToHtml([{
type: 'VariableDeclaration',
declarations: [{
type: 'VariableDeclarator',
id: htmlToTree(selectDom('.//Identifier', ctx)),
init: htmlToTree(selectDom('.//ClassExpression', ctx)),
kind: htmlToTree(selectDom('.//Type', ctx)),
static: selectDom('.//DeclspecifierContext//@value', ctx) === 'static'
}],
kind: selectDom('.//CvqualifierContext//@value', ctx) === 'const'
? 'const'
: selectDom('.//DeclspecifierContext//@value', ctx) === 'typedef'
? 'typedef'
: 'let'
}])))
], dom)
class GenericVisitor {
visitIdexpression(ctx) {
return {
type: 'Identifier',
name: this.visitChildren(ctx).flat().pop()
}
}
visitMemberdeclaration(ctx) {
const obj = this.getGenericContext(ctx);
const [kind, key] = this.visitChildren(ctx);
return {
type: 'Property',
kind: kind.flat(4).pop(),
key,
method: false,
computed: false,
value: null,
shorthand: false,
}
}
visitTrailingtypespecifier(ctx) {
return {
type: 'Type',
name: this.visitChildren(ctx).flat(4).pop()
}
}
visitTypespecifier(ctx) {
return this.visitChildren(ctx).flat().pop()
}
visitEqualityexpression(ctx) {
const obj = this.getGenericContext(ctx);
if (!obj.NotEqual &&!obj.Equal) return this.visitChildren(ctx);
return {
type: 'BinaryExpression',
operator: obj.NotEqual? obj.NotEqual.accept(this) : obj.Equal.accept(this),
left: obj.equalityexpression.accept(this),
right: obj.relationalexpression.accept(this),
}
}
visitClassspecifier(ctx) {
const obj = this.getGenericContext(ctx);
const superClass = obj.classhead.accept(this).flat(3).pop();
return {
type: 'ClassExpression',
id: null,
superClass,
body: obj.memberspecification.accept(this),
}
}
visitPtrdeclarator(ctx) {
// TODO: implement
return null;
}
visitSimpledeclaration(ctx) {
// TODO: implement
}
visitFunctiondefinition(ctx) {
const obj = this.getGenericContext(ctx);
const kind = this.getGenericContext(obj.declspecifierseq);
const declarator = obj.declarator.accept(this);
return {
type: 'Function',
id: declarator,
params: obj.parametersandqualifiers.accept(this),
body: obj.functionbody.accept(this),
kind: kind.flat(3).pop(),
static: kind[0].flat(3).pop() ==='static',
generator: false,
async: false,
expression: false,
}
}
visitParameterdeclaration(ctx) {
// TODO: implement
}
visitDeclspecifierseq(ctx) {
// TODO: implement
}
visitDeclspecifier(ctx) {
return {
storage: ctx.storageclassspecifier(),
type: ctx.typespecifier(),
function: ctx.functionspecifier(),
typedef: ctx.Typedef(),
friend: ctx.Friend(),
const: ctx.Constexpr(),
}
}
visitPseudodestructorname(ctx) {
return {
id: ctx.decltypespecifier().accept(this),
}
}
visitSimpledeclaration(ctx) {
return {
type: 'Declarator',
value: this.getGenericToken(ctx._start).value,
body: this.visitChildren(ctx),
}
}
visit() {
const visit = Object.getPrototypeOf(this).constructor.name
.replace(/Context$/, '');
return this['visit' + visit](...arguments);
}
visitTranslationunit(ctx) {
const obj = this.getGenericContext(ctx);
return {
type: 'Program',
body: obj.declarationseq.accept(this),
}
}
visitDeclarationseq(ctx) {
const obj = this.getGenericContext(ctx);
return obj.declarationseq? [...obj.declarationseq.accept(this),...obj.declaration.accept(this)] : obj.declaration.accept(this);
}
visitFunctionbody(ctx) {
return ctx.compoundstatement.accept(this);
}
visitCompoundstatement(ctx) {
return {
type: 'BlockStatement',
body: ctx.statementseq.accept(this),
}
}
visitStatementseq(ctx) {
const obj = this.getGenericContext(ctx);
return obj.statementseq? [...obj.statementseq.accept(this),...obj.statement.accept(this)] : obj.statement.accept(this);
}
visitStatement(ctx) {
return this.visitChildren(ctx);
}
visitExpressionstatement(ctx) {
return ctx.expression.accept(this);
}
visitExpression(ctx) {
return this.visitChildren(ctx)[0];
}
visitAssignmentexpression(ctx) {
return {
type: 'AssignmentExpression',
operator: ctx.op[0].text,
left: 0,
right: this.visitChildren(ctx)[0],
}
}
visitConditionalexpression(ctx) {
return {
type: 'ConditionalExpression',
test: this.visitChildren(ctx)[0],
consequent: 0,
alternate: 0,
}
}
visitInclusiveorexpression(ctx) {
return {
type: 'LogicalExpression',
operator: '||',
left: this.visitChildren(ctx),
right: 0,
}
}
visitExclusiveorexpression(ctx) {
return {
type: 'LogicalExpression',
operator: '||',
left: this.visitChildren(ctx),
right: 0,
}
}
visitRelationalexpression(ctx) {
return this.visitChildren(ctx)[0];
}
visitAdditiveexpression(ctx) {
return this.visitChildren(ctx)[0];
}
visitDeclarator(ctx) {
const params = ctx.parametersandqualifiers();
return params? params.accept(this) : {
type: 'Identifier',
name: this.getGenericToken(ctx._start).value,
body: this.visitChildren(ctx),
}
}
visitDeclspecifier(ctx) {
return {
storage: ctx.storageclassspecifier(),
type: ctx.typespecifier(),
function: ctx.functionspecifier(),
typedef: ctx.Typedef(),
friend: ctx.Friend(),
const: ctx.Constexpr(),
}
}
getGenericContext(ctx) {
return ctx;
}
getGenericToken(ctx, tokenName) {
return ctx[tokenName];
}
visitChildren(ctx) {
return this.visit(ctx);
}
}
//...
const selectDom = (selectors, dom) => {
//...
};
const replace = (callback, ctx) => {
//...
};
const treeToHtml = (ast) => {
//...
};
const htmlToTree = (html) => {
//...
};Overview
This code defines a set of methods for a class GenericVisitor that appears to be used for parsing and analyzing a programming language, likely C++. The methods are designed to extract specific information from the abstract syntax tree (AST) of a program.
Method Breakdown
visitIdexpression:
type: 'Identifier' and name set to the extracted identifier.visitMemberdeclaration:
type: 'Property', kind set to the property's kind (e.g., get, set, init), and key set to the property's key.visitTrailingtypespecifier:
type: 'Type' and name set to the extracted type.visitTypespecifier:
visitEqualityexpression:
type: 'BinaryExpression', operator set to the operator of the expression, and left and right set to the left and right operands of the expression.visitClassspecifier:
type: 'ClassExpression', id set to the class's ID, superClass set to the class's superclass, and body set to the class's body.visitPtrdeclarator:
visitSimpledeclaration:
visitFunctiondefinition:
Unused Methods
Methods visitPtrdeclarator, visitSimpledeclaration, and visitFunctiondefinition are currently empty and do not extract any information from the AST. These methods may have been left incomplete or are not currently being used in the code.