@lcap/nasl-parser
Version:
Take Nasl text to Nasl AST with the help of generalized parsing.
392 lines (335 loc) • 12.8 kB
text/typescript
import { namedTypeToNaslTypeAnno } from './to-nasl-type';
// toNaslPat, toNaslStatement,
import { toNaslValueParam } from './to-nasl-statement';
import { isEmpty, createQIdentifier, last, NAMESPACE_SEP, NASL_CORE_NL, TYPE, PackNaslAndCst, getNasl, AutoPackNaslAndCst, PackNaslAndCstSeq, getCst, APP, APP_LOGICS_AST, NAMESPACE_SEP_AST } from './common-util';
import * as nasl from './decorated-nasl-ast';
import { assert, error } from 'console';
import { isIdentifier, isAnonymousFunction } from '@lcap/nasl-concepts/asserts';
// import { toNaslCallQueryComponentImpl } from './to-nasl-call-query';
let toNaslCallQueryComponentImpl = undefined;
const binaryOpToName = new Map([
['+', 'Add'],
['-', 'Sub'],
['*', 'Mul'],
['/', 'Div'],
['%', 'Mod'],
// ['^', 'Pow'],
['&&', 'And'],
['||', 'Or'],
['==', 'Eq'],
['!=', 'Ne'],
['>', 'Gt'],
['<', 'Lt'],
['>=', 'Ge'],
['<=', 'Le'],
['in', 'In'],
['not in', 'NotIn'],
['is', 'Is'],
['is not', 'IsNot'],
])
export const toNaslPostfix = ([expr, sfx]) => {
// please refactor the four if to switch
switch (sfx.cst.__type) {
case 'CallSuffix':
return toNaslCallLogic(expr, sfx);
case 'ArrayAccessSuffix':
return toNaslArrayAccess(expr, sfx);
case 'MemberAccessSuffix':
return toNaslMemberAccess(expr, sfx);
case 'SQLFilterSuffix':
return toNaslSQLFilter(expr);
default:
throw new error('panic: should not reach here in postfixToNasl1')
}
}
export function dispatchToNaslExpr(e: any): nasl.LogicItem {
// if (isUnaryExpr(e)) {
// let expr : nasl.LogicItem;
// if (isPostfixable(e.expr)) {
// if (!isEmpty(e.suffix)) {
// let res = postfixToNasl1(e.expr, e.suffix.pop())
// e.suffix.forEach(sfx => {
// // @ts-ignore
// res = postfixToNasl2(res, sfx)
// })
// expr = res;
// } else {
// expr = toNaslExpr(e.expr);
// }
// e.prefix.forEach(pfx => {
// expr = new nasl.UnaryExpression({
// operator: '!',
// argument: expr
// })
// });
// return expr;
// } else {
// return toNaslExpr(e.expr);
// }
// }
// if (isBinaryExpression(e)) {
// return toNaslBinaryExpr(e);
// }
return new nasl.Identifier();
throw new error('panic: unimplemented in dispatchToNaslExpr.')
}
export const toNaslIdentifier = ([e]) => {
const ni = new nasl.Identifier({
name: e.name
});
ni.qName = e; // 非本身的属性,不能直接在初始化时构造
return PackNaslAndCst(ni, TYPE('TermRef', e));
}
export const toNaslIntegerLit = (e) => {
const nil = new nasl.NumericLiteral({
value: String(e),
typeAnnotation: getNasl(namedTypeToNaslTypeAnno(createQIdentifier('Integer'), [])),
});
return PackNaslAndCst(nil, e);
}
export const toNaslDecimalLit = (e) => {
const ndl = new nasl.NumericLiteral({
value: String(e),
typeAnnotation: getNasl(namedTypeToNaslTypeAnno(createQIdentifier('Decimal'), [])),
})
return PackNaslAndCst(ndl, e);
}
export const toNaslNullLit = ([e]) => {
return PackNaslAndCst(new nasl.NullLiteral(), e);
}
// 这里就是两层[[.]]
export const toNaslBooleanLit = ([[e]]) => {
const nb = new nasl.BooleanLiteral({
value: String(e.value)
});
return PackNaslAndCst(nb, e.value);
}
// fromStringLit
export const toNaslStringLit = ([e]) => {
const ns = new nasl.StringLiteral({ value: e[0].value });
return PackNaslAndCst(ns, e[0].value);
}
export const toNaslStringInterpolation = (d) => {
let res = {__type: 'StringInterpolation', parts: [] };
let buf = '';
d.forEach((elem, idx) => {
if (elem.__type !== 'Expression') {
buf += elem.str;
} else {
if (buf.length > 0) {
res.parts.push(PackNaslAndCst(new nasl.StringLiteral({ value: buf}),
{__type: 'String', str: buf }));
buf = '';
}
res.parts.push(elem.expr);
}
})
if (buf.length > 0) {
res.parts.push(PackNaslAndCst(new nasl.StringLiteral({ value: buf}),
{__type: 'String', str: buf }));
}
const nInterpolation = new nasl.StringInterpolation({ expressions: res.parts.map(getNasl) });
return PackNaslAndCst(nInterpolation, TYPE('StringInterpolation', res.parts.map(getCst)));
}
export const toNaslUnparsed = (str) =>
PackNaslAndCst(new nasl.Unparsed({ "code": str }), { __type: 'JSString', str })
export const toNaslArrayLit = (exprs?, ty?) => {
const nL = new nasl.NewList({ items: exprs?.nasl });
if (ty) {
nL.typeAnnotation = ty.nasl;
nL.typeAnnotation.inferred = false;
}
return PackNaslAndCst(nL, TYPE('ArrayLit', {exprs: exprs?.cst, ty: ty?.cst ?? undefined}));
}
export const toNaslMapLit = ([entries]) => {
const nm = new nasl.NewMap({
keys: entries.nasl.map(entry => entry.key), // 我™还是得给打散成 pair……
values: entries.nasl.map(entry => entry.val)
});
return PackNaslAndCst(nm, TYPE('MapLit', entries.cst));
}
// isEnumIntRef. please generate code without
export const toNaslEnumIntRef = ([namespaceArr, _digitName]) => {
let enumTypeName = namespaceArr[0];
// 暂时先支持两种写法吧
if (namespaceArr.length > 2 && namespaceArr[0] === 'app' && namespaceArr[1] === 'enums') {
enumTypeName = namespaceArr[2];
}
const value = _digitName.nasl.value;
const enumIntRef = new nasl.CstIntEnumRef(enumTypeName, value);
return PackNaslAndCst(enumIntRef, TYPE('EnumIntRef', { namespace: namespaceArr, name: _digitName.cst }));
}
export const toNaslEmptyBrackets = _ =>
PackNaslAndCst(new nasl.EmptyBrackets(), TYPE('EmptyBrackets', { expr: '[]' }))
// CompoundLambda or AnonymousStructure
// export const toNaslEmptyBraces = _ => PackNaslAndCst(new nasl.EmptyBraces(), TYPE('EmptyBraces', { expr: '{}' }))
export const toNaslAnonymousFunc = (e) => {
const nl = new nasl.AnonymousFunction({
params: e.params.map(toNaslValueParam),
// @ts-ignore
body: dispatchToNaslExpr(e.nasl.expr), // last expression
});
return PackNaslAndCst(nl, TYPE('AnonymousFunction', e));
}
export const toNaslCallQueryComponent = (e) =>
PackNaslAndCst(toNaslCallQueryComponentImpl(e.nasl), TYPE('CallQueryComponent', e.cst))
export const toNaslBinaryExpr = (left, op, right) => {
const nb = new nasl.BinaryExpression();
// @ts-ignore Nasl 未定义 Pow 幂运算 运算符 ^
nb.operator = op.toLowerCase(); // 牛的,必须用 startwith 而非 startWith
nb.left = left.nasl;
nb.right = right.nasl;
return PackNaslAndCst(nb, TYPE(binaryOpToName.get(op), { left: left.cst, op, right: right.cst }));
}
export const BuildBinary = ([left, op, _1, right]) => {
if (Array.isArray(op)) {
op = op[0].value;
} else {
op = op.value;
}
return toNaslBinaryExpr(left, op, right)
}
export const toNaslCallSuffix = ([tyArgs, valArgs]) => {
const res = AutoPackNaslAndCst({ tyArgs, valArgs });
TYPE('CallSuffix', res.cst);
return res;
}
export const toNaslArrayAccessSuffix = ([expr]) =>
PackNaslAndCst(expr.nasl, TYPE('ArrayAccessSuffix', { expr: expr.cst }));
export const toNaslMemberAccessSuffix = (rawIdent) =>
PackNaslAndCst(toNaslIdentifier([createQIdentifier(rawIdent)]).nasl, TYPE('MemberAccessSuffix', { rawIdent }));
export const toNaslSQLFilterSuffix = () =>
PackNaslAndCst(null, TYPE('SQLFilterSuffix', { }));
// 第一轮 toAST 先简单处理,后续 refine-nasl-ast 会细分不同的 call
export const toNaslCallLogic = (callee, sfx) => {
if (isAnonymousFunction(callee.nasl)) {
throw new Error('Nasl AST 暂时无法承载, AnonymousFunction cannot be called');
}
// console.log('CALLER NASL NAMESPACE', caller.nasl);
const callerNsp = callee.nasl.qName.namespace.join(NAMESPACE_SEP_AST);
const nc = new nasl.CallLogic({
calleeName: callee.nasl.name,
calleeNamespace: callerNsp?? APP_LOGICS_AST,
arguments: sfx.nasl.valArgs,
typeArguments: sfx.nasl.tyArgs,
});
if (isIdentifier(callee.nasl)) {
nc.qName = callee.nasl.qName;
} else {
// lambda literal { -> }(x)
// Nasl AST 暂时无法承载
// nc.simpleLambda = caller;
}
// if (isEmpty(nc.typeArguments)) {
// nc.typeArguments = null;
// }
nc.handleError = false;
return PackNaslAndCst(nc, TYPE('CallLogic', { caller: callee.cst, sfx: sfx.cst }));
}
const toNaslArrayAccess = (expr, sfx) => {
const valArg = toNaslValArg(sfx);
const ncf = new nasl.CallFunction({
calleeName: 'Get',
arguments: [
new nasl.Argument({ expression: expr.nasl }),
valArg.nasl
]
})
return PackNaslAndCst(ncf, TYPE('ArrayAccess', { expr: expr.cst, suffix: valArg.cst }));
}
const toNaslMemberAccess = (expr, sfx) => {
const nme = new nasl.MemberExpression({
object: expr.nasl,
property: sfx.nasl
})
return PackNaslAndCst(nme, TYPE('MemberAccess', { obj: expr.cst, prop: sfx.cst }));
}
const toNaslSQLFilter = (expr) => {
const nue = new nasl.UnaryExpression({
operator: 'isNull', // 这里又有大写啦
argument: expr.nasl
})
return PackNaslAndCst(nue, TYPE('SQLFilter', { expr: expr.cst }));
}
export const toNaslValArg = (expr, name?) => {
const na = new nasl.Argument({
expression: expr.nasl
});
if (name) {
na.keyword = name;
}
// console.log('toNaslValArg', na.keyword);
return PackNaslAndCst(na, TYPE('ValueArg', { expr: expr.cst, name }));
}
export const toNaslValArgList = (args, lam?) => {
if (!args?.nasl) {
args = {};
args.nasl = [];
args.cst = [];
}
if (lam) {
return PackNaslAndCst(args.nasl.concat(lam.nasl), args.cst.concat(lam.cst))
} else {
return PackNaslAndCst(args.nasl, args.cst)
}
}
// export const toNaslTyArg = ([arg]) =>
// PackNaslAndCst(arg.nasl, TYPE('TypeArg', arg.cst))
// export const toNaslTyArgList = ([args]) => PackNaslAndCst(args.nasl, args.cst)
export const toNaslDefaultValue = undefined;
export const toNaslSubLogic = (body, params?) => {
const nl = new nasl.Logic({
name: null,
params: params?.nasl,
returns: [], // TODO
body: [new nasl.Start(), body.nasl.stmts, new nasl.End()],
variables: body.nasl.vars
});
return PackNaslAndCst(nl, TYPE('SubLogic', { params: params?.cst, body: body.cst }));
}
export const toNaslLambda = (expr, params?) => {
const nl = new nasl.AnonymousFunction({
params: params?.nasl,
body: expr.nasl
});
// const nb = new nasl.BinaryExpression();
// // @ts-ignore Nasl 未定义 Pow 幂运算 运算符 ^
// nb.operator = op.toLowerCase(); // 牛的,必须用 startwith 而非 startWith
// nb.left = left.nasl;
// nb.right = right.nasl;
// return PackNaslAndCst(nb, TYPE(binaryOpToName.get(op), { left: left.cst, op, right: right.cst }));
return PackNaslAndCst(nl, TYPE('Lambda', { expr: expr.cst, params: params?.cst }));
}
export const toNaslLamParam = (name ,ty) => {
const np = new nasl.Param({
name: name,
typeAnnotation: ty?.nasl ?? null, // 难伺候
// defaultValue: null
});
return PackNaslAndCst(np, TYPE('Param', {name, ty: ty?.cst}));
}
export const toNaslLogicParam = ([varInit]) => {
const nv: nasl.Variable = varInit.nasl;
const np = new nasl.Param({
name: nv.name,
typeAnnotation: nv.typeAnnotation,
defaultValue: nv.defaultValue,
defaultExpression: nv.defaultValue?.expression
});
// if (e.anns) {
// // @ts-ignore
// np.annotations = e.anns;
// }
return PackNaslAndCst(np, TYPE('Param', varInit.cst));
}
// transform type variables introduced in <·> to type parameters
// not to be confused with types used <·> at the use site
export const toNaslTyParam = (ty: string) =>
PackNaslAndCst(new nasl.TypeParam({ name: ty }), TYPE("TypeParam", { ty }));
export const toNaslPrefix = (expr) => {
const e = new nasl.UnaryExpression({
operator: '!',
argument: expr.nasl
})
return PackNaslAndCst(e, TYPE('Prefix', expr.cst));
}