@lcap/nasl-parser
Version:
Take Nasl text to Nasl AST with the help of generalized parsing.
506 lines (494 loc) • 18.6 kB
JavaScript
;
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