From 5c0b3128792def1d7b594c06a9d591aa44749ee3 Mon Sep 17 00:00:00 2001 From: Matsuyuki Date: Sun, 23 Jan 2022 23:59:54 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20=E6=95=B0=E5=80=A4=E3=81=AE=E3=83=90?= =?UTF-8?q?=E3=83=AA=E3=83=87=E3=83=BC=E3=82=B7=E3=83=A7=E3=83=B3=E3=82=92?= =?UTF-8?q?=E3=81=97=E3=81=AA=E3=81=84=E3=82=88=E3=81=86=E3=81=AB=E3=81=99?= =?UTF-8?q?=E3=82=8B,=20=E3=83=8D=E3=82=B9=E3=83=88=E3=81=95=E3=82=8C?= =?UTF-8?q?=E3=81=9F=E5=BC=95=E6=95=B0=E3=81=AE=E5=86=8D=E5=B8=B0=E3=81=AB?= =?UTF-8?q?=E5=AF=BE=E5=BF=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/macro_parser.test.ts | 90 +++++++++++++++++----------------------- src/macro_parser.ts | 70 ++++++++++++++++--------------- 2 files changed, 76 insertions(+), 84 deletions(-) diff --git a/src/macro_parser.test.ts b/src/macro_parser.test.ts index dc6bdc3..449877f 100644 --- a/src/macro_parser.test.ts +++ b/src/macro_parser.test.ts @@ -25,8 +25,7 @@ describe('parse imgplayer', () => { expect(new MacroParser(message).parse()).toEqual(new Macro('imgplayer', ['1', '2'])); }); it('failure', () => { - const message = '$imgplayer=1'; - expect(new MacroParser(message).parse()).toEqual(message); + expect(new MacroParser('$imgplayer=1').parse()).toEqual(""); }); }); @@ -37,7 +36,7 @@ describe('parse imgyesno', () => { }); it('failure', () => { const message = '$imgyesno=1'; - expect(new MacroParser(message).parse()).toEqual(message); + expect(new MacroParser(message).parse()).toEqual(""); }); }); @@ -48,7 +47,7 @@ describe('parse hpmax', () => { }); it('failure', () => { const message = '$hpmax=hoge'; - expect(new MacroParser(message).parse()).toEqual(message); + expect(new MacroParser(message).parse()).toEqual(""); }); }); @@ -58,10 +57,9 @@ describe('parse save', () => { expect(new MacroParser(message).parse()).toEqual(new Macro('save', ['0'])); message = '$save=1'; expect(new MacroParser(message).parse()).toEqual(new Macro('save', ['1'])); - }); - it('failure', () => { - const message = '$save=2'; - expect(new MacroParser(message).parse()).toEqual(message); + // 想定されていない値でもパースは成功する (値のバリデーションはアプリケーション側の責務) + message = '$save=2'; + expect(new MacroParser(message).parse()).toEqual(new Macro('save', ['2'])); }); }); @@ -71,10 +69,8 @@ describe('parse item', () => { expect(new MacroParser(message).parse()).toEqual(new Macro('item', ['0', '5'])); message = '$item=11,90'; expect(new MacroParser(message).parse()).toEqual(new Macro('item', ['11', '90'])); - }); - it('failure', () => { - const message = '$item=23,5'; - expect(new MacroParser(message).parse()).toEqual(message); + message = '$item=23,5'; + expect(new MacroParser(message).parse()).toEqual(new Macro('item', ['23', '5'])); }); }); @@ -85,10 +81,11 @@ describe('parse default', () => { expect(new MacroParser(`$${name}=0`).parse()).toEqual(new Macro(name, ['0'])); message = '$default=1'; expect(new MacroParser(`$${name}=1`).parse()).toEqual(new Macro(name, ['1'])); + message = '$default=2'; + expect(new MacroParser(`$${name}=2`).parse()).toEqual(new Macro(name, ['2'])); }); it('failure', () => { - expect(new MacroParser(`$${name}=2,`).parse()).toEqual(`$${name}=2,`); - expect(new MacroParser(`$${name}=2`).parse()).toEqual(`$${name}=2`); + expect(new MacroParser(`$${name}=2,`).parse()).toEqual(""); }); }); @@ -97,10 +94,10 @@ describe('parse oldmap', () => { it('success', () => { expect(new MacroParser(`$${name}=0`).parse()).toEqual(new Macro(name, ['0'])); expect(new MacroParser(`$${name}=1`).parse()).toEqual(new Macro(name, ['1'])); + expect(new MacroParser(`$${name}=2`).parse()).toEqual(new Macro(name, ['2'])); }); it('failure', () => { - expect(new MacroParser(`$${name}=2,3`).parse()).toEqual(`$${name}=2,3`); - expect(new MacroParser(`$${name}=2`).parse()).toEqual(`$${name}=2`); + expect(new MacroParser(`$${name}=2,3`).parse()).toEqual(""); }); }); @@ -110,10 +107,10 @@ describe('parse parts', () => { expect(new MacroParser(`$${name}=4,10`).parse()).toEqual(new Macro(name, ['4', '10'])); expect(new MacroParser(`$${name}=9,72,0`).parse()).toEqual(new Macro(name, ['9', '72', '0'])); expect(new MacroParser(`$${name}=6,15,1`).parse()).toEqual(new Macro(name, ['6', '15', '1'])); + expect(new MacroParser(`$${name}=9,72,2`).parse()).toEqual(new Macro(name, ['9', '72', '2'])); }); it('failure', () => { - expect(new MacroParser(`$${name}=4,10,`).parse()).toEqual(`$${name}=4,10,`); - expect(new MacroParser(`$${name}=9,72,2`).parse()).toEqual(`$${name}=9,72,2`); + expect(new MacroParser(`$${name}=4,10,`).parse()).toEqual(""); }); }); @@ -121,10 +118,10 @@ describe('parse face', () => { const name = 'face'; it('success', () => { expect(new MacroParser(`$${name}=100,110,5,10,1,1`).parse()).toEqual(new Macro(name, ['100', '110', '5', '10', '1', '1'])); + expect(new MacroParser(`$${name}=100,110,5,10,1,1,2`).parse()).toEqual(""); }); it('failure', () => { - expect(new MacroParser(`$${name}=100,110,5,10,1`).parse()).toEqual(`$${name}=100,110,5,10,1`); - expect(new MacroParser(`$${name}=100,110,5,10,1,1,2`).parse()).toEqual(`$${name}=100,110,5,10,1,1,2`); + expect(new MacroParser(`$${name}=100,110,5,10,1`).parse()).toEqual(""); }); }); @@ -133,10 +130,10 @@ describe('parse delplayer', () => { it('success', () => { expect(new MacroParser(`$${name}=0`).parse()).toEqual(new Macro(name, ['0'])); expect(new MacroParser(`$${name}=1`).parse()).toEqual(new Macro(name, ['1'])); + expect(new MacroParser(`$${name}=2`).parse()).toEqual(new Macro(name, ['2'])); }); it('failure', () => { - expect(new MacroParser(`$${name}=2,3`).parse()).toEqual(`$${name}=2,3`); - expect(new MacroParser(`$${name}=2`).parse()).toEqual(`$${name}=2`); + expect(new MacroParser(`$${name}=2,3`).parse()).toEqual(""); }); }); @@ -147,9 +144,8 @@ describe('parse imgclick', () => { expect(new MacroParser(`$${name}=7,13`).parse()).toEqual(new Macro(name, ['7', '13'])); }); it('failure', () => { - expect(new MacroParser(`$${name}=1`).parse()).toEqual(`$${name}=1`); - expect(new MacroParser(`$${name}=1,`).parse()).toEqual(`$${name}=1,`); - expect(new MacroParser(`$${name}=1,2,`).parse()).toEqual(`$${name}=1,2,`); + expect(new MacroParser(`$${name}=1,`).parse()).toEqual(""); + expect(new MacroParser(`$${name}=1,2,`).parse()).toEqual(""); }); }); @@ -162,12 +158,6 @@ describe('parse color', () => { expect(new MacroParser(`$${name}=4,53,53,53`).parse()).toEqual(new Macro(name, ['4', '53', '53', '53'])); expect(new MacroParser(`$${name}=0,209,217,231`).parse()).toEqual(new Macro(name, ['0', '209', '217', '231'])); }); - it('failure', () => { - expect(new MacroParser(`$${name}=3,255,255,255`).parse()).toEqual(`$${name}=3,255,255,255`); - expect(new MacroParser(`$${name}=5,255,255,255`).parse()).toEqual(`$${name}=5,255,255,255`); - expect(new MacroParser(`$${name}=0,256,256,256`).parse()).toEqual(`$${name}=0,256,256,256`); - expect(new MacroParser(`$${name}=0,-1,-1,-1`).parse()).toEqual(`$${name}=0,-1,-1,-1`); - }); }); describe('parse gameover', () => { @@ -176,7 +166,7 @@ describe('parse gameover', () => { expect(new MacroParser(`$${name}=1,2`).parse()).toEqual(new Macro(name, ['1', '2'])); }); it('failure', () => { - expect(new MacroParser(`$${name}=1`).parse()).toEqual(`$${name}=1`); + expect(new MacroParser(`$${name}=1`).parse()).toEqual(""); }); }); @@ -186,11 +176,11 @@ describe('parse dirmap', () => { expect(new MacroParser(`$${name}=1,2`).parse()).toEqual(new Macro(name, ['1', '2'])); expect(new MacroParser(`$${name}=1,2,0`).parse()).toEqual(new Macro(name, ['1', '2', '0'])); expect(new MacroParser(`$${name}=1,2,1`).parse()).toEqual(new Macro(name, ['1', '2', '1'])); + expect(new MacroParser(`$${name}=1,2,2`).parse()).toEqual(new Macro(name, ['1', '2', '2'])); }); it('failure', () => { - expect(new MacroParser(`$${name}=1,2,2`).parse()).toEqual(`$${name}=1,2,2`); - expect(new MacroParser(`$${name}=1,2,`).parse()).toEqual(`$${name}=1,2,`); - expect(new MacroParser(`$${name}=1`).parse()).toEqual(`$${name}=1`); + expect(new MacroParser(`$${name}=1,2,`).parse()).toEqual(""); + expect(new MacroParser(`$${name}=1`).parse()).toEqual(""); }); }); @@ -200,11 +190,11 @@ describe('parse map', () => { expect(new MacroParser(`$${name}=1,2,3`).parse()).toEqual(new Macro(name, ['1', '2', '3'])); expect(new MacroParser(`$${name}=1,2,3,0`).parse()).toEqual(new Macro(name, ['1', '2', '3', '0'])); expect(new MacroParser(`$${name}=1,2,3,1`).parse()).toEqual(new Macro(name, ['1', '2', '3', '1'])); + expect(new MacroParser(`$${name}=1,2,3,2`).parse()).toEqual(new Macro(name, ['1', '2', '3', '2'])); }); it('failure', () => { - expect(new MacroParser(`$${name}=1,2,3,2`).parse()).toEqual(`$${name}=1,2,3,2`); - expect(new MacroParser(`$${name}=1,2,3,`).parse()).toEqual(`$${name}=1,2,3,`); - expect(new MacroParser(`$${name}=1`).parse()).toEqual(`$${name}=1`); + expect(new MacroParser(`$${name}=1,2,3,`).parse()).toEqual(""); + expect(new MacroParser(`$${name}=1`).parse()).toEqual(""); }); }); @@ -214,8 +204,8 @@ describe('parse imgframe', () => { expect(new MacroParser(`$${name}=1,2,3`).parse()).toEqual(new Macro(name, ['1', '2', '3'])); }); it('failure', () => { - expect(new MacroParser(`$${name}=1,2,3,`).parse()).toEqual(`$${name}=1,2,3,`); - expect(new MacroParser(`$${name}=1,2`).parse()).toEqual(`$${name}=1,2`); + expect(new MacroParser(`$${name}=1,2,3,`).parse()).toEqual(""); + expect(new MacroParser(`$${name}=1,2`).parse()).toEqual(""); }); }); @@ -226,8 +216,7 @@ describe('parse imgbom', () => { expect(new MacroParser(`$${name}=10,3`).parse()).toEqual(new Macro(name, ['10', '3'])); }); it('failure', () => { - expect(new MacroParser(`$${name}=11,3`).parse()).toEqual(`$${name}=11,3`); - expect(new MacroParser(`$${name}=1,2,`).parse()).toEqual(`$${name}=1,2,`); + expect(new MacroParser(`$${name}=1,2,`).parse()).toEqual(""); }); }); @@ -236,11 +225,11 @@ describe('parse effect', () => { it('success', () => { expect(new MacroParser(`$${name}=100,3,4`).parse()).toEqual(new Macro(name, ['100', '3', '4'])); expect(new MacroParser(`$${name}=5,10,10`).parse()).toEqual(new Macro(name, ['5', '10', '10'])); + expect(new MacroParser(`$${name}=100,11,4`).parse()).toEqual(new Macro(name, ['100', '11', '4'])); }); it('failure', () => { - expect(new MacroParser(`$${name}=100,11,4`).parse()).toEqual(`$${name}=100,11,4`); - expect(new MacroParser(`$${name}=11,3`).parse()).toEqual(`$${name}=11,3`); - expect(new MacroParser(`$${name}=1,2,`).parse()).toEqual(`$${name}=1,2,`); + expect(new MacroParser(`$${name}=11,3`).parse()).toEqual(""); + expect(new MacroParser(`$${name}=1,2,`).parse()).toEqual(""); }); }); @@ -252,9 +241,8 @@ describe('parse status', () => { expect(new MacroParser(`$${name}=4,10000`).parse()).toEqual(new Macro(name, ['4', '10000'])); }); it('failure', () => { - expect(new MacroParser(`$${name}=100,11,4`).parse()).toEqual(`$${name}=100,11,4`); - expect(new MacroParser(`$${name}=11,3`).parse()).toEqual(`$${name}=11,3`); - expect(new MacroParser(`$${name}=1,2,`).parse()).toEqual(`$${name}=1,2,`); + expect(new MacroParser(`$${name}=100,11,4`).parse()).toEqual(""); + expect(new MacroParser(`$${name}=1,2,`).parse()).toEqual(""); }); }); @@ -265,8 +253,8 @@ describe('parse sound', () => { expect(new MacroParser(`$${name}=256`).parse()).toEqual(new Macro(name, ['256'])); }); it('failure', () => { - expect(new MacroParser(`$${name}=1,`).parse()).toEqual(`$${name}=1,`); - expect(new MacroParser(`$${name}=`).parse()).toEqual(`$${name}=`); - expect(new MacroParser(`$${name}=a`).parse()).toEqual(`$${name}=a`); + expect(new MacroParser(`$${name}=1,`).parse()).toEqual(""); + expect(new MacroParser(`$${name}=`).parse()).toEqual(""); + expect(new MacroParser(`$${name}=a`).parse()).toEqual(""); }); }); \ No newline at end of file diff --git a/src/macro_parser.ts b/src/macro_parser.ts index 94369ed..49bf3db 100644 --- a/src/macro_parser.ts +++ b/src/macro_parser.ts @@ -12,6 +12,8 @@ export class Macro { type ParseResult = Macro | string; +type RawArgs = (string | RawArgs)[]; + export class MacroParser { message: string; @@ -31,75 +33,69 @@ export class MacroParser { // 引数にとる値 private num = Parser.regex(/\d+/); - private bool = Parser.choice([Parser.char('0'), Parser.char('1')]); - private item_range = Parser.regex(/^(1[0-2]|[0-9])/); - private parts_type = this.bool; private eol = Parser.regex(/$/); - private parts_x = Parser.regex(/^(10|[1-9])/); - private color_type = Parser.regex(/[0-2]|4/); - private color_range = Parser.regex(/25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9]/); - private status_type = Parser.regex(/[0-4]/); // 引数のパターン private position = Parser.seq([this.num, this.comma, this.num, this.eol]); private num_eol = Parser.seq([this.num, this.eol]); - private bool_eol = Parser.seq([this.bool, this.eol]); - private set_item = Parser.seq([this.item_range, this.comma, this.num, this.eol]); + private set_item = Parser.seq([this.num, this.comma, this.num, this.eol]); private replace_parts = Parser.choice( [ - Parser.seq([this.num, this.comma, this.num, this.comma, this.parts_type, this.eol]), + Parser.seq([this.num, this.comma, this.num, this.comma, this.num, this.eol]), Parser.seq([this.num, this.comma, this.num, this.eol]), ] ); private face_args = Parser.seq([ this.num, this.comma, this.num, this.comma, - this.parts_x, this.comma, this.num, this.comma, + this.num, this.comma, this.num, this.comma, this.num, this.comma, this.num_eol, ]); private imgclick_args = Parser.choice([ - Parser.seq([Parser.char('0'), this.eol]), - Parser.seq([this.parts_x, this.comma, this.num_eol]), + Parser.seq([ + this.num, Parser.option( + Parser.seq([this.comma, this.num]), + ), this.eol + ]), ]); private color_args = Parser.seq([ - this.color_type, this.comma, - this.color_range, this.comma, - this.color_range, this.comma, - this.color_range, this.eol, + this.num, this.comma, + this.num, this.comma, + this.num, this.comma, + this.num, this.eol, ]); private dirmap_args = Parser.choice([ - Parser.seq([this.num, this.comma, this.num, this.comma, this.parts_type, this.eol]), + Parser.seq([this.num, this.comma, this.num, this.comma, this.num, this.eol]), Parser.seq([this.num, this.comma, this.num_eol]), ]); private map_args = Parser.choice([ - Parser.seq([this.num, this.comma, this.num, this.comma, this.num, this.comma, this.parts_type, this.eol]), + Parser.seq([this.num, this.comma, this.num, this.comma, this.num, this.comma, this.num, this.eol]), Parser.seq([this.num, this.comma, this.num, this.comma, this.num_eol]), ]); - // ToDo: 第一引数の値の制限 private imgframe_args = Parser.seq([ - this.num, this.comma, this.parts_x, this.comma, this.num_eol, + this.num, this.comma, this.num, this.comma, this.num_eol, ]); private imgbom_args = Parser.seq([ - this.parts_x, this.comma, this.num_eol, + this.num, this.comma, this.num_eol, ]); private effect_args = Parser.seq([ - this.num, this.comma, this.parts_x, this.comma, this.num_eol, + this.num, this.comma, this.num, this.comma, this.num_eol, ]); private status_args = Parser.seq([ - this.status_type, this.comma, this.num_eol + this.num, this.comma, this.num_eol ]); // 各マクロのパーサ private imgplayer = this.make_macro_parser('imgplayer', this.position); private imgyesno = this.make_macro_parser('imgyesno', this.position); private hpmax = this.make_macro_parser('hpmax', this.num_eol); - private save = this.make_macro_parser('save', this.bool_eol); + private save = this.make_macro_parser('save', this.num_eol); private item = this.make_macro_parser('item', this.set_item); - private default = this.make_macro_parser('default', this.bool_eol); - private oldmap = this.make_macro_parser('oldmap', this.bool_eol); + private default = this.make_macro_parser('default', this.num_eol); + private oldmap = this.make_macro_parser('oldmap', this.num_eol); private parts = this.make_macro_parser('parts', this.replace_parts); private move = this.make_macro_parser('move', this.num_eol); private face = this.make_macro_parser('face', this.face_args); - private delplayer = this.make_macro_parser('delplayer', this.bool_eol); + private delplayer = this.make_macro_parser('delplayer', this.num_eol); private imgclick = this.make_macro_parser('imgclick', this.imgclick_args); private color = this.make_macro_parser('color', this.color_args); private gameover = this.make_macro_parser('gameover', this.position); @@ -135,22 +131,30 @@ export class MacroParser { this.sound, ]); + private resolveArgs = (raw_args: RawArgs): string[] => { + return raw_args.reduce( + (acc, val) => acc.concat( + val instanceof Array ? this.resolveArgs(val) : val) + , []); + } + parse: () => ParseResult = () => { const parse_result = this.macro_parser(this.message, 0); if (parse_result instanceof Success) { // マクロ名と引数に分解 const macro_name: string = parse_result.result[1]; - const raw_args: Array> = parse_result.result[3]; + const raw_args: RawArgs = parse_result.result[3]; // 結果の返却 // 引数はネストされて出てくるのでフラットにしてからカンマを除去 // 行末の終端記号もパースされるので除去しておく - const macro_args = raw_args.reduce( - (acc, val) => acc.concat(val), [] - ).slice(0, -1).filter((c: string) => c !== ","); + const macro_args = this.resolveArgs(raw_args).slice(0, -1).filter((c: string | null) => c && c !== ","); return new Macro(macro_name, macro_args); + } else if (this.message[0] === "$") { + // パースに失敗したときで、最初の文字が $ の場合はコメント行扱い + return ""; } else { // パースに失敗したときは入ってきた文字列をそのまま返す return this.message; } } -} \ No newline at end of file +}