UNPKG

@lcap/nasl-parser

Version:

Take Nasl text to Nasl AST with the help of generalized parsing.

181 lines (149 loc) 5.56 kB
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; }