UNPKG

@lcap/nasl-parser

Version:

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

506 lines (494 loc) 18.6 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.usingNamespace = exports.addLogicLocalBindings = void 0; exports.resolveCallee = resolveCallee; exports.resolveQEnumId = resolveQEnumId; exports.resolveTypeRef = resolveTypeRef; exports.lookUpResolvedNodes = lookUpResolvedNodes; exports.removeLogicLocalBindings = removeLogicLocalBindings; const nasl = __importStar(require("@lcap/nasl")); const asserts_1 = require("@lcap/nasl-concepts/asserts"); const decorated_nasl_ast_1 = require("./decorated-nasl-ast"); const common_util_1 = require("./common-util"); const builtin_namespace_1 = require("./builtin-namespace"); const resolve_global_bindings_1 = require("./resolve-global-bindings"); // 本质上可以合并为一个函数,但是 NASL 上的节点类型不同,所以分开处理了 /* 【P0】调用方式 1:直接带 namespace, nasl::util::方法名(...) 内置函数,硬编码 [O] 内置函数方法名(...) 内置函数,硬编码 app::logics::方法名(...) 逻辑调用,硬编码 [O] My::Namespace::方法名(...) 逻辑调用 [O] 方法名(...) 逻辑调用,无 namespace 默认 apis::应用id::interfaces::方法名(...) 接口调用 connector::连接器种类::连接器名(操作, 数据, ...) 连接器 【P1】调用方式 2:打开 namespace 后直接调用 [O] using nasl.util [O] using app.logics using apis.应用id.interfaces using connector.连接器种类 特殊调用 CallQueryComponent(...) //数据查询 OqlQueryComponent(dataSource, code) // Oql SQL 查询 JsonSerialize() JsonDeserialize() */ function resolveCallee(cei, callee) { if (!(0, asserts_1.isCallLogic)(callee)) { return callee; } const _qName = callee.qName; // 优先找 constructor,在下一个 pass 翻译到 new composite { let test = false; if (lookUpResolvedNodes(cei, { namespace: _qName.namespace, name: `${_qName.name}.constructor` }).length === 1) { test = true; } if (!test) { createHardCodedRefTypeOnUse(cei, _qName); test = lookUpResolvedNodes(cei, { namespace: _qName.namespace, name: `${_qName.name}.constructor` }).length === 1; } if (test) { callee.callKind = 'Constructor'; callee.name = _qName.name; return ctorToNewExpr(cei, callee); } } { // builtin functions 内置函数 if (builtin_namespace_1.builtinFunctionNames.includes(_qName.name)) { callee.callKind = 'Function'; callee.calleeNamespace = common_util_1.NASL_UTIL_AST; return toNaslCallFunction(callee); } } { if (_qName.name === 'jsonSerialize') { callee.calleeName = 'jsonSerialize'; callee.calleeNamespace = common_util_1.NASL_UTIL_AST; callee.label = 'JSON 序列化'; return callee; } } { if (_qName.name === 'jsonDeserialize') { callee.calleeName = 'jsonDeserialize'; callee.calleeNamespace = common_util_1.NASL_UTIL_AST; callee.label = 'JSON 反序列化'; return callee; } } // { if (['INFO', 'ERROR', 'WARN', 'DEBUG'].includes(_qName.name)) { callee.calleeName = _qName.name; callee.calleeNamespace = common_util_1.NASL_LOGGING_AST; callee.label = '输出日志'; return callee; } } // general cases // @ts-ignore const defs = lookUpResolvedNodes(cei, callee.qName); if (defs.length === 1) { const nd = (0, common_util_1.head)(defs); callee.calleeNamespace = common_util_1.APP_LOGICS_AST; // callee.name = nd.name; 好像不需要 // const info = cei.semInfo.get(nd); return callee; } else if (defs.length > 1) { let msg = `Ambiguous name: ${(0, common_util_1.projectIdentifier)(_qName)}, it could be:\n` + defs.map(n => n.name).join('\n'); throw new Error(msg); } else { const msg = `In resolveCallee, Unresolved identifier: ${(0, common_util_1.projectIdentifier)(_qName)}`; throw new Error(msg); } } function resolveQEnumId(cei, id) { if (!((0, asserts_1.isIdentifier)(id) && id?.qName) && !(id instanceof decorated_nasl_ast_1.CstIntEnumRef)) { // Identifier 变为 MemberExpression 后,子节点有个 Identifier,不需要再设置 qName 了,所以没有 qName return id; } // hard-coded and non-hard-coded int enum app::enums::EnumName::123 if (id instanceof decorated_nasl_ast_1.CstIntEnumRef) { return new nasl.MemberExpression({ object: new nasl.Identifier({ namespace: common_util_1.APP_ENUM, name: id.enumTypeName, }), property: new nasl.Identifier({ name: id.value, }), }); } const _qName = id.qName; // hard-coded string enum if (/app.enums./.test(_qName.namespace.join(common_util_1.NAMESPACE_SEP_AST))) { return createEnumIdMemberExpr(); } // non-hard-coded string enum const def = lookUpResolvedNodes(cei, _qName)?.[0]; if (def?.concept === 'EnumItem') { return createEnumIdMemberExpr(); } // otherwise, do nothing return id; function createEnumIdMemberExpr() { return new nasl.MemberExpression({ object: new nasl.Identifier({ namespace: common_util_1.APP_ENUM, name: (0, common_util_1.last)(_qName.namespace), }), property: new nasl.Identifier({ name: _qName.name }), }); } } function resolveBuiltinCollectionType(ty) { const ngt = new nasl.TypeAnnotation({ typeKind: 'generic', typeName: ty.qName.name, typeNamespace: common_util_1.NASL_COLLECTION_AST, typeArguments: ty.typeArguments, }); return ngt; } function resolveTypeRef(cei, ty) { if (!ty || !(0, asserts_1.isTypeAnnotation)(ty) || !ty.qName) { return ty; } if (ty.typeKind === 'reference') { if (/^(List|Map)$/.test(ty.qName.name) && ((ty.qName.namespace.length === 0) || new RegExp(common_util_1.NASL_COLLECTION_AST).test(ty.qName.namespace.join(common_util_1.NAMESPACE_SEP_AST)))) { return resolveBuiltinCollectionType(ty); } let def = lookUpResolvedNodes(cei, ty.qName)?.[0] ?? resolveHardCodedRefType(cei, ty); if (!def) { throw new Error(`Unresolved type reference: ${(0, common_util_1.projectIdentifier)(ty.qName)}`); } const nsi = cei.semInfo.get(def); ty.typeNamespace = nsi.namespace.join(common_util_1.NAMESPACE_SEP_AST); ty.typeName = nsi.name; } return ty; } // 顺便返回一个(可能是虚假的)数据定义(语义需要),一期硬编码 function resolveHardCodedRefType(cei, ty) { if (ty.typeKind === 'reference') { const nd = createHardCodedRefTypeOnUse(cei, ty.qName); if (nd) { // set proper type namespace and name ty.typeNamespace = ty.qName.namespace.join(common_util_1.NAMESPACE_SEP_AST); ty.typeName = ty.qName.name; ty.qName = ty.qName; // if (!cei.semInfo.has(es)) { // cei.semInfo.set(es, { name: ty.qName.name, namespace: ty.qName.namespace, isConst: false} ); // cei.resolvedNodes.add(projectIdentifierAST(ty.qName), es); // } return nd; } } return null; } // 无论是看到类型,还是构造器又或是其他,都要创建个假的数据定义,以便后续分析 function createHardCodedRefTypeOnUse(cei, qName) { const nsp = qName.namespace.join(common_util_1.NAMESPACE_SEP_AST); let test = false; let nd; let tempNsp = cei.currNamespace; // app.structures if (new RegExp(common_util_1.APP_STRUCTURE_AST).test(nsp)) { nd = new nasl.Structure({ name: qName.name, }); test = true; tempNsp = common_util_1.APP_STRUCTURE_AST.split(common_util_1.NAMESPACE_SEP_AST); } // app.dataSources.???.entities else if (/app.dataSources/.test(nsp) && /entities/.test(nsp)) { nd = new nasl.Entity({ name: qName.name, }); test = true; tempNsp = common_util_1.APP_ENTITY_AST.split(common_util_1.NAMESPACE_SEP_AST); } // app.enums else if (/app.enums/.test(nsp)) { nd = new nasl.Enum({ name: qName.name, }); test = true; tempNsp = common_util_1.APP_ENUM.split(common_util_1.NAMESPACE_SEP_AST); } if (!test) { return null; } // add to global definitions const savedNsp = cei.currNamespace; cei.currNamespace = tempNsp; if (nd instanceof nasl.Entity || nd instanceof nasl.Structure) { (0, resolve_global_bindings_1.addResolvedNode)(cei, nd); (0, resolve_global_bindings_1.addRefTypeSemInfo)(cei, nd); (0, resolve_global_bindings_1.addConstructor)(cei, nd); } else if (nd instanceof nasl.Enum) { (0, resolve_global_bindings_1.addResolvedNode)(cei, nd); (0, resolve_global_bindings_1.addEnumCons)(cei, nd); } cei.currNamespace = savedNsp; return nd; } function lookUpResolvedNodes(cei, nd) { const qName = nd.namespace.concat(nd.name).join(common_util_1.NAMESPACE_SEP_AST); let defs = [cei.resolvedNodes.get(qName)]; // 基于当前作用域,从内到外,找一遍 // ['nasl', 'core', 'utils'] 查找 nasl 下的、nasl::core 下的、nasl::core::utils 下的 expandNamespaces(cei.currNamespace).forEach(nsp => { const n = (0, common_util_1.prependNamespace)(nsp, nd); return defs.push(cei.resolvedNodes.get(n)); }); // 所有额外引入的命名空间,从内到外,找一遍 // 与上面的不同,引了 nasl::core::utils,那么只查找 nasl::core::utils 下的;因此没有 expandNamespaces cei.namespaceOpen.forEach(nsp => { const n = (0, common_util_1.prependNamespace)(nsp, nd); defs.push(cei.resolvedNodes.get(n)); }); defs = (0, common_util_1.removeDup)(defs.filter(common_util_1.wellDefined)); if (defs.length > 1) { let msg = `Ambiguous name: ${(0, common_util_1.projectIdentifierAST)(nd)}, it could be:\n` + defs.map(n => n.name).join('\n'); throw new Error(msg); } return defs; } function expandNamespaces(fragments) { const nss = []; for (let i = 0; i < fragments.length; i++) { nss.push(fragments.slice(0, i + 1)); } return nss; } // export const addLambdaLocalBindings = (cei: CompilerEnvInfo, naf: nasl.AnonymousFunction): nasl.AnonymousFunction => { // if (!isAnonymousFunction(naf)) { // return naf; // } // // env 里添加形参(类似局部变量) // cei.localVars.push([]) // naf?.params?.forEach(addLocalBindings(cei)); // return naf; // } // Add function-level scoped local variables (including parameters) to our symbol table. const addLocalBindings = (cei) => (node) => { const rNodes = cei.resolvedNodes; rNodes.add(node.name, node); const nsc = { namespace: [], name: node.name, isConst: false, }; if (node.typeAnnotation) { nsc['type'] = node.typeAnnotation; } if (node.defaultValue) { nsc['value'] = node.defaultValue.expression; } // constant analysis later cei.semInfo.set(node, nsc); (0, common_util_1.last)(cei.localVars).push(node.name); return node; }; const addLogicLocalBindings = (cei, nl) => { if (!(0, asserts_1.isLogic)(nl) && !(0, asserts_1.isAnonymousFunction)(nl)) { return nl; } // Add into symbol table a function's return's semantic information. const addReturnBinding = (cei, nr) => { const retQVarName = nr.name; cei.resolvedNodes.add(retQVarName, nr); const nsc = { namespace: [], name: nr.name, isConst: false, }; if (nr.typeAnnotation) { nsc['type'] = nr.typeAnnotation; } if (nr.defaultValue) { nsc['value'] = nr.defaultValue.expression; } // const analysis later cei.semInfo.set(nr, nsc); (0, common_util_1.last)(cei.localVars).push(retQVarName); return nr; }; cei.localVars.push([]); // env 里添加形参(类似局部变量) nl?.params?.forEach(addLocalBindings(cei)); // AnonymousFunction 里没有 variables 和 returns if (nl instanceof nasl.Logic) { // env 里添加局部变量 nl?.variables?.forEach(addLocalBindings(cei)); // 添加函数返回类型信息等,return 表达式要用 if (nl.returns && !(0, common_util_1.isEmpty)(nl.returns)) { addReturnBinding(cei, (0, common_util_1.head)(nl.returns)); } } return nl; }; exports.addLogicLocalBindings = addLogicLocalBindings; function removeLogicLocalBindings(cei, node) { if (!(0, asserts_1.isAnonymousFunction)(node) && !(0, asserts_1.isLogic)(node)) { return node; } const nthe = cei.resolvedNodes; let recentList = cei.localVars.pop(); recentList?.forEach(v => { nthe.remove(v); cei.semInfo.delete(nthe.get(v)); }); return node; } // using xxx.yyy.zzz; /* namespaceOpen: [ ['app', 'dataSources', 'defaultDS', 'entities'], ['nasl'], ... ] after using namespace core namespaceOpen: [ ['app', 'dataSources', 'defaultDS', 'entities'], ['nasl'], ['nasl', 'core'], ... ] after closing namespace core namespaceOpen: [ ['app', 'dataSources', 'defaultDS', 'entities'], ['nasl'], ... ] */ // 尚未支持局部打开命名空间 // 尚未支持关闭打开的命名空间 const usingNamespace = (cei, thisNsp) => { if (thisNsp instanceof decorated_nasl_ast_1.UsingNamespace) { cei.namespaceOpen.push(thisNsp.namespace); } return thisNsp; }; exports.usingNamespace = usingNamespace; // 构造函数转为 New 连线构造,难伺候 function ctorToNewExpr(cei, nd) { if (!(0, asserts_1.isCallLogic)(nd)) { return nd; } if (nd.callKind !== 'Constructor') { return nd; } const keywords = nd.arguments.map(arg => (console.assert(arg.keyword, 'Arguments in New Composite constructors should all be named'), arg.keyword)); const selMems = nd.arguments.map(arg => new nasl.SelectMembers({ // ? identifier xyz : literal 1 true 'abc' expression: (0, asserts_1.isMemberExpression)(arg.expression) ? (0, common_util_1.extractIdent)(arg.expression) : arg.expression, members: (0, asserts_1.isMemberExpression)(arg.expression) ? [arg.expression] : [] })); // 无能为力,认怂 const lines = nd.arguments.map((arg, idx) => new nasl.AssignmentLine({ leftIndex: [0, idx], rightIndex: (0, asserts_1.isMemberExpression)(arg.expression) ? [idx, 1] : [idx], })); return new nasl.NewComposite({ // name: nd.name, 不要名字 难伺候 properties: keywords.map(k => new nasl.Identifier({ name: k })), rights: selMems, assignmentLines: lines, typeAnnotation: createNaslRefType(cei, nd.name), }); } function createNaslRefType(cei, name) { const defs = lookUpResolvedNodes(cei, { name, namespace: [] }); const def = defs[0]; const ty = new nasl.TypeAnnotation({ typeKind: 'reference', typeNamespace: dispatchTypeNamespace(def), typeName: name, }); return ty; } const dispatchTypeNamespace = (nd) => { if ((0, asserts_1.isStructure)(nd)) { return common_util_1.APP_STRUCTURE_AST; } if ((0, asserts_1.isEntity)(nd)) { return common_util_1.APP_ENTITY_AST; } // if (isEnum(nd)) { // return null; // } throw new Error(`Unimplemented in dispatchTypeNamespace: ${nd.toString()}`); }; function toNaslCallFunction(nc) { return new nasl.CallFunction({ calleeName: nc.qName.name, calleeNamespace: common_util_1.NASL_UTIL_AST, arguments: nc.arguments, typeArguments: nc.typeArguments ?? [] // 难伺候 }); } // 二期 function toNaslCallInterface(nc) { // 已经从 cst 的 .name 转成了 nasl ast 的 .keyword const [authArgs, otherArgs] = (0, common_util_1.splitByPredicate)(nc.arguments, arg => arg.keyword === 'authArguments'); if (!(0, common_util_1.isEmpty)(authArgs)) { return new nasl.CallAuthInterface({ calleeName: nc.qName.name, calleeNamespace: nc.qName.namespace.join(common_util_1.NAMESPACE_SEP), arguments: otherArgs, authArguments: authArgs }); } else { return new nasl.CallInterface({ calleeName: nc.qName.name, calleeNamespace: nc.qName.namespace.join(common_util_1.NAMESPACE_SEP), arguments: nc.arguments }); } } // 二期 function toNaslCallConnector(nc) { return new nasl.CallConnector({ calleeName: nc.qName.name, calleeNamespace: nc.qName.namespace.join(common_util_1.NAMESPACE_SEP), arguments: nc.arguments }); } //# sourceMappingURL=resolve-local-bindings.js.map