Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 39 additions & 51 deletions src/macro_parser.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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("");
});
});

Expand All @@ -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("");
});
});

Expand All @@ -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("");
});
});

Expand All @@ -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']));
});
});

Expand All @@ -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']));
});
});

Expand All @@ -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("");
});
});

Expand All @@ -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("");
});
});

Expand All @@ -110,21 +107,21 @@ 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("");
});
});

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("");
});
});

Expand All @@ -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("");
});
});

Expand All @@ -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("");
});
});

Expand All @@ -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', () => {
Expand All @@ -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("");
});
});

Expand All @@ -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("");
});
});

Expand All @@ -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("");
});
});

Expand All @@ -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("");
});
});

Expand All @@ -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("");
});
});

Expand All @@ -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("");
});
});

Expand All @@ -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("");
});
});

Expand All @@ -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("");
});
});
70 changes: 37 additions & 33 deletions src/macro_parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ export class Macro {

type ParseResult = Macro | string;

type RawArgs = (string | RawArgs)[];

export class MacroParser {
message: string;

Expand All @@ -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);
Expand Down Expand Up @@ -135,22 +131,30 @@ export class MacroParser {
this.sound,
]);

private resolveArgs = (raw_args: RawArgs): string[] => {
return raw_args.reduce<string[]>(
(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<Array<string>> = 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;
}
}
}
}