nadesiko3 3.7.21 → 3.7.23
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/README.md +20 -1
- package/batch/command.txt +370 -334
- package/batch/generate_command_list.mjs +102 -0
- package/batch/jsplugin2text.nako3 +1 -1
- package/batch/pickup_command.nako3 +12 -0
- package/batch/search_command.mjs +34 -0
- package/batch/search_command.nako3 +430 -0
- package/core/command/snako.mts +5 -1
- package/core/deno/snako.ts +5 -1
- package/core/package-lock.json +382 -21
- package/core/package.json +7 -4
- package/core/sample/algorithms/README.md +43 -0
- package/core/sample/algorithms/graph/dijkstra.nako3 +47 -0
- package/core/sample/algorithms/graph/kruskal.nako3 +69 -0
- package/core/sample/algorithms/math/euclidean_gcd.nako3 +15 -0
- package/core/sample/algorithms/math/sieve_of_eratosthenes.nako3 +26 -0
- package/core/sample/algorithms/search/binary_search.nako3 +17 -0
- package/core/sample/algorithms/search/breadth_first_search.nako3 +33 -0
- package/core/sample/algorithms/search/depth_first_search.nako3 +25 -0
- package/core/sample/algorithms/sort/heap_sort.nako3 +37 -0
- package/core/sample/algorithms/sort/insertion_sort.nako3 +18 -0
- package/core/sample/algorithms/sort/merge_sort.nako3 +40 -0
- package/core/sample/algorithms/sort/quick_sort.nako3 +36 -0
- package/core/sample/algorithms/string/knuth_morris_pratt.nako3 +50 -0
- package/core/sample/algorithms/string/run_length_encoding.nako3 +25 -0
- package/core/src/nako3.mts +178 -614
- package/core/src/nako_basic_plugins.mts +39 -0
- package/core/src/nako_core_version.mts +2 -2
- package/core/src/nako_csv.mts +0 -1
- package/core/src/nako_event.mts +49 -0
- package/core/src/nako_gen.mts +320 -209
- package/core/src/nako_global.mts +18 -0
- package/core/src/nako_indent_inline.mts +2 -2
- package/core/src/nako_lex_rules.mts +1 -1
- package/core/src/nako_parser3.mts +111 -166
- package/core/src/nako_parser_async.mts +165 -0
- package/core/src/nako_parser_base.mts +4 -55
- package/core/src/nako_parser_message.mts +105 -0
- package/core/src/nako_parser_operator.mts +93 -0
- package/core/src/nako_plugin_manager.mts +260 -0
- package/core/src/nako_require.mts +292 -0
- package/core/src/nako_runner.mts +208 -0
- package/core/src/nako_tokenizer.mts +221 -0
- package/core/src/plugin_csv.mts +1 -1
- package/core/src/plugin_system.mts +34 -3259
- package/core/src/plugin_system_array.mts +699 -0
- package/core/src/plugin_system_datetime.mts +368 -0
- package/core/src/plugin_system_debug.mts +403 -0
- package/core/src/plugin_system_dict.mts +85 -0
- package/core/src/plugin_system_json.mts +73 -0
- package/core/src/plugin_system_math.mts +383 -0
- package/core/src/plugin_system_regexp.mts +120 -0
- package/core/src/plugin_system_stdio.mts +86 -0
- package/core/src/plugin_system_string.mts +666 -0
- package/core/src/plugin_system_timer.mts +152 -0
- package/core/src/plugin_system_types.mts +151 -0
- package/core/src/plugin_system_url.mts +193 -0
- package/core/src/plugin_toml.mts +3 -3
- package/core/test/algorithm_samples_test.mjs +58 -0
- package/core/test/algorithms/graph/dijkstra_test.nako3 +21 -0
- package/core/test/algorithms/graph/kruskal_test.nako3 +21 -0
- package/core/test/algorithms/helper.mjs +13 -0
- package/core/test/algorithms/math/euclidean_gcd_test.nako3 +13 -0
- package/core/test/algorithms/math/sieve_of_eratosthenes_test.nako3 +10 -0
- package/core/test/algorithms/search/binary_search_test.nako3 +15 -0
- package/core/test/algorithms/search/breadth_first_search_test.nako3 +13 -0
- package/core/test/algorithms/search/depth_first_search_test.nako3 +13 -0
- package/core/test/algorithms/sort/heap_sort_test.nako3 +13 -0
- package/core/test/algorithms/sort/insertion_sort_test.nako3 +13 -0
- package/core/test/algorithms/sort/merge_sort_test.nako3 +18 -0
- package/core/test/algorithms/sort/quick_sort_test.nako3 +34 -0
- package/core/test/algorithms/string/knuth_morris_pratt_test.nako3 +16 -0
- package/core/test/algorithms/string/run_length_encoding_test.nako3 +13 -0
- package/core/test/array_test.mjs +3 -0
- package/core/test/fixtures/README.md +39 -0
- package/core/test/fixtures/make_parser_ast_golden.mjs +31 -0
- package/core/test/fixtures/parser_ast_golden.json +8027 -0
- package/core/test/fixtures/parser_corpus.mjs +120 -0
- package/core/test/func_call.mjs +18 -0
- package/core/test/func_test.mjs +28 -0
- package/core/test/indent_test.mjs +6 -0
- package/core/test/nako_basic_plugins_test.mjs +44 -0
- package/core/test/nako_event_test.mjs +127 -0
- package/core/test/nako_gen_perf_test.mjs +178 -0
- package/core/test/nako_parser_async_test.mjs +385 -0
- package/core/test/nako_parser_test.mjs +160 -0
- package/core/test/nako_plugin_manager_test.mjs +185 -0
- package/core/test/nako_require_test.mjs +153 -0
- package/core/test/nako_runner_test.mjs +174 -0
- package/core/test/nako_tokenizer_test.mjs +115 -0
- package/core/test/plugin_system_debug_test.mjs +138 -0
- package/core/test/plugin_system_split_test.mjs +179 -0
- package/core/test/plugin_system_test.mjs +6 -0
- package/core/tsconfig.json +0 -1
- package/demo/browsers.html +1 -1
- package/doc/SETUP.md +1 -1
- package/doc/ai-code-generation.md +136 -0
- package/doc/browsers.md +1 -1
- package/doc/command_list.json +16842 -0
- package/doc/search_command.md +222 -0
- package/doc/syntax-nako3.md +344 -0
- package/package.json +29 -26
- package/release/_hash.txt +40 -40
- package/release/_script-tags.txt +16 -16
- package/release/command.json +1 -1
- package/release/command.json.js +1 -1
- package/release/command_cnako3.json +1 -1
- package/release/command_list.json +1 -1
- package/release/edit_main.js +6 -6
- package/release/edit_main.js.map +3 -3
- package/release/editor.js +6 -6
- package/release/plugin_caniuse.js +1 -1
- package/release/plugin_caniuse.js.map +2 -2
- package/release/plugin_keigo.js.map +3 -3
- package/release/plugin_markup.js +46 -46
- package/release/plugin_markup.js.map +3 -3
- package/release/plugin_weykturtle3d.js +1 -1
- package/release/plugin_weykturtle3d.js.map +3 -3
- package/release/version.js +2 -2
- package/release/version_main.js +2 -2
- package/release/version_main.js.map +1 -1
- package/release/wnako3.js +219 -230
- package/release/wnako3.js.map +4 -4
- package/release/wnako3webworker.js +193 -204
- package/release/wnako3webworker.js.map +4 -4
- package/src/browsers.mjs +1 -1
- package/src/browsers.txt +0 -1
- package/src/cnako3mod.mjs +7 -2
- package/src/cnako3mod.mts +7 -2
- package/src/nako_version.mjs +2 -2
- package/src/nako_version.mts +2 -2
- package/src/plugin_browser_ajax.mjs +4 -4
- package/src/plugin_browser_ajax.mts +4 -4
- package/src/plugin_browser_audio.mjs +10 -10
- package/src/plugin_browser_audio.mts +10 -10
- package/src/plugin_browser_camera.mjs +4 -4
- package/src/plugin_browser_camera.mts +4 -4
- package/src/plugin_browser_canvas.mjs +2 -2
- package/src/plugin_browser_canvas.mts +2 -2
- package/src/plugin_browser_crypto.mjs +3 -3
- package/src/plugin_browser_crypto.mts +3 -3
- package/src/plugin_browser_dom_event.mjs +1 -1
- package/src/plugin_browser_dom_event.mts +1 -1
- package/src/plugin_browser_geolocation.mjs +1 -1
- package/src/plugin_browser_geolocation.mts +1 -1
- package/src/plugin_browser_hotkey.mjs +1 -1
- package/src/plugin_browser_hotkey.mts +1 -1
- package/src/plugin_browser_html.mjs +1 -1
- package/src/plugin_browser_html.mts +1 -1
- package/src/plugin_browser_location.mjs +1 -1
- package/src/plugin_browser_location.mts +1 -1
- package/src/plugin_browser_speech.mjs +1 -1
- package/src/plugin_browser_speech.mts +1 -1
- package/src/plugin_browser_storage.mjs +2 -2
- package/src/plugin_browser_storage.mts +2 -2
- package/src/plugin_httpserver.mjs +3 -3
- package/src/plugin_httpserver.mts +3 -3
- package/src/plugin_keigo.mjs +2 -2
- package/src/plugin_keigo.mts +2 -2
- package/src/plugin_node.mjs +48 -48
- package/src/plugin_node.mts +53 -53
- package/src/plugin_weykturtle3d.mjs +56 -56
- package/src/plugin_weykturtle3d.mts +56 -56
- package/src/wnako3.mjs +1 -1
- package/src/wnako3.mts +1 -1
- package/src/wnako3_editor.mjs +5 -5
- package/src/wnako3_editor.mts +5 -5
- package/src/wnako3mod.mjs +2 -2
- package/src/wnako3mod.mts +2 -2
- package/test/nako3edit/index_nako3_test.mjs +282 -0
- package/test/nako3server/index_nako3_test.mjs +239 -0
- package/test/node/ai_code_generation_guide_test.mjs +29 -0
- package/test/node/node_version_support_test.mjs +45 -0
- package/test/node/search_command_test.mjs +174 -0
- package/tools/nako3edit/AGENTS.md +23 -0
- package/tools/nako3edit/index.nako3 +404 -0
- package/tools/nako3server/AGENTS.md +23 -0
- package/tools/nako3server/index.nako3 +156 -23
- package/core/src/nako3.mjs +0 -1021
- package/core/src/nako_ast.mjs +0 -4
- package/core/src/nako_colors.mjs +0 -77
- package/core/src/nako_core_version.mjs +0 -8
- package/core/src/nako_csv.mjs +0 -193
- package/core/src/nako_errors.mjs +0 -166
- package/core/src/nako_from_dncl.mjs +0 -285
- package/core/src/nako_from_dncl2.mjs +0 -347
- package/core/src/nako_gen.mjs +0 -2500
- package/core/src/nako_global.mjs +0 -138
- package/core/src/nako_indent.mjs +0 -442
- package/core/src/nako_indent_chars.mjs +0 -29
- package/core/src/nako_indent_inline.mjs +0 -361
- package/core/src/nako_josi_list.mjs +0 -47
- package/core/src/nako_lex_rules.mjs +0 -319
- package/core/src/nako_lexer.mjs +0 -794
- package/core/src/nako_logger.mjs +0 -221
- package/core/src/nako_parser3.mjs +0 -3250
- package/core/src/nako_parser_base.mjs +0 -403
- package/core/src/nako_parser_const.mjs +0 -37
- package/core/src/nako_prepare.mjs +0 -329
- package/core/src/nako_reserved_words.mjs +0 -42
- package/core/src/nako_source_mapping.mjs +0 -207
- package/core/src/nako_test.mjs +0 -37
- package/core/src/nako_token.mjs +0 -1
- package/core/src/nako_tools.mjs +0 -53
- package/core/src/nako_types.mjs +0 -14
- package/core/src/plugin_api.mjs +0 -4
- package/core/src/plugin_csv.mjs +0 -97
- package/core/src/plugin_math.mjs +0 -352
- package/core/src/plugin_promise.mjs +0 -102
- package/core/src/plugin_system.mjs +0 -3810
- package/core/src/plugin_test.mjs +0 -52
- package/core/src/plugin_toml.mjs +0 -39
package/core/src/nako_gen.mts
CHANGED
|
@@ -37,6 +37,37 @@ interface FunctionContext {
|
|
|
37
37
|
varsIndex: number;
|
|
38
38
|
usesClosure: boolean;
|
|
39
39
|
}
|
|
40
|
+
|
|
41
|
+
/** 生成したコードの各行を n段だけインデントする (空行は捨てる) */
|
|
42
|
+
function indentLines (text: string, n: number): string {
|
|
43
|
+
let result = ''
|
|
44
|
+
for (const line of text.split('\n')) {
|
|
45
|
+
if (line !== '') {
|
|
46
|
+
result += ' '.repeat(n) + line + '\n'
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return result
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* パフォーマンスモニタの計測結果を `__self.__performance_monitor[key]` に記録するコードを生成する。
|
|
54
|
+
* ユーザ関数・システム関数本体・システム関数の3箇所で共通して使う。(#2333)
|
|
55
|
+
* @param timeVar 経過時間(マイクロ秒)が入っているJS変数名
|
|
56
|
+
*/
|
|
57
|
+
function genPerfMonitorUpdate (timeVar: string): string {
|
|
58
|
+
const rec = `{ called:1, totel_usec: ${timeVar}, min_usec: ${timeVar}, max_usec: ${timeVar}, type: type }`
|
|
59
|
+
return 'if (!__self.__performance_monitor) {\n' +
|
|
60
|
+
'__self.__performance_monitor={};\n' +
|
|
61
|
+
`__self.__performance_monitor[key] = ${rec};\n` +
|
|
62
|
+
'} else if (!__self.__performance_monitor[key]) {\n' +
|
|
63
|
+
`__self.__performance_monitor[key] = ${rec};\n` +
|
|
64
|
+
'} else {\n' +
|
|
65
|
+
'__self.__performance_monitor[key].called++;\n' +
|
|
66
|
+
`__self.__performance_monitor[key].totel_usec+=${timeVar};\n` +
|
|
67
|
+
`if(__self.__performance_monitor[key].min_usec>${timeVar}){__self.__performance_monitor[key].min_usec=${timeVar};}\n` +
|
|
68
|
+
`if(__self.__performance_monitor[key].max_usec<${timeVar}){__self.__performance_monitor[key].max_usec=${timeVar};}\n` +
|
|
69
|
+
'}'
|
|
70
|
+
}
|
|
40
71
|
interface FindVarResult {
|
|
41
72
|
i: number;
|
|
42
73
|
name: string;
|
|
@@ -44,6 +75,15 @@ interface FindVarResult {
|
|
|
44
75
|
js: string,
|
|
45
76
|
js_set: string
|
|
46
77
|
}
|
|
78
|
+
/** 関数呼び出しコードを組み立てるための部品 (convCallFunc) */
|
|
79
|
+
interface CallCodeParts {
|
|
80
|
+
funcDef: string; // 'function' または 'async function'
|
|
81
|
+
funcCall: string; // 関数を呼び出す式
|
|
82
|
+
funcBegin: string; // 呼び出しの直前に実行するコード
|
|
83
|
+
funcEnd: string; // 呼び出しの後に必ず実行するコード
|
|
84
|
+
isAsync: boolean; // 非同期関数の呼び出しか
|
|
85
|
+
sysPerfKey: string | null; // システム関数の計測キー。計測しないときはnull
|
|
86
|
+
}
|
|
47
87
|
/** コード生成オプション */
|
|
48
88
|
export class NakoGenOptions {
|
|
49
89
|
isTest: boolean
|
|
@@ -340,6 +380,23 @@ export class NakoGen {
|
|
|
340
380
|
code += 'const __v0 = __self.__v0 = __self.__varslist[0];\n'
|
|
341
381
|
code += 'const __v1 = __self.__v1 = __self.__varslist[1];\n'
|
|
342
382
|
code += 'const __vars = __self.__vars = __self.__varslist[2];\n'
|
|
383
|
+
code += 'const __nako_scope_parents = new WeakMap();\n' +
|
|
384
|
+
'const __nako_active_scopes = new WeakSet();\n' +
|
|
385
|
+
'const __nako_scope_enter = () => {\n' +
|
|
386
|
+
' const local = new Map();\n' +
|
|
387
|
+
' __nako_scope_parents.set(local, __self.__vars);\n' +
|
|
388
|
+
' __nako_active_scopes.add(local);\n' +
|
|
389
|
+
' __self.__vars = local;\n' +
|
|
390
|
+
' return local;\n' +
|
|
391
|
+
'};\n' +
|
|
392
|
+
'const __nako_scope_leave = (local) => {\n' +
|
|
393
|
+
' __nako_active_scopes.delete(local);\n' +
|
|
394
|
+
' let parent = __nako_scope_parents.get(local) || __vars;\n' +
|
|
395
|
+
' while (parent !== __vars && !__nako_active_scopes.has(parent)) {\n' +
|
|
396
|
+
' parent = __nako_scope_parents.get(parent) || __vars;\n' +
|
|
397
|
+
' }\n' +
|
|
398
|
+
' __self.__vars = parent;\n' +
|
|
399
|
+
'};\n'
|
|
343
400
|
code += 'const __nako_make_closure = (local, parent) => ({\n' +
|
|
344
401
|
' has: (key) => local.has(key) || (parent !== null && parent.has(key)),\n' +
|
|
345
402
|
' get: (key) => local.has(key) ? local.get(key) : (parent !== null ? parent.get(key) : undefined),\n' +
|
|
@@ -872,31 +929,9 @@ export class NakoGen {
|
|
|
872
929
|
let performanceMonitorInjectAtStart = ''
|
|
873
930
|
let performanceMonitorInjectAtEnd = ''
|
|
874
931
|
if (this.performanceMonitor.userFunction !== 0) {
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
this.performanceMonitor.mumeiId = 0
|
|
879
|
-
}
|
|
880
|
-
this.performanceMonitor.mumeiId++
|
|
881
|
-
key = `anous_${this.performanceMonitor.mumeiId}`
|
|
882
|
-
}
|
|
883
|
-
performanceMonitorInjectAtStart = 'const performanceMonitorEnd = (function (key, type) {\n' +
|
|
884
|
-
'const uf_start = performance.now() * 1000;\n' +
|
|
885
|
-
'return function () {\n' +
|
|
886
|
-
'const el_time = performance.now() * 1000 - uf_start;\n' +
|
|
887
|
-
'if (!__self.__performance_monitor) {\n' +
|
|
888
|
-
'__self.__performance_monitor={};\n' +
|
|
889
|
-
'__self.__performance_monitor[key] = { called:1, totel_usec: el_time, min_usec: el_time, max_usec: el_time, type: type };\n' +
|
|
890
|
-
'} else if (!__self.__performance_monitor[key]) {\n' +
|
|
891
|
-
'__self.__performance_monitor[key] = { called:1, totel_usec: el_time, min_usec: el_time, max_usec: el_time, type: type };\n' +
|
|
892
|
-
'} else {\n' +
|
|
893
|
-
'__self.__performance_monitor[key].called++;\n' +
|
|
894
|
-
'__self.__performance_monitor[key].totel_usec+=el_time;\n' +
|
|
895
|
-
'if(__self.__performance_monitor[key].min_usec>el_time){__self.__performance_monitor[key].min_usec=el_time;}\n' +
|
|
896
|
-
'if(__self.__performance_monitor[key].max_usec<el_time){__self.__performance_monitor[key].max_usec=el_time;}\n' +
|
|
897
|
-
`}};})('${key}', 'user');` +
|
|
898
|
-
'try {\n'
|
|
899
|
-
performanceMonitorInjectAtEnd = '} finally { performanceMonitorEnd(); }\n'
|
|
932
|
+
const inject = this.genPerfMonitorInject(this.getPerfMonitorKey(name))
|
|
933
|
+
performanceMonitorInjectAtStart = inject[0]
|
|
934
|
+
performanceMonitorInjectAtEnd = inject[1]
|
|
900
935
|
}
|
|
901
936
|
let variableDeclarations = ''
|
|
902
937
|
const indent = ' '
|
|
@@ -923,16 +958,16 @@ export class NakoGen {
|
|
|
923
958
|
}
|
|
924
959
|
|
|
925
960
|
// ローカル変数を生成 (再帰関数呼び出しで引数の値が壊れる問題があるので修正 #1663 / タイミングによって壊れるので修理 #1758)
|
|
926
|
-
//
|
|
961
|
+
// 呼び出しごとのローカル変数を登録し、関数を抜ける時に有効な呼び出し元へ戻す。
|
|
962
|
+
// 非同期関数が開始順と異なる順番で終了しても、終了済みのスコープは復元しない。
|
|
927
963
|
// 関数として宣言しているが、JS関数となでしこ関数では変数管理の方法が異なるため、完全なローカル変数としては使えない
|
|
928
964
|
// 必ず、pushStack/popStack する必要がある
|
|
929
965
|
pushStack += '\n// PUSH STACK\n'
|
|
930
|
-
pushStack += 'const __localvars =
|
|
931
|
-
pushStack += '__self.__vars = new Map();\n'
|
|
966
|
+
pushStack += 'const __localvars = __nako_scope_enter();\n'
|
|
932
967
|
pushStack += 'try {\n'
|
|
933
968
|
popStack += '} finally {\n'
|
|
934
969
|
popStack += indent + '// POP STACK\n'
|
|
935
|
-
popStack += indent + '
|
|
970
|
+
popStack += indent + '__nako_scope_leave(__localvars);\n'
|
|
936
971
|
popStack += '}\n'
|
|
937
972
|
|
|
938
973
|
// 宣言済みの名前を保存
|
|
@@ -1019,7 +1054,9 @@ export class NakoGen {
|
|
|
1019
1054
|
const tof = (this.usedAsyncFn) ? topOfFunctionAsync : topOfFunction
|
|
1020
1055
|
// 関数コード全体を構築
|
|
1021
1056
|
const lineInfo = ' ' + this.convLineno(node, true, 1) + '\n'
|
|
1022
|
-
|
|
1057
|
+
// パフォーマンスモニタのinjectは、PUSH STACKのtry/finallyの内側に入れる。
|
|
1058
|
+
// 外側に置くと __localvars の宣言をまたいでしまい ReferenceError になる (#2333)
|
|
1059
|
+
code = tof + pushStack + performanceMonitorInjectAtStart + variableDeclarations + lineInfo + code + popStack
|
|
1023
1060
|
code += endOfFunction
|
|
1024
1061
|
if (funcContext.isAnonymous && funcContext.usesClosure) {
|
|
1025
1062
|
const parentClosure = `(typeof __nako_closure === 'undefined' ? null : __nako_closure)`
|
|
@@ -1412,8 +1449,8 @@ export class NakoGen {
|
|
|
1412
1449
|
* @param {boolean} isExpression
|
|
1413
1450
|
*/
|
|
1414
1451
|
convPerformanceMonitor(node: AstBlocks, isExpression: boolean): string {
|
|
1415
|
-
const prev = { ...this.performanceMonitor }
|
|
1416
1452
|
if (!node.options) { return '' }
|
|
1453
|
+
const prev = { ...this.performanceMonitor }
|
|
1417
1454
|
if (node.options['ユーザ関数']) {
|
|
1418
1455
|
this.performanceMonitor.userFunction++
|
|
1419
1456
|
}
|
|
@@ -1430,6 +1467,63 @@ export class NakoGen {
|
|
|
1430
1467
|
}
|
|
1431
1468
|
}
|
|
1432
1469
|
|
|
1470
|
+
/**
|
|
1471
|
+
* パフォーマンスモニタの計測キーを決める。名前が無ければ無名関数用のIDを採番する。(#2333)
|
|
1472
|
+
* @param name 関数名
|
|
1473
|
+
* @param suffix キーに付ける接尾辞 ('_body' / '_sys' など)
|
|
1474
|
+
*/
|
|
1475
|
+
private getPerfMonitorKey (name: string, suffix = ''): string {
|
|
1476
|
+
if (name) { return `${name}${suffix}` }
|
|
1477
|
+
this.performanceMonitor.mumeiId++
|
|
1478
|
+
return `anous_${this.performanceMonitor.mumeiId}${suffix}`
|
|
1479
|
+
}
|
|
1480
|
+
|
|
1481
|
+
/**
|
|
1482
|
+
* コードを、実行時間を計測する即時実行関数で包む。(#2333)
|
|
1483
|
+
* システム関数本体・システム関数の計測で使う。
|
|
1484
|
+
* @param body 計測対象。isExprなら式、そうでなければ文の並び
|
|
1485
|
+
* @param key 計測結果を記録するキー
|
|
1486
|
+
* @param type 計測の種別
|
|
1487
|
+
* @param opts isExpr:bodyが式か / isAsync:非同期か / startVar,timeVar:使用するJS変数名
|
|
1488
|
+
*/
|
|
1489
|
+
private wrapPerfMonitor (body: string, key: string, type: string,
|
|
1490
|
+
opts: { isExpr: boolean, isAsync: boolean, startVar: string, timeVar: string }): string {
|
|
1491
|
+
const funcDef = opts.isAsync ? 'async function' : 'function'
|
|
1492
|
+
// 式なら値を返す必要がある。文ならそのまま実行する。
|
|
1493
|
+
const inner = opts.isExpr ? `return ${body};\n` : `${body}\n`
|
|
1494
|
+
// 末尾に改行を置かないこと。行頭のセミコロンは cleanGeneratedCode で消えてしまい、
|
|
1495
|
+
// 直後の文が `(` で始まると関数呼び出しとして繋がってしまう (#2333)
|
|
1496
|
+
let code = `(${funcDef} (key, type) {\n` +
|
|
1497
|
+
`const ${opts.startVar} = performance.now() * 1000;\n` +
|
|
1498
|
+
'try {\n' +
|
|
1499
|
+
inner +
|
|
1500
|
+
'} finally {\n' +
|
|
1501
|
+
`const ${opts.timeVar} = performance.now() * 1000 - ${opts.startVar};\n` +
|
|
1502
|
+
genPerfMonitorUpdate(opts.timeVar) +
|
|
1503
|
+
`}})('${key}', '${type}')`
|
|
1504
|
+
// 非同期関数を包んだ場合、待たないと計測対象が完了しない (#2333)
|
|
1505
|
+
if (opts.isAsync) { code = `await ${code}` }
|
|
1506
|
+
// 文として包んだ場合は、ここで文を閉じる
|
|
1507
|
+
return opts.isExpr ? code : code + ';\n'
|
|
1508
|
+
}
|
|
1509
|
+
|
|
1510
|
+
/**
|
|
1511
|
+
* ユーザ関数の実行時間を計測するために、関数の本体の前後へ挿入するコードを返す。(#2333)
|
|
1512
|
+
* @param key 計測結果を記録するキー
|
|
1513
|
+
* @returns [関数本体の直前に挿入するコード, 関数本体の直後に挿入するコード]
|
|
1514
|
+
*/
|
|
1515
|
+
private genPerfMonitorInject (key: string): [string, string] {
|
|
1516
|
+
const injectAtStart = 'const performanceMonitorEnd = (function (key, type) {\n' +
|
|
1517
|
+
'const uf_start = performance.now() * 1000;\n' +
|
|
1518
|
+
'return function () {\n' +
|
|
1519
|
+
'const el_time = performance.now() * 1000 - uf_start;\n' +
|
|
1520
|
+
genPerfMonitorUpdate('el_time') +
|
|
1521
|
+
`};})('${key}', 'user');` +
|
|
1522
|
+
'try {\n'
|
|
1523
|
+
const injectAtEnd = '} finally { performanceMonitorEnd(); }\n'
|
|
1524
|
+
return [injectAtStart, injectAtEnd]
|
|
1525
|
+
}
|
|
1526
|
+
|
|
1433
1527
|
convWhile(node: AstWhile): string {
|
|
1434
1528
|
const exprAst = node.blocks[0]
|
|
1435
1529
|
const blockAst = node.blocks[1]
|
|
@@ -1534,18 +1628,14 @@ export class NakoGen {
|
|
|
1534
1628
|
}
|
|
1535
1629
|
|
|
1536
1630
|
/**
|
|
1537
|
-
*
|
|
1538
|
-
* @
|
|
1539
|
-
* @param {boolean} isExpression
|
|
1540
|
-
* @returns string コード
|
|
1631
|
+
* どの関数を呼び出すのか関数を特定する (convCallFunc用)
|
|
1632
|
+
* @returns 変数の検索結果 res と、関数の定義 func
|
|
1541
1633
|
*/
|
|
1542
|
-
|
|
1543
|
-
const funcName = NakoGen.getFuncName(node.name)
|
|
1634
|
+
private resolveCallTarget (funcName: string, node: AstCallFunc): { res: FindVarResult, func: any } {
|
|
1544
1635
|
const res = this.findVar(funcName)
|
|
1545
1636
|
if (res === null) {
|
|
1546
1637
|
throw NakoSyntaxError.fromNode(`関数『${funcName}』が見当たりません。有効プラグイン=[` + this.getPluginList().join(', ') + ']', node)
|
|
1547
1638
|
}
|
|
1548
|
-
// どの関数を呼び出すのか関数を特定する
|
|
1549
1639
|
let func
|
|
1550
1640
|
if (res.i === 0) { // plugin function
|
|
1551
1641
|
func = this.__self.getFunc(funcName)
|
|
@@ -1558,6 +1648,156 @@ export class NakoGen {
|
|
|
1558
1648
|
// 無名関数の可能性
|
|
1559
1649
|
if (func === undefined) { func = { return_none: false, asyncFn: !!node.asyncFn } }
|
|
1560
1650
|
}
|
|
1651
|
+
return { res, func }
|
|
1652
|
+
}
|
|
1653
|
+
|
|
1654
|
+
/**
|
|
1655
|
+
* 関数内からpureでないプラグイン関数を呼び出すとき、呼び出しの前後で
|
|
1656
|
+
* ローカル変数を __self.__locals と同期するコードを生成する。
|
|
1657
|
+
* @returns 呼び出し前に実行するコード begin と、呼び出し後に実行するコード end
|
|
1658
|
+
*/
|
|
1659
|
+
private genLocalVarsSyncCode (): { begin: string, end: string } {
|
|
1660
|
+
let begin = ''
|
|
1661
|
+
let end = ''
|
|
1662
|
+
// 展開されたローカル変数の列挙
|
|
1663
|
+
const localVars = []
|
|
1664
|
+
for (const name of Array.from(this.varsSet.names.values())) {
|
|
1665
|
+
if (NakoGen.isValidIdentifier(name)) {
|
|
1666
|
+
localVars.push({ str: JSON.stringify(name), js: this.varname_get(name) })
|
|
1667
|
+
}
|
|
1668
|
+
}
|
|
1669
|
+
|
|
1670
|
+
// --- 実行前 ---
|
|
1671
|
+
// 全ての展開されていないローカル変数を __self.__locals にコピーする
|
|
1672
|
+
begin += '__self.__locals = __vars;\n'
|
|
1673
|
+
// 全ての展開されたローカル変数を __self.__locals に保存する
|
|
1674
|
+
if (localVars.length > 0) {
|
|
1675
|
+
begin += '/* 全ての展開されたローカル変数を __self.__locals に保存 */\n'
|
|
1676
|
+
for (const v of localVars) {
|
|
1677
|
+
begin += `__self.__locals.set(${v.str}, ${v.js});\n`
|
|
1678
|
+
}
|
|
1679
|
+
}
|
|
1680
|
+
|
|
1681
|
+
// --- 実行後 ---
|
|
1682
|
+
// 全ての展開されたローカル変数を __self.__locals から受け取る
|
|
1683
|
+
// 「それ」は関数の実行結果を受け取るために使うためスキップ。
|
|
1684
|
+
if (localVars.length > 0) {
|
|
1685
|
+
end += '/* 全ての展開されたローカル変数を __self.__locals から受け取る */\n'
|
|
1686
|
+
for (const v of localVars) {
|
|
1687
|
+
if (v.js !== 'それ') {
|
|
1688
|
+
end += `__self.__varslist[2].set(${v.str}, __self.__locals.get(${v.str}));\n`
|
|
1689
|
+
}
|
|
1690
|
+
}
|
|
1691
|
+
}
|
|
1692
|
+
return { begin, end }
|
|
1693
|
+
}
|
|
1694
|
+
|
|
1695
|
+
/**
|
|
1696
|
+
* 引数のリストを連結してJSの実引数のコードにする。
|
|
1697
|
+
* 必要に応じて、引数のundefinedチェックのコードを挟む。
|
|
1698
|
+
*/
|
|
1699
|
+
private genCallArgsCode (funcName: string, res: FindVarResult, args: string[], node: AstCallFunc): string {
|
|
1700
|
+
if ((!this.warnUndefinedCallingUserFunc && res.i !== 0) || (!this.warnUndefinedCallingSystemFunc && res.i === 0)) {
|
|
1701
|
+
return args.join(',')
|
|
1702
|
+
}
|
|
1703
|
+
// 引数チェックの例外 #1260
|
|
1704
|
+
const noCheckFuncs: {[key: string]: boolean} = { 'TYPEOF': true, '変数型確認': true }
|
|
1705
|
+
const argsA: string[] = []
|
|
1706
|
+
args.forEach((arg: string) => {
|
|
1707
|
+
if (arg === '__self' || noCheckFuncs[funcName] === true) { // #1260
|
|
1708
|
+
argsA.push(`${arg}`)
|
|
1709
|
+
} else {
|
|
1710
|
+
// 引数のundefinedチェックのコードを入れる
|
|
1711
|
+
const msg = (res.i === 0) ? '命令『$0』の引数にundefinedを渡しています。' : 'ユーザ命令『$0』の引数にundefinedを渡しています。'
|
|
1712
|
+
const poolIndex = this.addConstPool(msg, [funcName], node.file, node.line)
|
|
1713
|
+
// argが空になる対策 #1315
|
|
1714
|
+
const argStr = (arg === '') ? '""' : arg
|
|
1715
|
+
argsA.push(`(__self.chk(${argStr}, ${poolIndex}))`)
|
|
1716
|
+
}
|
|
1717
|
+
})
|
|
1718
|
+
return argsA.join(', ')
|
|
1719
|
+
}
|
|
1720
|
+
|
|
1721
|
+
/**
|
|
1722
|
+
* 関数の戻り値を変数「それ」に代入するためのラッパを返す。
|
|
1723
|
+
* @returns [前置するコード, 後置するコード]
|
|
1724
|
+
*/
|
|
1725
|
+
private getSoreWrap (): [string, string] {
|
|
1726
|
+
if (this.speedMode.invalidSore !== 0) { return ['', ''] }
|
|
1727
|
+
return ['__self.__setSore(', ')']
|
|
1728
|
+
}
|
|
1729
|
+
|
|
1730
|
+
/** 戻り値のない関数呼び出しのコードを組み立てる */
|
|
1731
|
+
private genVoidCallCode (node: AstCallFunc, parts: CallCodeParts): string {
|
|
1732
|
+
const { funcCall, funcBegin, funcEnd } = parts
|
|
1733
|
+
let code: string
|
|
1734
|
+
if (funcEnd === '') {
|
|
1735
|
+
code = `/*VOID関数呼出*/${funcBegin}${funcCall}\n`
|
|
1736
|
+
} else {
|
|
1737
|
+
code = `/*VOID関数呼出(前後処理付)*/${funcBegin}try {\n${indentLines(funcCall, 1)};\n} finally {\n${indentLines(funcEnd, 1)}}\n`
|
|
1738
|
+
}
|
|
1739
|
+
// パフォーマンスモニタ:システム関数。ここでのcodeは式ではなく文なので、文として包む (#2333)
|
|
1740
|
+
if (parts.sysPerfKey) {
|
|
1741
|
+
code = this.wrapPerfMonitor(code, parts.sysPerfKey, 'system',
|
|
1742
|
+
{ isExpr: false, isAsync: parts.isAsync, startVar: 'sf_start', timeVar: 'sl_time' })
|
|
1743
|
+
}
|
|
1744
|
+
// 行番号を追加
|
|
1745
|
+
return this.convLineno(node, false) + code
|
|
1746
|
+
}
|
|
1747
|
+
|
|
1748
|
+
/** 戻り値のある関数呼び出しのコードを組み立てる */
|
|
1749
|
+
private genValueCallCode (node: AstCallFunc, isExpression: boolean, parts: CallCodeParts): string {
|
|
1750
|
+
const { funcDef, funcCall, funcBegin, funcEnd, isAsync } = parts
|
|
1751
|
+
// 関数の戻り値を「それ」に記録する
|
|
1752
|
+
const [sorePrefix, sorePostfix] = this.getSoreWrap()
|
|
1753
|
+
let code: string
|
|
1754
|
+
if (funcBegin === '' && funcEnd === '') {
|
|
1755
|
+
code = `${sorePrefix}${funcCall}${sorePostfix}`
|
|
1756
|
+
} else if (funcEnd === '') {
|
|
1757
|
+
const funcBody = `${sorePrefix}${funcCall}${sorePostfix}`
|
|
1758
|
+
const funcObj = `${funcDef}(){ return ${funcBody} }`
|
|
1759
|
+
const funcCallThis = `(${funcObj}).call(this)`
|
|
1760
|
+
code = `/* funcCallThis1 */${funcCallThis}`
|
|
1761
|
+
} else { // つまり、pure=falseの場合
|
|
1762
|
+
const varI = `$nako_i${this.loopId}`
|
|
1763
|
+
this.loopId++
|
|
1764
|
+
code = `/* funcCallThis2 */(${funcDef}(){\n` +
|
|
1765
|
+
indentLines(funcBegin, 1) + '\n' +
|
|
1766
|
+
indentLines('try {', 1) + '\n' +
|
|
1767
|
+
indentLines(`let ${varI} = ${funcCall};`, 2) + '\n' +
|
|
1768
|
+
indentLines(`return ${varI};`, 2) + '\n' +
|
|
1769
|
+
indentLines('} finally {', 2) + '\n' +
|
|
1770
|
+
indentLines(funcEnd, 1) + '\n' +
|
|
1771
|
+
indentLines('}', 1) + '\n' +
|
|
1772
|
+
'}).call(this)'
|
|
1773
|
+
if (isAsync) {
|
|
1774
|
+
code = `await (${code})`
|
|
1775
|
+
}
|
|
1776
|
+
code = `${sorePrefix}${code}${sorePostfix}`
|
|
1777
|
+
}
|
|
1778
|
+
// パフォーマンスモニタ:システム関数。ここでのcodeは式なので、値を返す形で包む (#2333)
|
|
1779
|
+
if (parts.sysPerfKey) {
|
|
1780
|
+
code = this.wrapPerfMonitor(code, parts.sysPerfKey, 'system',
|
|
1781
|
+
{ isExpr: true, isAsync, startVar: 'sf_start', timeVar: 'sl_time' })
|
|
1782
|
+
}
|
|
1783
|
+
// ...して
|
|
1784
|
+
// (メモ) 式の中では文末の『;』を付けてはいけない。付けると不正なJSになる (#2064)
|
|
1785
|
+
if (!isExpression && (node.josi === 'して' || node.josi === '')) {
|
|
1786
|
+
code = this.convLineno(node, false) + code
|
|
1787
|
+
code += ';\n'
|
|
1788
|
+
}
|
|
1789
|
+
return code
|
|
1790
|
+
}
|
|
1791
|
+
|
|
1792
|
+
/**
|
|
1793
|
+
* 関数の呼び出し
|
|
1794
|
+
* @param {Ast} node
|
|
1795
|
+
* @param {boolean} isExpression
|
|
1796
|
+
* @returns string コード
|
|
1797
|
+
*/
|
|
1798
|
+
convCallFunc(node: AstCallFunc, isExpression: boolean): string {
|
|
1799
|
+
const funcName = NakoGen.getFuncName(node.name)
|
|
1800
|
+
const { res, func } = this.resolveCallTarget(funcName, node)
|
|
1561
1801
|
// 関数の参照渡しか?
|
|
1562
1802
|
if (node.type === 'func_pointer') {
|
|
1563
1803
|
return res.js
|
|
@@ -1589,73 +1829,15 @@ export class NakoGen {
|
|
|
1589
1829
|
// 関数内 (__varslist.length > 3) からプラグイン関数 (res.i === 0) を呼び出すとき、 そのプラグイン関数がpureでなければ
|
|
1590
1830
|
// 呼び出しの直前に全てのローカル変数をthis.__localsに入れる。
|
|
1591
1831
|
if (res.i === 0 && this.varslistSet.length > 3 && func.pure !== true && this.speedMode.forcePure === 0) { // undefinedはfalseとみなす
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
if (NakoGen.isValidIdentifier(name)) {
|
|
1596
|
-
localVars.push({ str: JSON.stringify(name), js: this.varname_get(name) })
|
|
1597
|
-
}
|
|
1598
|
-
}
|
|
1599
|
-
|
|
1600
|
-
// --- 実行前 ---
|
|
1601
|
-
// 全ての展開されていないローカル変数を __self.__locals にコピーする
|
|
1602
|
-
funcBegin += '__self.__locals = __vars;\n'
|
|
1603
|
-
// 全ての展開されたローカル変数を __self.__locals に保存する
|
|
1604
|
-
if (localVars.length > 0) {
|
|
1605
|
-
funcBegin += '/* 全ての展開されたローカル変数を __self.__locals に保存 */\n'
|
|
1606
|
-
for (const v of localVars) {
|
|
1607
|
-
funcBegin += `__self.__locals.set(${v.str}, ${v.js});\n`
|
|
1608
|
-
}
|
|
1609
|
-
}
|
|
1610
|
-
|
|
1611
|
-
// --- 実行後 ---
|
|
1612
|
-
// 全ての展開されたローカル変数を __self.__locals から受け取る
|
|
1613
|
-
// 「それ」は関数の実行結果を受け取るために使うためスキップ。
|
|
1614
|
-
if (localVars.length > 0) {
|
|
1615
|
-
funcEnd += '/* 全ての展開されたローカル変数を __self.__locals から受け取る */\n'
|
|
1616
|
-
for (const v of localVars) {
|
|
1617
|
-
if (v.js !== 'それ') {
|
|
1618
|
-
funcEnd += `__self.__varslist[2].set(${v.str}, __self.__locals[${v.str}]);\n`
|
|
1619
|
-
}
|
|
1620
|
-
}
|
|
1621
|
-
}
|
|
1832
|
+
const sync = this.genLocalVarsSyncCode()
|
|
1833
|
+
funcBegin += sync.begin
|
|
1834
|
+
funcEnd += sync.end
|
|
1622
1835
|
}
|
|
1623
1836
|
// 変数「それ」が補完されていることをヒントとして出力
|
|
1624
1837
|
if (argsOpts.sore) { funcBegin += '/*[sore]*/' }
|
|
1625
1838
|
|
|
1626
|
-
const indent = (text: string, n: number) => {
|
|
1627
|
-
let result = ''
|
|
1628
|
-
for (const line of text.split('\n')) {
|
|
1629
|
-
if (line !== '') {
|
|
1630
|
-
result += ' '.repeat(n) + line + '\n'
|
|
1631
|
-
}
|
|
1632
|
-
}
|
|
1633
|
-
return result
|
|
1634
|
-
}
|
|
1635
|
-
|
|
1636
|
-
// 引数チェックの例外 #1260
|
|
1637
|
-
const noCheckFuncs: {[key: string]: boolean} = { 'TYPEOF': true, '変数型確認': true }
|
|
1638
1839
|
// 関数呼び出しコードの構築
|
|
1639
|
-
|
|
1640
|
-
if ((!this.warnUndefinedCallingUserFunc && res.i !== 0) || (!this.warnUndefinedCallingSystemFunc && res.i === 0)) {
|
|
1641
|
-
argsCode = args.join(',')
|
|
1642
|
-
} else {
|
|
1643
|
-
const argsA: string[] = []
|
|
1644
|
-
args.forEach((arg: string) => {
|
|
1645
|
-
if (arg === '__self' || noCheckFuncs[funcName] === true) { // #1260
|
|
1646
|
-
argsA.push(`${arg}`)
|
|
1647
|
-
} else {
|
|
1648
|
-
// 引数のundefinedチェックのコードを入れる
|
|
1649
|
-
const msg = (res.i === 0) ? '命令『$0』の引数にundefinedを渡しています。' : 'ユーザ命令『$0』の引数にundefinedを渡しています。'
|
|
1650
|
-
const poolIndex = this.addConstPool(msg, [funcName], node.file, node.line)
|
|
1651
|
-
// argが空になる対策 #1315
|
|
1652
|
-
const argStr = (arg === '') ? '""' : arg
|
|
1653
|
-
argsA.push(`(__self.chk(${argStr}, ${poolIndex}))`)
|
|
1654
|
-
}
|
|
1655
|
-
})
|
|
1656
|
-
argsCode = argsA.join(', ')
|
|
1657
|
-
}
|
|
1658
|
-
|
|
1840
|
+
const argsCode = this.genCallArgsCode(funcName, res, args, node)
|
|
1659
1841
|
let funcCall = `${res.js}(${argsCode})`
|
|
1660
1842
|
if (func.asyncFn) {
|
|
1661
1843
|
funcDef = `async ${funcDef}`
|
|
@@ -1668,111 +1850,20 @@ export class NakoGen {
|
|
|
1668
1850
|
funcBegin += `const __local_async${varI} = __self.__vars;\n`
|
|
1669
1851
|
funcEnd += `__self.__vars = __local_async${varI};\n`
|
|
1670
1852
|
}
|
|
1853
|
+
// パフォーマンスモニタ:システム関数本体 (呼び出しコードを除く)
|
|
1671
1854
|
if (res.i === 0 && this.performanceMonitor.systemFunctionBody !== 0) {
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
if (typeof this.performanceMonitor.mumeiId === 'undefined') {
|
|
1675
|
-
this.performanceMonitor.mumeiId = 0
|
|
1676
|
-
}
|
|
1677
|
-
this.performanceMonitor.mumeiId++
|
|
1678
|
-
key = `anous_${this.performanceMonitor.mumeiId}`
|
|
1679
|
-
}
|
|
1680
|
-
funcCall = `(${funcDef} (key, type) {\n` +
|
|
1681
|
-
'const sbf_start = performance.now() * 1000;\n' +
|
|
1682
|
-
'try {\n' +
|
|
1683
|
-
'return ' + funcCall + ';\n' +
|
|
1684
|
-
'} finally {\n' +
|
|
1685
|
-
'const sbl_time = performance.now() * 1000 - sbf_start;\n' +
|
|
1686
|
-
'if (!__self.__performance_monitor) {\n' +
|
|
1687
|
-
'__self.__performance_monitor={};\n' +
|
|
1688
|
-
'__self.__performance_monitor[key] = { called:1, totel_usec: sbl_time, min_usec: sbl_time, max_usec: sbl_time, type: type };\n' +
|
|
1689
|
-
'} else if (!__self.__performance_monitor[key]) {\n' +
|
|
1690
|
-
'__self.__performance_monitor[key] = { called:1, totel_usec: sbl_time, min_usec: sbl_time, max_usec: sbl_time, type: type };\n' +
|
|
1691
|
-
'} else {\n' +
|
|
1692
|
-
'__self.__performance_monitor[key].called++;\n' +
|
|
1693
|
-
'__self.__performance_monitor[key].totel_usec+=sbl_time;\n' +
|
|
1694
|
-
'if(__self.__performance_monitor[key].min_usec>sbl_time){__self.__performance_monitor[key].min_usec=sbl_time;}\n' +
|
|
1695
|
-
'if(__self.__performance_monitor[key].max_usec<sbl_time){__self.__performance_monitor[key].max_usec=sbl_time;}\n' +
|
|
1696
|
-
`}}})('${funcName}_body', 'sysbody')\n`
|
|
1697
|
-
}
|
|
1698
|
-
|
|
1699
|
-
let code = ''
|
|
1700
|
-
if (func.return_none) {
|
|
1701
|
-
// ------------------------------------
|
|
1702
|
-
// 戻り値のない関数の場合
|
|
1703
|
-
// ------------------------------------
|
|
1704
|
-
if (funcEnd === '') {
|
|
1705
|
-
code = `/*VOID関数呼出*/${funcBegin}${funcCall}\n`
|
|
1706
|
-
} else {
|
|
1707
|
-
code = `/*VOID関数呼出(前後処理付)*/${funcBegin}try {\n${indent(funcCall, 1)};\n} finally {\n${indent(funcEnd, 1)}}\n`
|
|
1708
|
-
}
|
|
1709
|
-
// 行番号を追加
|
|
1710
|
-
code = this.convLineno(node, false) + code
|
|
1711
|
-
} else {
|
|
1712
|
-
// ------------------------------------
|
|
1713
|
-
// 戻り値のある関数の場合
|
|
1714
|
-
// ------------------------------------
|
|
1715
|
-
let sorePrefex = ''
|
|
1716
|
-
let sorePostfix = ''
|
|
1717
|
-
if (this.speedMode.invalidSore === 0) {
|
|
1718
|
-
// 関数の戻り値を記録
|
|
1719
|
-
sorePrefex = '__self.__setSore('
|
|
1720
|
-
sorePostfix = ')'
|
|
1721
|
-
}
|
|
1722
|
-
if (funcBegin === '' && funcEnd === '') {
|
|
1723
|
-
code = `${sorePrefex}${funcCall}${sorePostfix}`
|
|
1724
|
-
} else {
|
|
1725
|
-
if (funcEnd === '') {
|
|
1726
|
-
const funcBody = `${sorePrefex}${funcCall}${sorePostfix}`
|
|
1727
|
-
const funcObj = `${funcDef}(){ return ${funcBody} }`
|
|
1728
|
-
const funcCallThis = `(${funcObj}).call(this)`
|
|
1729
|
-
code = `/* funcCallThis1 */${funcCallThis}`
|
|
1730
|
-
} else { // つまり、pure=falseの場合
|
|
1731
|
-
const varI = `$nako_i${this.loopId}`
|
|
1732
|
-
this.loopId++
|
|
1733
|
-
code = `/* funcCallThis2 */(${funcDef}(){\n` +
|
|
1734
|
-
indent(funcBegin, 1) + '\n' +
|
|
1735
|
-
indent('try {', 1) + '\n' +
|
|
1736
|
-
indent(`let ${varI} = ${funcCall};`, 2) + '\n' +
|
|
1737
|
-
indent(`return ${varI};`, 2) + '\n' +
|
|
1738
|
-
indent('} finally {', 2) + '\n' +
|
|
1739
|
-
indent(funcEnd, 1) + '\n' +
|
|
1740
|
-
indent('}', 1) + '\n' +
|
|
1741
|
-
'}).call(this)'
|
|
1742
|
-
if (func.asyncFn) {
|
|
1743
|
-
code = `await (${code})`
|
|
1744
|
-
}
|
|
1745
|
-
code = `${sorePrefex}${code}${sorePostfix}`
|
|
1746
|
-
}
|
|
1747
|
-
}
|
|
1748
|
-
// ...して
|
|
1749
|
-
if (node.josi === 'して' || (node.josi === '' && !isExpression)) {
|
|
1750
|
-
code = this.convLineno(node, false) + code
|
|
1751
|
-
code += ';\n'
|
|
1752
|
-
}
|
|
1753
|
-
}
|
|
1754
|
-
|
|
1755
|
-
if (res.i === 0 && this.performanceMonitor.systemFunction !== 0) {
|
|
1756
|
-
code = '(function (key, type) {\n' +
|
|
1757
|
-
'const sf_start = performance.now() * 1000;\n' +
|
|
1758
|
-
'try {\n' +
|
|
1759
|
-
'return ' + code + ';\n' +
|
|
1760
|
-
'} finally {\n' +
|
|
1761
|
-
'const sl_time = performance.now() * 1000 - sf_start;\n' +
|
|
1762
|
-
'if (!__self.__performance_monitor) {\n' +
|
|
1763
|
-
'__self.__performance_monitor={};\n' +
|
|
1764
|
-
'__self.__performance_monitor[key] = { called:1, totel_usec: sl_time, min_usec: sl_time, max_usec: sl_time, type: type };\n' +
|
|
1765
|
-
'} else if (!__self.__performance_monitor[key]) {\n' +
|
|
1766
|
-
'__self.__performance_monitor[key] = { called:1, totel_usec: sl_time, min_usec: sl_time, max_usec: sl_time, type: type };\n' +
|
|
1767
|
-
'} else {\n' +
|
|
1768
|
-
'__self.__performance_monitor[key].called++;\n' +
|
|
1769
|
-
'__self.__performance_monitor[key].totel_usec+=sl_time;\n' +
|
|
1770
|
-
'if(__self.__performance_monitor[key].min_usec>sl_time){__self.__performance_monitor[key].min_usec=sl_time;}\n' +
|
|
1771
|
-
'if(__self.__performance_monitor[key].max_usec<sl_time){__self.__performance_monitor[key].max_usec=sl_time;}\n' +
|
|
1772
|
-
`}}})('${funcName}_sys', 'system')\n`
|
|
1855
|
+
funcCall = this.wrapPerfMonitor(funcCall, this.getPerfMonitorKey(funcName, '_body'), 'sysbody',
|
|
1856
|
+
{ isExpr: true, isAsync: !!func.asyncFn, startVar: 'sbf_start', timeVar: 'sbl_time' })
|
|
1773
1857
|
}
|
|
1858
|
+
// パフォーマンスモニタ:システム関数 (呼び出しコードを含む) はコードの組み立て中に適用する
|
|
1859
|
+
const sysPerfKey = (res.i === 0 && this.performanceMonitor.systemFunction !== 0)
|
|
1860
|
+
? this.getPerfMonitorKey(funcName, '_sys')
|
|
1861
|
+
: null
|
|
1774
1862
|
|
|
1775
|
-
|
|
1863
|
+
const parts: CallCodeParts = { funcDef, funcCall, funcBegin, funcEnd, isAsync: !!func.asyncFn, sysPerfKey }
|
|
1864
|
+
return (func.return_none)
|
|
1865
|
+
? this.genVoidCallCode(node, parts)
|
|
1866
|
+
: this.genValueCallCode(node, isExpression, parts)
|
|
1776
1867
|
}
|
|
1777
1868
|
|
|
1778
1869
|
convCallValue(node: AstBlocks, isExpression: boolean): string {
|
|
@@ -1783,9 +1874,8 @@ export class NakoGen {
|
|
|
1783
1874
|
if (isExpression) {
|
|
1784
1875
|
return funcCall
|
|
1785
1876
|
}
|
|
1786
|
-
const
|
|
1787
|
-
|
|
1788
|
-
return this.convLineno(node, false) + `${sorePrefex}${funcCall}${sorePostfix};\n`
|
|
1877
|
+
const [sorePrefix, sorePostfix] = this.getSoreWrap()
|
|
1878
|
+
return this.convLineno(node, false) + `${sorePrefix}${funcCall}${sorePostfix};\n`
|
|
1789
1879
|
}
|
|
1790
1880
|
|
|
1791
1881
|
convRenbun(node: AstOperator): string {
|
|
@@ -2272,6 +2362,7 @@ export function generateJS(com: NakoCompiler, ast: Ast, opt: NakoGenOptions): Na
|
|
|
2272
2362
|
|
|
2273
2363
|
// ランダムな関数名を生成
|
|
2274
2364
|
const funcID = String((new Date()).getTime()) + '_' + Math.floor(0xFFFFFFFF * Math.random()).toString()
|
|
2365
|
+
let runtimeResult = ''
|
|
2275
2366
|
// テストの実行
|
|
2276
2367
|
if (js && opt.isTest) {
|
|
2277
2368
|
js += '\n__self._runTests(__tests);\n'
|
|
@@ -2279,6 +2370,8 @@ export function generateJS(com: NakoCompiler, ast: Ast, opt: NakoGenOptions): Na
|
|
|
2279
2370
|
// async method
|
|
2280
2371
|
if (gen.numAsyncFn > 0 || gen.debugOption.useDebug) {
|
|
2281
2372
|
const asyncMain = '__eval_nako3async_' + funcID + '__'
|
|
2373
|
+
const asyncMainPromise = '__eval_nako3async_promise_' + funcID + '__'
|
|
2374
|
+
runtimeResult = `return ${asyncMainPromise}`
|
|
2282
2375
|
js = `
|
|
2283
2376
|
// ------------------------------------------------------------------
|
|
2284
2377
|
// <nadesiko3::gen::async id="${funcID}" times="${gen.numAsyncFn}">
|
|
@@ -2291,12 +2384,11 @@ async function ${asyncMain}(__self) {
|
|
|
2291
2384
|
} // end of ${asyncMain}
|
|
2292
2385
|
// ------------------------------------------------------------------
|
|
2293
2386
|
// call ${asyncMain}
|
|
2294
|
-
(async () => {
|
|
2387
|
+
const ${asyncMainPromise} = (async () => {
|
|
2295
2388
|
if (__self.__v0.get('__standalone')) {
|
|
2296
2389
|
await ${asyncMain}(self);
|
|
2297
2390
|
} else {
|
|
2298
|
-
${asyncMain}.call(self, self)
|
|
2299
|
-
.then(() => { /* __async_ok__ */ })
|
|
2391
|
+
await ${asyncMain}.call(self, self)
|
|
2300
2392
|
.catch(err => {
|
|
2301
2393
|
if (err.message === '__終わる__') { return }
|
|
2302
2394
|
__self.numFailures++
|
|
@@ -2337,14 +2429,32 @@ ${syncMain}(__self)
|
|
|
2337
2429
|
// デバッグメッセージ
|
|
2338
2430
|
let codeImportFiles = ''
|
|
2339
2431
|
const importNames = []
|
|
2432
|
+
// プラグインとして登録せず、コピーだけが必要なファイル
|
|
2433
|
+
// (plugin_system_*.mjs は plugin_system.mjs 側でマージ済みのため二重登録しない) #2351
|
|
2434
|
+
const noRegisterFiles = [
|
|
2435
|
+
'nako_errors.mjs',
|
|
2436
|
+
'plugin_system_debug.mjs',
|
|
2437
|
+
'plugin_system_math.mjs',
|
|
2438
|
+
'plugin_system_string.mjs',
|
|
2439
|
+
'plugin_system_array.mjs',
|
|
2440
|
+
'plugin_system_datetime.mjs',
|
|
2441
|
+
'plugin_system_url.mjs',
|
|
2442
|
+
'plugin_system_types.mjs',
|
|
2443
|
+
'plugin_system_json.mjs',
|
|
2444
|
+
'plugin_system_regexp.mjs',
|
|
2445
|
+
'plugin_system_dict.mjs',
|
|
2446
|
+
'plugin_system_stdio.mjs',
|
|
2447
|
+
'plugin_system_timer.mjs'
|
|
2448
|
+
]
|
|
2340
2449
|
for (const f of opt.importFiles) {
|
|
2341
|
-
if (f
|
|
2450
|
+
if (noRegisterFiles.includes(f)) { continue }
|
|
2342
2451
|
const ff = 'nako3runtime_' + f.replace(/\.(js|mjs)$/, '').replace(/[^a-zA-Z0-9_]/g, '_')
|
|
2343
2452
|
importNames.push(ff)
|
|
2344
2453
|
codeImportFiles += `import ${ff} from './nako3runtime/${f}'\n`
|
|
2345
2454
|
}
|
|
2346
2455
|
// ---
|
|
2347
2456
|
const initCode = gen.getPluginInitCode()
|
|
2457
|
+
// runtimeEnvはnew Functionの関数本体として実行するコードで、非同期時はトップレベルのreturnを含む。
|
|
2348
2458
|
const runtimeEnvCode = `
|
|
2349
2459
|
// <runtimeEnvCode>
|
|
2350
2460
|
const self = this
|
|
@@ -2352,6 +2462,7 @@ ${opt.codeEnv}
|
|
|
2352
2462
|
${jsInit}
|
|
2353
2463
|
${initCode}
|
|
2354
2464
|
${js}
|
|
2465
|
+
${runtimeResult}
|
|
2355
2466
|
// </runtimeEnvCode>
|
|
2356
2467
|
`
|
|
2357
2468
|
com.getLogger().trace('--- generate::jsInit ---\n' + jsInit)
|