@lcap/nasl-language-server-core 4.1.0-rc.8 → 4.1.0-rc.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/out/checker.d.ts +1 -1
- package/out/checker.d.ts.map +1 -1
- package/out/checker.js +87 -121
- package/out/checker.js.map +1 -1
- package/out/index.d.ts +2 -2
- package/out/index.d.ts.map +1 -1
- package/out/index.js +4 -3
- package/out/index.js.map +1 -1
- package/out/reference-manager/builtin-q-name.d.ts +1 -2
- package/out/reference-manager/builtin-q-name.d.ts.map +1 -1
- package/out/reference-manager/builtin-q-name.js +1 -5
- package/out/reference-manager/builtin-q-name.js.map +1 -1
- package/out/reference-manager/collect-q-name.d.ts.map +1 -1
- package/out/reference-manager/collect-q-name.js +8 -7
- package/out/reference-manager/collect-q-name.js.map +1 -1
- package/out/reference-manager/helper.d.ts +1 -1
- package/out/reference-manager/helper.d.ts.map +1 -1
- package/out/reference-manager/helper.js +11 -1
- package/out/reference-manager/helper.js.map +1 -1
- package/out/reference-manager/reference-manager.d.ts +64 -7
- package/out/reference-manager/reference-manager.d.ts.map +1 -1
- package/out/reference-manager/reference-manager.js +198 -56
- package/out/reference-manager/reference-manager.js.map +1 -1
- package/out/reference-manager/remove-q-name.js +8 -8
- package/out/reference-manager/remove-q-name.js.map +1 -1
- package/out/reference-manager/rename-q-name.d.ts.map +1 -1
- package/out/reference-manager/rename-q-name.js +6 -6
- package/out/reference-manager/rename-q-name.js.map +1 -1
- package/out/reference-manager/update-nasl-fragment.d.ts +0 -1
- package/out/reference-manager/update-nasl-fragment.d.ts.map +1 -1
- package/out/reference-manager/update-nasl-fragment.js +2 -33
- package/out/reference-manager/update-nasl-fragment.js.map +1 -1
- package/out/typer/component-def-manager/utils.js +1 -1
- package/out/typer/component-def-manager/utils.js.map +1 -1
- package/out/typer/dispatch-all.d.ts +10 -3
- package/out/typer/dispatch-all.d.ts.map +1 -1
- package/out/typer/dispatch-all.js +44 -7
- package/out/typer/dispatch-all.js.map +1 -1
- package/out/typer/dispatch-call.d.ts +14 -0
- package/out/typer/dispatch-call.d.ts.map +1 -0
- package/out/typer/dispatch-call.js +637 -0
- package/out/typer/dispatch-call.js.map +1 -0
- package/out/typer/dispatch-def.d.ts +9 -3
- package/out/typer/dispatch-def.d.ts.map +1 -1
- package/out/typer/dispatch-def.js +101 -91
- package/out/typer/dispatch-def.js.map +1 -1
- package/out/typer/dispatch-expr.d.ts +3 -15
- package/out/typer/dispatch-expr.d.ts.map +1 -1
- package/out/typer/dispatch-expr.js +94 -698
- package/out/typer/dispatch-expr.js.map +1 -1
- package/out/typer/dispatch-process.d.ts.map +1 -1
- package/out/typer/dispatch-process.js +25 -10
- package/out/typer/dispatch-process.js.map +1 -1
- package/out/typer/dispatch-stmt.d.ts.map +1 -1
- package/out/typer/dispatch-stmt.js +39 -38
- package/out/typer/dispatch-stmt.js.map +1 -1
- package/out/typer/dispatch-view.d.ts.map +1 -1
- package/out/typer/dispatch-view.js +22 -16
- package/out/typer/dispatch-view.js.map +1 -1
- package/out/typer/get-oql-files.d.ts +13 -0
- package/out/typer/get-oql-files.d.ts.map +1 -0
- package/out/typer/get-oql-files.js +136 -0
- package/out/typer/get-oql-files.js.map +1 -0
- package/out/typer/helper.d.ts +2 -2
- package/out/typer/helper.d.ts.map +1 -1
- package/out/typer/helper.js +5 -5
- package/out/typer/helper.js.map +1 -1
- package/out/typer/incremental-update.d.ts +0 -12
- package/out/typer/incremental-update.d.ts.map +1 -1
- package/out/typer/incremental-update.js +99 -193
- package/out/typer/incremental-update.js.map +1 -1
- package/out/typer/index.d.ts +6 -4
- package/out/typer/index.d.ts.map +1 -1
- package/out/typer/index.js +9 -10
- package/out/typer/index.js.map +1 -1
- package/out/typer/subster.d.ts +0 -1
- package/out/typer/subster.d.ts.map +1 -1
- package/out/typer/subster.js +3 -23
- package/out/typer/subster.js.map +1 -1
- package/out/typer/topo-sort.d.ts +4 -4
- package/out/typer/topo-sort.d.ts.map +1 -1
- package/out/typer/topo-sort.js +5 -1
- package/out/typer/topo-sort.js.map +1 -1
- package/out/typer/type-manager.d.ts +2 -2
- package/out/typer/type-manager.d.ts.map +1 -1
- package/out/typer/type-manager.js +32 -9
- package/out/typer/type-manager.js.map +1 -1
- package/out/typer/type-predicate.d.ts +6 -1
- package/out/typer/type-predicate.d.ts.map +1 -1
- package/out/typer/type-predicate.js +22 -4
- package/out/typer/type-predicate.js.map +1 -1
- package/out/typer/typer.d.ts +27 -6
- package/out/typer/typer.d.ts.map +1 -1
- package/out/typer/typer.js +69 -18
- package/out/typer/typer.js.map +1 -1
- package/out/typer/unifier.d.ts +1 -1
- package/out/typer/unifier.d.ts.map +1 -1
- package/out/typer/unifier.js +48 -69
- package/out/typer/unifier.js.map +1 -1
- package/out/utils/string.d.ts.map +1 -1
- package/out/utils/string.js +1 -0
- package/out/utils/string.js.map +1 -1
- package/package.json +5 -5
- package/out/typer/nasl-predicate.d.ts +0 -8
- package/out/typer/nasl-predicate.d.ts.map +0 -1
- package/out/typer/nasl-predicate.js +0 -25
- package/out/typer/nasl-predicate.js.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getRightByLine = exports.
|
|
3
|
+
exports.getRightByLine = exports.tpMatch = exports.tpSolvingExpr = exports.extractNameTyPair = exports.tpSubLogic = exports.tpAnonymousFunction = exports.dispatchExpr = void 0;
|
|
4
4
|
const nasl_concepts_1 = require("@lcap/nasl-concepts");
|
|
5
5
|
const fp_macros_1 = require("../utils/fp-macros");
|
|
6
6
|
const sem_diag_1 = require("./sem-diag");
|
|
@@ -11,7 +11,6 @@ const dispatch_stmt_2 = require("./dispatch-stmt");
|
|
|
11
11
|
const dispatch_def_1 = require("./dispatch-def");
|
|
12
12
|
const get_q_name_1 = require("../reference-manager/get-q-name");
|
|
13
13
|
const reference_manager_1 = require("../reference-manager/reference-manager");
|
|
14
|
-
const symbol_type_1 = require("../reference-manager/symbol-type");
|
|
15
14
|
const string_1 = require("../utils/string");
|
|
16
15
|
const assertion_1 = require("../utils/assertion");
|
|
17
16
|
const service_1 = require("@lcap/nasl-concepts/service");
|
|
@@ -19,15 +18,13 @@ const asserts_1 = require("@lcap/nasl-concepts/asserts");
|
|
|
19
18
|
const type_manager_1 = require("./type-manager");
|
|
20
19
|
const type_predicate_1 = require("./type-predicate");
|
|
21
20
|
const type_predicate_2 = require("./type-predicate");
|
|
22
|
-
const dispatch_process_1 = require("./dispatch-process");
|
|
23
21
|
const dispatch_view_1 = require("./dispatch-view");
|
|
24
22
|
const subster_2 = require("./subster");
|
|
25
|
-
const parseTsClassType_1 = require("../utils/parseTsClassType");
|
|
26
23
|
const error_boundary_1 = require("../utils/error-boundary");
|
|
27
24
|
const types_1 = require("../utils/types");
|
|
28
25
|
const type_operator_1 = require("../utils/type-operator");
|
|
29
26
|
const nasl_type_manipulation_1 = require("../utils/nasl-type-manipulation");
|
|
30
|
-
const
|
|
27
|
+
const dispatch_call_1 = require("./dispatch-call");
|
|
31
28
|
// speed consideration
|
|
32
29
|
function dispatchExpr(env, nd, tgtTy) {
|
|
33
30
|
if (!nd) {
|
|
@@ -46,15 +43,16 @@ function dispatchExpr(env, nd, tgtTy) {
|
|
|
46
43
|
case 'NullLiteral': return tpNullLiteral(env, nd, tgtTy);
|
|
47
44
|
case 'Function': return tpFunction(env, nd, tgtTy); // 历史兼容
|
|
48
45
|
case 'DefaultValue': return tpDefaultValue(env, nd, tgtTy);
|
|
49
|
-
case 'CallLogic': return tpCallLogic(env, nd, tgtTy);
|
|
50
|
-
case 'CallFunction': return tpCallFunction(env, nd, tgtTy);
|
|
46
|
+
case 'CallLogic': return (0, dispatch_call_1.tpCallLogic)(env, nd, tgtTy);
|
|
47
|
+
case 'CallFunction': return (0, dispatch_call_1.tpCallFunction)(env, nd, tgtTy);
|
|
51
48
|
case 'CallEvent': return (0, dispatch_view_1.tpCallEvent)(env, nd, tgtTy);
|
|
52
|
-
case 'CallInterface':
|
|
53
|
-
case '
|
|
54
|
-
case '
|
|
49
|
+
case 'CallInterface':
|
|
50
|
+
case 'CallAuthInterface':
|
|
51
|
+
case 'CallMicroserviceInterface':
|
|
52
|
+
case 'CallGatewayInterface': return (0, dispatch_call_1.tpCallInterface)(env, nd, tgtTy);
|
|
55
53
|
case 'CallQueryComponent': return tpCallQueryComponent(env, nd, tgtTy);
|
|
56
54
|
// @ts-ignore
|
|
57
|
-
case 'CallConnector': return (0,
|
|
55
|
+
case 'CallConnector': return (0, dispatch_call_1.tpCallLogic)(env, nd, tgtTy);
|
|
58
56
|
case 'Argument': return tpArgument(env, nd, tgtTy);
|
|
59
57
|
case 'ValidationRule': return (0, dispatch_view_1.tpViewValidationRule)(env, nd);
|
|
60
58
|
case 'NewComposite': return tpNewComposite(env, nd, tgtTy);
|
|
@@ -62,8 +60,8 @@ function dispatchExpr(env, nd, tgtTy) {
|
|
|
62
60
|
case 'NewMap': return tpNewMap(env, nd, tgtTy);
|
|
63
61
|
case 'Match': return tpMatch(env, nd, tgtTy);
|
|
64
62
|
case 'StringInterpolation': return tpStringInterpolation(env, nd, tgtTy);
|
|
65
|
-
case 'AnonymousFunction': return tpAnonymousFunction(env, nd, tgtTy);
|
|
66
|
-
case 'SubLogic': return tpSubLogic(env, nd, tgtTy);
|
|
63
|
+
case 'AnonymousFunction': return (0, exports.tpAnonymousFunction)(env, nd, tgtTy);
|
|
64
|
+
case 'SubLogic': return (0, exports.tpSubLogic)(env, nd, tgtTy);
|
|
67
65
|
case 'Unparsed': return tpUnparsed(env, nd, tgtTy);
|
|
68
66
|
case 'QueryFieldExpression': return fakeTpQueryFieldExpression(env, nd, tgtTy);
|
|
69
67
|
case 'Paginate': return tpPaginate(env, nd, tgtTy);
|
|
@@ -155,7 +153,7 @@ function tpNumericLiteral(env, nd, tgtTy) {
|
|
|
155
153
|
function tpStringInterpolation(env, nd, tgtTy) {
|
|
156
154
|
nd.expressions.forEach((expr) => {
|
|
157
155
|
// HACK: 动态拖入一个表达式的时候,在 expressions 数组中是 proxied
|
|
158
|
-
return dispatchExpr(env, toRaw(expr), undefined);
|
|
156
|
+
return dispatchExpr(env, (0, dispatch_stmt_1.toRaw)(expr), undefined);
|
|
159
157
|
});
|
|
160
158
|
env.setType(nd, type_manager_1.naslStringTy);
|
|
161
159
|
env.unifier.unify(type_manager_1.naslStringTy, tgtTy);
|
|
@@ -637,7 +635,7 @@ const tpBinaryOrderExpr = (env, nd, tgtTy) => {
|
|
|
637
635
|
if (!ty) {
|
|
638
636
|
return false;
|
|
639
637
|
}
|
|
640
|
-
if ((0, type_predicate_2.isPrimitiveTy)(ty) && orderableTyNames.includes(ty.typeName)) {
|
|
638
|
+
if ((0, type_predicate_2.isPrimitiveTy)(ty) && orderableTyNames.includes(ty.typeName) || (0, type_predicate_2.isNullTy)(ty) || (0, type_predicate_2.isAnyTy)(ty)) {
|
|
641
639
|
return true;
|
|
642
640
|
}
|
|
643
641
|
// 支持Union类型:如果所有成员都是可排序类型,则Union类型也是可排序的
|
|
@@ -688,474 +686,7 @@ function tpUnaryExpression(env, nd, tgtTy) {
|
|
|
688
686
|
return env.getRawType(nd);
|
|
689
687
|
}
|
|
690
688
|
}
|
|
691
|
-
|
|
692
|
-
return nsp.startsWith('app.dataSources.') && nsp.endsWith('logics') && /\.entities\./.test(nsp);
|
|
693
|
-
}
|
|
694
|
-
function isLoggingLogic(nsp) {
|
|
695
|
-
return nsp === 'nasl.logging';
|
|
696
|
-
}
|
|
697
|
-
function tpCallLogic(env, nd, tgtTy) {
|
|
698
|
-
if (!nd.calleeName) {
|
|
699
|
-
return undefined;
|
|
700
|
-
}
|
|
701
|
-
// 特殊处理咯 ad hoc treatment for entity logics
|
|
702
|
-
if (isEntityLogic(nd.calleeNamespace)) {
|
|
703
|
-
return tpEntityLogic(env, nd, tgtTy);
|
|
704
|
-
}
|
|
705
|
-
// 特殊处理咯,你自己看看你的 Call 的 NASL 和定义能对得上一毫米吗?
|
|
706
|
-
if (isLoggingLogic(nd.calleeNamespace)) {
|
|
707
|
-
// Use a different approach to avoid the parameter issues
|
|
708
|
-
for (const arg of nd.arguments) {
|
|
709
|
-
dispatchExpr(env, arg, type_manager_1.naslAnyTy);
|
|
710
|
-
}
|
|
711
|
-
env.setType(nd, type_manager_1.naslVoidTy);
|
|
712
|
-
return env.getRawType(nd);
|
|
713
|
-
}
|
|
714
|
-
let def;
|
|
715
|
-
if (nd.calleeNamespace !== 'nasl.util') {
|
|
716
|
-
def = env.resolveRef(nd);
|
|
717
|
-
}
|
|
718
|
-
else {
|
|
719
|
-
// 'nasl.util' 时 是 json 序列化
|
|
720
|
-
def = env.quickGetLibDef(nd, nd.calleeName, undefined);
|
|
721
|
-
}
|
|
722
|
-
// 处理调用处的验证规则
|
|
723
|
-
if (nd.validation?.rules && nd.validation.rules.length > 0 && def) {
|
|
724
|
-
def.params.forEach(param => (0, dispatch_def_1.dispatchDef)(env, param));
|
|
725
|
-
nd.validation?.rules?.forEach(rule => (0, dispatch_stmt_1.dispatchStmt)(env, rule));
|
|
726
|
-
def.params.forEach(env.removeVar);
|
|
727
|
-
}
|
|
728
|
-
if ((0, symbol_type_1.isProcessLogicCall)(nd.calleeNamespace) && (0, symbol_type_1.isSpecialProcessLogic)(nd.calleeName)) {
|
|
729
|
-
return (0, dispatch_process_1.tpSpecialProcessLogicCall)(env, nd, tgtTy);
|
|
730
|
-
}
|
|
731
|
-
// 余下的流程逻辑比较正常,就走正常的 CallLogic 处理流程好了
|
|
732
|
-
let fnTy = determineCallLogicFnTy(env, nd, def);
|
|
733
|
-
if (!fnTy) {
|
|
734
|
-
// TODO fnTy 可能为undefined 或 typeKind!=function, 需要考虑
|
|
735
|
-
env.addError(`无法找到逻辑 ${nd.calleeName}`);
|
|
736
|
-
return;
|
|
737
|
-
}
|
|
738
|
-
if (fnTy.typeParams?.length) {
|
|
739
|
-
fnTy = renameAndMakePartialTyApp(env, fnTy, nd);
|
|
740
|
-
}
|
|
741
|
-
// typing arguments
|
|
742
|
-
for (const [idx, parTy] of fnTy.typeArguments.entries()) {
|
|
743
|
-
// 先获取 param,因为 spread 属性在 param 上,而不是在 parTy 上
|
|
744
|
-
let param = def ? def.params?.[idx] : undefined;
|
|
745
|
-
if (param?.spread) {
|
|
746
|
-
// 按照约定,spread为true时,其上TypeAnnotation就已经是List<T>中的T。
|
|
747
|
-
// CallFunction因为大都是从TS parse出来,原样写入List<T>,因此可以看到tpCallFunction中仍然获取了List中的T
|
|
748
|
-
// TODO 修正 spread 相关的 TS parse,让两边一致
|
|
749
|
-
const elemTy = parTy;
|
|
750
|
-
// 余下的一并处理
|
|
751
|
-
for (let i = idx; i < nd.arguments.length; ++i) {
|
|
752
|
-
const arg = nd.arguments[i];
|
|
753
|
-
if (arg?.expression) {
|
|
754
|
-
dispatchExpr(env, arg, elemTy);
|
|
755
|
-
changeArgTyToParamTy(env, arg, elemTy);
|
|
756
|
-
}
|
|
757
|
-
else {
|
|
758
|
-
env.setType(arg, type_manager_1.naslAnyTy);
|
|
759
|
-
}
|
|
760
|
-
}
|
|
761
|
-
break; // spread 参数处理完毕,跳出循环
|
|
762
|
-
}
|
|
763
|
-
else {
|
|
764
|
-
// TODO: json序列化等没有 def,导致 param 直接 undefined
|
|
765
|
-
const arg = nd.arguments[idx];
|
|
766
|
-
if (!arg) {
|
|
767
|
-
env.setType(nd, type_manager_1.naslAnyTy);
|
|
768
|
-
continue;
|
|
769
|
-
}
|
|
770
|
-
if (arg?.expression) {
|
|
771
|
-
dispatchExpr(env, arg, parTy);
|
|
772
|
-
changeArgTyToParamTy(env, arg, parTy);
|
|
773
|
-
}
|
|
774
|
-
else if (param) {
|
|
775
|
-
if (param.optional || parTy.optional) { // 组件逻辑等现在没有 def,用 type 判断
|
|
776
|
-
env.setType(arg, parTy);
|
|
777
|
-
}
|
|
778
|
-
else if (param.defaultValue?.expression) {
|
|
779
|
-
env.setType(arg, parTy);
|
|
780
|
-
}
|
|
781
|
-
else {
|
|
782
|
-
// 报错:泛型逻辑调用,最后的 callInfo 里有 type variables,会被判定为 unresolved,目前不检查 arg 会缺少报错
|
|
783
|
-
// env.addError(`调用逻辑:参数不能为空`, env.getCurFileNode(), arg);
|
|
784
|
-
env.setType(arg, type_manager_1.naslAnyTy);
|
|
785
|
-
}
|
|
786
|
-
}
|
|
787
|
-
else {
|
|
788
|
-
// 报错
|
|
789
|
-
env.setType(arg, type_manager_1.naslAnyTy);
|
|
790
|
-
}
|
|
791
|
-
}
|
|
792
|
-
}
|
|
793
|
-
let finalRetTy = fnTy.returnType?.[0];
|
|
794
|
-
// CallConnector 不支持 handleError 错误处理参数
|
|
795
|
-
if (nd.concept !== 'CallConnector') {
|
|
796
|
-
if (nd.handleError === true) {
|
|
797
|
-
dispatchExpr(env, nd.errorMessage, undefined);
|
|
798
|
-
}
|
|
799
|
-
else {
|
|
800
|
-
// 做了手动处理 Error 需求后,需要 remove Error types from return types
|
|
801
|
-
finalRetTy = (0, exports.removeErrTys)(env, nd, fnTy?.returnType?.[0]);
|
|
802
|
-
}
|
|
803
|
-
}
|
|
804
|
-
env.unifier.unify(finalRetTy, tgtTy);
|
|
805
|
-
env.setType(nd, finalRetTy);
|
|
806
|
-
// 给 checker 报错用,都给吧,CallLogic 也有要处理 Error | T 返回类型的复杂情形,checker 直接拿结果就行不用重复处理
|
|
807
|
-
// TODO: 前端的部分组件逻辑好像指飞了(env.resoleRef 和 env.resolvedCallInfo 结果不一样)……先用 !env.isView 判断一下
|
|
808
|
-
if (!env.isView || nd.calleeNamespace === 'nasl.util') { // json 序列化 - similarly add param info for nasl.util
|
|
809
|
-
const callInfo = (0, type_manager_1.createFunctionDef)(fnTy.typeArguments, finalRetTy, def, fnTy.typeParams);
|
|
810
|
-
env.resolvedCallInfo.set(nd, callInfo);
|
|
811
|
-
}
|
|
812
|
-
if (fnTy.typeParams?.length) {
|
|
813
|
-
env.addPostCheckTask(nd, (e, pSubst) => {
|
|
814
|
-
// 写入 __TypeArguments 字段,调用泛型依赖库时,代码生成要用。
|
|
815
|
-
const typeArgs = fnTy?.typeParams
|
|
816
|
-
?.map((x) => {
|
|
817
|
-
return e.getType(pSubst(x));
|
|
818
|
-
})
|
|
819
|
-
.filter(types_1.isNotNil) ?? [];
|
|
820
|
-
// 写入来自:_getQuickInfoNodesTypeMapWithGenerator
|
|
821
|
-
nd.__TypeArguments = typeArgs;
|
|
822
|
-
});
|
|
823
|
-
}
|
|
824
|
-
return finalRetTy;
|
|
825
|
-
}
|
|
826
|
-
exports.tpCallLogic = tpCallLogic;
|
|
827
|
-
function determineCallLogicFnTy(env, nd, def) {
|
|
828
|
-
if (def && (0, service_1.isCallableNaslLogic)(def)) {
|
|
829
|
-
// TODO zzr 需要用个 cache 加快速度吗
|
|
830
|
-
return env.getRawType(def);
|
|
831
|
-
}
|
|
832
|
-
else {
|
|
833
|
-
const qName = (0, get_q_name_1.getTokenQualifiedName)(nd);
|
|
834
|
-
if (!qName) {
|
|
835
|
-
return undefined;
|
|
836
|
-
}
|
|
837
|
-
const placeholderFnTy = createAndSetForwardReferencePlaceholder(env, nd);
|
|
838
|
-
// @ts-expect-error
|
|
839
|
-
if (def?.concept === 'TypeAnnotation') {
|
|
840
|
-
// 令根据根据本次 Call 计算得出的类型为 placeholderFnTy
|
|
841
|
-
// 所有出现 placeholderFnTy 的地方,都可以被 def 替换,因此 def 为 placeholderFnTy 的子类型
|
|
842
|
-
env.unifier.unify(def, placeholderFnTy);
|
|
843
|
-
}
|
|
844
|
-
else {
|
|
845
|
-
if (env.isDebugMode) {
|
|
846
|
-
// FIXME wudengke 修复use before def的问题,debug模式下先报出来。
|
|
847
|
-
env.addDiagnosticsFor(`[DEBUG] determineCallLogicFnTy: 可能出现了use before def。 ${qName}`, nd);
|
|
848
|
-
}
|
|
849
|
-
}
|
|
850
|
-
return placeholderFnTy;
|
|
851
|
-
}
|
|
852
|
-
}
|
|
853
|
-
exports.determineCallLogicFnTy = determineCallLogicFnTy;
|
|
854
|
-
function changeArgTyToParamTy(env, nd, parTy) {
|
|
855
|
-
// 初始时, nd.type === nd.expression.type
|
|
856
|
-
// FIXME: 例如后端需要 argument.type 与 argument.expression.type 不一样做 long -> decimal 的强制转换
|
|
857
|
-
// 这里有个问题,JSON 序列化不是 CallFunction 是 CallLogic,所以会走到这里
|
|
858
|
-
// 但是它 的 paramTy 是 NASL 不存在的类型 Any,炸裂还是得用 argTy
|
|
859
|
-
if (!(0, type_predicate_2.isAnyTy)(parTy)) {
|
|
860
|
-
env.setType(nd, parTy);
|
|
861
|
-
}
|
|
862
|
-
// Magic!
|
|
863
|
-
nd.paramTypeAnnotation = parTy;
|
|
864
|
-
}
|
|
865
|
-
exports.changeArgTyToParamTy = changeArgTyToParamTy;
|
|
866
|
-
function renameAndMakePartialTyApp(env, fnTy, nd) {
|
|
867
|
-
// 先 rename bound type variables
|
|
868
|
-
if ((0, type_predicate_1.isUnResolvedTy)(fnTy)) {
|
|
869
|
-
fnTy = (0, type_manager_1.copyTyAnn)(fnTy);
|
|
870
|
-
env.unifier.inPlaceRenameTy(fnTy);
|
|
871
|
-
}
|
|
872
|
-
// 再做 type arguments partial application
|
|
873
|
-
// 用户选定部分 type params,这一块 Java 依赖库好像还有特殊处理,估计之后要大改
|
|
874
|
-
// 事实证明 Add 这种函数 nd.typeArguments 是 null 不是空数组 []
|
|
875
|
-
if (nd.typeArguments && nd.typeArguments.length > 0) {
|
|
876
|
-
if (fnTy.typeParams) {
|
|
877
|
-
const subst = new Map();
|
|
878
|
-
nd.typeArguments.forEach((ty, idx) => {
|
|
879
|
-
if (ty.typeName && ty.typeKind) {
|
|
880
|
-
fnTy.typeParams[idx] && subst.set(fnTy.typeParams[idx].typeName, ty);
|
|
881
|
-
}
|
|
882
|
-
});
|
|
883
|
-
fnTy.typeParams = fnTy.typeParams.map((0, subster_1.substTyAnn)(env, subst));
|
|
884
|
-
fnTy = (0, subster_1.substTyAnn)(env, subst)(fnTy);
|
|
885
|
-
}
|
|
886
|
-
}
|
|
887
|
-
return fnTy;
|
|
888
|
-
}
|
|
889
|
-
function tpCallFunction(env, nd, tgtTy) {
|
|
890
|
-
let calleeName = nd.calleeName;
|
|
891
|
-
if (!calleeName) {
|
|
892
|
-
env.addError('没有函数名,无法进行调用');
|
|
893
|
-
return undefined;
|
|
894
|
-
}
|
|
895
|
-
// 处理 enum 函数
|
|
896
|
-
if (parseTsClassType_1.enumBuiltinFns.includes(calleeName)) {
|
|
897
|
-
return handleEnumFn(env, nd, tgtTy);
|
|
898
|
-
}
|
|
899
|
-
// 前端全局类型推导 + 重载函数几乎无法做任何类型推导,只能做后置验证。后端可以推导,但简单起见,不区分前后端了。
|
|
900
|
-
// 总结:全局类型推导 + 重载 = 灾难
|
|
901
|
-
if (parseTsClassType_1.overloadedFns.includes(calleeName)) {
|
|
902
|
-
return handleOverloadedFunction(env, nd, tgtTy, calleeName);
|
|
903
|
-
}
|
|
904
|
-
const fnDef = env.quickGetLibDef(nd, calleeName, env.ctxCQC?.dataSourceSqlType);
|
|
905
|
-
let fnTy = fnDef?.__TypeAnnotation;
|
|
906
|
-
if (!fnTy) {
|
|
907
|
-
env.addError('无法找到函数定义(类型)');
|
|
908
|
-
return;
|
|
909
|
-
}
|
|
910
|
-
if (fnTy.typeParams?.length) {
|
|
911
|
-
fnTy = renameAndMakePartialTyApp(env, fnTy, nd);
|
|
912
|
-
}
|
|
913
|
-
for (const [idx, parTy] of fnTy.typeArguments.entries()) {
|
|
914
|
-
if (parTy.spread) { // 抽取 Array<T> 中的 T
|
|
915
|
-
const elemTy = parTy.typeArguments[0];
|
|
916
|
-
// 余下的一并处理
|
|
917
|
-
for (let i = idx; i < nd.arguments.length; ++i) {
|
|
918
|
-
/**
|
|
919
|
-
* ListSort 只能特殊处理了。
|
|
920
|
-
* nasl.util 里定义为 { asc: Boolean, by: Long | Decimal | ... } 的话会有匿名数据类型不匹配报错(invariance)
|
|
921
|
-
* 如果定义为泛型 T2 extends Long | Decimal | ... 且 { asc: Boolean, by: T2 } 的话 T2 不支持实例化成 Union
|
|
922
|
-
* (页面是全局求解,暂时不好区分 T2 的约束是来自多个赋值还是一个赋值,如果是多个则报错,如果是一个则使用 Union 作为解这种复杂的机制
|
|
923
|
-
*/
|
|
924
|
-
if (calleeName === 'ListSort' || calleeName === 'ListSortAsync') {
|
|
925
|
-
const expr = nd.arguments[i].expression;
|
|
926
|
-
// 抠出函数类型的参数和返回类型
|
|
927
|
-
if (!(0, type_predicate_2.isFuncTy)(elemTy)) {
|
|
928
|
-
continue; // 干不了了
|
|
929
|
-
}
|
|
930
|
-
const parTy = elemTy.typeArguments?.[0];
|
|
931
|
-
const retTy = elemTy.returnType?.[0];
|
|
932
|
-
// 留给 checker.ts 去做后置检查吧
|
|
933
|
-
if (expr?.concept === 'AnonymousFunction') {
|
|
934
|
-
tpAnonymousFunction(env, expr, (0, type_manager_1.createFnTyFromTyAnns)([parTy], undefined), true);
|
|
935
|
-
// dispatchExpr(env, expr.params[0], parTy);
|
|
936
|
-
// dispatchExpr(env, expr.body, retTy);
|
|
937
|
-
}
|
|
938
|
-
else if (expr?.concept === 'SubLogic') {
|
|
939
|
-
tpSubLogic(env, expr, (0, type_manager_1.createFnTyFromTyAnns)([parTy], undefined), true);
|
|
940
|
-
}
|
|
941
|
-
}
|
|
942
|
-
else {
|
|
943
|
-
// 正常处理
|
|
944
|
-
dispatchExpr(env, nd.arguments[i], elemTy);
|
|
945
|
-
}
|
|
946
|
-
}
|
|
947
|
-
}
|
|
948
|
-
else {
|
|
949
|
-
dispatchExpr(env, nd.arguments[idx], parTy);
|
|
950
|
-
}
|
|
951
|
-
}
|
|
952
|
-
const finalRetTy = fnTy.returnType?.[0] ?? tgtTy;
|
|
953
|
-
env.unifier.unify(finalRetTy, tgtTy);
|
|
954
|
-
// TODO:处理可选参数必填选填问题
|
|
955
|
-
env.setType(nd, finalRetTy); // 似乎不可能为空
|
|
956
|
-
const callInfo = (0, type_manager_1.createFunctionDef)(fnTy.typeArguments, finalRetTy, fnDef, // 内置函数
|
|
957
|
-
fnTy.typeParams);
|
|
958
|
-
env.resolvedCallInfo.set(nd, callInfo);
|
|
959
|
-
return finalRetTy;
|
|
960
|
-
function handleEnumFn(env, nd, tgtTy) {
|
|
961
|
-
const createAnonymousRetTy = (ty) => (0, type_manager_1.createAnonymousTyAnn)(['text', 'value'], [type_manager_1.naslStringTy, ty]);
|
|
962
|
-
let res = undefined;
|
|
963
|
-
let tyParam = undefined; // <T>. 但是是实例化后的
|
|
964
|
-
let paramTy = undefined; // (T)
|
|
965
|
-
let def = env.resolveRef(nd);
|
|
966
|
-
switch (nd.calleeName) {
|
|
967
|
-
// 暂时不合并代码了,也不是特别长
|
|
968
|
-
case 'EnumToList': {
|
|
969
|
-
if (!nd.typeArguments?.[0]) {
|
|
970
|
-
// 报错 缺参数
|
|
971
|
-
return;
|
|
972
|
-
}
|
|
973
|
-
tyParam = nd.typeArguments[0];
|
|
974
|
-
const enumDef = env.resolveRef(nd.typeArguments[0]);
|
|
975
|
-
if (enumDef?.concept === 'Enum') {
|
|
976
|
-
const ty = enumDef.valueType ?? type_manager_1.naslStringTy; // FIXME:还能是空的,服了
|
|
977
|
-
res = (0, type_manager_1.createListTyAnn)(createAnonymousRetTy(ty));
|
|
978
|
-
}
|
|
979
|
-
else {
|
|
980
|
-
env.addError((0, sem_diag_1.mkIncompatibleTyErr)(env, tyParam || type_manager_1.naslAnyTy, '枚举'), env.getCurFileNode(), nd);
|
|
981
|
-
}
|
|
982
|
-
break;
|
|
983
|
-
}
|
|
984
|
-
case 'ToEnumItem': {
|
|
985
|
-
if (!nd.typeArguments?.[0]) {
|
|
986
|
-
// 报错 缺参数
|
|
987
|
-
return;
|
|
988
|
-
}
|
|
989
|
-
tyParam = nd.typeArguments[0];
|
|
990
|
-
const enumDef = env.resolveRef(tyParam);
|
|
991
|
-
if (enumDef?.concept === 'Enum') {
|
|
992
|
-
const exprTy = dispatchExpr(env, nd.arguments[0], enumDef.valueType ?? type_manager_1.naslStringTy);
|
|
993
|
-
res = env.getRawType(enumDef);
|
|
994
|
-
paramTy = exprTy;
|
|
995
|
-
}
|
|
996
|
-
else {
|
|
997
|
-
env.addError((0, sem_diag_1.mkIncompatibleTyErr)(env, tyParam || type_manager_1.naslAnyTy, '枚举'), env.getCurFileNode(), nd);
|
|
998
|
-
}
|
|
999
|
-
break;
|
|
1000
|
-
}
|
|
1001
|
-
case 'EnumItemToStructure': {
|
|
1002
|
-
if (!nd.arguments?.[0]) {
|
|
1003
|
-
// 报错 缺参数
|
|
1004
|
-
return;
|
|
1005
|
-
}
|
|
1006
|
-
const exprTy = dispatchExpr(env, nd.arguments[0], undefined);
|
|
1007
|
-
if (!exprTy) {
|
|
1008
|
-
return;
|
|
1009
|
-
}
|
|
1010
|
-
paramTy = exprTy;
|
|
1011
|
-
const enumValueTy = (0, type_operator_1.createValueTypeForAssumedEnumTy)(exprTy);
|
|
1012
|
-
const postChk = (fileNode, severity, exprTy) => (env, pSubst) => {
|
|
1013
|
-
const ty = (0, subster_1.normalizeWithSubst)(env, pSubst, exprTy);
|
|
1014
|
-
// 断言: 它是枚举类型
|
|
1015
|
-
if (!(0, type_predicate_1.isEnumTy)(ty)) {
|
|
1016
|
-
const errMsg = (0, sem_diag_1.mkIncompatibleTyErr)(env, ty || type_manager_1.naslAnyTy, '枚举');
|
|
1017
|
-
env.addError(errMsg, fileNode, nd, severity);
|
|
1018
|
-
}
|
|
1019
|
-
};
|
|
1020
|
-
env.addPostCheckTask(env.errBoundary, postChk(env.getCurFileNode(), env.errSeverity, exprTy));
|
|
1021
|
-
res = createAnonymousRetTy(enumValueTy);
|
|
1022
|
-
break;
|
|
1023
|
-
}
|
|
1024
|
-
case 'EnumItemToText': {
|
|
1025
|
-
const exprTy = dispatchExpr(env, nd.arguments[0], undefined);
|
|
1026
|
-
// 如果不是枚举类型就报错,稍后建立 List、Map、Enums 等通用检测机制
|
|
1027
|
-
// FIXME zzr exprTy可能包含类型变元,此时无法立刻判断求解
|
|
1028
|
-
paramTy = exprTy;
|
|
1029
|
-
res = type_manager_1.naslStringTy;
|
|
1030
|
-
const postChk = (fileNode, severity, exprTy) => (env, pSubst) => {
|
|
1031
|
-
const ty = (0, subster_1.normalizeWithSubst)(env, pSubst, exprTy);
|
|
1032
|
-
if (!(0, type_predicate_1.isEnumTy)(ty)) {
|
|
1033
|
-
const errMsg = (0, sem_diag_1.mkIncompatibleTyErr)(env, ty || type_manager_1.naslAnyTy, '枚举');
|
|
1034
|
-
env.addError(errMsg, fileNode, nd, severity);
|
|
1035
|
-
}
|
|
1036
|
-
};
|
|
1037
|
-
env.addPostCheckTask(env.errBoundary, postChk(env.getCurFileNode(), env.errSeverity, exprTy));
|
|
1038
|
-
break;
|
|
1039
|
-
}
|
|
1040
|
-
default: {
|
|
1041
|
-
throw new Error(`未实现的 enum 枚举内置函数,函数名 ${nd.calleeName}`);
|
|
1042
|
-
}
|
|
1043
|
-
}
|
|
1044
|
-
env.unifier.unify(res, tgtTy);
|
|
1045
|
-
const retTy = res ?? tgtTy;
|
|
1046
|
-
env.setType(nd, retTy);
|
|
1047
|
-
const callInfo = (0, type_manager_1.createFunctionDef)(paramTy ? [paramTy] : [], type_manager_1.naslBooleanTy, def, tyParam ? [tyParam] : []);
|
|
1048
|
-
env.resolvedCallInfo.set(nd, callInfo);
|
|
1049
|
-
return retTy;
|
|
1050
|
-
}
|
|
1051
|
-
}
|
|
1052
|
-
exports.tpCallFunction = tpCallFunction;
|
|
1053
|
-
/**
|
|
1054
|
-
* 处理重载函数的调用
|
|
1055
|
-
* @param env 语义环境
|
|
1056
|
-
* @param nd 函数调用节点
|
|
1057
|
-
* @param tgtTy 目标类型
|
|
1058
|
-
* @param calleeName 被调用函数名
|
|
1059
|
-
* @returns 处理后的类型注解
|
|
1060
|
-
*/
|
|
1061
|
-
const handleOverloadedFunction = (env, nd, tgtTy, calleeName) => {
|
|
1062
|
-
const ovParamIdx = (0, overload_helper_1.getOvParamIdx)(calleeName);
|
|
1063
|
-
const argTys = [];
|
|
1064
|
-
for (const arg of nd.arguments) {
|
|
1065
|
-
argTys.push(dispatchExpr(env, arg, undefined) ?? type_manager_1.naslAnyTy);
|
|
1066
|
-
}
|
|
1067
|
-
if (calleeName === 'CAST') {
|
|
1068
|
-
argTys[ovParamIdx] = (0, overload_helper_1.createCastLiteralType)(nd.arguments?.[ovParamIdx]?.expression?.value ?? '');
|
|
1069
|
-
}
|
|
1070
|
-
// Convert, Length, CAST 的返回类型可以从用户选择的类型(通过 type picker)拿到
|
|
1071
|
-
// 其他重载函数都在 SQL 里,都在服务端逻辑里,可以立即从参数类型获得,没有页面全局类型推导的问题
|
|
1072
|
-
let retTy = (0, overload_helper_1.getOverloadFuncRetTy)(nd, argTys[ovParamIdx]);
|
|
1073
|
-
if (!retTy) {
|
|
1074
|
-
if (!env.isView) {
|
|
1075
|
-
const mangledCalleeName = (0, overload_helper_1.mangleOvFnName)(calleeName, argTys[ovParamIdx]);
|
|
1076
|
-
const fnDef = env.quickGetLibDef(nd, mangledCalleeName, env.ctxCQC?.dataSourceSqlType);
|
|
1077
|
-
const fnTy = fnDef?.__TypeAnnotation;
|
|
1078
|
-
retTy = fnTy?.returnType?.[0];
|
|
1079
|
-
}
|
|
1080
|
-
else {
|
|
1081
|
-
retTy = type_manager_1.naslAnyTy;
|
|
1082
|
-
}
|
|
1083
|
-
}
|
|
1084
|
-
env.unifier.unify(retTy, tgtTy);
|
|
1085
|
-
const callInfo = (0, type_manager_1.createFunctionDef)(argTys, retTy, undefined, undefined);
|
|
1086
|
-
env.resolvedCallInfo.set(nd, callInfo);
|
|
1087
|
-
const capturedDbSqlType = env.ctxCQC?.dataSourceSqlType;
|
|
1088
|
-
// 剩下的需要后置处理
|
|
1089
|
-
const postChk = (fileNode, errBoundary, severity) => (env) => {
|
|
1090
|
-
const argTys = nd.arguments.map((arg) => env.getType(arg.expression));
|
|
1091
|
-
if (calleeName === 'CAST') {
|
|
1092
|
-
argTys[ovParamIdx] = (0, overload_helper_1.createCastLiteralType)(nd.arguments?.[ovParamIdx]?.expression?.value ?? '');
|
|
1093
|
-
}
|
|
1094
|
-
const ovArgTy = argTys[ovParamIdx];
|
|
1095
|
-
const mangledCalleeName = (0, overload_helper_1.mangleOvFnName)(calleeName, ovArgTy);
|
|
1096
|
-
let fnDef = mangledCalleeName ? env.quickGetLibDef(nd, mangledCalleeName, capturedDbSqlType) : undefined;
|
|
1097
|
-
let fnTy = fnDef?.__TypeAnnotation;
|
|
1098
|
-
// If no matching overload found, validate and report error
|
|
1099
|
-
if (!fnDef || !fnTy) {
|
|
1100
|
-
// Create fallback definition to prevent further errors
|
|
1101
|
-
const fallbackDef = (0, overload_helper_1.createFallbackOverloadDef)(calleeName, nd.calleeNamespace, nd.arguments.length);
|
|
1102
|
-
fnDef = fallbackDef;
|
|
1103
|
-
fnTy = fallbackDef.__TypeAnnotation;
|
|
1104
|
-
// Convert 允许接收任何类型,跳过报错(mangled name convertList convertMap 等查不到定义会产生额外错误)
|
|
1105
|
-
if (calleeName !== 'Convert') {
|
|
1106
|
-
const possibleTypes = (0, overload_helper_1.getOverloadParameterTypes)(env, nd, capturedDbSqlType);
|
|
1107
|
-
if (possibleTypes.length > 0) {
|
|
1108
|
-
const errorMsg = (0, sem_diag_1.createOverloadTypeError)(calleeName, ovArgTy, possibleTypes);
|
|
1109
|
-
// precise error boundary nd.arguments[i]! is not working here, why?
|
|
1110
|
-
env.addError(errorMsg, fileNode, errBoundary, severity);
|
|
1111
|
-
}
|
|
1112
|
-
}
|
|
1113
|
-
}
|
|
1114
|
-
// 后置类型校验,暂时都不需要,不可能报错
|
|
1115
|
-
// for (let i = 0; i < argTys.length && i < (fnTy?.typeArguments?.length ?? 0); ++i) {
|
|
1116
|
-
// const sub = argTys[i];
|
|
1117
|
-
// const sup = fnTy!.typeArguments![i];
|
|
1118
|
-
// if (!isSubTy(env, sub, sup)) { // precise error boundary nd.arguments[i]! is not working here, why?
|
|
1119
|
-
// env.addError(mkIncompatibleTyErr(env, sub, sup), fileNode, errBoundary, severity);
|
|
1120
|
-
// }
|
|
1121
|
-
// }
|
|
1122
|
-
};
|
|
1123
|
-
env.addPostCheckTask(nd, postChk(env.getCurFileNode(), nd, env.errSeverity));
|
|
1124
|
-
env.setType(nd, retTy); // 似乎不可能为空
|
|
1125
|
-
return env.getRawType(nd);
|
|
1126
|
-
};
|
|
1127
|
-
function tpCallInterface(env, nd, tgtTy) {
|
|
1128
|
-
const qName = (0, get_q_name_1.getTokenQualifiedName)(nd);
|
|
1129
|
-
if (!qName) {
|
|
1130
|
-
env.setType(nd, type_manager_1.naslAnyTy);
|
|
1131
|
-
return type_manager_1.naslAnyTy;
|
|
1132
|
-
}
|
|
1133
|
-
const def = env.refMgr.gQNameDefs.get(qName);
|
|
1134
|
-
if (!def) {
|
|
1135
|
-
env.setType(nd, type_manager_1.naslAnyTy);
|
|
1136
|
-
return type_manager_1.naslAnyTy;
|
|
1137
|
-
}
|
|
1138
|
-
// 说起来你可能不信,但是事实令人震惊,参数与形参的顺序是乱的,仅能通过 keyword 来匹配
|
|
1139
|
-
for (const param of def.params) {
|
|
1140
|
-
dispatchExpr(env, nd.arguments.find(p => p.keyword === param.name), param.typeAnnotation);
|
|
1141
|
-
}
|
|
1142
|
-
const retTy = def.returns?.[0]?.typeAnnotation;
|
|
1143
|
-
const finalRetTy = nd?.handleError === true
|
|
1144
|
-
? (retTy ? (0, type_manager_1.createUnionTyAnn)([retTy, type_manager_1.naslInterfaceError]) : type_manager_1.naslInterfaceError)
|
|
1145
|
-
: (retTy ?? tgtTy);
|
|
1146
|
-
env.setType(nd, finalRetTy);
|
|
1147
|
-
env.unifier.unify(finalRetTy, tgtTy);
|
|
1148
|
-
if (!env.isView) {
|
|
1149
|
-
const callInfo = (0, type_manager_1.createFunctionDef)(def.params.map(p => p.typeAnnotation), finalRetTy, def, undefined);
|
|
1150
|
-
env.resolvedCallInfo.set(nd, callInfo);
|
|
1151
|
-
}
|
|
1152
|
-
return finalRetTy;
|
|
1153
|
-
}
|
|
1154
|
-
exports.tpCallInterface = tpCallInterface;
|
|
1155
|
-
exports.tpCallAuthInterface = tpCallInterface;
|
|
1156
|
-
exports.tpCallMicroserviceInterface = tpCallInterface;
|
|
1157
|
-
exports.tpCallConnector = tpCallLogic;
|
|
1158
|
-
function tpAnonymousFunction(env, nd, tgtTy, isListSort = false) {
|
|
689
|
+
const tpAnonymousFunction = (env, nd, tgtTy, isListSort = false) => {
|
|
1159
690
|
if (!tgtTy || !(0, type_predicate_2.isFuncTy)(tgtTy)) {
|
|
1160
691
|
env.setType(nd, type_manager_1.naslAnyTy);
|
|
1161
692
|
env.addError((0, sem_diag_1.mkIncompatibleTyErr)(env, '函数', tgtTy || type_manager_1.naslAnyTy));
|
|
@@ -1164,8 +695,9 @@ function tpAnonymousFunction(env, nd, tgtTy, isListSort = false) {
|
|
|
1164
695
|
(0, assertion_1.assertTrusy)(tgtTy);
|
|
1165
696
|
const paramsArr = [];
|
|
1166
697
|
// TODO: 通过 default value 生成 constraints
|
|
698
|
+
env.refMgr.setLocalSymBindings(nd, nd.params);
|
|
1167
699
|
nd.params.forEach((param, idx) => {
|
|
1168
|
-
|
|
700
|
+
env.addLexicalSym(param); // param name to mem addr
|
|
1169
701
|
paramsArr.push(param);
|
|
1170
702
|
const ctxParTy = tgtTy.typeArguments[idx];
|
|
1171
703
|
ctxParTy && env.setType(param, ctxParTy);
|
|
@@ -1173,16 +705,18 @@ function tpAnonymousFunction(env, nd, tgtTy, isListSort = false) {
|
|
|
1173
705
|
dispatchExpr(env, nd.body, isListSort ? undefined : tgtTy?.returnType?.[0]);
|
|
1174
706
|
env.setType(nd, (0, type_manager_1.createFnTyFromTyAnns)(// @ts-expect-error
|
|
1175
707
|
nd.params.map(env.getRawType), env.getRawType(nd.body) ?? type_manager_1.naslAnyTy));
|
|
1176
|
-
paramsArr.forEach(p => env.
|
|
708
|
+
paramsArr.forEach(p => env.removeLexicalSym(p));
|
|
1177
709
|
const ndTy = env.getRawType(nd);
|
|
1178
710
|
!isListSort && env.unifier.unify(ndTy, tgtTy);
|
|
1179
711
|
return ndTy;
|
|
1180
|
-
}
|
|
1181
|
-
|
|
712
|
+
};
|
|
713
|
+
exports.tpAnonymousFunction = tpAnonymousFunction;
|
|
714
|
+
const tpSubLogic = (env, nd, tgtTy, isListSort = false) => {
|
|
1182
715
|
// 若非前端,则 shallow copy,因为内部会触发 solve,会把进来前的约束清掉;
|
|
1183
716
|
// 若是前端,则无需 copy
|
|
1184
717
|
const csCopy = env.isView ? env.unifier.cs : new Map(env.unifier.cs);
|
|
1185
718
|
const subLogicVars = [...nd.params, ...nd.returns, ...nd.variables];
|
|
719
|
+
env.refMgr.setLocalSymBindings(nd, subLogicVars);
|
|
1186
720
|
subLogicVars.forEach(v => (0, dispatch_def_1.dispatchDef)(env, v));
|
|
1187
721
|
// 处理 tgtTy 缺失的情况
|
|
1188
722
|
if (tgtTy && !(0, type_predicate_2.isFuncTy)(tgtTy) && !isListSort) {
|
|
@@ -1199,13 +733,14 @@ function tpSubLogic(env, nd, tgtTy, isListSort = false) {
|
|
|
1199
733
|
}
|
|
1200
734
|
(0, dispatch_stmt_2.tpSolvingStmts)(env, nd.body);
|
|
1201
735
|
(0, dispatch_stmt_1.tpSolvingPlayground)(env, nd.playground);
|
|
1202
|
-
subLogicVars.forEach(env.
|
|
736
|
+
subLogicVars.forEach(env.removeLexicalSym);
|
|
1203
737
|
const ndTy = (0, type_manager_1.createRefTyAnnFromDef)(nd, env);
|
|
1204
738
|
env.setType(nd, ndTy);
|
|
1205
739
|
env.unifier.cs = csCopy;
|
|
1206
740
|
!isListSort && env.unifier.unify(ndTy, tgtTy); // 这里需要额外的 unify,否则 SubLogic 算出来的类型不能与外侧进来时的约束产生关系
|
|
1207
741
|
return ndTy;
|
|
1208
|
-
}
|
|
742
|
+
};
|
|
743
|
+
exports.tpSubLogic = tpSubLogic;
|
|
1209
744
|
function tpArgument(env, nd, tgtTy) {
|
|
1210
745
|
// TODO CallConnector 硬塞了一个特殊的 Argument Content_Type,这个 Argument 没有 expression
|
|
1211
746
|
if (nd.expression) {
|
|
@@ -1221,13 +756,14 @@ function tpArgument(env, nd, tgtTy) {
|
|
|
1221
756
|
}
|
|
1222
757
|
// 一个实体逻辑,浪费一整天,LJ。
|
|
1223
758
|
function tpFunction(env, nd, tgtTy) {
|
|
759
|
+
env.refMgr.setLocalSymBindings(nd, nd.params);
|
|
1224
760
|
// 历史兼容,似乎只有 实体逻辑的 filter 是这个东西
|
|
1225
761
|
if (!(0, type_predicate_2.isFuncTy)(tgtTy)) {
|
|
1226
762
|
throw new Error('In Function__.ts, Function Typing 传入的参数不是函数类型');
|
|
1227
763
|
}
|
|
1228
764
|
const paramsArr = [];
|
|
1229
765
|
nd.params.forEach((param, idx) => {
|
|
1230
|
-
|
|
766
|
+
env.addLexicalSym(param); // param name to mem addr
|
|
1231
767
|
paramsArr.push(param);
|
|
1232
768
|
if (tgtTy) {
|
|
1233
769
|
const ctxParTy = tgtTy.typeArguments?.[idx];
|
|
@@ -1239,7 +775,7 @@ function tpFunction(env, nd, tgtTy) {
|
|
|
1239
775
|
env.setType(nd.returns[0], retTy);
|
|
1240
776
|
// FIXME: 强行一致,现在标的不是函数类型,标的是函数的返回类型
|
|
1241
777
|
env.setType(nd, retTy);
|
|
1242
|
-
paramsArr.forEach(p => env.
|
|
778
|
+
paramsArr.forEach(p => env.removeLexicalSym(p));
|
|
1243
779
|
return env.getRawType(nd);
|
|
1244
780
|
}
|
|
1245
781
|
function tpCallQueryComponent(env, nd, tgtTy) {
|
|
@@ -1292,8 +828,8 @@ function tpCallQueryComponent(env, nd, tgtTy) {
|
|
|
1292
828
|
env.ctxTpQFE = undefined;
|
|
1293
829
|
env.ctxCQC = undefined;
|
|
1294
830
|
createdVars.forEach(v => {
|
|
1295
|
-
const varNode =
|
|
1296
|
-
|
|
831
|
+
const varNode = env.getLexicalSym(v);
|
|
832
|
+
env.removeLexicalVarByName(v);
|
|
1297
833
|
env.typeBindings.delete(varNode);
|
|
1298
834
|
});
|
|
1299
835
|
return env.getRawType(nd);
|
|
@@ -1525,14 +1061,14 @@ function tpCallQueryComponent(env, nd, tgtTy) {
|
|
|
1525
1061
|
aggrAsNames.forEach((ty, name) => {
|
|
1526
1062
|
// 反正现在是这样的
|
|
1527
1063
|
const v = nasl_concepts_1.Variable.createProtoTypeOnly({ name: `inner.${name}` });
|
|
1528
|
-
|
|
1064
|
+
env.addLexicalSym(v);
|
|
1529
1065
|
env.setType(v, ty);
|
|
1530
1066
|
variables.push(v.name);
|
|
1531
1067
|
});
|
|
1532
1068
|
groupByAsNames.forEach((ty, name) => {
|
|
1533
1069
|
// 反正现在是这样的
|
|
1534
1070
|
const v = nasl_concepts_1.Variable.createProtoTypeOnly({ name: `inner.${name}` });
|
|
1535
|
-
|
|
1071
|
+
env.addLexicalSym(v);
|
|
1536
1072
|
env.setType(v, ty);
|
|
1537
1073
|
variables.push(v.name);
|
|
1538
1074
|
});
|
|
@@ -1572,8 +1108,8 @@ function tpNewComposite(env, nd, tgtTy) {
|
|
|
1572
1108
|
// 参考:【rg3】+ saas + 批量赋值时,将同一变量(三层变量)同时赋值给两个不同的变量有报错,、New 等自动连线功能失效
|
|
1573
1109
|
// http://projectmanage.netease-official.lcap.163yun.com/dashboard/BugDetail?id=3148436628556032
|
|
1574
1110
|
nd.rights.forEach(selMem => {
|
|
1575
|
-
dispatchExpr(env, toRaw(selMem.expression), undefined);
|
|
1576
|
-
selMem.members.forEach(mem => dispatchExpr(env, toRaw(mem), undefined));
|
|
1111
|
+
dispatchExpr(env, (0, dispatch_stmt_1.toRaw)(selMem.expression), undefined);
|
|
1112
|
+
selMem.members.forEach(mem => dispatchExpr(env, (0, dispatch_stmt_1.toRaw)(mem), undefined));
|
|
1577
1113
|
});
|
|
1578
1114
|
const lNameTyPair = (0, exports.extractNameTyPair)(env, nd.typeAnnotation);
|
|
1579
1115
|
if (!lNameTyPair) {
|
|
@@ -1603,11 +1139,12 @@ function tpNewComposite(env, nd, tgtTy) {
|
|
|
1603
1139
|
}
|
|
1604
1140
|
env.unifier.unifyWithBoundary(rTy, lPropTyAnn, right);
|
|
1605
1141
|
});
|
|
1142
|
+
const properties = toRaws(nd.properties);
|
|
1606
1143
|
// 没连线的左边的元素们。其实无所谓,但要跟现在保持一致。
|
|
1607
|
-
|
|
1144
|
+
properties.forEach((pIdent) => {
|
|
1608
1145
|
if (!env.typeBindings.get(pIdent)) {
|
|
1609
1146
|
let lPropTyAnn = lNameTyPair.find(([name, _]) => name === pIdent.name)?.[1];
|
|
1610
|
-
// setType 应该够了,直接 dispatchExpr 会因为 pIdent 没有加到 env.
|
|
1147
|
+
// setType 应该够了,直接 dispatchExpr 会因为 pIdent 没有加到 env.lexicalVarStacks 里,导致找不到而报错
|
|
1611
1148
|
if (!lPropTyAnn) {
|
|
1612
1149
|
if (nd.typeAnnotation?.typeKind === 'anonymousStructure') {
|
|
1613
1150
|
lPropTyAnn = type_manager_1.naslStringTy;
|
|
@@ -1624,7 +1161,7 @@ function tpNewComposite(env, nd, tgtTy) {
|
|
|
1624
1161
|
const propNames = new Array();
|
|
1625
1162
|
const propTys = new Array();
|
|
1626
1163
|
// ty.properties 与 nd.properties 顺序不一样,有一个被排序过,神坑!!!
|
|
1627
|
-
|
|
1164
|
+
properties.forEach((pIdent) => {
|
|
1628
1165
|
propNames.push(pIdent.name);
|
|
1629
1166
|
propTys.push(env.getRawType(pIdent) ?? env.unifier.nextFreshTyAnn('free'));
|
|
1630
1167
|
});
|
|
@@ -1758,35 +1295,43 @@ function tpMatch(env, nd, tgtTy) {
|
|
|
1758
1295
|
const exprTy = nd.isExpression ?
|
|
1759
1296
|
dispatchExpr(env, nd.expression, undefined) :
|
|
1760
1297
|
tpSolvingExpr(env, nd.expression, undefined);
|
|
1761
|
-
const tpMatchTypeRefineCase = (nd,
|
|
1762
|
-
let exprRefinedTy = exprTy
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1298
|
+
const tpMatchTypeRefineCase = (nd, exprTy) => (mc) => {
|
|
1299
|
+
let exprRefinedTy = exprTy;
|
|
1300
|
+
// mc.patterns 中可能包含类型模式和值模式,分别对应类型匹配和值匹配。
|
|
1301
|
+
// 产品上要求:当被Match的表达式为Union类型时,只能使用类型匹配;否则只能使用值模式匹配。mc.patterns 中值模式和类型模式不会同时出现。
|
|
1302
|
+
// 因此: mc.pattern 中一旦出现非类型的项,就可以判定为这是值模式匹配。值模式匹配时,无需对匹配项的类型做精化。
|
|
1303
|
+
if (mc.patterns.length > 0 && mc.patterns.every((x) => (0, type_predicate_1.isTypeAnnotation)(x))) {
|
|
1304
|
+
// 模式非空且类型模式匹配
|
|
1305
|
+
exprRefinedTy = (0, type_manager_1.createUnionTyAnnIfNecessary)(env, mc.patterns.map(getPatTy).filter(types_1.isNotNil));
|
|
1306
|
+
env.addPostCheckTask(mc, (env, pSubst) => {
|
|
1307
|
+
const resolvedSub = pSubst(exprRefinedTy);
|
|
1308
|
+
const resolvedSup = pSubst(exprTy);
|
|
1309
|
+
if (!(0, type_predicate_1.isSubTy)(env, resolvedSub, resolvedSup)) {
|
|
1310
|
+
env.addError((0, sem_diag_1.mkIncompatibleTyErr)(env, resolvedSub, resolvedSup), undefined, mc);
|
|
1311
|
+
}
|
|
1312
|
+
});
|
|
1313
|
+
}
|
|
1314
|
+
else {
|
|
1315
|
+
// 类型模式匹配('其他' 分支或 空模式的分支) 或者 值模式匹配的分支
|
|
1769
1316
|
// 对其他所有 case 的所有类型取关于全集 exprTy 的补集
|
|
1770
1317
|
const prevCases = nd.cases.filter((c) => c !== mc); // mem addr compare
|
|
1771
|
-
const prevPatterns = prevCases.flatMap(pc => pc.patterns);
|
|
1318
|
+
const prevPatterns = prevCases.flatMap((pc) => pc.patterns);
|
|
1772
1319
|
const pureTys = prevPatterns.filter((x) => (0, type_predicate_1.isTypeAnnotation)(x));
|
|
1773
|
-
//
|
|
1320
|
+
// 确保我们在处理纯类型的匹配。值匹配不用任何精化。
|
|
1774
1321
|
if (pureTys.length === prevPatterns.length) {
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
})) : [];
|
|
1322
|
+
const caseRefinedTys = (0, type_predicate_1.isUnionTy)(exprTy)
|
|
1323
|
+
? exprTy?.typeArguments?.filter((t1) => !pureTys.find((t2) => (0, type_predicate_1.isEqualTy)(env, t1, t2)))
|
|
1324
|
+
: [];
|
|
1779
1325
|
if (caseRefinedTys?.length) {
|
|
1780
|
-
// TODO 报错
|
|
1781
|
-
exprRefinedTy = (0, type_manager_1.createUnionTyAnnIfNecessary)(env, caseRefinedTys);
|
|
1326
|
+
exprRefinedTy = (0, type_manager_1.createUnionTyAnnIfNecessary)(env, caseRefinedTys); // TODO 报错
|
|
1782
1327
|
}
|
|
1783
1328
|
}
|
|
1784
1329
|
}
|
|
1785
1330
|
const allocatedVars = new Set();
|
|
1786
1331
|
const itVar = nasl_concepts_1.Variable.createProtoTypeOnly({ name: 'it', typeAnnotation: exprRefinedTy }); // 新加的每个分支里的 'it' 变量
|
|
1787
1332
|
allocatedVars.add(itVar);
|
|
1788
|
-
const isRefined = shouldRefine(nd.expression);
|
|
1789
1333
|
let matchedVarName = undefined;
|
|
1334
|
+
const isRefined = shouldRefineType(nd.expression, exprTy);
|
|
1790
1335
|
if (isRefined) {
|
|
1791
1336
|
matchedVarName = (0, get_q_name_1.getTokenQualifiedNameForMatchedExpr)(env, nd.expression);
|
|
1792
1337
|
const freshMatchedVar = nasl_concepts_1.Variable.createProtoTypeOnly({
|
|
@@ -1809,33 +1354,27 @@ function tpMatch(env, nd, tgtTy) {
|
|
|
1809
1354
|
// setType(mc, env.getRawType(getListLast(mc.body))) // Not really useful but to keep the same as the current behaviour
|
|
1810
1355
|
allocatedVars.forEach(v => {
|
|
1811
1356
|
// recover un-refined type. Note that `delete` is not proper here.Should use removeLastOne
|
|
1812
|
-
|
|
1357
|
+
env.removeLexicalVarByName(v.name);
|
|
1813
1358
|
env.typeBindings.delete(v);
|
|
1814
1359
|
});
|
|
1815
1360
|
if (isRefined) {
|
|
1816
1361
|
env.matchedVars.delete(matchedVarName);
|
|
1817
1362
|
}
|
|
1818
1363
|
};
|
|
1819
|
-
function handleMatchingAgainstTypes(unionTy) {
|
|
1820
|
-
const tpMcTyRefineCase = tpMatchTypeRefineCase(nd, tgtTy, unionTy);
|
|
1821
|
-
nd.cases.forEach(tpMcTyRefineCase);
|
|
1822
|
-
}
|
|
1823
|
-
function inferTy(x) {
|
|
1824
|
-
if ((0, type_predicate_1.isTypeAnnotation)(x)) {
|
|
1825
|
-
return x;
|
|
1826
|
-
}
|
|
1827
|
-
return dispatchExpr(env, x, undefined);
|
|
1828
|
-
}
|
|
1829
|
-
function inferUnionTyFromMatchCases(mcs) {
|
|
1830
|
-
// 从已有的 match cases 的类型构造出 union-like type
|
|
1831
|
-
const patTys = mcs.flatMap(c => c.patterns).map(inferTy).filter(types_1.isNotNil);
|
|
1832
|
-
patTys.push(exprTy);
|
|
1833
|
-
return (0, type_manager_1.createUnionTyAnnIfNecessary)(env, patTys);
|
|
1834
|
-
}
|
|
1835
1364
|
if (exprTy) {
|
|
1365
|
+
for (const cs of nd.cases) {
|
|
1366
|
+
for (const p of cs.patterns) {
|
|
1367
|
+
dispatchExpr(env, p, undefined);
|
|
1368
|
+
}
|
|
1369
|
+
}
|
|
1836
1370
|
if ((0, type_predicate_2.isTyAnnTyParam)(exprTy)) {
|
|
1837
|
-
|
|
1838
|
-
|
|
1371
|
+
// 从已有的 match cases 的类型构造出 union-like type
|
|
1372
|
+
const patTys = nd.cases.flatMap(c => c.patterns).map(getPatTy).filter(types_1.isNotNil);
|
|
1373
|
+
for (const pTy of patTys) {
|
|
1374
|
+
env.unifier.unify(pTy, exprTy); // 各个分支的类型的 union <: 类型变元
|
|
1375
|
+
}
|
|
1376
|
+
const unionTy = (0, type_manager_1.createUnionTyAnnIfNecessary)(env, patTys);
|
|
1377
|
+
handleMatchingAgainstTypes(unionTy);
|
|
1839
1378
|
}
|
|
1840
1379
|
else {
|
|
1841
1380
|
handleMatchingAgainstTypes(exprTy);
|
|
@@ -1854,8 +1393,22 @@ function tpMatch(env, nd, tgtTy) {
|
|
|
1854
1393
|
env.setType(nd, type_manager_1.naslVoidTy);
|
|
1855
1394
|
}
|
|
1856
1395
|
return env.getRawType(nd);
|
|
1857
|
-
function
|
|
1858
|
-
|
|
1396
|
+
function handleMatchingAgainstTypes(unionTy) {
|
|
1397
|
+
nd.cases.forEach(tpMatchTypeRefineCase(nd, unionTy));
|
|
1398
|
+
}
|
|
1399
|
+
function getPatTy(x) {
|
|
1400
|
+
if ((0, type_predicate_1.isTypeAnnotation)(x)) {
|
|
1401
|
+
return x;
|
|
1402
|
+
}
|
|
1403
|
+
return env.getRawType(x);
|
|
1404
|
+
// 这不仅引人深思:为什么 1 的类型就不能随着上下文变化呢,而要 argument: Decimal argument.expr : Long
|
|
1405
|
+
// 那好了,match 这里其实是又要特殊处理的
|
|
1406
|
+
}
|
|
1407
|
+
function shouldRefineType(nd, exprRefinedTy) {
|
|
1408
|
+
const validExpr = nd.concept === 'Identifier' || nd.concept === 'MemberExpression';
|
|
1409
|
+
// 仅当输入是 union 类型或可以实例化为 union 类型的类型变元才进行 type refinement
|
|
1410
|
+
const validTy = (0, type_predicate_1.isUnionTy)(exprRefinedTy) || (0, type_predicate_2.isTyAnnTyParam)(exprRefinedTy);
|
|
1411
|
+
return validExpr && validTy;
|
|
1859
1412
|
}
|
|
1860
1413
|
}
|
|
1861
1414
|
exports.tpMatch = tpMatch;
|
|
@@ -1865,167 +1418,10 @@ function tpUnparsed(env, nd, tgtTy) {
|
|
|
1865
1418
|
env.setType(nd, type_manager_1.naslNullTy);
|
|
1866
1419
|
return type_manager_1.naslNullTy;
|
|
1867
1420
|
}
|
|
1868
|
-
// 看不懂?一看 NASL 便知
|
|
1869
|
-
function tpEntityLogic(env, nd, tgtTy) {
|
|
1870
|
-
const def = env.resolveRef(nd);
|
|
1871
|
-
if (!def) {
|
|
1872
|
-
env.setType(nd, type_manager_1.naslAnyTy);
|
|
1873
|
-
return type_manager_1.naslAnyTy;
|
|
1874
|
-
}
|
|
1875
|
-
// 例如 app.dataSources.${dbName}.entities.${entityName}
|
|
1876
|
-
// 从 'a.b.c.logics.e' 中提取 'a.b.c'
|
|
1877
|
-
const getEntityQName = (ctxCallLogic) => {
|
|
1878
|
-
const qualifiedNames = (0, get_q_name_1.getTokenQualifiedName)(ctxCallLogic);
|
|
1879
|
-
const parts = qualifiedNames.split('.');
|
|
1880
|
-
return parts.slice(0, parts.length - 2).join('.');
|
|
1881
|
-
};
|
|
1882
|
-
const calleeName = nd.calleeName;
|
|
1883
|
-
const entityDef = env.refMgr.gQNameDefs.get(getEntityQName(nd));
|
|
1884
|
-
const entityPrimaryKeys = entityDef?.properties.filter(p => p.primaryKey) ?? [];
|
|
1885
|
-
const entityRefTy = entityDef ? (0, type_manager_1.createRefTyAnnFromDef)(entityDef, env) ?? type_manager_1.naslAnyTy : type_manager_1.naslAnyTy;
|
|
1886
|
-
const entityOrErrTy = entityRefTy ? (0, type_manager_1.createUnionTyAnn)([entityRefTy, type_manager_1.naslDatabaseDuplicateKeyError]) : undefined;
|
|
1887
|
-
const listEntityRefTy = (0, type_manager_1.createListTyAnn)(entityRefTy);
|
|
1888
|
-
// pre-determined type of arguments[0]
|
|
1889
|
-
const getArg0TgtTy = () => {
|
|
1890
|
-
const fstPrimaryKeyTy = entityDef?.properties.find(p => p.primaryKey)?.typeAnnotation;
|
|
1891
|
-
switch (calleeName) {
|
|
1892
|
-
case 'get': return fstPrimaryKeyTy; // 主键类型
|
|
1893
|
-
case 'create': return entityRefTy;
|
|
1894
|
-
case 'delete': return fstPrimaryKeyTy; // 主键类型
|
|
1895
|
-
case 'update': return entityRefTy;
|
|
1896
|
-
case 'createOrUpdate': return entityRefTy;
|
|
1897
|
-
case 'updateBy': return (0, type_manager_1.createFnTyFromTyAnns)([entityRefTy ?? type_manager_1.naslAnyTy], type_manager_1.naslBooleanTy);
|
|
1898
|
-
case 'deleteBy': return (0, type_manager_1.createFnTyFromTyAnns)([entityRefTy ?? type_manager_1.naslAnyTy], type_manager_1.naslBooleanTy);
|
|
1899
|
-
case 'batchCreate': return listEntityRefTy;
|
|
1900
|
-
case 'batchUpdate': return listEntityRefTy;
|
|
1901
|
-
case 'batchDelete': return (0, type_manager_1.createListTyAnn)(fstPrimaryKeyTy ?? type_manager_1.naslAnyTy); // 主键类型
|
|
1902
|
-
case 'import': return type_manager_1.naslBinaryTy;
|
|
1903
|
-
}
|
|
1904
|
-
};
|
|
1905
|
-
const paramTys = new Array();
|
|
1906
|
-
const arg0TgtTy = getArg0TgtTy();
|
|
1907
|
-
paramTys.push(arg0TgtTy ?? type_manager_1.naslAnyTy);
|
|
1908
|
-
env.ctxTpEntityTy = entityRefTy;
|
|
1909
|
-
nd.arguments[0] && dispatchExpr(env, nd.arguments[0], arg0TgtTy);
|
|
1910
|
-
if (calleeName === 'updateBy' || calleeName === 'deleteBy') {
|
|
1911
|
-
const arg1TgtTy = entityRefTy;
|
|
1912
|
-
if (nd.arguments[1]) {
|
|
1913
|
-
const arg1Ty = dispatchExpr(env, nd.arguments[1], arg1TgtTy);
|
|
1914
|
-
paramTys.push(arg1Ty ?? arg1TgtTy ?? type_manager_1.naslAnyTy);
|
|
1915
|
-
}
|
|
1916
|
-
// 这里不能直接 dispatchExpr(callee.arguments[2]),因为里面藏了个非标准的 NewList,元素因为没有公共父类型而会报错,下同
|
|
1917
|
-
const fnDef = nd.arguments[2]?.expression;
|
|
1918
|
-
// NASL 实在是太 🐂🍺 拉,到处都是 NewList,人间处处皆学问!
|
|
1919
|
-
const fnBody = fnDef?.body;
|
|
1920
|
-
if (fnBody?.items) {
|
|
1921
|
-
const paramItem = fnDef?.params?.[0];
|
|
1922
|
-
checkItemMemExprTy(paramItem, fnBody?.items);
|
|
1923
|
-
// FIXME: 只能说是强行保持一致
|
|
1924
|
-
env.setType(nd.arguments[2], type_manager_1.naslStringTy);
|
|
1925
|
-
paramTys.push(type_manager_1.naslStringTy);
|
|
1926
|
-
const itemTys = fnBody?.items?.map(item => env.getRawType(item) ?? type_manager_1.naslAnyTy);
|
|
1927
|
-
const bodyListUnionTy = (0, type_manager_1.createListTyAnn)((0, type_manager_1.createUnionTyAnnIfNecessary)(env, itemTys));
|
|
1928
|
-
env.setType(fnBody, bodyListUnionTy);
|
|
1929
|
-
}
|
|
1930
|
-
}
|
|
1931
|
-
else if (calleeName === 'update' || calleeName === 'batchUpdate') {
|
|
1932
|
-
const fnDef = nd.arguments[1]?.expression;
|
|
1933
|
-
const fnBody = fnDef?.body;
|
|
1934
|
-
if (fnBody?.items) {
|
|
1935
|
-
const paramItem = fnDef?.params?.[0];
|
|
1936
|
-
checkItemMemExprTy(paramItem, fnBody?.items);
|
|
1937
|
-
// FIXME: 只能说是强行保持一致
|
|
1938
|
-
env.setType(nd.arguments[1], type_manager_1.naslStringTy);
|
|
1939
|
-
paramTys.push(type_manager_1.naslStringTy);
|
|
1940
|
-
const itemTys = fnBody?.items?.map(item => env.getRawType(item) ?? type_manager_1.naslAnyTy);
|
|
1941
|
-
const bodyListUnionTy = (0, type_manager_1.createListTyAnn)((0, type_manager_1.createUnionTyAnnIfNecessary)(env, itemTys));
|
|
1942
|
-
env.setType(fnBody, bodyListUnionTy);
|
|
1943
|
-
}
|
|
1944
|
-
}
|
|
1945
|
-
else if ((calleeName === 'get' || calleeName === 'delete') && entityPrimaryKeys.length > 1) {
|
|
1946
|
-
// 处理多主键
|
|
1947
|
-
for (let i = 1; i < entityPrimaryKeys.length; i++) {
|
|
1948
|
-
const argTgtTy = entityPrimaryKeys[i].typeAnnotation;
|
|
1949
|
-
if (nd.arguments[i]) {
|
|
1950
|
-
dispatchExpr(env, nd.arguments[i], argTgtTy);
|
|
1951
|
-
paramTys.push(argTgtTy ?? type_manager_1.naslAnyTy);
|
|
1952
|
-
}
|
|
1953
|
-
}
|
|
1954
|
-
}
|
|
1955
|
-
env.ctxTpEntityTy = undefined;
|
|
1956
|
-
const retTy = getRetTy();
|
|
1957
|
-
const finalRetTy = nd.handleError === true
|
|
1958
|
-
? retTy
|
|
1959
|
-
// 做了手动处理 Error 需求后,需要 remove Error types from return types
|
|
1960
|
-
: (0, exports.removeErrTys)(env, nd, retTy);
|
|
1961
|
-
nd.handleError === true && dispatchExpr(env, nd.errorMessage, undefined);
|
|
1962
|
-
env.setType(nd, finalRetTy);
|
|
1963
|
-
env.unifier.unify(finalRetTy, tgtTy);
|
|
1964
|
-
// Create a mock definition for entity logics
|
|
1965
|
-
const mockDef = { params: paramTys.map(() => ({ optional: false })) };
|
|
1966
|
-
const callInfo = (0, type_manager_1.createFunctionDef)(paramTys, finalRetTy, mockDef, undefined);
|
|
1967
|
-
env.resolvedCallInfo.set(nd, callInfo);
|
|
1968
|
-
return finalRetTy;
|
|
1969
|
-
function getRetTy() {
|
|
1970
|
-
switch (calleeName) {
|
|
1971
|
-
case 'get': return entityRefTy;
|
|
1972
|
-
case 'create': return entityOrErrTy; // 带个 Error 类型
|
|
1973
|
-
case 'delete': return type_manager_1.naslLongTy; // 现在如此
|
|
1974
|
-
case 'update': return entityRefTy;
|
|
1975
|
-
case 'createOrUpdate': return entityOrErrTy; // 带个 Error 类型
|
|
1976
|
-
case 'updateBy': return type_manager_1.naslLongTy;
|
|
1977
|
-
case 'deleteBy': return type_manager_1.naslLongTy;
|
|
1978
|
-
case 'batchCreate': return listEntityRefTy;
|
|
1979
|
-
case 'batchUpdate': return listEntityRefTy;
|
|
1980
|
-
case 'batchDelete': return type_manager_1.naslLongTy;
|
|
1981
|
-
case 'import': return type_manager_1.naslStringTy;
|
|
1982
|
-
}
|
|
1983
|
-
}
|
|
1984
|
-
function checkItemMemExprTy(paramItem, itemMemExprs) {
|
|
1985
|
-
// createOnPush(env.nameBindings, 'item', paramItem);
|
|
1986
|
-
// FIXME
|
|
1987
|
-
(0, dispatch_def_1.dispatchDef)(env, paramItem);
|
|
1988
|
-
itemMemExprs.forEach(expr => dispatchExpr(env, expr, undefined));
|
|
1989
|
-
env.removeVar(paramItem);
|
|
1990
|
-
}
|
|
1991
|
-
}
|
|
1992
|
-
exports.tpEntityLogic = tpEntityLogic;
|
|
1993
1421
|
function tpAnchor(env, nd, tgtTy) {
|
|
1994
1422
|
return dispatchExpr(env, nd.expression, tgtTy);
|
|
1995
1423
|
}
|
|
1996
|
-
|
|
1997
|
-
// 尝试创建一个函数类型placeholderFnTy,并和qName关联起来。
|
|
1998
|
-
// 1. 之后遇到callee定义的时候再进行检查
|
|
1999
|
-
// 2. 如果在一个批次检查后这个callee仍然没有定义,那么报错
|
|
2000
|
-
/**
|
|
2001
|
-
* 创建前向引用占位符(简单的函数类型)
|
|
2002
|
-
*/
|
|
2003
|
-
function createAndSetForwardReferencePlaceholder(env, nd) {
|
|
2004
|
-
// 为每个参数创建一个新的类型变量
|
|
2005
|
-
const paramTypes = nd.arguments.map(() => env.unifier.nextFreshTyAnn('free'));
|
|
2006
|
-
// 为返回值创建一个新的类型变量
|
|
2007
|
-
const returnType = env.unifier.nextFreshTyAnn('free');
|
|
2008
|
-
const placeholderFnTy = (0, type_manager_1.createFnTyFromTyAnns)(paramTypes, returnType);
|
|
2009
|
-
return placeholderFnTy;
|
|
2010
|
-
}
|
|
2011
|
-
// @ts-expect-error
|
|
2012
|
-
const toRaw = (nd) => nd?.__v_raw ?? nd;
|
|
2013
|
-
const toRaws = (nds) => nds.map(toRaw);
|
|
2014
|
-
/**
|
|
2015
|
-
* 处理函数返回类型,过滤错误类型并设置节点类型
|
|
2016
|
-
*/
|
|
2017
|
-
const removeErrTys = (env, nd, retTy) => {
|
|
2018
|
-
let finalRetTy = retTy;
|
|
2019
|
-
if (finalRetTy && finalRetTy.typeKind === 'union') {
|
|
2020
|
-
finalRetTy = (0, fp_macros_1.IfBind)(finalRetTy.typeArguments?.filter(ty => !((0, type_predicate_2.isErrorTy)(ty))))(filteredRetTys => (0, type_manager_1.createUnionTyAnnIfNecessary)(env, filteredRetTys))((0, fp_macros_1.feed)(finalRetTy));
|
|
2021
|
-
}
|
|
2022
|
-
// @ts-ignore
|
|
2023
|
-
if ((0, type_predicate_1.isUnionTy)(finalRetTy) && !finalRetTy.typeArguments?.length) {
|
|
2024
|
-
return type_manager_1.naslVoidTy; // createUnionTyAnnIfNecessary 得到 Union<> 时表示无返回类型
|
|
2025
|
-
}
|
|
2026
|
-
return finalRetTy;
|
|
2027
|
-
};
|
|
2028
|
-
exports.removeErrTys = removeErrTys;
|
|
1424
|
+
const toRaws = (nds) => nds.map(dispatch_stmt_1.toRaw);
|
|
2029
1425
|
const tpNewStructure = (env, nd, tgtTy) => {
|
|
2030
1426
|
const ndTy = (0, type_manager_1.createAnonymousTyAnn)(nd.properties.map((p) => p.name), nd.properties.map((p) => {
|
|
2031
1427
|
// p.name可能有两个取值:format和title。其中:
|
|
@@ -2050,10 +1446,10 @@ const tpNewStructure = (env, nd, tgtTy) => {
|
|
|
2050
1446
|
// 一个通用的方法,获取各种连线右侧的逻辑项
|
|
2051
1447
|
const getRightByLine = (nd, itemIdx, memIdx) => {
|
|
2052
1448
|
if (memIdx !== undefined) {
|
|
2053
|
-
return toRaw(nd.rights[itemIdx].members[memIdx]);
|
|
1449
|
+
return (0, dispatch_stmt_1.toRaw)(nd.rights[itemIdx].members[memIdx]);
|
|
2054
1450
|
}
|
|
2055
1451
|
else {
|
|
2056
|
-
return toRaw(nd.rights[itemIdx].expression);
|
|
1452
|
+
return (0, dispatch_stmt_1.toRaw)(nd.rights[itemIdx].expression);
|
|
2057
1453
|
}
|
|
2058
1454
|
};
|
|
2059
1455
|
exports.getRightByLine = getRightByLine;
|