@lcap/nasl-parser
Version:
Take Nasl text to Nasl AST with the help of generalized parsing.
140 lines (118 loc) • 4.52 kB
text/typescript
import { PackNaslAndCst, wellDefined } from './common-util';
// import * as nasl from '@lcap/nasl';
import * as nasl from './decorated-nasl-ast';
import { Visitor, sequenceWithEnv_, composeWithEnv } from './common-util';
import { processAnnotations, processLogicAnnotations } from './process-annotations';
import { addLogicLocalBindings, removeLogicLocalBindings, usingNamespace,
resolveCallee,
resolveTypeRef,
resolveQEnumId,
} from './resolve-local-bindings';
import { isStructure, isEnum, isLogic, isDataSource, isFrontendType } from '@lcap/nasl-concepts/asserts';
import { collectAllGlobalDefinitions, CompilerEnvInfo, leaveNamespace } from './resolve-global-bindings';
/**
* 缺失:
* *** Type<Ty, Ty> 使用处的 Ty 区分是引入的 type variable 还是外层定义的 reference type。
* *** Annotation 处理
* NewList 缺 TypeAnnotation
* ArrayAccess 多维下标支持,翻译成连续 Get 调用
* callNameSpace 完整实现
* type 的 nameSpace 完整实现
* qualified name 等
* { } 和 [ ] 的识别
*
*/
/**
* 已实现:
* toNaslAST 不会区分函数、逻辑、接口调用、new 构造器调用,先统一为逻辑调用。会在下一个 refine-nasl-call 阶段区分。
*
*/
/**
* class 方法与全局函数相比
* - 可隐式传递数据,(通过 this)。仁者见仁,智者见智。
*
* 承上,visitor 模式与普通架构相比
* - 在 this 上动态派发(通过 override),将多个函数名 toNaslAAA、toNaslBBB、toNaslCCC 全部统一为 toNasl 或 visit。
* 这样大量的递归调用 toNaslAAA、toNaslBBB 也可全部统一为 toNasl 或 visit。仁者见仁,智者见智。
* - 如使用外部 visitor 模式,仍需要遍历一遍整棵 AST 结构来写出 visitor,并不节约代码量。
* 如使用内部 visitor 模式,仍没有充足的控制权,如遍历顺序等。仁者见仁,智者见智。
*/
// defs.nasl 是一个数组,方便后续处理
export function toNaslAST(seqNasl : Array<nasl.SupportedDefinition>) {
if (!seqNasl) {
return null;
}
const cei = new CompilerEnvInfo();
seqNasl = addGlobalBindings(cei, seqNasl);
seqNasl = addLocalBindings(cei, seqNasl);
const dataSources = new Array();
processAnnotations(cei, seqNasl, dataSources);
const app = new nasl.App({
logics: extractLogics(seqNasl),
enums: extractEnums(seqNasl),
structures: extractStructures(seqNasl),
frontendTypes: seqNasl.filter(isFrontendType),
dataSources: [],
});
app.name = 'UnstableFeatureTestOnly';
// const app : nasl.App = collectAppFromSeqNasl(sn);
// app.dataSources = dataSources;
// return PackNaslAndCst(app, {App: defs.cst});
return app;
}
function addGlobalBindings(cei: CompilerEnvInfo, seqNaslDefs: any) {
const tasks = (env: CompilerEnvInfo, obj: any) => {
collectAllGlobalDefinitions(env, obj);
return obj;
}
const clean = (env: CompilerEnvInfo, obj: any) => {
leaveNamespace(env, obj);
return obj;
}
return new Visitor().preOrderVisitAll(cei, seqNaslDefs, tasks, clean);
}
function addLocalBindings(cei: CompilerEnvInfo, seqNaslDefs: any) {
const tasks = (env: CompilerEnvInfo, obj: any) => {
usingNamespace(env, obj);
addLogicLocalBindings(env, obj);
obj = resolveCallee(env, obj);
obj = resolveTypeRef(env, obj);
obj = resolveQEnumId(env, obj);
return obj;
}
const clean = (env: CompilerEnvInfo, obj: any) => {
removeLogicLocalBindings(env, obj);
return obj;
}
return new Visitor().preOrderVisitAll(cei, seqNaslDefs, tasks, clean);
}
function extractStructures(nodes: Array<nasl.SupportedDefinition>) {
const res = [];
new Visitor().preOrderVisitAll(null, nodes, (env, obj) => {
if (isStructure(obj)) {
res.push(obj);
}
return obj;
});
return res;
}
function extractEnums(nodes: Array<nasl.SupportedDefinition>) {
const res = [];
new Visitor().preOrderVisitAll(null, nodes, (env, obj) => {
if (isEnum(obj)) {
res.push(obj);
}
return obj;
});
return res;
}
function extractLogics(nodes: Array<nasl.SupportedDefinition>) {
const res = [];
new Visitor().preOrderVisitAll(null, nodes, (env, obj) => {
if (isLogic(obj)) {
res.push(obj);
}
return obj;
});
return res;
}