nadesiko3 3.3.48 → 3.3.49
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/core/.editorconfig +6 -0
- package/core/.eslintrc.cjs +33 -0
- package/core/.github/dependabot.yml +7 -0
- package/core/.github/workflows/nodejs.yml +37 -0
- package/core/.github/workflows/super-linter.yml +61 -0
- package/core/.github/workflows/textlint.yml +199 -0
- package/core/LICENSE +21 -0
- package/core/README.md +66 -0
- package/core/batch/build_nako_version.nako3 +42 -0
- package/core/command/snako.mjs +105 -0
- package/core/command/snako.mts +116 -0
- package/core/index.mjs +21 -0
- package/core/index.mts +21 -0
- package/core/package.json +47 -0
- package/core/sample/hello.nako3 +7 -0
- package/core/sample/hoge.mjs +4 -0
- package/core/sample/hoge.mts +6 -0
- package/core/src/nako3.mjs +858 -0
- package/core/src/nako3.mts +967 -0
- package/core/src/nako_colors.mjs +78 -0
- package/core/src/nako_colors.mts +86 -0
- package/core/src/nako_core_version.mjs +8 -0
- package/core/src/nako_core_version.mts +19 -0
- package/core/src/nako_csv.mjs +185 -0
- package/core/src/nako_csv.mts +188 -0
- package/core/src/nako_errors.mjs +173 -0
- package/core/src/nako_errors.mts +197 -0
- package/core/src/nako_from_dncl.mjs +255 -0
- package/core/src/nako_from_dncl.mts +250 -0
- package/core/src/nako_gen.mjs +1648 -0
- package/core/src/nako_gen.mts +1719 -0
- package/core/src/nako_gen_async.mjs +1659 -0
- package/core/src/nako_gen_async.mts +1732 -0
- package/core/src/nako_global.mjs +107 -0
- package/core/src/nako_global.mts +138 -0
- package/core/src/nako_indent.mjs +445 -0
- package/core/src/nako_indent.mts +492 -0
- package/core/src/nako_josi_list.mjs +38 -0
- package/core/src/nako_josi_list.mts +45 -0
- package/core/src/nako_lex_rules.mjs +253 -0
- package/core/src/nako_lex_rules.mts +260 -0
- package/core/src/nako_lexer.mjs +609 -0
- package/core/src/nako_lexer.mts +612 -0
- package/core/src/nako_logger.mjs +199 -0
- package/core/src/nako_logger.mts +232 -0
- package/core/src/nako_parser3.mjs +2439 -0
- package/core/src/nako_parser3.mts +2195 -0
- package/core/src/nako_parser_base.mjs +370 -0
- package/core/src/nako_parser_base.mts +370 -0
- package/core/src/nako_parser_const.mjs +37 -0
- package/core/src/nako_parser_const.mts +37 -0
- package/core/src/nako_prepare.mjs +304 -0
- package/core/src/nako_prepare.mts +315 -0
- package/core/src/nako_reserved_words.mjs +38 -0
- package/core/src/nako_reserved_words.mts +38 -0
- package/core/src/nako_source_mapping.mjs +207 -0
- package/core/src/nako_source_mapping.mts +262 -0
- package/core/src/nako_test.mjs +37 -0
- package/core/src/nako_types.mjs +25 -0
- package/core/src/nako_types.mts +151 -0
- package/core/src/plugin_csv.mjs +49 -0
- package/core/src/plugin_csv.mts +50 -0
- package/core/src/plugin_math.mjs +328 -0
- package/core/src/plugin_math.mts +326 -0
- package/core/src/plugin_promise.mjs +91 -0
- package/core/src/plugin_promise.mts +91 -0
- package/core/src/plugin_system.mjs +2832 -0
- package/core/src/plugin_system.mts +2690 -0
- package/core/src/plugin_test.mjs +34 -0
- package/core/src/plugin_test.mts +34 -0
- package/core/test/array_test.mjs +34 -0
- package/core/test/basic_test.mjs +344 -0
- package/core/test/calc_test.mjs +140 -0
- package/core/test/core_module_test.mjs +23 -0
- package/core/test/debug_test.mjs +16 -0
- package/core/test/dncl_test.mjs +94 -0
- package/core/test/error_message_test.mjs +210 -0
- package/core/test/error_test.mjs +16 -0
- package/core/test/flow_test.mjs +373 -0
- package/core/test/func_call.mjs +160 -0
- package/core/test/func_test.mjs +149 -0
- package/core/test/indent_test.mjs +364 -0
- package/core/test/lex_test.mjs +168 -0
- package/core/test/literal_test.mjs +73 -0
- package/core/test/nako_lexer_test.mjs +35 -0
- package/core/test/nako_logger_test.mjs +76 -0
- package/core/test/nako_logger_test.mts +78 -0
- package/core/test/plugin_csv_test.mjs +38 -0
- package/core/test/plugin_promise_test.mjs +18 -0
- package/core/test/plugin_system_test.mjs +630 -0
- package/core/test/prepare_test.mjs +96 -0
- package/core/test/re_test.mjs +22 -0
- package/core/test/side_effects_test.mjs +92 -0
- package/core/test/variable_scope_test.mjs +149 -0
- package/core/tsconfig.json +101 -0
- package/package.json +4 -2
- package/release/_hash.txt +12 -12
- package/release/_script-tags.txt +14 -14
- package/release/editor.js +1 -1
- package/release/stats.json +1 -1
- package/release/version.js +1 -1
- package/release/wnako3.js +1 -1
- package/src/nako_version.mjs +2 -2
- package/src/nako_version.mts +2 -2
- package/test/async/async_basic_test.mjs +3 -3
|
@@ -0,0 +1,1719 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* パーサーが生成した中間オブジェクトを実際のJavaScriptのコードに変換する。
|
|
3
|
+
* なお速度優先で忠実にJavaScriptのコードを生成する。
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { NakoRuntimeError, NakoSyntaxError, NakoError } from './nako_errors.mjs'
|
|
7
|
+
import { NakoLexer } from './nako_lexer.mjs'
|
|
8
|
+
import { Ast, FuncList, FuncArgs, Token } from './nako_types.mjs'
|
|
9
|
+
import { NakoCompiler } from './nako3.mjs'
|
|
10
|
+
|
|
11
|
+
// なでしこで定義した関数の開始コードと終了コード
|
|
12
|
+
const topOfFunction = '(function(){\n'
|
|
13
|
+
const endOfFunction = '})'
|
|
14
|
+
const topOfFunctionAsync = '(async function(){\n'
|
|
15
|
+
|
|
16
|
+
interface VarsSet {
|
|
17
|
+
isFunction: boolean;
|
|
18
|
+
names: Set<string>;
|
|
19
|
+
readonly: Set<string>;
|
|
20
|
+
}
|
|
21
|
+
interface SpeedMode {
|
|
22
|
+
lineNumbers: number; // 行番号を出力しない
|
|
23
|
+
implicitTypeCasting: number; // 数値加算でparseFloatを出力しない
|
|
24
|
+
invalidSore: number; // 「それ」を用いない
|
|
25
|
+
forcePure: number; // 全てのシステム命令をpureとして扱う。命令からローカル変数への参照が出来なくなる。
|
|
26
|
+
}
|
|
27
|
+
interface PerformanceMonitor {
|
|
28
|
+
userFunction: number; // 呼び出されたユーザ関数
|
|
29
|
+
systemFunction: number; // システム関数(呼び出しコードを含む)
|
|
30
|
+
systemFunctionBody: number; // システム関数(呼び出しコードを除く)
|
|
31
|
+
mumeiId: number;
|
|
32
|
+
}
|
|
33
|
+
interface FindVarResult {
|
|
34
|
+
i: number;
|
|
35
|
+
name: string;
|
|
36
|
+
isTop: boolean;
|
|
37
|
+
js: string
|
|
38
|
+
}
|
|
39
|
+
/** コード生成オプション */
|
|
40
|
+
export class NakoGenOptions {
|
|
41
|
+
isTest: boolean
|
|
42
|
+
importFiles: string[]
|
|
43
|
+
codeStandalone: string
|
|
44
|
+
codeEnv: string
|
|
45
|
+
constructor (isTest = false, importFiles: string[] = [], codeStandalone = '', convEnv = '') {
|
|
46
|
+
this.isTest = isTest
|
|
47
|
+
this.codeStandalone = codeStandalone
|
|
48
|
+
this.codeEnv = convEnv
|
|
49
|
+
this.importFiles = ['plugin_system.mjs', 'plugin_math.mjs', 'plugin_csv.mjs', 'plugin_promise.mjs', 'plugin_test.mjs']
|
|
50
|
+
for (const fname of importFiles) {
|
|
51
|
+
this.importFiles.push(fname)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* 構文木からJSのコードを生成するクラス
|
|
58
|
+
*/
|
|
59
|
+
export class NakoGen {
|
|
60
|
+
private nakoFuncList: FuncList; // なでしこ自身で定義した関数の一覧
|
|
61
|
+
private nakoTestFuncs: FuncList; // テストのための関数
|
|
62
|
+
private usedFuncSet: Set<string>; // 利用があった関数をメモする
|
|
63
|
+
private usedAsyncFn: boolean; // 非同期関数が使われているか判定
|
|
64
|
+
private loopId: number; // ループを生成する際にダミーのループ変数を管理するため
|
|
65
|
+
private flagLoop: boolean; // 変換中のソースがループの中かどうかを判定する
|
|
66
|
+
// コード生成オプション
|
|
67
|
+
private speedMode: SpeedMode;
|
|
68
|
+
private performanceMonitor: PerformanceMonitor;
|
|
69
|
+
private warnUndefinedVar: boolean;
|
|
70
|
+
private warnUndefinedReturnUserFunc: number;
|
|
71
|
+
private warnUndefinedCallingUserFunc: number;
|
|
72
|
+
private warnUndefinedCallingSystemFunc: number;
|
|
73
|
+
private warnUndefinedCalledUserFuncArgs: number;
|
|
74
|
+
// 変数管理
|
|
75
|
+
private varslistSet: VarsSet[]; // [システム変数一覧, グローバル変数一覧, ローカル変数一覧]で変数セットを記録
|
|
76
|
+
private varsSet: VarsSet; // ローカルな変数を記録
|
|
77
|
+
// public
|
|
78
|
+
numAsyncFn: number;
|
|
79
|
+
__self: NakoCompiler;
|
|
80
|
+
genMode: string;
|
|
81
|
+
lastLineNo: string | null; // `l123:main.nako3`形式
|
|
82
|
+
|
|
83
|
+
/** constructor
|
|
84
|
+
* @param com コンパイラのインスタンス
|
|
85
|
+
*/
|
|
86
|
+
constructor (com: NakoCompiler) {
|
|
87
|
+
/**
|
|
88
|
+
* 出力するJavaScriptコードのヘッダー部分で定義する必要のある関数。fnはjsのコード。
|
|
89
|
+
* プラグイン関数は含まれない。
|
|
90
|
+
*/
|
|
91
|
+
this.nakoFuncList = { ...com.getNakoFuncList() }
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* なでしこで定義したテストの一覧
|
|
95
|
+
*/
|
|
96
|
+
this.nakoTestFuncs = {}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* プログラム内で参照された関数のリスト。プラグインの命令を含む。
|
|
100
|
+
* JavaScript単体で実行するとき、このリストにある関数の定義をJavaScriptコードの先頭に付け足す。
|
|
101
|
+
*/
|
|
102
|
+
this.usedFuncSet = new Set()
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* ループ時の一時変数が被らないようにIDで管理
|
|
106
|
+
*/
|
|
107
|
+
this.loopId = 1
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* 非同関数を何回使ったか
|
|
111
|
+
*/
|
|
112
|
+
this.numAsyncFn = 0
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* 関数定義の際、関数の中でasyncFn=trueの関数を呼び出したかどうかを調べる @see convDefFuncCommon
|
|
116
|
+
*/
|
|
117
|
+
this.usedAsyncFn = false
|
|
118
|
+
|
|
119
|
+
/** 変換中の処理が、ループの中かどうかを判定する */
|
|
120
|
+
this.flagLoop = false
|
|
121
|
+
|
|
122
|
+
this.__self = com
|
|
123
|
+
|
|
124
|
+
/** コードジェネレータの種類 */
|
|
125
|
+
this.genMode = 'sync'
|
|
126
|
+
|
|
127
|
+
/** 行番号とファイル名が分かるときは `l123:main.nako3`、行番号だけ分かるときは `l123`、そうでなければ任意の文字列。 */
|
|
128
|
+
this.lastLineNo = null
|
|
129
|
+
|
|
130
|
+
/** スタック */
|
|
131
|
+
this.varslistSet = com.__varslist.map((v) => ({ isFunction: false, names: new Set(Object.keys(v)), readonly: new Set() }))
|
|
132
|
+
|
|
133
|
+
/** スタックトップ */
|
|
134
|
+
this.varsSet = { isFunction: false, names: new Set(), readonly: new Set() }
|
|
135
|
+
this.varslistSet[2] = this.varsSet
|
|
136
|
+
|
|
137
|
+
// 1以上のとき高速化する。
|
|
138
|
+
// 実行速度優先ブロック内で1増える。
|
|
139
|
+
this.speedMode = {
|
|
140
|
+
lineNumbers: 0, // 行番号を出力しない
|
|
141
|
+
implicitTypeCasting: 0, // 数値加算でparseFloatを出力しない
|
|
142
|
+
invalidSore: 0, // 「それ」を用いない
|
|
143
|
+
forcePure: 0 // 全てのシステム命令をpureとして扱う。命令からローカル変数への参照が出来なくなる。
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// 1以上のとき測定をinjectする。
|
|
147
|
+
// パフォーマンスモニタのブロック内で1増える。
|
|
148
|
+
this.performanceMonitor = {
|
|
149
|
+
userFunction: 0, // 呼び出されたユーザ関数
|
|
150
|
+
systemFunction: 0, // システム関数(呼び出しコードを含む)
|
|
151
|
+
systemFunctionBody: 0, // システム関数(呼び出しコードを除く)
|
|
152
|
+
mumeiId: 0
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* 未定義の変数の警告を行う
|
|
157
|
+
*/
|
|
158
|
+
this.warnUndefinedVar = true
|
|
159
|
+
|
|
160
|
+
// 暫定変数
|
|
161
|
+
this.warnUndefinedReturnUserFunc = 1
|
|
162
|
+
this.warnUndefinedCallingUserFunc = 1
|
|
163
|
+
this.warnUndefinedCallingSystemFunc = 1
|
|
164
|
+
this.warnUndefinedCalledUserFuncArgs = 1
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
static isValidIdentifier (name: string) {
|
|
168
|
+
// TODO: いらなそうな部分は削る
|
|
169
|
+
// https://stackoverflow.com/a/9337047
|
|
170
|
+
// eslint-disable-next-line no-misleading-character-class
|
|
171
|
+
return /^(?!(?:do|if|in|for|let|new|try|var|case|else|enum|eval|false|null|this|true|void|with|break|catch|class|const|super|throw|while|yield|delete|export|import|public|return|static|switch|typeof|default|extends|finally|package|private|continue|debugger|function|arguments|interface|protected|implements|instanceof)$)[$A-Z_a-z\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05d0-\u05ea\u05f0-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u08a0\u08a2-\u08ac\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097f\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c33\u0c35-\u0c39\u0c3d\u0c58\u0c59\u0c60\u0c61\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d60\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1877\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191c\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19c1-\u19c7\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4b\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1ce9-\u1cec\u1cee-\u1cf1\u1cf5\u1cf6\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2e2f\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua697\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa80-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc][$A-Z_a-z\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05d0-\u05ea\u05f0-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u08a0\u08a2-\u08ac\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097f\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c33\u0c35-\u0c39\u0c3d\u0c58\u0c59\u0c60\u0c61\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d60\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1877\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191c\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19c1-\u19c7\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4b\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1ce9-\u1cec\u1cee-\u1cf1\u1cf5\u1cf6\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2e2f\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua697\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa80-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc0-9\u0300-\u036f\u0483-\u0487\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u0669\u0670\u06d6-\u06dc\u06df-\u06e4\u06e7\u06e8\u06ea-\u06ed\u06f0-\u06f9\u0711\u0730-\u074a\u07a6-\u07b0\u07c0-\u07c9\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0859-\u085b\u08e4-\u08fe\u0900-\u0903\u093a-\u093c\u093e-\u094f\u0951-\u0957\u0962\u0963\u0966-\u096f\u0981-\u0983\u09bc\u09be-\u09c4\u09c7\u09c8\u09cb-\u09cd\u09d7\u09e2\u09e3\u09e6-\u09ef\u0a01-\u0a03\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a66-\u0a71\u0a75\u0a81-\u0a83\u0abc\u0abe-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ae2\u0ae3\u0ae6-\u0aef\u0b01-\u0b03\u0b3c\u0b3e-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b66-\u0b6f\u0b82\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd7\u0be6-\u0bef\u0c01-\u0c03\u0c3e-\u0c44\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0c66-\u0c6f\u0c82\u0c83\u0cbc\u0cbe-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0ce6-\u0cef\u0d02\u0d03\u0d3e-\u0d44\u0d46-\u0d48\u0d4a-\u0d4d\u0d57\u0d62\u0d63\u0d66-\u0d6f\u0d82\u0d83\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0df2\u0df3\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0e50-\u0e59\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0ed0-\u0ed9\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f3e\u0f3f\u0f71-\u0f84\u0f86\u0f87\u0f8d-\u0f97\u0f99-\u0fbc\u0fc6\u102b-\u103e\u1040-\u1049\u1056-\u1059\u105e-\u1060\u1062-\u1064\u1067-\u106d\u1071-\u1074\u1082-\u108d\u108f-\u109d\u135d-\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b4-\u17d3\u17dd\u17e0-\u17e9\u180b-\u180d\u1810-\u1819\u18a9\u1920-\u192b\u1930-\u193b\u1946-\u194f\u19b0-\u19c0\u19c8\u19c9\u19d0-\u19d9\u1a17-\u1a1b\u1a55-\u1a5e\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1b00-\u1b04\u1b34-\u1b44\u1b50-\u1b59\u1b6b-\u1b73\u1b80-\u1b82\u1ba1-\u1bad\u1bb0-\u1bb9\u1be6-\u1bf3\u1c24-\u1c37\u1c40-\u1c49\u1c50-\u1c59\u1cd0-\u1cd2\u1cd4-\u1ce8\u1ced\u1cf2-\u1cf4\u1dc0-\u1de6\u1dfc-\u1dff\u200c\u200d\u203f\u2040\u2054\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2cef-\u2cf1\u2d7f\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua620-\ua629\ua66f\ua674-\ua67d\ua69f\ua6f0\ua6f1\ua802\ua806\ua80b\ua823-\ua827\ua880\ua881\ua8b4-\ua8c4\ua8d0-\ua8d9\ua8e0-\ua8f1\ua900-\ua909\ua926-\ua92d\ua947-\ua953\ua980-\ua983\ua9b3-\ua9c0\ua9d0-\ua9d9\uaa29-\uaa36\uaa43\uaa4c\uaa4d\uaa50-\uaa59\uaa7b\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uaaeb-\uaaef\uaaf5\uaaf6\uabe3-\uabea\uabec\uabed\uabf0-\uabf9\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\ufe33\ufe34\ufe4d-\ufe4f\uff10-\uff19\uff3f]*$/.test(name)
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* @param {Ast} node
|
|
176
|
+
* @param {boolean} forceUpdate
|
|
177
|
+
*/
|
|
178
|
+
convLineno (node: Ast, forceUpdate = false): string {
|
|
179
|
+
if (this.speedMode.lineNumbers > 0) { return '' }
|
|
180
|
+
|
|
181
|
+
let lineNo: string
|
|
182
|
+
if (typeof node.line !== 'number') {
|
|
183
|
+
lineNo = 'unknown'
|
|
184
|
+
} else if (typeof node.file !== 'string') {
|
|
185
|
+
lineNo = `l${node.line}`
|
|
186
|
+
} else {
|
|
187
|
+
lineNo = `l${node.line}:${node.file}`
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// 強制的に行番号をアップデートするか
|
|
191
|
+
if (!forceUpdate) {
|
|
192
|
+
if (lineNo === this.lastLineNo) { return '' }
|
|
193
|
+
this.lastLineNo = lineNo
|
|
194
|
+
}
|
|
195
|
+
// 例: __v0.line='l1:main.nako3'
|
|
196
|
+
return `__v0.line=${JSON.stringify(lineNo)};`
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* ローカル変数のJavaScriptコードを生成する。
|
|
201
|
+
* @param {string} name
|
|
202
|
+
*/
|
|
203
|
+
varname (name: string): string {
|
|
204
|
+
if (this.varslistSet.length === 3) {
|
|
205
|
+
// グローバル
|
|
206
|
+
return `__varslist[${2}][${JSON.stringify(name)}]`
|
|
207
|
+
} else {
|
|
208
|
+
// 関数内
|
|
209
|
+
if (NakoGen.isValidIdentifier(name)) {
|
|
210
|
+
return name
|
|
211
|
+
} else {
|
|
212
|
+
return `__vars[${JSON.stringify(name)}]`
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* @param {string} name
|
|
219
|
+
* @returns {string}
|
|
220
|
+
*/
|
|
221
|
+
static getFuncName (name: string): string {
|
|
222
|
+
if (name.indexOf('__') >= 0) { // スコープがある場合
|
|
223
|
+
const a = name.split('__')
|
|
224
|
+
const scope = a[0]
|
|
225
|
+
const name3 = NakoGen.getFuncName(a[1])
|
|
226
|
+
return `${scope}__${name3}`
|
|
227
|
+
}
|
|
228
|
+
let name2 = name.replace(/[ぁ-ん]+$/, '')
|
|
229
|
+
if (name2 === '') { name2 = name }
|
|
230
|
+
return name2
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/** @param {Ast} node */
|
|
234
|
+
static convPrint (node: Ast): string {
|
|
235
|
+
return `__print(${node});`
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/** @param {Ast} node */
|
|
239
|
+
convRequire (node: Ast): string {
|
|
240
|
+
const moduleName = node.value
|
|
241
|
+
return this.convLineno(node, false) +
|
|
242
|
+
`__module['${moduleName}'] = require('${moduleName}');\n`
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* プログラムの実行に必要な関数定義を書き出す(グローバル領域)
|
|
247
|
+
* convGenの結果を利用するため、convGenの後に呼び出すこと。
|
|
248
|
+
* @param com
|
|
249
|
+
* @param opt
|
|
250
|
+
*/
|
|
251
|
+
getDefFuncCode (com: NakoCompiler, opt: NakoGenOptions): string {
|
|
252
|
+
let code = ''
|
|
253
|
+
// よく使う変数のショートカット
|
|
254
|
+
code += `const nakoVersion = { version: ${JSON.stringify(com.version)} }\n`
|
|
255
|
+
code += 'const __self = self;\n'
|
|
256
|
+
code += 'self.__self = self;\n'
|
|
257
|
+
code += 'const __varslist = self.__varslist;\n'
|
|
258
|
+
code += 'const __module = self.__module;\n'
|
|
259
|
+
code += 'const __v0 = self.__v0 = self.__varslist[0];\n'
|
|
260
|
+
code += 'const __v1 = self.__v1 = self.__varslist[1];\n'
|
|
261
|
+
code += 'const __vars = self.__vars = self.__varslist[2];\n'
|
|
262
|
+
// なでしこの関数定義を行う
|
|
263
|
+
let nakoFuncCode = ''
|
|
264
|
+
for (const key in this.nakoFuncList) {
|
|
265
|
+
const f = this.nakoFuncList[key].fn
|
|
266
|
+
const isAsync = this.nakoFuncList[key].asyncFn ? 'true' : 'false'
|
|
267
|
+
nakoFuncCode += '' +
|
|
268
|
+
`//[DEF_FUNC name='${key}' asyncFn=${isAsync}]\n` +
|
|
269
|
+
`self.__varslist[1]["${key}"]=${f};\n;` +
|
|
270
|
+
`//[/DEF_FUNC name='${key}']\n`
|
|
271
|
+
}
|
|
272
|
+
if (nakoFuncCode !== '') { code += '__v0.line=\'関数の定義\';\n' + nakoFuncCode }
|
|
273
|
+
|
|
274
|
+
// テストの定義を行う
|
|
275
|
+
if (opt.isTest) {
|
|
276
|
+
let testCode = 'const __tests = [];\n'
|
|
277
|
+
|
|
278
|
+
for (const key in this.nakoTestFuncs) {
|
|
279
|
+
const f = this.nakoTestFuncs[key].fn
|
|
280
|
+
testCode += `${f};\n;`
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
if (testCode !== '') {
|
|
284
|
+
code += '__v0.line=\'テストの定義\';\n'
|
|
285
|
+
code += testCode + '\n'
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
return code
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* プラグイン・オブジェクトを追加
|
|
294
|
+
* @param po プラグイン・オブジェクト
|
|
295
|
+
*/
|
|
296
|
+
addPlugin (po: FuncList): void {
|
|
297
|
+
return this.__self.addPlugin(po)
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* プラグイン・オブジェクトを追加(ブラウザ向け)
|
|
302
|
+
* @param name オブジェクト名
|
|
303
|
+
* @param po 関数リスト
|
|
304
|
+
*/
|
|
305
|
+
addPluginObject (name: string, po: FuncList): void {
|
|
306
|
+
this.__self.addPluginObject(name, po)
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* プラグイン・ファイルを追加(Node.js向け)
|
|
311
|
+
* @param objName オブジェクト名
|
|
312
|
+
* @param path ファイルパス
|
|
313
|
+
* @param po 登録するオブジェクト
|
|
314
|
+
*/
|
|
315
|
+
addPluginFile (objName: string, path: string, po: FuncList): void {
|
|
316
|
+
this.__self.addPluginFile(objName, path, po)
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* 関数を追加する
|
|
321
|
+
* @param key 関数名
|
|
322
|
+
* @param josi 助詞
|
|
323
|
+
* @param fn 関数
|
|
324
|
+
*/
|
|
325
|
+
addFunc (key: string, josi: FuncArgs, fn: any) {
|
|
326
|
+
this.__self.addFunc(key, josi, fn)
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* プラグイン関数を参照する
|
|
331
|
+
* @param key プラグイン関数の関数名
|
|
332
|
+
* @returns プラグイン・オブジェクト
|
|
333
|
+
*/
|
|
334
|
+
getFunc (key: string) {
|
|
335
|
+
return this.__self.getFunc(key)
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* 関数を先に登録してしまう
|
|
340
|
+
*/
|
|
341
|
+
registerFunction (ast: Ast) {
|
|
342
|
+
if (ast.type !== 'block') { throw NakoSyntaxError.fromNode('構文解析に失敗しています。構文は必ずblockが先頭になります', ast) }
|
|
343
|
+
|
|
344
|
+
/** 関数一覧 */
|
|
345
|
+
const funcList: {name: string; node:Ast}[] = []
|
|
346
|
+
// なでしこ関数を定義して this.nako_func[name] に定義する
|
|
347
|
+
const registFunc = (node: Ast) => {
|
|
348
|
+
if (!node.block) { return }
|
|
349
|
+
const blockList: Ast[] = (node.block instanceof Array) ? node.block : [node.block]
|
|
350
|
+
for (let i = 0; i < blockList.length; i++) {
|
|
351
|
+
const t = blockList[i]
|
|
352
|
+
if (t.type === 'def_func') {
|
|
353
|
+
if (!t.name) { throw new Error('[System Error] 関数の定義で関数名が指定されていない') }
|
|
354
|
+
const name: string = (t.name as Token).value
|
|
355
|
+
this.usedFuncSet.add(name)
|
|
356
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
357
|
+
this.__self.__varslist[1][name] = function () { } // 事前に適当な値を設定
|
|
358
|
+
this.varslistSet[1].names.add(name) // global
|
|
359
|
+
const meta = ((t.name) as Ast).meta // todo: 強制変換したが正しいかチェック
|
|
360
|
+
this.nakoFuncList[name] = {
|
|
361
|
+
josi: meta.josi,
|
|
362
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
363
|
+
fn: () => {},
|
|
364
|
+
type: 'func',
|
|
365
|
+
asyncFn: t.asyncFn
|
|
366
|
+
}
|
|
367
|
+
funcList.push({ name, node: t })
|
|
368
|
+
// eslint-disable-next-line brace-style
|
|
369
|
+
}
|
|
370
|
+
// 実行速度優先 などのオプションが付いている場合の処理
|
|
371
|
+
else if (t.type === 'speed_mode') {
|
|
372
|
+
if (!t.block) { continue }
|
|
373
|
+
if ((t.block as Ast).type === 'block') {
|
|
374
|
+
registFunc(t.block as Ast)
|
|
375
|
+
} else {
|
|
376
|
+
registFunc(t)
|
|
377
|
+
}
|
|
378
|
+
} else if (t.type === 'performance_monitor') {
|
|
379
|
+
if (!t.block) { continue }
|
|
380
|
+
if ((t.block as Ast).type === 'block') {
|
|
381
|
+
registFunc(t.block as Ast)
|
|
382
|
+
} else {
|
|
383
|
+
registFunc(t)
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
// 関数の登録
|
|
389
|
+
registFunc(ast)
|
|
390
|
+
|
|
391
|
+
// __self.__varslistの変更を反映
|
|
392
|
+
const initialNames: Set<string> = new Set()
|
|
393
|
+
if (this.speedMode.invalidSore === 0) {
|
|
394
|
+
initialNames.add('それ')
|
|
395
|
+
}
|
|
396
|
+
this.varsSet = { isFunction: false, names: initialNames, readonly: new Set() }
|
|
397
|
+
this.varslistSet = this.__self.__varslist.map((v) => ({ isFunction: false, names: new Set(Object.keys(v)), readonly: new Set() }))
|
|
398
|
+
this.varslistSet[2] = this.varsSet
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/**
|
|
402
|
+
* @param node
|
|
403
|
+
* @param opt
|
|
404
|
+
*/
|
|
405
|
+
convGen (node: Ast, opt: NakoGenOptions): string {
|
|
406
|
+
const result = this.convLineno(node, false) + this._convGen(node, true)
|
|
407
|
+
if (opt.isTest) {
|
|
408
|
+
return ''
|
|
409
|
+
} else {
|
|
410
|
+
return result
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* @param {Ast} node
|
|
416
|
+
* @param {boolean} isExpression
|
|
417
|
+
*/
|
|
418
|
+
_convGen (node: Ast|null, isExpression: boolean): string {
|
|
419
|
+
if (!node) { return '' }
|
|
420
|
+
let code = ''
|
|
421
|
+
if (node instanceof Array) {
|
|
422
|
+
for (let i = 0; i < node.length; i++) {
|
|
423
|
+
const n = node[i]
|
|
424
|
+
code += this._convGen(n, isExpression)
|
|
425
|
+
}
|
|
426
|
+
return code
|
|
427
|
+
}
|
|
428
|
+
if (node === null) { return 'null' }
|
|
429
|
+
if (node === undefined) { return 'undefined' }
|
|
430
|
+
if (typeof (node) !== 'object') { return '' + node }
|
|
431
|
+
// switch
|
|
432
|
+
switch (node.type) {
|
|
433
|
+
case 'nop':
|
|
434
|
+
break
|
|
435
|
+
case 'block':
|
|
436
|
+
// eslint-disable-next-line no-case-declarations
|
|
437
|
+
const modName: string = NakoLexer.filenameToModName(node.file || '')
|
|
438
|
+
code += `;__self.__modName='${modName}';\n`
|
|
439
|
+
if (!node.block) { return code }
|
|
440
|
+
// eslint-disable-next-line no-case-declarations
|
|
441
|
+
const blocks: any = (node.block instanceof Array) ? node.block : [node.block]
|
|
442
|
+
for (let i = 0; i < blocks.length; i++) {
|
|
443
|
+
const b = blocks[i]
|
|
444
|
+
code += this._convGen(b, false)
|
|
445
|
+
}
|
|
446
|
+
break
|
|
447
|
+
case 'comment':
|
|
448
|
+
case 'eol':
|
|
449
|
+
code += this.convComment(node)
|
|
450
|
+
break
|
|
451
|
+
case 'break':
|
|
452
|
+
code += this.convCheckLoop(node, 'break')
|
|
453
|
+
break
|
|
454
|
+
case 'continue':
|
|
455
|
+
code += this.convCheckLoop(node, 'continue')
|
|
456
|
+
break
|
|
457
|
+
case 'end':
|
|
458
|
+
code += '__varslist[0][\'終\']();'
|
|
459
|
+
break
|
|
460
|
+
case 'number':
|
|
461
|
+
code += node.value
|
|
462
|
+
break
|
|
463
|
+
case 'string':
|
|
464
|
+
code += this.convString(node)
|
|
465
|
+
break
|
|
466
|
+
case 'def_local_var':
|
|
467
|
+
code += this.convDefLocalVar(node)
|
|
468
|
+
break
|
|
469
|
+
case 'def_local_varlist':
|
|
470
|
+
code += this.convDefLocalVarlist(node)
|
|
471
|
+
break
|
|
472
|
+
case 'let':
|
|
473
|
+
code += this.convLet(node)
|
|
474
|
+
break
|
|
475
|
+
case 'inc':
|
|
476
|
+
code += this.convInc(node)
|
|
477
|
+
break
|
|
478
|
+
case 'word':
|
|
479
|
+
case 'variable':
|
|
480
|
+
code += this.convGetVar(node)
|
|
481
|
+
break
|
|
482
|
+
case 'op':
|
|
483
|
+
case 'calc':
|
|
484
|
+
code += this.convOp(node)
|
|
485
|
+
break
|
|
486
|
+
case 'renbun':
|
|
487
|
+
code += this.convRenbun(node)
|
|
488
|
+
break
|
|
489
|
+
case 'not':
|
|
490
|
+
code += '((' + this._convGen(node.value as Ast, true) + ')?0:1)'
|
|
491
|
+
break
|
|
492
|
+
case 'func':
|
|
493
|
+
case 'func_pointer':
|
|
494
|
+
case 'calc_func':
|
|
495
|
+
code += this.convCallFunc(node, isExpression)
|
|
496
|
+
break
|
|
497
|
+
case 'if':
|
|
498
|
+
code += this.convIf(node)
|
|
499
|
+
break
|
|
500
|
+
case 'tikuji':
|
|
501
|
+
code += this.convTikuji(node)
|
|
502
|
+
break
|
|
503
|
+
case 'for':
|
|
504
|
+
code += this.convFor(node)
|
|
505
|
+
break
|
|
506
|
+
case 'foreach':
|
|
507
|
+
code += this.convForeach(node)
|
|
508
|
+
break
|
|
509
|
+
case 'repeat_times':
|
|
510
|
+
code += this.convRepeatTimes(node)
|
|
511
|
+
break
|
|
512
|
+
case 'speed_mode':
|
|
513
|
+
code += this.convSpeedMode(node, isExpression)
|
|
514
|
+
break
|
|
515
|
+
case 'performance_monitor':
|
|
516
|
+
code += this.convPerformanceMonitor(node, isExpression)
|
|
517
|
+
break
|
|
518
|
+
case 'while':
|
|
519
|
+
code += this.convWhile(node)
|
|
520
|
+
break
|
|
521
|
+
case 'atohantei':
|
|
522
|
+
code += this.convAtohantei(node)
|
|
523
|
+
break
|
|
524
|
+
case 'switch':
|
|
525
|
+
code += this.convSwitch(node)
|
|
526
|
+
break
|
|
527
|
+
case 'let_array':
|
|
528
|
+
code += this.convLetArray(node)
|
|
529
|
+
break
|
|
530
|
+
case '配列参照':
|
|
531
|
+
code += this.convRefArray(node)
|
|
532
|
+
break
|
|
533
|
+
case 'json_array':
|
|
534
|
+
code += this.convJsonArray(node)
|
|
535
|
+
break
|
|
536
|
+
case 'json_obj':
|
|
537
|
+
code += this.convJsonObj(node)
|
|
538
|
+
break
|
|
539
|
+
case 'func_obj':
|
|
540
|
+
code += this.convFuncObj(node)
|
|
541
|
+
break
|
|
542
|
+
case 'bool':
|
|
543
|
+
code += (node.value) ? 'true' : 'false'
|
|
544
|
+
break
|
|
545
|
+
case 'null':
|
|
546
|
+
code += 'null'
|
|
547
|
+
break
|
|
548
|
+
case 'def_test':
|
|
549
|
+
code += this.convDefTest(node)
|
|
550
|
+
break
|
|
551
|
+
case 'def_func':
|
|
552
|
+
code += this.convDefFunc(node)
|
|
553
|
+
break
|
|
554
|
+
case 'return':
|
|
555
|
+
code += this.convReturn(node)
|
|
556
|
+
break
|
|
557
|
+
case 'try_except':
|
|
558
|
+
code += this.convTryExcept(node)
|
|
559
|
+
break
|
|
560
|
+
case 'require':
|
|
561
|
+
code += this.convRequire(node)
|
|
562
|
+
break
|
|
563
|
+
default:
|
|
564
|
+
throw new Error('System Error: unknown_type=' + node.type)
|
|
565
|
+
}
|
|
566
|
+
return code
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
/** 変数を検索 */
|
|
570
|
+
findVar (name: string): FindVarResult|null {
|
|
571
|
+
// __vars ? (ローカル変数)
|
|
572
|
+
if (this.varslistSet.length > 3 && this.varsSet.names.has(name)) {
|
|
573
|
+
return { i: this.varslistSet.length - 1, name, isTop: true, js: this.varname(name) }
|
|
574
|
+
}
|
|
575
|
+
// __varslist ?
|
|
576
|
+
for (let i = 2; i >= 0; i--) {
|
|
577
|
+
if (this.varslistSet[i].names.has(name)) {
|
|
578
|
+
// ユーザーの定義したグローバル変数 (__varslist[2]) は、変数展開されている(そのままの名前で定義されている)可能性がある。
|
|
579
|
+
// それ以外の変数は、必ず__varslistに入っている。
|
|
580
|
+
return { i, name, isTop: false, js: `__varslist[${i}][${JSON.stringify(name)}]` }
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
return null
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
/**
|
|
588
|
+
* 定義済みの変数の参照
|
|
589
|
+
* @param {string} name
|
|
590
|
+
* @param {Ast} position
|
|
591
|
+
*/
|
|
592
|
+
genVar (name: string, position: Ast): string {
|
|
593
|
+
const res = this.findVar(name)
|
|
594
|
+
const lno = position.line
|
|
595
|
+
if (res === null) {
|
|
596
|
+
// 定義されていない名前の参照は変数の定義とみなす。
|
|
597
|
+
// 多くの場合はundefined値を持つ変数であり分かりづらいバグを引き起こすが、
|
|
598
|
+
// 「ナデシコする」などの命令の中で定義された変数の参照の場合があるため警告に留める。
|
|
599
|
+
// ただし、自動的に定義される変数『引数』『それ』などは例外 #952
|
|
600
|
+
if (name === '引数' || name === 'それ' || name === '対象' || name === '対象キー') {
|
|
601
|
+
// デフォルト定義されている変数名
|
|
602
|
+
} else {
|
|
603
|
+
if (this.warnUndefinedVar) {
|
|
604
|
+
// main__は省略して表示するように。 #1223
|
|
605
|
+
const dispName = name.replace(/^main__(.+)$/, '$1')
|
|
606
|
+
this.__self.getLogger().warn(`変数『${dispName}』は定義されていません。`, position)
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
this.varsSet.names.add(name)
|
|
610
|
+
return this.varname(name)
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
const i = res.i
|
|
614
|
+
// システム関数・変数の場合
|
|
615
|
+
if (i === 0) {
|
|
616
|
+
const pv = this.__self.getNakoFunc(name)
|
|
617
|
+
if (!pv) { return `${res.js}/*err:${lno}*/` }
|
|
618
|
+
if (pv.type === 'const' || pv.type === 'var') { return res.js }
|
|
619
|
+
if (pv.type === 'func') {
|
|
620
|
+
if (!pv.josi || pv.josi.length === 0) { return `(${res.js}())` }
|
|
621
|
+
|
|
622
|
+
throw NakoSyntaxError.fromNode(`『${name}』が複文で使われました。単文で記述してください。(v1非互換)`, position)
|
|
623
|
+
}
|
|
624
|
+
throw NakoSyntaxError.fromNode(`『${name}』は関数であり参照できません。`, position)
|
|
625
|
+
}
|
|
626
|
+
return res.js
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
convGetVar (node: Ast): string {
|
|
630
|
+
const name = node.value
|
|
631
|
+
return this.genVar(name, node)
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
convComment (node:Ast): string {
|
|
635
|
+
let commentSrc = String(node.value)
|
|
636
|
+
commentSrc = commentSrc.replace(/\n/g, '¶')
|
|
637
|
+
const lineNo = this.convLineno(node, false)
|
|
638
|
+
if (commentSrc === '' && lineNo === '') { return ';' }
|
|
639
|
+
if (commentSrc === '') {
|
|
640
|
+
return ';' + lineNo + '\n'
|
|
641
|
+
}
|
|
642
|
+
return ';' + lineNo + '//' + commentSrc + '\n'
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
convReturn (node: Ast): string {
|
|
646
|
+
// 関数の中であれば利用可能
|
|
647
|
+
if (this.varsSet.names.has('!関数')) { throw NakoSyntaxError.fromNode('『戻る』がありますが、関数定義内のみで使用可能です。', node) }
|
|
648
|
+
|
|
649
|
+
const lno = this.convLineno(node, false)
|
|
650
|
+
let value
|
|
651
|
+
if (node.value) {
|
|
652
|
+
value = this._convGen(node.value, true)
|
|
653
|
+
} else
|
|
654
|
+
if (this.speedMode.invalidSore === 0) {
|
|
655
|
+
value = this.varname('それ')
|
|
656
|
+
} else {
|
|
657
|
+
return lno + 'return;'
|
|
658
|
+
}
|
|
659
|
+
if (this.warnUndefinedReturnUserFunc === 0) {
|
|
660
|
+
return lno + `return ${value};`
|
|
661
|
+
} else {
|
|
662
|
+
return lno + `return (function(a){if(a===undefined){__self.logger.warn('ユーザ関数からundefinedが返されています',{file:'${node.file}',line:${node.line}});};return a;})(${value});`
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
convCheckLoop (node: Ast, cmd: string): string {
|
|
667
|
+
// ループの中であれば利用可能
|
|
668
|
+
if (!this.flagLoop) {
|
|
669
|
+
const cmdj = (cmd === 'continue') ? '続ける' : '抜ける'
|
|
670
|
+
throw NakoSyntaxError.fromNode(`『${cmdj}』文がありますが、それは繰り返しの中で利用してください。`, node)
|
|
671
|
+
}
|
|
672
|
+
return this.convLineno(node) + cmd + ';'
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
convDefFuncCommon (node: Ast, name: string): string {
|
|
676
|
+
// パフォーマンスモニタ:ユーザ関数のinjectの定義
|
|
677
|
+
let performanceMonitorInjectAtStart = ''
|
|
678
|
+
let performanceMonitorInjectAtEnd = ''
|
|
679
|
+
if (this.performanceMonitor.userFunction !== 0) {
|
|
680
|
+
let key = name
|
|
681
|
+
if (!key) {
|
|
682
|
+
if (typeof this.performanceMonitor.mumeiId === 'undefined') {
|
|
683
|
+
this.performanceMonitor.mumeiId = 0
|
|
684
|
+
}
|
|
685
|
+
this.performanceMonitor.mumeiId++
|
|
686
|
+
key = `anous_${this.performanceMonitor.mumeiId}`
|
|
687
|
+
}
|
|
688
|
+
performanceMonitorInjectAtStart = 'const performanceMonitorEnd = (function (key, type) {\n' +
|
|
689
|
+
'const uf_start = performance.now() * 1000;\n' +
|
|
690
|
+
'return function () {\n' +
|
|
691
|
+
'const el_time = performance.now() * 1000 - uf_start;\n' +
|
|
692
|
+
'if (!__self.__performance_monitor) {\n' +
|
|
693
|
+
'__self.__performance_monitor={};\n' +
|
|
694
|
+
'__self.__performance_monitor[key] = { called:1, totel_usec: el_time, min_usec: el_time, max_usec: el_time, type: type };\n' +
|
|
695
|
+
'} else if (!__self.__performance_monitor[key]) {\n' +
|
|
696
|
+
'__self.__performance_monitor[key] = { called:1, totel_usec: el_time, min_usec: el_time, max_usec: el_time, type: type };\n' +
|
|
697
|
+
'} else {\n' +
|
|
698
|
+
'__self.__performance_monitor[key].called++;\n' +
|
|
699
|
+
'__self.__performance_monitor[key].totel_usec+=el_time;\n' +
|
|
700
|
+
'if(__self.__performance_monitor[key].min_usec>el_time){__self.__performance_monitor[key].min_usec=el_time;}\n' +
|
|
701
|
+
'if(__self.__performance_monitor[key].max_usec<el_time){__self.__performance_monitor[key].max_usec=el_time;}\n' +
|
|
702
|
+
`}};})('${key}', 'user');` +
|
|
703
|
+
'try {\n'
|
|
704
|
+
performanceMonitorInjectAtEnd = '} finally { performanceMonitorEnd(); }\n'
|
|
705
|
+
}
|
|
706
|
+
let variableDeclarations = ''
|
|
707
|
+
const popStack = ''
|
|
708
|
+
const initialNames: Set<string> = new Set()
|
|
709
|
+
if (this.speedMode.invalidSore === 0) {
|
|
710
|
+
initialNames.add('それ')
|
|
711
|
+
}
|
|
712
|
+
this.varsSet = { isFunction: true, names: initialNames, readonly: new Set() }
|
|
713
|
+
// ローカル変数をPUSHする
|
|
714
|
+
this.varslistSet.push(this.varsSet)
|
|
715
|
+
// JSの引数と引数をバインド
|
|
716
|
+
variableDeclarations += ' var 引数 = arguments;\n'
|
|
717
|
+
// ローカル変数を生成
|
|
718
|
+
variableDeclarations += ' var __vars = {};\n'
|
|
719
|
+
// 宣言済みの名前を保存
|
|
720
|
+
const varsDeclared = Array.from(this.varsSet.names.values())
|
|
721
|
+
let code = ''
|
|
722
|
+
// 引数をローカル変数に設定
|
|
723
|
+
const meta = (!name) ? node.meta : (node.name as Ast).meta
|
|
724
|
+
for (let i = 0; i < meta.varnames.length; i++) {
|
|
725
|
+
const word = meta.varnames[i]
|
|
726
|
+
if (this.warnUndefinedCalledUserFuncArgs === 0) {
|
|
727
|
+
code += ` ${this.varname(word)} = arguments[${i}];\n`
|
|
728
|
+
} else
|
|
729
|
+
if (name) {
|
|
730
|
+
code += ` ${this.varname(word)} = (function(a){if(a===undefined){__self.logger.warn('ユーザ関数(${name})の引数(${this.varname(word)})にundefinedが渡されました',{file:'${node.file}',line:${node.line}});};return a;})(arguments[${i}]);\n`
|
|
731
|
+
} else {
|
|
732
|
+
code += ` ${this.varname(word)} = (function(a){if(a===undefined){__self.logger.warn('匿名関数の引数(${this.varname(word)})にundefinedが渡されました',{file:'${node.file}',line:${node.line}});};return a;})(arguments[${i}]);\n`
|
|
733
|
+
}
|
|
734
|
+
this.varsSet.names.add(word)
|
|
735
|
+
}
|
|
736
|
+
// 関数定義は、グローバル領域で。
|
|
737
|
+
if (name) {
|
|
738
|
+
this.usedFuncSet.add(name)
|
|
739
|
+
this.varslistSet[1].names.add(name)
|
|
740
|
+
if (this.nakoFuncList[name] === undefined) {
|
|
741
|
+
// 既に generate で作成済みのはず(念のため)
|
|
742
|
+
this.nakoFuncList[name] = {
|
|
743
|
+
josi: (node.name as Ast).meta.josi,
|
|
744
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
745
|
+
fn: () => {},
|
|
746
|
+
type: 'func',
|
|
747
|
+
asyncFn: false
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
// ブロックを解析
|
|
752
|
+
const oldUsedAsyncFn = this.usedAsyncFn
|
|
753
|
+
this.usedAsyncFn = false
|
|
754
|
+
const block = this._convGen(node.block as Ast, false)
|
|
755
|
+
code += block.split('\n').map((line) => ' ' + line).join('\n') + '\n'
|
|
756
|
+
// 関数の最後に、変数「それ」をreturnするようにする
|
|
757
|
+
if (this.speedMode.invalidSore === 0) {
|
|
758
|
+
code += ` return (${this.varname('それ')});\n`
|
|
759
|
+
}
|
|
760
|
+
// パフォーマンスモニタ:ユーザ関数のinject
|
|
761
|
+
code += performanceMonitorInjectAtEnd
|
|
762
|
+
// ブロックでasyncFnを使ったか
|
|
763
|
+
if (name && this.usedAsyncFn) {
|
|
764
|
+
this.nakoFuncList[name].asyncFn = true
|
|
765
|
+
}
|
|
766
|
+
// 関数の末尾に、ローカル変数をPOP
|
|
767
|
+
|
|
768
|
+
// 関数内で定義されたローカル変数の宣言
|
|
769
|
+
for (const name of Array.from(this.varsSet.names.values())) {
|
|
770
|
+
if (!varsDeclared.includes(name)) {
|
|
771
|
+
if (NakoGen.isValidIdentifier(name)) {
|
|
772
|
+
variableDeclarations += ` var ${name};\n`
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
if (this.speedMode.invalidSore === 0) {
|
|
777
|
+
if (NakoGen.isValidIdentifier('それ')) {
|
|
778
|
+
variableDeclarations += ' var それ = \'\';\n'
|
|
779
|
+
} else {
|
|
780
|
+
variableDeclarations += ` ${this.varname('それ')} = '';`
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
// usedAsyncFnの値に応じて関数定義の方法を変更
|
|
784
|
+
const tof = (this.usedAsyncFn) ? topOfFunctionAsync : topOfFunction
|
|
785
|
+
// 関数コード全体を構築
|
|
786
|
+
code = tof + performanceMonitorInjectAtStart + variableDeclarations + code + popStack
|
|
787
|
+
code += endOfFunction
|
|
788
|
+
|
|
789
|
+
// 名前があれば、関数を登録する
|
|
790
|
+
if (name) {
|
|
791
|
+
this.nakoFuncList[name].fn = code
|
|
792
|
+
this.nakoFuncList[name].asyncFn = this.usedAsyncFn
|
|
793
|
+
meta.asyncFn = this.usedAsyncFn
|
|
794
|
+
}
|
|
795
|
+
this.usedAsyncFn = oldUsedAsyncFn // 以前の値を戻す
|
|
796
|
+
|
|
797
|
+
this.varslistSet.pop()
|
|
798
|
+
this.varsSet = this.varslistSet[this.varslistSet.length - 1]
|
|
799
|
+
if (name) { this.__self.__varslist[1][name] = code }
|
|
800
|
+
return code
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
convDefTest (node: Ast): string {
|
|
804
|
+
const name = (node.name as Ast).value
|
|
805
|
+
let code = `__tests.push({ name: '${name}', f: () => {\n`
|
|
806
|
+
|
|
807
|
+
// ブロックを解析
|
|
808
|
+
const block = this._convGen(node.block as Ast, false)
|
|
809
|
+
|
|
810
|
+
code += ` ${block}\n` +
|
|
811
|
+
'}});'
|
|
812
|
+
|
|
813
|
+
this.nakoTestFuncs[name] = {
|
|
814
|
+
josi: (node.name as Ast).meta.josi,
|
|
815
|
+
fn: code,
|
|
816
|
+
type: 'test_func'
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
// ★この時点ではテストコードを生成しない★
|
|
820
|
+
// プログラム冒頭でコード生成時にテストの定義を行う
|
|
821
|
+
return ''
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
convDefFunc (node: Ast): string {
|
|
825
|
+
// ※ [関数定義のメモ]
|
|
826
|
+
// ※ 関数の定義はプログラムの冒頭に移される。
|
|
827
|
+
// ※ そのため、生成されたコードはここでは返さない
|
|
828
|
+
// ※ registerFunction を参照
|
|
829
|
+
if (!node.name) { return '' }
|
|
830
|
+
const name = NakoGen.getFuncName((node.name as Ast).value as string)
|
|
831
|
+
this.convDefFuncCommon(node, name)
|
|
832
|
+
return ''
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
convFuncObj (node: Ast): string {
|
|
836
|
+
return this.convDefFuncCommon(node, '')
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
convJsonObj (node: Ast): string {
|
|
840
|
+
const list = node.value
|
|
841
|
+
const codelist = list.map((e: {key: Ast, value: Ast}) => {
|
|
842
|
+
const key = this._convGen(e.key, true)
|
|
843
|
+
const val = this._convGen(e.value, true)
|
|
844
|
+
return `${key}:${val}`
|
|
845
|
+
})
|
|
846
|
+
return '{' + codelist.join(',') + '}'
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
convJsonArray (node: Ast): string {
|
|
850
|
+
const list = node.value
|
|
851
|
+
const codelist = list.map((e: Ast) => {
|
|
852
|
+
return this._convGen(e, true)
|
|
853
|
+
})
|
|
854
|
+
return '[' + codelist.join(',') + ']'
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
convRefArray (node: Ast): string {
|
|
858
|
+
const name = this._convGen(node.name as Ast, true)
|
|
859
|
+
const list: Ast[] | undefined = node.index
|
|
860
|
+
let code = name
|
|
861
|
+
if (!list) { return code }
|
|
862
|
+
for (let i = 0; i < list.length; i++) {
|
|
863
|
+
const idx = this._convGen(list[i] as Ast, true)
|
|
864
|
+
code += '[' + idx + ']'
|
|
865
|
+
}
|
|
866
|
+
return code
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
convLetArray (node: Ast): string {
|
|
870
|
+
const name = this._convGen(node.name as Ast, true)
|
|
871
|
+
const list: Ast[] = node.index || []
|
|
872
|
+
let codeInit = ''
|
|
873
|
+
let code = name
|
|
874
|
+
let codeArray = ''
|
|
875
|
+
// codeInit?
|
|
876
|
+
if (node.checkInit) {
|
|
877
|
+
const arrayDefCode = '[0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0]'
|
|
878
|
+
codeInit += `\n/*配列初期化*/if (!(${name} instanceof Array)) { ${name} = ${arrayDefCode}; console.log('初期化:${name}') };`
|
|
879
|
+
for (let i = 0; i < list.length - 1; i++) {
|
|
880
|
+
const idx = this._convGen(list[i], true)
|
|
881
|
+
codeArray += `[${idx}]`
|
|
882
|
+
codeInit += `\n/*配列初期化${i}*/if (!(${name}${codeArray} instanceof Array)) { ${name}${codeArray} = ${arrayDefCode}; };`
|
|
883
|
+
// codeInit += `\n/*配列初期化${i}*/if (!(${name}${codeArray} instanceof Array)) { ${name}${codeArray} = ${arrayDefCode}; console.log('初期化:${i}:${name}${codeArray}',JSON.stringify(${name})) }; `
|
|
884
|
+
}
|
|
885
|
+
codeInit += '\n'
|
|
886
|
+
}
|
|
887
|
+
// array
|
|
888
|
+
for (let i = 0; i < list.length; i++) {
|
|
889
|
+
const idx = this._convGen(list[i], true)
|
|
890
|
+
code += '[' + idx + ']'
|
|
891
|
+
}
|
|
892
|
+
const value = this._convGen(node.value, true)
|
|
893
|
+
code += ' = ' + value + ';\n'
|
|
894
|
+
// generate code
|
|
895
|
+
const src = this.convLineno(node, false) + codeInit + code
|
|
896
|
+
return src
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
convGenLoop (node: Ast): string {
|
|
900
|
+
const tmpflag = this.flagLoop
|
|
901
|
+
this.flagLoop = true
|
|
902
|
+
try {
|
|
903
|
+
return this._convGen(node, false)
|
|
904
|
+
} finally {
|
|
905
|
+
this.flagLoop = tmpflag
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
convFor (node: Ast): string {
|
|
910
|
+
// ループ変数について
|
|
911
|
+
let word
|
|
912
|
+
if (node.word !== null) { // ループ変数を使う時
|
|
913
|
+
const varName = (node.word as Token).value // todo: Forの最初のパラメータが Token か Astか確認
|
|
914
|
+
this.varsSet.names.add(varName)
|
|
915
|
+
word = this.varname(varName)
|
|
916
|
+
} else {
|
|
917
|
+
this.varsSet.names.add('dummy')
|
|
918
|
+
word = this.varname('dummy')
|
|
919
|
+
}
|
|
920
|
+
const idLoop = this.loopId++
|
|
921
|
+
const varI = `$nako_i${idLoop}`
|
|
922
|
+
// ループ条件を確認
|
|
923
|
+
const kara = this._convGen(node.from as Ast, true)
|
|
924
|
+
const made = this._convGen(node.to as Ast, true)
|
|
925
|
+
let inc = '1'
|
|
926
|
+
if (node.inc !== null || node.inc === undefined || node.inc === 'null') {
|
|
927
|
+
inc = this._convGen(node.inc as Ast, true)
|
|
928
|
+
}
|
|
929
|
+
// ループ内のブロック内容を得る
|
|
930
|
+
const block = this.convGenLoop(node.block as Ast)
|
|
931
|
+
// ループ条件を変数に入れる用
|
|
932
|
+
const varFrom = `$nako_from${idLoop}`
|
|
933
|
+
const varTo = `$nako_to${idLoop}`
|
|
934
|
+
let sorePrefex = ''
|
|
935
|
+
if (this.speedMode.invalidSore === 0) {
|
|
936
|
+
sorePrefex = `${this.varname('それ')} = `
|
|
937
|
+
}
|
|
938
|
+
const code =
|
|
939
|
+
`\n//[FOR id=${idLoop}]\n` +
|
|
940
|
+
`const ${varFrom} = ${kara};\n` +
|
|
941
|
+
`const ${varTo} = ${made};\n` +
|
|
942
|
+
`if (${varFrom} <= ${varTo}) { // up\n` +
|
|
943
|
+
` for (let ${varI} = ${varFrom}; ${varI} <= ${varTo}; ${varI}+= ${inc}) {\n` +
|
|
944
|
+
` ${sorePrefex}${word} = ${varI};\n` +
|
|
945
|
+
` ${block}\n` +
|
|
946
|
+
' };\n' +
|
|
947
|
+
'} else { // down\n' +
|
|
948
|
+
` for (let ${varI} = ${varFrom}; ${varI} >= ${varTo}; ${varI}-= ${inc}) {\n` +
|
|
949
|
+
` ${sorePrefex}${word} = ${varI};` + '\n' +
|
|
950
|
+
` ${block}\n` +
|
|
951
|
+
' };\n' +
|
|
952
|
+
`};\n//[/FOR id=${idLoop}]\n`
|
|
953
|
+
return this.convLineno(node, false) + code
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
convForeach (node: Ast): string {
|
|
957
|
+
let target
|
|
958
|
+
if (node.target === null) {
|
|
959
|
+
if (this.speedMode.invalidSore === 0) {
|
|
960
|
+
target = this.varname('それ')
|
|
961
|
+
} else {
|
|
962
|
+
throw NakoSyntaxError.fromNode('『反復』の対象がありません。', node)
|
|
963
|
+
}
|
|
964
|
+
} else { target = this._convGen(node.target as Ast, true) }
|
|
965
|
+
|
|
966
|
+
// blockより早く変数を定義する必要がある
|
|
967
|
+
let nameS = '__v0["対象"]'
|
|
968
|
+
if (node.name) {
|
|
969
|
+
nameS = this.varname((node.name as Ast).value)
|
|
970
|
+
this.varsSet.names.add((node.name as Ast).value)
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
const block = this.convGenLoop(node.block as Ast)
|
|
974
|
+
const id = this.loopId++
|
|
975
|
+
const key = '__v0["対象キー"]'
|
|
976
|
+
let sorePrefex = ''
|
|
977
|
+
if (this.speedMode.invalidSore === 0) {
|
|
978
|
+
sorePrefex = `${this.varname('それ')} = `
|
|
979
|
+
}
|
|
980
|
+
const code =
|
|
981
|
+
`let $nako_foreach_v${id}=${target};\n` +
|
|
982
|
+
`for (let $nako_i${id} in $nako_foreach_v${id})` + '{\n' +
|
|
983
|
+
` if ($nako_foreach_v${id}.hasOwnProperty($nako_i${id})) {\n` +
|
|
984
|
+
` ${nameS} = ${sorePrefex}$nako_foreach_v${id}[$nako_i${id}];` + '\n' +
|
|
985
|
+
` ${key} = $nako_i${id};\n` +
|
|
986
|
+
` ${block}\n` +
|
|
987
|
+
' }\n' +
|
|
988
|
+
'};\n'
|
|
989
|
+
return this.convLineno(node, false) + code
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
convRepeatTimes (node: Ast): string {
|
|
993
|
+
const id = this.loopId++
|
|
994
|
+
const value = this._convGen(node.value, true)
|
|
995
|
+
const block = this.convGenLoop(node.block as Ast)
|
|
996
|
+
const kaisu = '__v0["回数"]'
|
|
997
|
+
let sorePrefex = ''
|
|
998
|
+
if (this.speedMode.invalidSore === 0) {
|
|
999
|
+
sorePrefex = `${this.varname('それ')} = `
|
|
1000
|
+
}
|
|
1001
|
+
const code =
|
|
1002
|
+
`let $nako_times_v${id} = ${value};\n` +
|
|
1003
|
+
`for(var $nako_i${id} = 1; $nako_i${id} <= $nako_times_v${id}; $nako_i${id}++)` + '{\n' +
|
|
1004
|
+
` ${sorePrefex}${kaisu} = $nako_i${id};` + '\n' +
|
|
1005
|
+
' ' + block + '\n}\n'
|
|
1006
|
+
return this.convLineno(node, false) + code
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
/**
|
|
1010
|
+
* @param {Ast} node
|
|
1011
|
+
* @param {boolean} isExpression
|
|
1012
|
+
*/
|
|
1013
|
+
convSpeedMode (node: Ast, isExpression: boolean): string {
|
|
1014
|
+
if (!node.options) { return '' }
|
|
1015
|
+
const prev = { ...this.speedMode }
|
|
1016
|
+
if (node.options['行番号無し']) {
|
|
1017
|
+
this.speedMode.lineNumbers++
|
|
1018
|
+
}
|
|
1019
|
+
if (node.options['暗黙の型変換無し']) {
|
|
1020
|
+
this.speedMode.implicitTypeCasting++
|
|
1021
|
+
}
|
|
1022
|
+
if (node.options['強制ピュア']) {
|
|
1023
|
+
this.speedMode.forcePure++
|
|
1024
|
+
}
|
|
1025
|
+
if (node.options['それ無効']) {
|
|
1026
|
+
this.speedMode.invalidSore++
|
|
1027
|
+
}
|
|
1028
|
+
try {
|
|
1029
|
+
return this._convGen(node.block as Ast, isExpression)
|
|
1030
|
+
} finally {
|
|
1031
|
+
this.speedMode = prev
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
/**
|
|
1036
|
+
* @param {Ast} node
|
|
1037
|
+
* @param {boolean} isExpression
|
|
1038
|
+
*/
|
|
1039
|
+
convPerformanceMonitor (node: Ast, isExpression: boolean): string {
|
|
1040
|
+
const prev = { ...this.performanceMonitor }
|
|
1041
|
+
if (!node.options) { return '' }
|
|
1042
|
+
if (node.options['ユーザ関数']) {
|
|
1043
|
+
this.performanceMonitor.userFunction++
|
|
1044
|
+
}
|
|
1045
|
+
if (node.options['システム関数本体']) {
|
|
1046
|
+
this.performanceMonitor.systemFunctionBody++
|
|
1047
|
+
}
|
|
1048
|
+
if (node.options['システム関数']) {
|
|
1049
|
+
this.performanceMonitor.systemFunction++
|
|
1050
|
+
}
|
|
1051
|
+
try {
|
|
1052
|
+
return this._convGen(node.block as Ast, isExpression)
|
|
1053
|
+
} finally {
|
|
1054
|
+
this.performanceMonitor = prev
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
convWhile (node: Ast): string {
|
|
1059
|
+
const cond = this._convGen(node.cond as Ast, true)
|
|
1060
|
+
const block = this.convGenLoop(node.block as Ast)
|
|
1061
|
+
const code =
|
|
1062
|
+
`while (${cond})` + '{\n' +
|
|
1063
|
+
` ${block}` + '\n' +
|
|
1064
|
+
'}\n'
|
|
1065
|
+
return this.convLineno(node, false) + code
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
convAtohantei (node: Ast): string {
|
|
1069
|
+
const id = this.loopId++
|
|
1070
|
+
const varId = `$nako_i${id}`
|
|
1071
|
+
const cond = this._convGen(node.cond as Ast, true)
|
|
1072
|
+
const block = this.convGenLoop(node.block as Ast)
|
|
1073
|
+
const code =
|
|
1074
|
+
'for(;;) {\n' +
|
|
1075
|
+
` ${block}\n` +
|
|
1076
|
+
` let ${varId} = ${cond};\n` +
|
|
1077
|
+
` if (${varId}) { continue } else { break }\n` +
|
|
1078
|
+
'}\n\n'
|
|
1079
|
+
return this.convLineno(node, false) + code
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
convSwitch (node: Ast): string {
|
|
1083
|
+
const value: string = this._convGen(node.value, true)
|
|
1084
|
+
const cases: any[] = node.cases || []
|
|
1085
|
+
let body = ''
|
|
1086
|
+
for (let i = 0; i < cases.length; i++) {
|
|
1087
|
+
const cvalue = cases[i][0]
|
|
1088
|
+
const cblock = this.convGenLoop(cases[i][1])
|
|
1089
|
+
if (cvalue.type === '違えば') {
|
|
1090
|
+
body += ' default:\n'
|
|
1091
|
+
} else {
|
|
1092
|
+
const cvalueCode = this._convGen(cvalue, true)
|
|
1093
|
+
body += ` case ${cvalueCode}:\n`
|
|
1094
|
+
}
|
|
1095
|
+
body += ` ${cblock}\n` +
|
|
1096
|
+
' break\n'
|
|
1097
|
+
}
|
|
1098
|
+
const code =
|
|
1099
|
+
`switch (${value})` + '{\n' +
|
|
1100
|
+
`${body}` + '\n' +
|
|
1101
|
+
'}\n'
|
|
1102
|
+
return this.convLineno(node, false) + code
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
convIf (node: Ast): string {
|
|
1106
|
+
const expr = this._convGen(node.expr as Ast, true)
|
|
1107
|
+
const block = this._convGen(node.block as Ast, false)
|
|
1108
|
+
const falseBlock = (node.false_block === null)
|
|
1109
|
+
? ''
|
|
1110
|
+
: 'else {' + this._convGen(node.false_block as Ast, false) + '};\n'
|
|
1111
|
+
return this.convLineno(node, false) +
|
|
1112
|
+
`if (${expr}) {\n ${block}\n}` + falseBlock + ';\n'
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1115
|
+
convTikuji (node: Ast): string {
|
|
1116
|
+
const pid = this.loopId++
|
|
1117
|
+
// gen tikuji blocks
|
|
1118
|
+
const curName = `__tikuji${pid}`
|
|
1119
|
+
let code = `const ${curName} = []\n`
|
|
1120
|
+
const blocks: Ast[] = (node.blocks) ? node.blocks : []
|
|
1121
|
+
for (let i = 0; i < blocks.length; i++) {
|
|
1122
|
+
const block = this._convGen(blocks[i], false).replace(/\s+$/, '') + '\n'
|
|
1123
|
+
const blockLineNo = this.convLineno(blocks[i], true)
|
|
1124
|
+
const blockCode =
|
|
1125
|
+
`${curName}.push(function(resolve, reject) {\n` +
|
|
1126
|
+
' __self.resolve = resolve;\n' +
|
|
1127
|
+
' __self.reject = reject;\n' +
|
|
1128
|
+
' __self.resolveCount = 0;\n' +
|
|
1129
|
+
` ${blockLineNo}\n` +
|
|
1130
|
+
` ${block}` +
|
|
1131
|
+
' if (__self.resolveCount === 0) resolve();\n' +
|
|
1132
|
+
// eslint-disable-next-line no-template-curly-in-string
|
|
1133
|
+
'}); // end of tikuji__${pid}[{$i}]\n'
|
|
1134
|
+
code += blockCode
|
|
1135
|
+
}
|
|
1136
|
+
code += `// end of ${curName} \n`
|
|
1137
|
+
// gen error block
|
|
1138
|
+
let errorCode =
|
|
1139
|
+
` ${curName}.splice(0);\n` + // clear
|
|
1140
|
+
' __v0["エラーメッセージ"]=errMsg;\n'
|
|
1141
|
+
if (node.errorBlock != null) {
|
|
1142
|
+
const errBlock = this._convGen(node.errorBlock as Ast, false).replace(/\s+$/, '') + '\n'
|
|
1143
|
+
errorCode += errBlock
|
|
1144
|
+
}
|
|
1145
|
+
code += `const ${curName}__reject = function(errMsg){\n${errorCode}};\n`
|
|
1146
|
+
// gen run block
|
|
1147
|
+
code += '__self.resolve = undefined;\n'
|
|
1148
|
+
code += `const ${curName}__resolve = function(){\n`
|
|
1149
|
+
code += ' setTimeout(function(){\n'
|
|
1150
|
+
code += ` if (${curName}.length == 0) {return}\n`
|
|
1151
|
+
code += ` const f = ${curName}.shift()\n`
|
|
1152
|
+
code += ` f(${curName}__resolve, ${curName}__reject);\n`
|
|
1153
|
+
code += ' }, 0);\n'
|
|
1154
|
+
code += '};\n'
|
|
1155
|
+
code += `${curName}__resolve()\n`
|
|
1156
|
+
return this.convLineno(node, false) + code
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
convFuncGetArgsCalcType (_funcName: string, _func: any, node: Ast): [any, any] {
|
|
1160
|
+
const args = []
|
|
1161
|
+
const opts: {[key: string]: boolean} = {}
|
|
1162
|
+
const nodeArgs = (node.args) ? node.args : []
|
|
1163
|
+
for (let i = 0; i < nodeArgs.length; i++) {
|
|
1164
|
+
const arg = nodeArgs[i]
|
|
1165
|
+
if (i === 0 && arg === null && this.speedMode.invalidSore === 0) {
|
|
1166
|
+
args.push(this.varname('それ'))
|
|
1167
|
+
opts.sore = true
|
|
1168
|
+
} else {
|
|
1169
|
+
args.push(this._convGen(arg, true))
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
1172
|
+
return [args, opts]
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
getPluginList () {
|
|
1176
|
+
const r = []
|
|
1177
|
+
for (const name in this.__self.__module) { r.push(name) }
|
|
1178
|
+
return r
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
/**
|
|
1182
|
+
* 関数の呼び出し
|
|
1183
|
+
* @param {Ast} node
|
|
1184
|
+
* @param {boolean} isExpression
|
|
1185
|
+
* @returns string コード
|
|
1186
|
+
*/
|
|
1187
|
+
convCallFunc (node: Ast, isExpression: boolean): string {
|
|
1188
|
+
const funcName = NakoGen.getFuncName(node.name as string)
|
|
1189
|
+
const res = this.findVar(funcName)
|
|
1190
|
+
if (res === null) {
|
|
1191
|
+
throw NakoSyntaxError.fromNode(`関数『${funcName}』が見当たりません。有効プラグイン=[` + this.getPluginList().join(', ') + ']', node)
|
|
1192
|
+
}
|
|
1193
|
+
// どの関数を呼び出すのか関数を特定する
|
|
1194
|
+
let func
|
|
1195
|
+
if (res.i === 0) { // plugin function
|
|
1196
|
+
func = this.__self.getFunc(funcName)
|
|
1197
|
+
if (!func) { throw new Error(`[System Error] 関数「${funcName}」NakoCompiler.nakoFuncList の不整合があります。`) }
|
|
1198
|
+
if (func.type !== 'func') {
|
|
1199
|
+
throw NakoSyntaxError.fromNode(`『${funcName}』は関数ではありません。`, node)
|
|
1200
|
+
}
|
|
1201
|
+
} else {
|
|
1202
|
+
func = this.nakoFuncList[funcName]
|
|
1203
|
+
// 無名関数の可能性
|
|
1204
|
+
if (func === undefined) { func = { return_none: false } }
|
|
1205
|
+
}
|
|
1206
|
+
// 関数の参照渡しか?
|
|
1207
|
+
if (node.type === 'func_pointer') {
|
|
1208
|
+
return res.js
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
// 関数の参照渡しでない場合
|
|
1212
|
+
// 関数定義より助詞を一つずつ調べる
|
|
1213
|
+
const argsInfo = this.convFuncGetArgsCalcType(funcName, func, node)
|
|
1214
|
+
const args = argsInfo[0]
|
|
1215
|
+
const argsOpts = argsInfo[1]
|
|
1216
|
+
// function
|
|
1217
|
+
this.usedFuncSet.add(funcName)
|
|
1218
|
+
|
|
1219
|
+
// 関数呼び出しで、引数の末尾にthisを追加する-システム情報を参照するため
|
|
1220
|
+
args.push('__self')
|
|
1221
|
+
let funcDef = 'function'
|
|
1222
|
+
let funcBegin = ''
|
|
1223
|
+
let funcEnd = ''
|
|
1224
|
+
// setter?
|
|
1225
|
+
if (node.setter) {
|
|
1226
|
+
funcBegin += ';__self.isSetter = true;\n'
|
|
1227
|
+
funcEnd += ';__self.isSetter = false;\n'
|
|
1228
|
+
}
|
|
1229
|
+
// 関数内 (__varslist.length > 3) からプラグイン関数 (res.i === 0) を呼び出すとき、 そのプラグイン関数がpureでなければ
|
|
1230
|
+
// 呼び出しの直前に全てのローカル変数をthis.__localsに入れる。
|
|
1231
|
+
if (res.i === 0 && this.varslistSet.length > 3 && func.pure !== true && this.speedMode.forcePure === 0) { // undefinedはfalseとみなす
|
|
1232
|
+
// 展開されたローカル変数の列挙
|
|
1233
|
+
const localVars = []
|
|
1234
|
+
for (const name of Array.from(this.varsSet.names.values())) {
|
|
1235
|
+
if (NakoGen.isValidIdentifier(name)) {
|
|
1236
|
+
localVars.push({ str: JSON.stringify(name), js: this.varname(name) })
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1239
|
+
|
|
1240
|
+
// --- 実行前 ---
|
|
1241
|
+
|
|
1242
|
+
// 全ての展開されていないローカル変数を __self.__locals にコピーする
|
|
1243
|
+
funcBegin += '__self.__locals = __vars;\n'
|
|
1244
|
+
|
|
1245
|
+
// 全ての展開されたローカル変数を __self.__locals に保存する
|
|
1246
|
+
for (const v of localVars) {
|
|
1247
|
+
funcBegin += `__self.__locals[${v.str}] = ${v.js};\n`
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1250
|
+
// --- 実行後 ---
|
|
1251
|
+
|
|
1252
|
+
// 全ての展開されたローカル変数を __self.__locals から受け取る
|
|
1253
|
+
// 「それ」は関数の実行結果を受け取るために使うためスキップ。
|
|
1254
|
+
for (const v of localVars) {
|
|
1255
|
+
if (v.js !== 'それ') {
|
|
1256
|
+
funcEnd += `${v.js} = __self.__locals[${v.str}];\n`
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
// 変数「それ」が補完されていることをヒントとして出力
|
|
1261
|
+
if (argsOpts.sore) { funcBegin += '/*[sore]*/' }
|
|
1262
|
+
|
|
1263
|
+
const indent = (text: string, n: number) => {
|
|
1264
|
+
let result = ''
|
|
1265
|
+
for (const line of text.split('\n')) {
|
|
1266
|
+
if (line !== '') {
|
|
1267
|
+
result += ' '.repeat(n) + line + '\n'
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
return result
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
// 関数呼び出しコードの構築
|
|
1274
|
+
let argsCode: string
|
|
1275
|
+
if ((this.warnUndefinedCallingUserFunc === 0 && res.i !== 0) || (this.warnUndefinedCallingSystemFunc === 0 && res.i === 0)) {
|
|
1276
|
+
argsCode = args.join(',')
|
|
1277
|
+
} else {
|
|
1278
|
+
argsCode = ''
|
|
1279
|
+
args.forEach((arg: string) => {
|
|
1280
|
+
if (arg === '__self') {
|
|
1281
|
+
argsCode += `,${arg}`
|
|
1282
|
+
} else {
|
|
1283
|
+
if (res.i === 0) {
|
|
1284
|
+
argsCode += `,(function(a){if(a===undefined){__self.logger.warn('命令『${funcName}』の引数にundefinedを渡しています。',{file:'${node.file}',line:${node.line}});};return a;})(${arg})`
|
|
1285
|
+
} else {
|
|
1286
|
+
argsCode += `,(function(a){if(a===undefined){__self.logger.warn('ユーザ関数『${funcName}』の引数にundefinedを渡しています。',{file:'${node.file}',line:${node.line}});};return a;})(${arg})`
|
|
1287
|
+
}
|
|
1288
|
+
}
|
|
1289
|
+
})
|
|
1290
|
+
argsCode = argsCode.substring(1)
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1293
|
+
let funcCall = `${res.js}(${argsCode})`
|
|
1294
|
+
if (func.asyncFn) {
|
|
1295
|
+
funcDef = `async ${funcDef}`
|
|
1296
|
+
funcCall = `await ${funcCall}`
|
|
1297
|
+
this.numAsyncFn++
|
|
1298
|
+
this.usedAsyncFn = true
|
|
1299
|
+
}
|
|
1300
|
+
if (res.i === 0 && this.performanceMonitor.systemFunctionBody !== 0) {
|
|
1301
|
+
let key = funcName
|
|
1302
|
+
if (!key) {
|
|
1303
|
+
if (typeof this.performanceMonitor.mumeiId === 'undefined') {
|
|
1304
|
+
this.performanceMonitor.mumeiId = 0
|
|
1305
|
+
}
|
|
1306
|
+
this.performanceMonitor.mumeiId++
|
|
1307
|
+
key = `anous_${this.performanceMonitor.mumeiId}`
|
|
1308
|
+
}
|
|
1309
|
+
funcCall = `(${funcDef} (key, type) {\n` +
|
|
1310
|
+
'const sbf_start = performance.now() * 1000;\n' +
|
|
1311
|
+
'try {\n' +
|
|
1312
|
+
'return ' + funcCall + ';\n' +
|
|
1313
|
+
'} finally {\n' +
|
|
1314
|
+
'const sbl_time = performance.now() * 1000 - sbf_start;\n' +
|
|
1315
|
+
'if (!__self.__performance_monitor) {\n' +
|
|
1316
|
+
'__self.__performance_monitor={};\n' +
|
|
1317
|
+
'__self.__performance_monitor[key] = { called:1, totel_usec: sbl_time, min_usec: sbl_time, max_usec: sbl_time, type: type };\n' +
|
|
1318
|
+
'} else if (!__self.__performance_monitor[key]) {\n' +
|
|
1319
|
+
'__self.__performance_monitor[key] = { called:1, totel_usec: sbl_time, min_usec: sbl_time, max_usec: sbl_time, type: type };\n' +
|
|
1320
|
+
'} else {\n' +
|
|
1321
|
+
'__self.__performance_monitor[key].called++;\n' +
|
|
1322
|
+
'__self.__performance_monitor[key].totel_usec+=sbl_time;\n' +
|
|
1323
|
+
'if(__self.__performance_monitor[key].min_usec>sbl_time){__self.__performance_monitor[key].min_usec=sbl_time;}\n' +
|
|
1324
|
+
'if(__self.__performance_monitor[key].max_usec<sbl_time){__self.__performance_monitor[key].max_usec=sbl_time;}\n' +
|
|
1325
|
+
`}}})('${funcName}_body', 'sysbody')\n`
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1328
|
+
let code = ''
|
|
1329
|
+
if (func.return_none) {
|
|
1330
|
+
// 戻り値のない関数の場合
|
|
1331
|
+
if (funcEnd === '') {
|
|
1332
|
+
if (funcBegin === '') {
|
|
1333
|
+
code = `${funcCall};\n`
|
|
1334
|
+
} else {
|
|
1335
|
+
code = `${funcBegin} ${funcCall};\n`
|
|
1336
|
+
}
|
|
1337
|
+
} else {
|
|
1338
|
+
code = `${funcBegin}try {\n${indent(funcCall, 1)};\n} finally {\n${indent(funcEnd, 1)}}\n`
|
|
1339
|
+
}
|
|
1340
|
+
} else {
|
|
1341
|
+
// 戻り値のある関数の場合
|
|
1342
|
+
let sorePrefex = ''
|
|
1343
|
+
if (this.speedMode.invalidSore === 0) {
|
|
1344
|
+
sorePrefex = `${this.varname('それ')} = `
|
|
1345
|
+
}
|
|
1346
|
+
if (funcBegin === '' && funcEnd === '') {
|
|
1347
|
+
code = `(${sorePrefex}${funcCall})`
|
|
1348
|
+
} else {
|
|
1349
|
+
if (funcEnd === '') {
|
|
1350
|
+
code = `(${funcDef}(){\n${indent(`${funcBegin};\nreturn ${sorePrefex} ${funcCall}`, 1)}}).call(this)`
|
|
1351
|
+
} else {
|
|
1352
|
+
code = `(${funcDef}(){\n${indent(`${funcBegin}try {\n${indent(`return ${sorePrefex}${funcCall};`, 1)}\n} finally {\n${indent(funcEnd, 1)}}`, 1)}}).call(this)`
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
// ...して
|
|
1356
|
+
if (node.josi === 'して' || (node.josi === '' && !isExpression)) { code += ';\n' }
|
|
1357
|
+
}
|
|
1358
|
+
|
|
1359
|
+
if (res.i === 0 && this.performanceMonitor.systemFunction !== 0) {
|
|
1360
|
+
code = '(function (key, type) {\n' +
|
|
1361
|
+
'const sf_start = performance.now() * 1000;\n' +
|
|
1362
|
+
'try {\n' +
|
|
1363
|
+
'return ' + code + ';\n' +
|
|
1364
|
+
'} finally {\n' +
|
|
1365
|
+
'const sl_time = performance.now() * 1000 - sf_start;\n' +
|
|
1366
|
+
'if (!__self.__performance_monitor) {\n' +
|
|
1367
|
+
'__self.__performance_monitor={};\n' +
|
|
1368
|
+
'__self.__performance_monitor[key] = { called:1, totel_usec: sl_time, min_usec: sl_time, max_usec: sl_time, type: type };\n' +
|
|
1369
|
+
'} else if (!__self.__performance_monitor[key]) {\n' +
|
|
1370
|
+
'__self.__performance_monitor[key] = { called:1, totel_usec: sl_time, min_usec: sl_time, max_usec: sl_time, type: type };\n' +
|
|
1371
|
+
'} else {\n' +
|
|
1372
|
+
'__self.__performance_monitor[key].called++;\n' +
|
|
1373
|
+
'__self.__performance_monitor[key].totel_usec+=sl_time;\n' +
|
|
1374
|
+
'if(__self.__performance_monitor[key].min_usec>sl_time){__self.__performance_monitor[key].min_usec=sl_time;}\n' +
|
|
1375
|
+
'if(__self.__performance_monitor[key].max_usec<sl_time){__self.__performance_monitor[key].max_usec=sl_time;}\n' +
|
|
1376
|
+
`}}})('${funcName}_sys', 'system')\n`
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1379
|
+
return code
|
|
1380
|
+
}
|
|
1381
|
+
|
|
1382
|
+
convRenbun (node: Ast): string {
|
|
1383
|
+
const right = this._convGen(node.right as Ast, true)
|
|
1384
|
+
const left = this._convGen(node.left as Ast, false)
|
|
1385
|
+
return `(function(){${left}; return ${right}}).call(this)`
|
|
1386
|
+
}
|
|
1387
|
+
|
|
1388
|
+
convOp (node: Ast): string {
|
|
1389
|
+
const OP_TBL: {[key: string]: string} = { // トークン名からJS演算子
|
|
1390
|
+
'&': '+""+',
|
|
1391
|
+
eq: '==',
|
|
1392
|
+
noteq: '!=',
|
|
1393
|
+
'===': '===',
|
|
1394
|
+
'!==': '!==',
|
|
1395
|
+
gt: '>',
|
|
1396
|
+
lt: '<',
|
|
1397
|
+
gteq: '>=',
|
|
1398
|
+
lteq: '<=',
|
|
1399
|
+
and: '&&',
|
|
1400
|
+
or: '||',
|
|
1401
|
+
shift_l: '<<',
|
|
1402
|
+
shift_r: '>>',
|
|
1403
|
+
shift_r0: '>>>',
|
|
1404
|
+
'÷': '/'
|
|
1405
|
+
}
|
|
1406
|
+
let op: string = node.operator || '' // 演算子
|
|
1407
|
+
let right = this._convGen(node.right as Ast, true)
|
|
1408
|
+
let left = this._convGen(node.left as Ast, true)
|
|
1409
|
+
if (op === '+' && this.speedMode.implicitTypeCasting === 0) {
|
|
1410
|
+
if (node.left && (node.left as Ast).type !== 'number') {
|
|
1411
|
+
left = `parseFloat(${left})`
|
|
1412
|
+
}
|
|
1413
|
+
if (node.right && (node.right as Ast).type !== 'number') {
|
|
1414
|
+
right = `parseFloat(${right})`
|
|
1415
|
+
}
|
|
1416
|
+
}
|
|
1417
|
+
// 階乗
|
|
1418
|
+
if (op === '^') { return `(Math.pow(${left}, ${right}))` }
|
|
1419
|
+
// 整数の割り算 #1152
|
|
1420
|
+
if (op === '÷÷') { return `(Math.floor(${left} / ${right}))` }
|
|
1421
|
+
|
|
1422
|
+
// 一般的なオペレータに変換
|
|
1423
|
+
if (OP_TBL[op]) { op = OP_TBL[op] }
|
|
1424
|
+
//
|
|
1425
|
+
return `(${left} ${op} ${right})`
|
|
1426
|
+
}
|
|
1427
|
+
|
|
1428
|
+
convInc (node: Ast): string {
|
|
1429
|
+
// もし値が省略されていたら、変数「それ」に代入する
|
|
1430
|
+
let value = null
|
|
1431
|
+
if (this.speedMode.invalidSore === 0) { value = this.varname('それ') }
|
|
1432
|
+
if (node.value) { value = this._convGen(node.value, true) }
|
|
1433
|
+
if (value == null) {
|
|
1434
|
+
throw NakoSyntaxError.fromNode('加算する先の変数名がありません。', node)
|
|
1435
|
+
}
|
|
1436
|
+
// 変数名
|
|
1437
|
+
const name: string = (node.name as Ast).value
|
|
1438
|
+
let res = this.findVar(name)
|
|
1439
|
+
let code = ''
|
|
1440
|
+
if (res === null) {
|
|
1441
|
+
this.varsSet.names.add(name)
|
|
1442
|
+
res = this.findVar(name)
|
|
1443
|
+
if (!res) { throw new Error('『増』または『減』で変数が見当たりません。') }
|
|
1444
|
+
}
|
|
1445
|
+
const jsName = res.js
|
|
1446
|
+
// 自動初期化するか
|
|
1447
|
+
code += `if (typeof(${jsName}) === 'undefined') { ${jsName} = 0; }`
|
|
1448
|
+
code += `${jsName} += ${value}`
|
|
1449
|
+
return ';' + this.convLineno(node, false) + code + '\n'
|
|
1450
|
+
}
|
|
1451
|
+
|
|
1452
|
+
convLet (node: Ast): string {
|
|
1453
|
+
// もし値が省略されていたら、変数「それ」に代入する
|
|
1454
|
+
let value = null
|
|
1455
|
+
if (this.speedMode.invalidSore === 0) { value = this.varname('それ') }
|
|
1456
|
+
if (node.value) { value = this._convGen(node.value, true) }
|
|
1457
|
+
if (value == null) {
|
|
1458
|
+
throw NakoSyntaxError.fromNode('代入する先の変数名がありません。', node)
|
|
1459
|
+
}
|
|
1460
|
+
// 変数名
|
|
1461
|
+
const name: string = (node.name as Ast).value
|
|
1462
|
+
const res = this.findVar(name)
|
|
1463
|
+
let code = ''
|
|
1464
|
+
if (res === null) {
|
|
1465
|
+
this.varsSet.names.add(name)
|
|
1466
|
+
code = `${this.varname(name)} = ${value};`
|
|
1467
|
+
} else {
|
|
1468
|
+
// 定数ならエラーを出す
|
|
1469
|
+
if (this.varslistSet[res.i].readonly.has(name)) {
|
|
1470
|
+
throw NakoSyntaxError.fromNode(
|
|
1471
|
+
`定数『${name}』は既に定義済みなので、値を代入することはできません。`, node)
|
|
1472
|
+
}
|
|
1473
|
+
code = `${res.js} = ${value};`
|
|
1474
|
+
}
|
|
1475
|
+
|
|
1476
|
+
return ';' + this.convLineno(node, false) + code + '\n'
|
|
1477
|
+
}
|
|
1478
|
+
|
|
1479
|
+
convDefLocalVar (node: Ast): string {
|
|
1480
|
+
const value = (node.value === null) ? 'null' : this._convGen(node.value, true)
|
|
1481
|
+
const name = (node.name as Ast).value
|
|
1482
|
+
const vtype = node.vartype // 変数 or 定数
|
|
1483
|
+
// 二重定義?
|
|
1484
|
+
if (this.varsSet.names.has(name)) { throw NakoSyntaxError.fromNode(`${vtype}『${name}』の二重定義はできません。`, node) }
|
|
1485
|
+
|
|
1486
|
+
//
|
|
1487
|
+
this.varsSet.names.add(name)
|
|
1488
|
+
if (vtype === '定数') {
|
|
1489
|
+
this.varsSet.readonly.add(name)
|
|
1490
|
+
}
|
|
1491
|
+
const code = `${this.varname(name)}=${value};\n`
|
|
1492
|
+
return this.convLineno(node, false) + code
|
|
1493
|
+
}
|
|
1494
|
+
|
|
1495
|
+
// #563 複数変数への代入
|
|
1496
|
+
convDefLocalVarlist (node: Ast): string {
|
|
1497
|
+
let code = ''
|
|
1498
|
+
const vtype = node.vartype // 変数 or 定数
|
|
1499
|
+
const value = (node.value === null) ? 'null' : this._convGen(node.value, true)
|
|
1500
|
+
this.loopId++
|
|
1501
|
+
const varI = `$nako_i${this.loopId}`
|
|
1502
|
+
code += `${varI}=${value}\n`
|
|
1503
|
+
code += `if (!(${varI} instanceof Array)) { ${varI}=[${varI}] }\n`
|
|
1504
|
+
const names: Ast[] = (node.names) ? node.names : []
|
|
1505
|
+
for (let i = 0; i < names.length; i++) {
|
|
1506
|
+
const nameObj = names[i]
|
|
1507
|
+
const name = nameObj.value
|
|
1508
|
+
// 二重定義?
|
|
1509
|
+
if (this.varsSet.names.has(name)) {
|
|
1510
|
+
// 複数変数文では、二重定義も許容する #1027
|
|
1511
|
+
// throw NakoSyntaxError.fromNode(`${vtype}『${name}』の二重定義はできません。`, node)
|
|
1512
|
+
}
|
|
1513
|
+
this.varsSet.names.add(name)
|
|
1514
|
+
if (vtype === '定数') {
|
|
1515
|
+
this.varsSet.readonly.add(name)
|
|
1516
|
+
}
|
|
1517
|
+
const vname = this.varname(name)
|
|
1518
|
+
code += `${vname}=${varI}[${i}];\n`
|
|
1519
|
+
}
|
|
1520
|
+
return this.convLineno(node, false) + code
|
|
1521
|
+
}
|
|
1522
|
+
|
|
1523
|
+
convString (node: Ast): string {
|
|
1524
|
+
let value = '' + node.value
|
|
1525
|
+
const mode = node.mode
|
|
1526
|
+
value = value.replace(/\\/g, '\\\\')
|
|
1527
|
+
value = value.replace(/"/g, '\\"')
|
|
1528
|
+
value = value.replace(/\r/g, '\\r')
|
|
1529
|
+
value = value.replace(/\n/g, '\\n')
|
|
1530
|
+
if (mode === 'ex') {
|
|
1531
|
+
const rf = (a: string, name: string) => {
|
|
1532
|
+
return '"+' + this.genVar(name, node) + '+"'
|
|
1533
|
+
}
|
|
1534
|
+
value = value.replace(/\{(.+?)\}/g, rf)
|
|
1535
|
+
value = value.replace(/{(.+?)}/g, rf)
|
|
1536
|
+
}
|
|
1537
|
+
return '"' + value + '"'
|
|
1538
|
+
}
|
|
1539
|
+
|
|
1540
|
+
convTryExcept (node: Ast): string {
|
|
1541
|
+
const block = this._convGen(node.block as Ast, false)
|
|
1542
|
+
const errBlock = this._convGen(node.errBlock as Ast, false)
|
|
1543
|
+
return this.convLineno(node, false) +
|
|
1544
|
+
`try {\n${block}\n} catch (e) {\n` +
|
|
1545
|
+
' __v0["エラーメッセージ"] = e.message;\n' +
|
|
1546
|
+
';\n' +
|
|
1547
|
+
`${errBlock}}\n`
|
|
1548
|
+
}
|
|
1549
|
+
|
|
1550
|
+
getUsedFuncSet (): Set<string> {
|
|
1551
|
+
return this.usedFuncSet
|
|
1552
|
+
}
|
|
1553
|
+
|
|
1554
|
+
getPluginInitCode (): string {
|
|
1555
|
+
// プラグインの初期化関数を実行する
|
|
1556
|
+
let code = ''
|
|
1557
|
+
let pluginCode = ''
|
|
1558
|
+
for (const name in this.__self.__module) {
|
|
1559
|
+
const initkey = `!${name}:初期化`
|
|
1560
|
+
if (this.varslistSet[0].names.has(initkey)) {
|
|
1561
|
+
this.usedFuncSet.add(`!${name}:初期化`)
|
|
1562
|
+
pluginCode += `__v0["!${name}:初期化"](__self);\n`
|
|
1563
|
+
}
|
|
1564
|
+
}
|
|
1565
|
+
if (pluginCode !== '') { code += '__v0.line=\'l0:プラグインの初期化\';\n' + pluginCode }
|
|
1566
|
+
return code
|
|
1567
|
+
}
|
|
1568
|
+
}
|
|
1569
|
+
|
|
1570
|
+
export interface NakoGenResult {
|
|
1571
|
+
// なでしこの実行環境ありの場合
|
|
1572
|
+
runtimeEnv: string;
|
|
1573
|
+
// JavaScript単体で動かす場合
|
|
1574
|
+
standalone: string;
|
|
1575
|
+
// コード生成に使ったNakoGenのインスタンス
|
|
1576
|
+
gen: any
|
|
1577
|
+
}
|
|
1578
|
+
|
|
1579
|
+
/**
|
|
1580
|
+
* @param com
|
|
1581
|
+
* @param ast
|
|
1582
|
+
* @param opt
|
|
1583
|
+
*/
|
|
1584
|
+
export function generateJS (com: NakoCompiler, ast: Ast, opt: NakoGenOptions): NakoGenResult {
|
|
1585
|
+
const gen = new NakoGen(com)
|
|
1586
|
+
|
|
1587
|
+
// ※ [関数定義に関するコード生成のヒント]
|
|
1588
|
+
// ※ 関数の名前だけを(1)で登録して、(2)で実際に関数のコードを生成する。
|
|
1589
|
+
// ※ ただし(2)では生成するだけなので、(3)でプログラム冒頭に関数定義のコードを記述する。
|
|
1590
|
+
// この順番を変えることはできない (グローバル変数が認識できなくなったり、関数定義のタイミングがずれる)
|
|
1591
|
+
|
|
1592
|
+
// (1) ユーザー定義関数をシステムに登録する
|
|
1593
|
+
gen.registerFunction(ast)
|
|
1594
|
+
|
|
1595
|
+
// (2) JSコードを生成する
|
|
1596
|
+
let js = gen.convGen(ast, opt)
|
|
1597
|
+
|
|
1598
|
+
// (3) JSコードを実行するための事前ヘッダ部分の生成
|
|
1599
|
+
const jsInit = gen.getDefFuncCode(com, opt)
|
|
1600
|
+
|
|
1601
|
+
// テストの実行
|
|
1602
|
+
if (js && opt.isTest) {
|
|
1603
|
+
js += '\n__self._runTests(__tests);\n'
|
|
1604
|
+
}
|
|
1605
|
+
// async method
|
|
1606
|
+
if (gen.numAsyncFn > 0) {
|
|
1607
|
+
const asyncMain = '__nako3async' + (new Date()).getTime() + '_' + ('' + Math.random()).replace('.', '_') + '__'
|
|
1608
|
+
js = `
|
|
1609
|
+
// --------------------------------------------------
|
|
1610
|
+
// <nadesiko3::gen::async times="${gen.numAsyncFn}">
|
|
1611
|
+
async function ${asyncMain}(self) {
|
|
1612
|
+
${jsInit}
|
|
1613
|
+
${js}
|
|
1614
|
+
} // end of ${asyncMain}
|
|
1615
|
+
${asyncMain}.call(self, self).catch(err => {
|
|
1616
|
+
self.numFailures++
|
|
1617
|
+
throw new NakoRuntimeError(err, self.__v0.line) // エラー位置を認識
|
|
1618
|
+
})
|
|
1619
|
+
// <nadesiko3::gen::async>
|
|
1620
|
+
// --------------------------------------------------
|
|
1621
|
+
`
|
|
1622
|
+
} else {
|
|
1623
|
+
js = `
|
|
1624
|
+
// --------------------------------------------------
|
|
1625
|
+
try {
|
|
1626
|
+
${jsInit}
|
|
1627
|
+
${js}
|
|
1628
|
+
} catch (err) {
|
|
1629
|
+
self.numFailures++
|
|
1630
|
+
throw new NakoRuntimeError(err, self.__v0.line) // エラー位置を認識
|
|
1631
|
+
}
|
|
1632
|
+
// --------------------------------------------------
|
|
1633
|
+
`
|
|
1634
|
+
}
|
|
1635
|
+
// デバッグメッセージ
|
|
1636
|
+
com.getLogger().trace('--- generate ---\n' + js)
|
|
1637
|
+
let codeImportFiles = ''
|
|
1638
|
+
const importNames = []
|
|
1639
|
+
for (const f of opt.importFiles) {
|
|
1640
|
+
if (f === 'nako_errors.mjs') { continue }
|
|
1641
|
+
const ff = 'nako3runtime_' + f.replace(/\.(js|mjs)$/, '').replace(/[^a-zA-Z0-9_]/g, '_')
|
|
1642
|
+
importNames.push(ff)
|
|
1643
|
+
codeImportFiles += `import ${ff} from './nako3runtime/${f}'\n`
|
|
1644
|
+
}
|
|
1645
|
+
const standaloneJSCode = `\
|
|
1646
|
+
// <standaloneCode>
|
|
1647
|
+
// 将来的に ESModule に対応する #1217
|
|
1648
|
+
import path from 'path'
|
|
1649
|
+
import { NakoRuntimeError } from './nako3runtime/nako_errors.mjs'
|
|
1650
|
+
${codeImportFiles}
|
|
1651
|
+
const self = {}
|
|
1652
|
+
self.coreVersion = '${com.coreVersion}'
|
|
1653
|
+
self.version = '${com.version}'
|
|
1654
|
+
self.logger = {
|
|
1655
|
+
error: (message) => { console.error(message) },
|
|
1656
|
+
warn: (message) => { console.warn(message) },
|
|
1657
|
+
send: (level, message) => { console.log(message) },
|
|
1658
|
+
};
|
|
1659
|
+
self.__varslist = [{}, {}, {}]
|
|
1660
|
+
self.__v0 = self.__varslist[0]
|
|
1661
|
+
self.initFuncList = []
|
|
1662
|
+
self.clearFuncList = []
|
|
1663
|
+
// Copy module functions
|
|
1664
|
+
for (const mod of [${importNames.join(', ')}]) {
|
|
1665
|
+
for (const funcName in mod) {
|
|
1666
|
+
if (funcName === '初期化') {
|
|
1667
|
+
self.initFuncList.push(mod[funcName].fn)
|
|
1668
|
+
continue
|
|
1669
|
+
}
|
|
1670
|
+
if (funcName === '!クリア') {
|
|
1671
|
+
self.clearFuncList.push(mod[funcName].fn)
|
|
1672
|
+
continue
|
|
1673
|
+
}
|
|
1674
|
+
self.__varslist[0][funcName] = mod[funcName].fn
|
|
1675
|
+
}
|
|
1676
|
+
}
|
|
1677
|
+
self.__vars = self.__varslist[2];
|
|
1678
|
+
self.__module = {};
|
|
1679
|
+
self.__locals = {};
|
|
1680
|
+
self.__genMode = 'sync';
|
|
1681
|
+
|
|
1682
|
+
// プラグインの初期化コードを実行
|
|
1683
|
+
self.initFuncList.map(f => f(self))
|
|
1684
|
+
|
|
1685
|
+
try {
|
|
1686
|
+
${opt.codeStandalone}
|
|
1687
|
+
// <JS>
|
|
1688
|
+
${js}
|
|
1689
|
+
// </JS>
|
|
1690
|
+
// プラグインのクリアコードを実行
|
|
1691
|
+
self.clearFuncList.map(f => f(self))
|
|
1692
|
+
} catch (err) {
|
|
1693
|
+
self.logger.error(err);
|
|
1694
|
+
throw err;
|
|
1695
|
+
}
|
|
1696
|
+
// </standaloneCode>
|
|
1697
|
+
`
|
|
1698
|
+
// ---
|
|
1699
|
+
const initCode = gen.getPluginInitCode()
|
|
1700
|
+
const runtimeEnvCode = `
|
|
1701
|
+
// runtimeEnv
|
|
1702
|
+
${NakoError.toString()}
|
|
1703
|
+
${NakoRuntimeError.toString()}
|
|
1704
|
+
const self = this
|
|
1705
|
+
${opt.codeEnv}
|
|
1706
|
+
${jsInit}
|
|
1707
|
+
${initCode}
|
|
1708
|
+
${js}
|
|
1709
|
+
// end of runtimeEnv
|
|
1710
|
+
`
|
|
1711
|
+
return {
|
|
1712
|
+
// なでしこの実行環境ありの場合(thisが有効)
|
|
1713
|
+
runtimeEnv: runtimeEnvCode,
|
|
1714
|
+
// JavaScript単体で動かす場合
|
|
1715
|
+
standalone: standaloneJSCode,
|
|
1716
|
+
// コード生成に使ったNakoGenのインスタンス
|
|
1717
|
+
gen
|
|
1718
|
+
}
|
|
1719
|
+
}
|