diff --git a/core/src/nako_lex_rules.mts b/core/src/nako_lex_rules.mts index 2c7f2173..9fdbdc00 100644 --- a/core/src/nako_lex_rules.mts +++ b/core/src/nako_lex_rules.mts @@ -3,7 +3,6 @@ * なでしこ3字句解析のためのルール */ -import { NakoLexerError } from './nako_errors.mjs' import { josiRE, removeJosiMap } from './nako_josi_list.mjs' import { TokenType } from './nako_token.mjs' diff --git a/core/src/nako_parser3.mts b/core/src/nako_parser3.mts index cdcee368..45d8ab95 100644 --- a/core/src/nako_parser3.mts +++ b/core/src/nako_parser3.mts @@ -139,7 +139,7 @@ export class NakoParser extends NakoParserBase { if (this.check('エラー監視')) { return this.yTryExcept() } if (this.accept(['抜ける'])) { return { type: 'break', josi: '', ...map, end: this.peekSourceMap() } } if (this.accept(['続ける'])) { return { type: 'continue', josi: '', ...map, end: this.peekSourceMap() } } - if (this.check('??')) { return this.yPrint() } + if (this.check('??')) { return this.yDebugPrint() } // 実行モードの指定 if (this.accept(['DNCLモード'])) { return this.yDNCLMode(1) } if (this.accept(['DNCL2モード'])) { return this.yDNCLMode(2) } @@ -699,9 +699,8 @@ export class NakoParser extends NakoParserBase { /** * 表示(関数)を返す 「??」のエイリアスで利用 (#1745) - * @returns {AstCallFunc | null} */ - yPrint (): AstCallFunc | null { + yDebugPrint (): AstCallFunc | null { const map = this.peekSourceMap() const t = this.get() // skip '??' if (!t || t.value !== '??') { @@ -711,11 +710,11 @@ export class NakoParser extends NakoParserBase { if (!arg) { throw NakoSyntaxError.fromNode('『??(計算式)』で指定してください。', map) } - const meta = this.funclist.get('表示') - if (!meta) { throw new Error('関数『表示』が見つかりません。plugin_systemをシステムに追加してください。') } + const meta = this.funclist.get('ハテナ関数実行') + if (!meta) { throw new Error('関数『ハテナ関数実行』が見つかりません。plugin_systemをシステムに追加してください。') } return { type: 'func', - name: '表示', + name: 'ハテナ関数実行', blocks: [arg], josi: '', meta, diff --git a/core/src/plugin_api.mts b/core/src/plugin_api.mts index 14df86b2..b7f53b2a 100644 --- a/core/src/plugin_api.mts +++ b/core/src/plugin_api.mts @@ -26,6 +26,7 @@ export interface NakoSystem { __setSore(v: any): void; __getSore(): any; __loadScript(url: string): Promise; // JSのスクリプトを読み込む (ex) グラフ描画(plguin_browser_chart.mts) + __hatena: (s: string, sys: NakoSystem) => void; // 「??」記法の関数キャッシュ #1852 logger: any; // Logger // 便利なメソッド __zero (s: string, keta: number): string; // 桁を指定してゼロ埋めする diff --git a/core/src/plugin_system.mts b/core/src/plugin_system.mts index 97bd5c73..200b131d 100644 --- a/core/src/plugin_system.mts +++ b/core/src/plugin_system.mts @@ -205,7 +205,8 @@ export default { obj.__getProp = obj.__setProp = null } } - + // 「??」ハテナ関数の設定 + sys.__hatena = sys.__getSysVar('デバッグ表示') } }, '!クリア': { @@ -2918,6 +2919,69 @@ export default { } }, // @デバッグ支援 + 'デバッグ表示': { // @デバッグ用にSを表示する // @でばっぐひょうじ + type: 'func', + josi: [['と', 'を', 'の']], + pure: true, + fn: function (s: any, sys: NakoSystem) { + // 行番号の情報を得る + const lineInfo: string = sys.__getSysVar('__line', 0) + '::' + const a = lineInfo.split(':', 2) + const no = parseInt(String(a[0]).replace('l', '')) + 1 + const fname = a[1] + // オブジェクトならJSON文字列に変換 + if (typeof s == 'object') { + s = JSON.stringify(s) + } + s = `${fname}(${no}): ${s}` + sys.__exec('表示', [s, sys]) + }, + return_none: true + }, + 'ハテナ関数設定': { // @ハテナ関数「?? (計算式)」の動作をカスタマイズする。文字列の配列を指定可能で、システム関数名か「js:code」を指定可能。 // @はてなかんすうせってい + type: 'func', + josi: [['を', 'の']], + pure: true, + fn: function (s: any, sys: NakoSystem) { + if (typeof s === 'function') { + sys.__hatena = s + return + } + if (typeof s === 'string') { + sys.__hatena = sys.__getSysVar(s, 'デバッグ表示') + return + } + if (s instanceof Array) { + const fa: ((s: string, sys: NakoSystem)=>string)[] = (s as Array).map((fstr: string) => { + if (fstr.substring(0, 3) === 'JS:') { + const code = fstr.substring(3) + return sys.__evalJS(code, sys) + } else { + return sys.__getSysVar(fstr, 'デバッグ表示') + } + }) + sys.__hatena = (p: any, sys: NakoSystem) => { + let param: any = p + for (const f of fa) { + param = f(param, sys) + } + return + } + return + } + sys.__hatena = sys.__getSysVar('デバッグ表示') + }, + return_none: true + }, + 'ハテナ関数実行': { // @『ハテナ関数設定』で設定した関数を実行する // @はてなかんすうじっこう + type: 'func', + josi: [['の', 'を', 'と']], + pure: true, + fn: function (s: any, sys: NakoSystem) { + sys.__hatena(s, sys) + }, + return_none: true + }, 'エラー発生': { // @故意にエラーSを発生させる // @えらーはっせい type: 'func', josi: [['の', 'で']], diff --git a/core/test/plugin_system_test.mjs b/core/test/plugin_system_test.mjs index e8034a68..d973d158 100644 --- a/core/test/plugin_system_test.mjs +++ b/core/test/plugin_system_test.mjs @@ -11,7 +11,7 @@ describe('plugin_system_test', async () => { const g = await nako.runAsync(code, 'main.nako3') assert.strictEqual(g.log, res) } - const cmpex = async (/** @type {string} */ code, /** @type {name: string, message: string} */ exinfo) => { + const cmpex = async (/** @type {string} */ code, /** @type {{name: string, message: string}} */ exinfo) => { const nako = new NakoCompiler() nako.getLogger().debug('code=' + code) try { @@ -690,11 +690,6 @@ describe('plugin_system_test', async () => { await cmp('A=[0,1,2,3];Aから0...5を参照してJSONエンコードして表示', '[0,1,2,3]') // 範囲を超えて指定もエラーにならない await cmp('A=[0,1,2,3];Aから5...9を参照してJSONエンコードして表示', '[]') // 範囲を超えて指定もエラーにならない }) - it('「?? 計算式文」 #1745', async () => { - await cmp('??1+1', '2') - await cmp('??1+2*3', '7') - await cmp('??(1+2)*3', '9') - }) it('ASC/CHRの配列 #1853', async () => { await cmp('["a","b","c"]のASCをJSON_Eして表示', '[97,98,99]') // 配列なら全ての文字のASC await cmp('「abc」のASCをJSON_Eして表示', '97') // 文字列なら最初の文字のみ @@ -707,4 +702,15 @@ describe('plugin_system_test', async () => { await cmp('「 abc 」を右トリムして表示', ' abc') await cmp('「 abc 」を末尾空白除去して表示', ' abc') }) + it('「?? 計算式文」 #1745', async () => { + await cmp('「表示」をハテナ関数設定; ?? 1+1', '2') + await cmp('「表示」をハテナ関数設定; ?? 1+2*3', '7') + await cmp('「表示」をハテナ関数設定; ?? (1+2)*3', '9') + }) + it('「??」のカスタマイズ機能を追加 #1852', async () => { + await cmp('["JSON_E","表示"]をハテナ関数設定; ?? [1,2,3]', '[1,2,3]') + await cmp('["文字列分解", "ASC", "JSON_E","表示"]をハテナ関数設定; ?? "abc"', '[97,98,99]') + await cmp('["JS:Math.ceil","表示"]をハテナ関数設定; ?? 3.2', '4') + await cmp('[『JS:(function(v,sys){return Math.ceil(v);})』,"表示"]をハテナ関数設定; ?? 3.2', '4') + }) })