UNPKG

@lcap/nasl-parser

Version:

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

392 lines (335 loc) 12.8 kB
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)); }