@lcap/nasl-parser
Version:
Take Nasl text to Nasl AST with the help of generalized parsing.
181 lines (149 loc) • 5.56 kB
text/typescript
import * as nasl from '@lcap/nasl';
import { Env } from './env-stack';
import { CstNamespace } from './decorated-nasl-ast';
import {
head, isEmpty, NASL_CORE_NL, SimpleSillyDeepClone,
prependNamespace,
} from './common-util';
/*
Definition index structure:
app -> {
structures -> {
structure 1 2 3 ...
}
enums -> {}
dataSources -> {
defaultDS -> {
entities -> { entity 1 2 3 ...}
}
otherOS ->{
entities -> { entity 1 2 3 ...}
}
}
logics -> {
logic 1 2 3 ...
}
views -> { ... }
}
nasl -> {
core -> {
}
utils -> {
}
}
*/
export interface NodeSemanticInfo {
namespace: Array<string>,
name: string,
// 语义类型
type?: nasl.TypeAnnotation,
// 默认值
value?: nasl.LogicItem,
// 值在编译期确定
isConst: boolean,
}
export type QVarName = string;
// 大致思路:node string name ---> define-side node ---> semantic information
export class CompilerEnvInfo {
// node 的 hash 到 node 的语义信息的映射
semInfo: Map<nasl.BaseNode | CstNamespace, NodeSemanticInfo> = new Map();
// string 表示的名字到定义处的 node hash 的映射,因为 shadow 等特性,是个一对多结构
resolvedNodes: ResolveNodeEnv = new Env(i => i);
// 现阶段所有已经打开的 namespace,每个 namespace 用 Array<string> 表示,如 ['nasl', 'core']
// using nasl.core 生成 [['nasl', 'core']],但不会生成 [['nasl', 'core'], ['core']] 这种结构
namespaceOpen: Array<Array<string>> = [];
// 现在所处的 namespace,如对于 namespace nasl { namespace core { #1 }; namespace util { #2 } },
// #1 处于 ['nasl', 'core'],#2 处于 ['nasl', 'util']
currNamespace: Array<string> = [];
// 记录函数的形参和局部变量,这些信息离开函数体后即删除,可减少符号表的体积加快查找速度。
// 双层 Array 支持嵌套作用域,每个作用域一个 Array<QVarName>
localVars: Array<Array<QVarName>> = [[]];
}
// 可访问到的 name,应该指向哪个定义处的 node,注意 value 实际上是个数组
export type ResolveNodeEnv = Env<QVarName, nasl.BaseNode | CstNamespace, string>;
// nd : nasl nodes + cst nodes
export function collectAllGlobalDefinitions(cei: CompilerEnvInfo, nd: nasl.BaseNode | any) {
if (nd instanceof nasl.Logic || nd instanceof nasl.LogicDeclaration) {
// env 里添加函数签名
addLogicSigBinding(cei, nd);
}
// no nasl.Function in this phase
if (nd instanceof nasl.Entity || nd instanceof nasl.Structure) {
addResolvedNode(cei, nd);
addRefTypeSemInfo(cei, nd);
addConstructor(cei, nd);
}
if (nd instanceof nasl.Enum) {
addResolvedNode(cei, nd);
addEnumCons(cei, nd);
}
if (nd instanceof CstNamespace) {
addResolvedNode(cei, nd);
cei.currNamespace.push(nd.name);
}
}
export const addResolvedNode = (cei: CompilerEnvInfo, nd : nasl.BaseNode | any) => {
const nodeName = nd.name ?? nd.value; // EnumItem 没有 name 只有 value
cei.semInfo.set(nd, {
namespace: SimpleSillyDeepClone(cei.currNamespace),
name: nodeName,
isConst: false,
});
cei.resolvedNodes.add(prependNamespace(cei.currNamespace, nodeName), nd);
}
export const addEnumCons = (cei: CompilerEnvInfo, ne: nasl.Enum) => {
cei.currNamespace.push(ne.name);
ne.enumItems.forEach(ei => {
addResolvedNode(cei, ei);
});
cei.currNamespace.pop();
}
// Add a function's signature to our symbol table.
const addLogicSigBinding = (cei: CompilerEnvInfo, nl: nasl.Logic | nasl.LogicDeclaration) : nasl.Logic | nasl.LogicDeclaration => {
// env 里添加函数签名
if (nl.name) {
cei.resolvedNodes.add(prependNamespace(cei.currNamespace, nl.name), nl);
const nsi: NodeSemanticInfo = {
namespace: SimpleSillyDeepClone(cei.currNamespace), // 调了半天,原来是忘了 clone
name: nl.name,
isConst: false,
};
nsi['type'] = new nasl.TypeAnnotation({
typeKind: 'function',
typeArguments: nl?.params?.map(p => p.typeAnnotation),
})
// 用户标注返回类型
if (nl.returns && !isEmpty(nl.returns) && head(nl.returns)) {
nsi['type'].returnType = [head(nl.returns).typeAnnotation];
} else {
// 未标注返回类型,先当做无返回吧
nsi['type'].returnType = [new nasl.TypeAnnotation({
typeKind: 'primitive',
typeNamespace: NASL_CORE_NL,
typeName: 'void',
})];
}
cei.semInfo.set(nl, nsi);
}
return nl;
}
export const leaveNamespace = (cei: CompilerEnvInfo, cns: CstNamespace): CstNamespace => {
if (cns instanceof CstNamespace) {
cei.currNamespace.pop();
}
return cns;
}
export function addRefTypeSemInfo(cei: CompilerEnvInfo, nd: nasl.Entity | nasl.Structure) {
const nsi = {
name: nd.name,
namespace: SimpleSillyDeepClone(cei.currNamespace),
isConst: false,
};
cei.semInfo.set(nd, nsi);
cei.resolvedNodes.add(nd.name, nd);
}
export function addConstructor(cei: CompilerEnvInfo, nd: nasl.Entity | nasl.Structure): nasl.Entity | nasl.Structure {
const ctorName = `${prependNamespace(cei.currNamespace, nd.name)}.constructor`;
cei.resolvedNodes.add(ctorName, nd);
return nd;
}