@lcap/nasl-parser
Version:
Take Nasl text to Nasl AST with the help of generalized parsing.
185 lines (161 loc) • 6.81 kB
text/typescript
import * as nasl from '@lcap/nasl';
import { dispatchToNaslExpr, toNaslDefaultValue } from './to-nasl-expression';
import { isEnd } from '@lcap/nasl-concepts/asserts';
import { CstNamespace, UsingNamespace, CstAnnotationArg, SupportedDefinition, CstAnnotation, CstIdentifier } from './decorated-nasl-ast';
import { AstCstPack, PackNaslAndCst, PackNaslAndCstSeq, TYPE, getCst, getNasl, isEmpty, last, projectIdentifier, projectIdentifierAST, wellDefined } from './common-util';
import { createNaslPrimitiveType } from './to-nasl-type';
export const toNaslVarsAndStmts = ([vars, stmts]) => {
return { nasl: {vars: vars.nasl, stmts: stmts.nasl }
, cst: {vars: vars.cst, stmts: stmts.cst} }
}
export const toNaslLogicSig = (name, tyVars, params, _ret, anns) => {
tyVars = tyVars ?? []
const ret = _ret ? new nasl.Return({
name: _ret.nasl.name,
typeAnnotation: _ret.nasl.typeAnnotation,
defaultValue: _ret.nasl.defaultValue
}) : null;
return PackNaslAndCst({ name
, tyVars: tyVars.nasl
, params: params.nasl
, ret
, anns: anns?.map(getNasl)}
, TYPE('LogicSig', { name
, tyVars: tyVars.cst
, params: params.cst
, ret: _ret?.cst
, anns: anns?.map(getCst)})
);
}
export const toNaslLogic = ([_sig, _body]) => {
const sig = _sig.nasl;
const body = _body.nasl;
const nl = new nasl.Logic();
nl.name = sig.name;
nl.typeParams = sig.tyVars; // null 与 IDE 兼容,绝妙!=> 3.11 又不兼容了 又要改成 undefined
nl.params = sig.params ?? []; // [] 与 IDE 兼容,绝妙!
nl.returns = sig.ret ? [sig.ret] : [];
nl.annotations = sig.annotations;
nl.body = [new nasl.Start({label: '开始'}), ...body.stmts]; // 不写 label 还真就不加了,🐂
if (!isEnd(last(nl.body))) {
nl.body.push(new nasl.End({label: '结束'})); // 不写 label 还真就不加了,🐂
}
nl.variables = body.vars; // 无法自由创建局部变量,都在逻辑开头处
nl.annotations = sig.anns;
return PackNaslAndCst(nl, TYPE('Logic', { sig: _sig.cst, body: _body.cst }));
}
// transform type variables introduced in <·> to type parameters
// not to be confused with types used <·> at the use site
const toNaslTypeParam = (n) =>
new nasl.TypeParam({
name: n
});
export const toNaslStructure = (tyIntro, pCtor, supTy, body, anns) => {
const ns = new nasl.Structure({
name: tyIntro.tyCon,
// description: ,
// origin: 'CallQueryComponent'; ???
typeParams: tyIntro.tyVars.map(toNaslTypeParam),
properties: pCtor?.nasl ? pCtor.nasl.concat(body?.nasl.props) : body?.nasl.props,
});
ns.annotations = anns?.map(getNasl);
const cst = TYPE("Struct", {anns: anns?.map(getCst), ty: tyIntro, props: body.cst.props, logics: body.cst.logics, ctors: body.cst.ctors })
return PackNaslAndCst(ns, cst);
}
export const toNaslStructureProperty = (vd, anns?) => {
const nsp = new nasl.StructureProperty({
// sp.nasl : nasl.Variable
name: vd.nasl.name,
typeAnnotation: vd.nasl.typeAnnotation,
defaultValue: vd.nasl.defaultValue,
// label: TODO
// jsonName: TODO
// description: TODO
// required 看起来废弃了
});
nsp.annotations = anns?.map(getNasl);
return PackNaslAndCst(nsp, TYPE("StructProperty", { prop: vd.cst, anns: anns?.map(getCst) }));
}
export const pCtorToProperty = ([vds]) => {
if (isEmpty(vds)) {
return PackNaslAndCst([], [])
}
return PackNaslAndCstSeq(vds?.nasl?.map(toNaslStructureProperty));
}
export function toNaslEnum(name, defs, anns?) {
const body = PackNaslAndCstSeq(defs);
const isInt = /^\d+$/.test(body.nasl[0].value);
const ne = new nasl.Enum({
name,
enumItems: body.nasl,
valueType: createNaslPrimitiveType(isInt ? 'Long' : 'String'),
// ne.label = e.label; 似乎是废弃属性
});
ne.annotations = anns?.map(getNasl);
return PackNaslAndCst(ne, TYPE("Enum", { name, body: body.cst, anns: anns?.map(getCst) }));
}
export const toNaslEnumItem = (prop: string | AstCstPack, anns?) => {
if (typeof prop !== 'string') {
// @ts-ignore
prop = prop.nasl.value;
}
const nei = new nasl.EnumItem({
// @ts-ignore
value: prop,
// label: title, 后续 ProcessAnnotation 流程统一处理
});
nei.annotations = anns?.map(getNasl);
return PackNaslAndCst(nei, TYPE("EnumItem", { value: prop, anns: anns?.map(getCst) }))
}
export const toNaslVarInit = ([name, ty, val]) => {
const nv = new nasl.Variable({
name: name,
typeAnnotation: ty?.nasl,
defaultValue: val?.nasl ? new nasl.DefaultValue({expression: val?.nasl}) : undefined,
});
return PackNaslAndCst(nv, TYPE("VarInit", { name, ty: ty?.cst, val: val?.cst }));
}
export function toNaslUsingNamespace(_qName: CstIdentifier) {
const nsp = _qName.namespace.concat(_qName.name);
return PackNaslAndCst(
new UsingNamespace(nsp),
TYPE("UsingNamespace", { namespace: nsp })
);
}
export function toNaslLogicDeclare(_sig) {
const decl = new nasl.LogicDeclaration({
name: _sig.nasl.name,
typeParams: _sig.nasl.tyVars,
params: _sig.nasl.params,
returns: _sig.nasl.ret,
});
return PackNaslAndCst(decl, TYPE('LogicDeclare', _sig.cst));
}
export function toNaslCstAnn(type: 'Builtin' | 'Custom', name, args) {
const cAnn = new CstAnnotation(type, name, args.nasl);
return PackNaslAndCst(cAnn, TYPE('Annotation', { type, name, args: args.cst }));
}
export function toNaslCstAnnArg(name: string, val: any) {
const cAArg = new CstAnnotationArg(name, val?.nasl);
return PackNaslAndCst(cAArg, TYPE('AnnotationArg', { name: name, val: val?.cst }) );
}
export function toNaslNamespace(name: string, defs: Array<any>) {
const packed = PackNaslAndCstSeq(defs);
const nsp = new CstNamespace(name, packed.nasl);
return PackNaslAndCst(nsp, TYPE('Namespace', { defs: packed.cst }));
}
// pctor: primary constructor
export function toNaslEntity(tyIntro, pctor, props, anns?) {
const ne = new nasl.Entity({
name: tyIntro.tyCon,
properties: props.nasl,
annotations: anns?.map(getNasl)
});
const cst = TYPE('Entity', {
ty: tyIntro,
pctor: null, // 暂不支持
props: props.cst,
anns: anns?.map(getCst)
});
return PackNaslAndCst(ne, cst);
}