Added test suite generator for ruby
This commit is contained in:
parent
8bd6671f90
commit
6a35872470
7 changed files with 1091 additions and 6 deletions
258
lib/tsgenruby.pl
Normal file
258
lib/tsgenruby.pl
Normal file
|
|
@ -0,0 +1,258 @@
|
||||||
|
% -*- prolog -*-
|
||||||
|
% Run with:
|
||||||
|
% $ swipl -q -t halt -g tsgenruby:prolog tsgenruby.pl >output-file
|
||||||
|
% Note: this needs to be run from the lib/ directory.
|
||||||
|
|
||||||
|
% So, from the ruby directory
|
||||||
|
% (cd ../../../lib && swipl -q -t halt -g tsgenruby:prolog tsgenruby.pl ) >test/autogen_test.rb
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
:- module(tsgenruby,
|
||||||
|
[gen_ts/2]).
|
||||||
|
|
||||||
|
:- expects_dialect(swi).
|
||||||
|
:- use_module(tsparser).
|
||||||
|
:- use_module(library(record)).
|
||||||
|
|
||||||
|
:- record testsuite_state(parser_no:integer = 0, test_no:integer=0).
|
||||||
|
% TODO: build a Box-like pretty-printer
|
||||||
|
|
||||||
|
to_title_case([], []) :- !.
|
||||||
|
to_title_case([WSep,S0|Ss], [R0|Rs]) :-
|
||||||
|
memberchk(WSep, "_-"), !,
|
||||||
|
code_type(R0, to_upper(S0)),
|
||||||
|
to_title_case(Ss,Rs).
|
||||||
|
to_title_case([S0|Ss], [S0|Rs]) :-
|
||||||
|
\+ memberchk(S0, "_-"),
|
||||||
|
!, to_title_case(Ss,Rs).
|
||||||
|
|
||||||
|
format_parser_name(Name, Result) :-
|
||||||
|
atom_codes(Name, CName),
|
||||||
|
append("h.", CName, Result), !.
|
||||||
|
|
||||||
|
format_test_name(Name, Result) :-
|
||||||
|
atom_codes(Name, CName),
|
||||||
|
to_title_case([0x5f|CName], RName),
|
||||||
|
append("Test", RName, Result), !.
|
||||||
|
|
||||||
|
indent(0) --> "", !.
|
||||||
|
indent(N) -->
|
||||||
|
{N > 0},
|
||||||
|
" ",
|
||||||
|
{Np is N - 1},
|
||||||
|
indent(Np).
|
||||||
|
|
||||||
|
pp_char_guts(0x22) -->
|
||||||
|
"\\\"", !.
|
||||||
|
pp_char_guts(0x27) -->
|
||||||
|
"\\'", !.
|
||||||
|
pp_char_guts(A) -->
|
||||||
|
{ A >= 0x20, A < 0x7F } ->
|
||||||
|
[A];
|
||||||
|
"\\x",
|
||||||
|
{ H is A >> 4, L is A /\ 0xF,
|
||||||
|
code_type(Hc, xdigit(H)),
|
||||||
|
code_type(Lc, xdigit(L)) },
|
||||||
|
[Hc,Lc].
|
||||||
|
|
||||||
|
pp_hexnum_guts(0) --> !.
|
||||||
|
pp_hexnum_guts(A) -->
|
||||||
|
{ L is A /\ 0xF,
|
||||||
|
H is A >> 4,
|
||||||
|
code_type(Lc, xdigit(L)) },
|
||||||
|
pp_hexnum_guts(H),
|
||||||
|
[Lc], !.
|
||||||
|
pp_string_guts([]) --> !.
|
||||||
|
pp_string_guts([X|Xs]) -->
|
||||||
|
pp_char_guts(X),
|
||||||
|
pp_string_guts(Xs), !.
|
||||||
|
|
||||||
|
pp_parser_args([]) --> !.
|
||||||
|
pp_parser_args([X|Rest]) -->
|
||||||
|
pp_parser(X),
|
||||||
|
pp_parser_args_rest(Rest).
|
||||||
|
pp_parser_args_rest([]) --> !.
|
||||||
|
pp_parser_args_rest([X|Xs]) -->
|
||||||
|
", ",
|
||||||
|
pp_parser(X),
|
||||||
|
pp_parser_args_rest(Xs).
|
||||||
|
|
||||||
|
pp_parser(parser(Name, Args)) -->
|
||||||
|
!,
|
||||||
|
{format_parser_name(Name,Fname)},
|
||||||
|
Fname,
|
||||||
|
({Args \= []} ->
|
||||||
|
|
||||||
|
"(", pp_parser_args(Args), ")"
|
||||||
|
; "") .
|
||||||
|
pp_parser(string(Str)) --> !,
|
||||||
|
"\"",
|
||||||
|
pp_string_guts(Str),
|
||||||
|
"\"", !.
|
||||||
|
pp_parser(num(0)) --> "0", !.
|
||||||
|
pp_parser(num(Num)) --> !,
|
||||||
|
( {Num < 0} ->
|
||||||
|
"-0x", {RNum is -Num}; "0x", {RNum = Num} ),
|
||||||
|
pp_hexnum_guts(RNum).
|
||||||
|
pp_parser(char(C)) --> !,
|
||||||
|
"'", pp_char_guts(C), "'", !.
|
||||||
|
|
||||||
|
pp_parser(ref(Name)) -->
|
||||||
|
{atom_codes(Name,CName)},
|
||||||
|
"@sp_", CName, !.
|
||||||
|
|
||||||
|
|
||||||
|
pp_parser(A) -->
|
||||||
|
{ writef("WTF is a %w?\n", [A]),
|
||||||
|
!, fail
|
||||||
|
}.
|
||||||
|
|
||||||
|
upd_state_test_elem(parser(_), OldSt, NewSt) :- !,
|
||||||
|
testsuite_state_parser_no(OldSt, OldRNo),
|
||||||
|
NewRNo is OldRNo + 1,
|
||||||
|
set_parser_no_of_testsuite_state(NewRNo, OldSt, NewSt).
|
||||||
|
upd_state_test_elem(test(_, _), OldSt, NewSt) :- !,
|
||||||
|
testsuite_state_test_no(OldSt, OldTNo),
|
||||||
|
NewTNo is OldTNo + 1,
|
||||||
|
set_test_no_of_testsuite_state(NewTNo, OldSt, NewSt).
|
||||||
|
upd_state_test_elem(testFail(_), OldSt, NewSt) :- !,
|
||||||
|
testsuite_state_test_no(OldSt, OldTNo),
|
||||||
|
NewTNo is OldTNo + 1,
|
||||||
|
set_test_no_of_testsuite_state(NewTNo, OldSt, NewSt).
|
||||||
|
upd_state_test_elem(_, St, St).
|
||||||
|
|
||||||
|
curparser_name(St) --> !,
|
||||||
|
{ testsuite_state_parser_no(St, RNo),
|
||||||
|
format(string(X), "@parser_~w", RNo) },
|
||||||
|
X.
|
||||||
|
curtest_name(St) --> !,
|
||||||
|
{ testsuite_state_test_no(St, RNo),
|
||||||
|
format(string(X), "test_~w", RNo) },
|
||||||
|
X.
|
||||||
|
|
||||||
|
pp_test_elem(decl, parser(_), _) --> !.
|
||||||
|
pp_test_elem(init, parser(P), St) -->
|
||||||
|
!, indent(2),
|
||||||
|
curparser_name(St), " = ",
|
||||||
|
pp_parser(P),
|
||||||
|
"\n".
|
||||||
|
pp_test_elem(exec, parser(_), _) --> !.
|
||||||
|
pp_test_elem(decl, subparser(Name,_), _) -->
|
||||||
|
!, indent(2),
|
||||||
|
pp_parser(ref(Name)),
|
||||||
|
" = ",
|
||||||
|
pp_parser(parser(indirect,[])),
|
||||||
|
"\n".
|
||||||
|
pp_test_elem(init, subparser(Name, Parser), _) -->
|
||||||
|
!, indent(2),
|
||||||
|
pp_parser(ref(Name)), ".bind ",
|
||||||
|
pp_parser(Parser),
|
||||||
|
"\n".
|
||||||
|
pp_test_elem(exec, subparser(_,_), _) --> !.
|
||||||
|
pp_test_elem(decl, test(_,_), _) --> !.
|
||||||
|
pp_test_elem(init, test(_,_), _) --> !.
|
||||||
|
pp_test_elem(decl, testFail(_), _) --> !.
|
||||||
|
pp_test_elem(init, testFail(_), _) --> !.
|
||||||
|
pp_test_elem(exec, test(Str, Result), St) -->
|
||||||
|
!,
|
||||||
|
"\n",
|
||||||
|
indent(1), "def ", curtest_name(St), "\n",
|
||||||
|
indent(2), "assert_parse_ok ", curparser_name(St), ", ", pp_parser(string(Str)),
|
||||||
|
", ",
|
||||||
|
pp_parse_result(Result),
|
||||||
|
"\n",
|
||||||
|
indent(1), "end\n".
|
||||||
|
pp_test_elem(exec, testFail(Str), St) -->
|
||||||
|
!,
|
||||||
|
"\n",
|
||||||
|
indent(1), "def ", curtest_name(St), "\n",
|
||||||
|
indent(2), "refute_parse_ok ", curparser_name(St), ", ", pp_parser(string(Str)), "\n",
|
||||||
|
indent(1), "end\n".
|
||||||
|
|
||||||
|
% pp_test_elem(_, _) --> !.
|
||||||
|
|
||||||
|
pp_result_seq([]) --> !.
|
||||||
|
pp_result_seq([X|Xs]) --> !,
|
||||||
|
pp_parse_result(X),
|
||||||
|
pp_result_seq_r(Xs).
|
||||||
|
pp_result_seq_r([]) --> !.
|
||||||
|
pp_result_seq_r([X|Xs]) --> !,
|
||||||
|
", ",
|
||||||
|
pp_parse_result(X),
|
||||||
|
pp_result_seq_r(Xs).
|
||||||
|
|
||||||
|
pp_byte_seq([]) --> !.
|
||||||
|
pp_byte_seq([X|Xs]) --> !,
|
||||||
|
pp_parser(num(X)),
|
||||||
|
pp_byte_seq_r(Xs).
|
||||||
|
pp_byte_seq_r([]) --> !.
|
||||||
|
pp_byte_seq_r([X|Xs]) --> !,
|
||||||
|
", ",
|
||||||
|
pp_parser(num(X)),
|
||||||
|
pp_byte_seq_r(Xs).
|
||||||
|
|
||||||
|
pp_parse_result(char(C)) --> !,
|
||||||
|
%"(System.UInt64)",
|
||||||
|
pp_parser(char(C)).
|
||||||
|
pp_parse_result(seq(Args)) --> !,
|
||||||
|
"[", pp_result_seq(Args), "]".
|
||||||
|
pp_parse_result(none) --> !,
|
||||||
|
"null".
|
||||||
|
pp_parse_result(uint(V)) --> !,
|
||||||
|
pp_parser(num(V)).
|
||||||
|
pp_parse_result(sint(V)) --> !,
|
||||||
|
pp_parser(num(V)).
|
||||||
|
pp_parse_result(string(A)) --> !,
|
||||||
|
pp_parser(string(A)).
|
||||||
|
|
||||||
|
%pp_parse_result(A) -->
|
||||||
|
% "\x1b[1;31m",
|
||||||
|
% {with_output_to(codes(C), write(A))},
|
||||||
|
% C,
|
||||||
|
% "\x1b[0m".
|
||||||
|
|
||||||
|
|
||||||
|
pp_test_elems(Phase, Elems) -->
|
||||||
|
{ default_testsuite_state(State) },
|
||||||
|
pp_test_elems(Phase, Elems, State).
|
||||||
|
pp_test_elems(_, [], _) --> !.
|
||||||
|
pp_test_elems(Phase, [X|Xs], St) -->
|
||||||
|
!,
|
||||||
|
{ upd_state_test_elem(X, St, NewSt) },
|
||||||
|
%{NewSt = St},
|
||||||
|
pp_test_elem(Phase,X, NewSt),
|
||||||
|
pp_test_elems(Phase,Xs, NewSt).
|
||||||
|
|
||||||
|
pp_test_case(testcase(Name, Elems)) -->
|
||||||
|
!,
|
||||||
|
{ format_test_name(Name, TName) },
|
||||||
|
indent(0), "class ", TName, " < Minitest::Test\n",
|
||||||
|
indent(1), "def setup\n",
|
||||||
|
indent(2), "super\n",
|
||||||
|
indent(2), "h = Hammer::Parser\n",
|
||||||
|
pp_test_elems(decl, Elems),
|
||||||
|
pp_test_elems(init, Elems),
|
||||||
|
indent(1), "end\n",
|
||||||
|
pp_test_elems(exec, Elems),
|
||||||
|
indent(0), "end\n\n".
|
||||||
|
|
||||||
|
|
||||||
|
pp_test_cases([]) --> !.
|
||||||
|
pp_test_cases([A|As]) -->
|
||||||
|
pp_test_case(A),
|
||||||
|
pp_test_cases(As).
|
||||||
|
|
||||||
|
pp_test_suite(Suite) -->
|
||||||
|
"require 'bundler/setup'\n",
|
||||||
|
"require 'minitest/autorun'\n",
|
||||||
|
"require 'hammer'\n",
|
||||||
|
pp_test_cases(Suite).
|
||||||
|
|
||||||
|
gen_ts(Foo,Str) :-
|
||||||
|
phrase(pp_test_suite(Foo),Str).
|
||||||
|
|
||||||
|
prolog :-
|
||||||
|
read_tc(A),
|
||||||
|
gen_ts(A, Res),
|
||||||
|
writef("%s", [Res]).
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
require 'rake/testtask'
|
require 'rake/testtask'
|
||||||
|
|
||||||
Rake::TestTask.new do |t|
|
Rake::TestTask.new do |t|
|
||||||
t.pattern = "test/*_test.rb"
|
#t.pattern = "test/*_test.rb"
|
||||||
|
t.test_files = FileList['test/*_test.rb']
|
||||||
end
|
end
|
||||||
|
|
||||||
task :default => [:test]
|
task :default => [:test]
|
||||||
|
|
|
||||||
|
|
@ -19,14 +19,14 @@ x.bind(Hammer::Parser.token('abd'))
|
||||||
#$p = parser
|
#$p = parser
|
||||||
$r = parser.parse 'abcabd'
|
$r = parser.parse 'abcabd'
|
||||||
|
|
||||||
p $r[:ast][:data][:seq].elements.map {|e| e[:data][:bytes].token }
|
#p $r[:ast][:data][:seq].elements.map {|e| e[:data][:bytes].token }
|
||||||
|
|
||||||
|
|
||||||
h = Hammer::Parser
|
h = Hammer::Parser
|
||||||
parser =
|
parser =
|
||||||
h.many(
|
h.many(
|
||||||
h.action(h.uint8) { |r|
|
h.action(h.uint8) { |r|
|
||||||
p "TT=#{r[:ast][:token_type]}, value=#{r[:ast][:data][:uint]}"
|
#p "TT=#{r[:ast][:token_type]}, value=#{r[:ast][:data][:uint]}"
|
||||||
r[:ast][:data][:uint] *= 2
|
r[:ast][:data][:uint] *= 2
|
||||||
r[:ast] if r[:ast][:data][:uint] % 3 == 0
|
r[:ast] if r[:ast][:data][:uint] % 3 == 0
|
||||||
})
|
})
|
||||||
|
|
@ -43,11 +43,11 @@ parser =
|
||||||
|
|
||||||
$r = parser.parse 'abcdefgh'
|
$r = parser.parse 'abcdefgh'
|
||||||
|
|
||||||
p $r[:ast][:data][:seq].elements.map {|e| e[:data][:uint]}
|
#p $r[:ast][:data][:seq].elements.map {|e| e[:data][:uint]}
|
||||||
# or:
|
# or:
|
||||||
p $r.ast.data.map(&:data)
|
#p $r.ast.data.map(&:data)
|
||||||
|
|
||||||
|
|
||||||
h = Hammer::Parser
|
h = Hammer::Parser
|
||||||
parser = h.many(h.attr_bool(h.uint8) { |r| r.ast.data <= 100 })
|
parser = h.many(h.attr_bool(h.uint8) { |r| r.ast.data <= 100 })
|
||||||
p parser.parse('abcdefgh').ast.data.map(&:data)
|
#p parser.parse('abcdefgh').ast.data.map(&:data)
|
||||||
|
|
|
||||||
|
|
@ -102,6 +102,23 @@ module Hammer
|
||||||
def bit_offset
|
def bit_offset
|
||||||
self[:bit_offset]
|
self[:bit_offset]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def unmarshal
|
||||||
|
case token_type
|
||||||
|
when :sequence
|
||||||
|
self[:data][:seq].each {|x| x.unmarshal}
|
||||||
|
when :bytes
|
||||||
|
self[:data][:bytes].token
|
||||||
|
when :uint
|
||||||
|
self[:data][:uint]
|
||||||
|
when :sint
|
||||||
|
self[:data][:sint]
|
||||||
|
when :none
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
class HParseResult < FFI::Struct
|
class HParseResult < FFI::Struct
|
||||||
|
|
|
||||||
28
src/bindings/ruby/lib/minitest/hamer-parser_plugin.rb
Normal file
28
src/bindings/ruby/lib/minitest/hamer-parser_plugin.rb
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
module Minitest
|
||||||
|
|
||||||
|
module Assertions
|
||||||
|
HAMMER_JUST_PARSE = Object.new
|
||||||
|
def assert_parse_ok(parser, probe, expected=HAMMER_JUST_PARSE)
|
||||||
|
refute_nil parser, "Parser must not be nil (this is a problem with your test)"
|
||||||
|
parse_result = parser.parse(probe)
|
||||||
|
refute_nil parse_result, "Parse failed"
|
||||||
|
if HAMMER_JUST_PARSE != expected
|
||||||
|
if parse_result.ast == nil
|
||||||
|
assert_nil expected, "Parser returned nil AST; expected #{expected}"
|
||||||
|
else
|
||||||
|
assert_equal parse_result.ast.unmarshal, expected
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def refute_parse_ok(parser, probe)
|
||||||
|
refute_nil parser, "Parser must not be nil (this is a problem with your test)"
|
||||||
|
parse_result = parser.parse(probe)
|
||||||
|
assert_nil parse_result, "Parse succeeded unexpectedly with " + parse_result.ast.inspect
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
#def self.plugin_hammer-parser_init(options)
|
||||||
|
end
|
||||||
|
|
||||||
781
src/bindings/ruby/test/autogen_test.rb
Normal file
781
src/bindings/ruby/test/autogen_test.rb
Normal file
|
|
@ -0,0 +1,781 @@
|
||||||
|
require 'bundler/setup'
|
||||||
|
require 'minitest/autorun'
|
||||||
|
require 'hammer'
|
||||||
|
class TestToken < Minitest::Test
|
||||||
|
def setup
|
||||||
|
super
|
||||||
|
h = Hammer::Parser
|
||||||
|
@parser_1 = h.token("95\xa2")
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_1
|
||||||
|
assert_parse_ok @parser_1, "95\xa2", "95\xa2"
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_2
|
||||||
|
refute_parse_ok @parser_1, "95\xa2"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class TestCh < Minitest::Test
|
||||||
|
def setup
|
||||||
|
super
|
||||||
|
h = Hammer::Parser
|
||||||
|
@parser_1 = h.ch(0xa2)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_1
|
||||||
|
assert_parse_ok @parser_1, "\xa2", '\xa2'
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_2
|
||||||
|
refute_parse_ok @parser_1, "\xa3"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class TestChRange < Minitest::Test
|
||||||
|
def setup
|
||||||
|
super
|
||||||
|
h = Hammer::Parser
|
||||||
|
@parser_1 = h.ch_range(0x61, 0x63)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_1
|
||||||
|
assert_parse_ok @parser_1, "b", 'b'
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_2
|
||||||
|
refute_parse_ok @parser_1, "d"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class TestInt64 < Minitest::Test
|
||||||
|
def setup
|
||||||
|
super
|
||||||
|
h = Hammer::Parser
|
||||||
|
@parser_1 = h.int64
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_1
|
||||||
|
assert_parse_ok @parser_1, "\xff\xff\xff\xfe\x00\x00\x00\x00", -0x200000000
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_2
|
||||||
|
refute_parse_ok @parser_1, "\xff\xff\xff\xfe\x00\x00\x00"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class TestInt32 < Minitest::Test
|
||||||
|
def setup
|
||||||
|
super
|
||||||
|
h = Hammer::Parser
|
||||||
|
@parser_1 = h.int32
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_1
|
||||||
|
assert_parse_ok @parser_1, "\xff\xfe\x00\x00", -0x20000
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_2
|
||||||
|
refute_parse_ok @parser_1, "\xff\xfe\x00"
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_3
|
||||||
|
assert_parse_ok @parser_1, "\x00\x02\x00\x00", 0x20000
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_4
|
||||||
|
refute_parse_ok @parser_1, "\x00\x02\x00"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class TestInt16 < Minitest::Test
|
||||||
|
def setup
|
||||||
|
super
|
||||||
|
h = Hammer::Parser
|
||||||
|
@parser_1 = h.int16
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_1
|
||||||
|
assert_parse_ok @parser_1, "\xfe\x00", -0x200
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_2
|
||||||
|
refute_parse_ok @parser_1, "\xfe"
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_3
|
||||||
|
assert_parse_ok @parser_1, "\x02\x00", 0x200
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_4
|
||||||
|
refute_parse_ok @parser_1, "\x02"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class TestInt8 < Minitest::Test
|
||||||
|
def setup
|
||||||
|
super
|
||||||
|
h = Hammer::Parser
|
||||||
|
@parser_1 = h.int8
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_1
|
||||||
|
assert_parse_ok @parser_1, "\x88", -0x78
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_2
|
||||||
|
refute_parse_ok @parser_1, ""
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class TestUint64 < Minitest::Test
|
||||||
|
def setup
|
||||||
|
super
|
||||||
|
h = Hammer::Parser
|
||||||
|
@parser_1 = h.uint64
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_1
|
||||||
|
assert_parse_ok @parser_1, "\x00\x00\x00\x02\x00\x00\x00\x00", 0x200000000
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_2
|
||||||
|
refute_parse_ok @parser_1, "\x00\x00\x00\x02\x00\x00\x00"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class TestUint32 < Minitest::Test
|
||||||
|
def setup
|
||||||
|
super
|
||||||
|
h = Hammer::Parser
|
||||||
|
@parser_1 = h.uint32
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_1
|
||||||
|
assert_parse_ok @parser_1, "\x00\x02\x00\x00", 0x20000
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_2
|
||||||
|
refute_parse_ok @parser_1, "\x00\x02\x00"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class TestUint16 < Minitest::Test
|
||||||
|
def setup
|
||||||
|
super
|
||||||
|
h = Hammer::Parser
|
||||||
|
@parser_1 = h.uint16
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_1
|
||||||
|
assert_parse_ok @parser_1, "\x02\x00", 0x200
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_2
|
||||||
|
refute_parse_ok @parser_1, "\x02"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class TestUint8 < Minitest::Test
|
||||||
|
def setup
|
||||||
|
super
|
||||||
|
h = Hammer::Parser
|
||||||
|
@parser_1 = h.uint8
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_1
|
||||||
|
assert_parse_ok @parser_1, "x", 0x78
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_2
|
||||||
|
refute_parse_ok @parser_1, ""
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class TestIntRange < Minitest::Test
|
||||||
|
def setup
|
||||||
|
super
|
||||||
|
h = Hammer::Parser
|
||||||
|
@parser_1 = h.int_range(h.uint8, 0x3, 0x10)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_1
|
||||||
|
assert_parse_ok @parser_1, "\x05", 0x5
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_2
|
||||||
|
refute_parse_ok @parser_1, "\x0b"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class TestWhitespace < Minitest::Test
|
||||||
|
def setup
|
||||||
|
super
|
||||||
|
h = Hammer::Parser
|
||||||
|
@parser_1 = h.whitespace(h.ch(0x61))
|
||||||
|
@parser_2 = h.whitespace(h.end_p)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_1
|
||||||
|
assert_parse_ok @parser_1, "a", 'a'
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_2
|
||||||
|
assert_parse_ok @parser_1, " a", 'a'
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_3
|
||||||
|
assert_parse_ok @parser_1, " a", 'a'
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_4
|
||||||
|
assert_parse_ok @parser_1, "\x09a", 'a'
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_5
|
||||||
|
refute_parse_ok @parser_1, "_a"
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_6
|
||||||
|
assert_parse_ok @parser_2, "", null
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_7
|
||||||
|
assert_parse_ok @parser_2, " ", null
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_8
|
||||||
|
refute_parse_ok @parser_2, " x"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class TestLeft < Minitest::Test
|
||||||
|
def setup
|
||||||
|
super
|
||||||
|
h = Hammer::Parser
|
||||||
|
@parser_1 = h.left(h.ch(0x61), h.ch(0x20))
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_1
|
||||||
|
assert_parse_ok @parser_1, "a ", 'a'
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_2
|
||||||
|
refute_parse_ok @parser_1, "a"
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_3
|
||||||
|
refute_parse_ok @parser_1, " "
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_4
|
||||||
|
refute_parse_ok @parser_1, "ba"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class TestMiddle < Minitest::Test
|
||||||
|
def setup
|
||||||
|
super
|
||||||
|
h = Hammer::Parser
|
||||||
|
@parser_1 = h.middle(h.ch(' '), h.ch('a'), h.ch(' '))
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_1
|
||||||
|
assert_parse_ok @parser_1, " a ", 'a'
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_2
|
||||||
|
refute_parse_ok @parser_1, "a"
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_3
|
||||||
|
refute_parse_ok @parser_1, " a"
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_4
|
||||||
|
refute_parse_ok @parser_1, "a "
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_5
|
||||||
|
refute_parse_ok @parser_1, " b "
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_6
|
||||||
|
refute_parse_ok @parser_1, "ba "
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_7
|
||||||
|
refute_parse_ok @parser_1, " ab"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class TestIn < Minitest::Test
|
||||||
|
def setup
|
||||||
|
super
|
||||||
|
h = Hammer::Parser
|
||||||
|
@parser_1 = h.in("abc")
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_1
|
||||||
|
assert_parse_ok @parser_1, "b", 'b'
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_2
|
||||||
|
refute_parse_ok @parser_1, "d"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class TestNotIn < Minitest::Test
|
||||||
|
def setup
|
||||||
|
super
|
||||||
|
h = Hammer::Parser
|
||||||
|
@parser_1 = h.not_in("abc")
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_1
|
||||||
|
assert_parse_ok @parser_1, "d", 'd'
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_2
|
||||||
|
refute_parse_ok @parser_1, "a"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class TestEndP < Minitest::Test
|
||||||
|
def setup
|
||||||
|
super
|
||||||
|
h = Hammer::Parser
|
||||||
|
@parser_1 = h.sequence(h.ch('a'), h.end_p)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_1
|
||||||
|
assert_parse_ok @parser_1, "a", ['a']
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_2
|
||||||
|
refute_parse_ok @parser_1, "aa"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class TestNothingP < Minitest::Test
|
||||||
|
def setup
|
||||||
|
super
|
||||||
|
h = Hammer::Parser
|
||||||
|
@parser_1 = h.nothing_p
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_1
|
||||||
|
refute_parse_ok @parser_1, "a"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class TestSequence < Minitest::Test
|
||||||
|
def setup
|
||||||
|
super
|
||||||
|
h = Hammer::Parser
|
||||||
|
@parser_1 = h.sequence(h.ch('a'), h.ch('b'))
|
||||||
|
@parser_2 = h.sequence(h.ch('a'), h.whitespace(h.ch('b')))
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_1
|
||||||
|
assert_parse_ok @parser_1, "ab", ['a', 'b']
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_2
|
||||||
|
refute_parse_ok @parser_1, "a"
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_3
|
||||||
|
refute_parse_ok @parser_1, "b"
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_4
|
||||||
|
assert_parse_ok @parser_2, "ab", ['a', 'b']
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_5
|
||||||
|
assert_parse_ok @parser_2, "a b", ['a', 'b']
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_6
|
||||||
|
assert_parse_ok @parser_2, "a b", ['a', 'b']
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class TestChoice < Minitest::Test
|
||||||
|
def setup
|
||||||
|
super
|
||||||
|
h = Hammer::Parser
|
||||||
|
@parser_1 = h.choice(h.ch('a'), h.ch('b'))
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_1
|
||||||
|
assert_parse_ok @parser_1, "a", 'a'
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_2
|
||||||
|
assert_parse_ok @parser_1, "b", 'b'
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_3
|
||||||
|
assert_parse_ok @parser_1, "ab", 'a'
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_4
|
||||||
|
refute_parse_ok @parser_1, "c"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class TestButnot < Minitest::Test
|
||||||
|
def setup
|
||||||
|
super
|
||||||
|
h = Hammer::Parser
|
||||||
|
@parser_1 = h.butnot(h.ch('a'), h.token("ab"))
|
||||||
|
@parser_2 = h.butnot(h.ch_range('0', '9'), h.ch('6'))
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_1
|
||||||
|
assert_parse_ok @parser_1, "a", 'a'
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_2
|
||||||
|
refute_parse_ok @parser_1, "ab"
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_3
|
||||||
|
assert_parse_ok @parser_1, "aa", 'a'
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_4
|
||||||
|
assert_parse_ok @parser_2, "5", '5'
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_5
|
||||||
|
refute_parse_ok @parser_2, "6"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class TestDifference < Minitest::Test
|
||||||
|
def setup
|
||||||
|
super
|
||||||
|
h = Hammer::Parser
|
||||||
|
@parser_1 = h.difference(h.token("ab"), h.ch('a'))
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_1
|
||||||
|
assert_parse_ok @parser_1, "ab", "ab"
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_2
|
||||||
|
refute_parse_ok @parser_1, "a"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class TestXor < Minitest::Test
|
||||||
|
def setup
|
||||||
|
super
|
||||||
|
h = Hammer::Parser
|
||||||
|
@parser_1 = h.xor(h.ch_range('0', '6'), h.ch_range('5', '9'))
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_1
|
||||||
|
assert_parse_ok @parser_1, "0", '0'
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_2
|
||||||
|
assert_parse_ok @parser_1, "9", '9'
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_3
|
||||||
|
refute_parse_ok @parser_1, "5"
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_4
|
||||||
|
refute_parse_ok @parser_1, "a"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class TestMany < Minitest::Test
|
||||||
|
def setup
|
||||||
|
super
|
||||||
|
h = Hammer::Parser
|
||||||
|
@parser_1 = h.many(h.choice(h.ch('a'), h.ch('b')))
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_1
|
||||||
|
assert_parse_ok @parser_1, "", []
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_2
|
||||||
|
assert_parse_ok @parser_1, "a", ['a']
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_3
|
||||||
|
assert_parse_ok @parser_1, "b", ['b']
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_4
|
||||||
|
assert_parse_ok @parser_1, "aabbaba", ['a', 'a', 'b', 'b', 'a', 'b', 'a']
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class TestMany1 < Minitest::Test
|
||||||
|
def setup
|
||||||
|
super
|
||||||
|
h = Hammer::Parser
|
||||||
|
@parser_1 = h.many1(h.choice(h.ch('a'), h.ch('b')))
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_1
|
||||||
|
refute_parse_ok @parser_1, ""
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_2
|
||||||
|
assert_parse_ok @parser_1, "a", ['a']
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_3
|
||||||
|
assert_parse_ok @parser_1, "b", ['b']
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_4
|
||||||
|
assert_parse_ok @parser_1, "aabbaba", ['a', 'a', 'b', 'b', 'a', 'b', 'a']
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_5
|
||||||
|
refute_parse_ok @parser_1, "daabbabadef"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class TestRepeatN < Minitest::Test
|
||||||
|
def setup
|
||||||
|
super
|
||||||
|
h = Hammer::Parser
|
||||||
|
@parser_1 = h.repeat_n(h.choice(h.ch('a'), h.ch('b')), 0x2)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_1
|
||||||
|
refute_parse_ok @parser_1, "adef"
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_2
|
||||||
|
assert_parse_ok @parser_1, "abdef", ['a', 'b']
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_3
|
||||||
|
refute_parse_ok @parser_1, "dabdef"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class TestOptional < Minitest::Test
|
||||||
|
def setup
|
||||||
|
super
|
||||||
|
h = Hammer::Parser
|
||||||
|
@parser_1 = h.sequence(h.ch('a'), h.optional(h.choice(h.ch('b'), h.ch('c'))), h.ch('d'))
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_1
|
||||||
|
assert_parse_ok @parser_1, "abd", ['a', 'b', 'd']
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_2
|
||||||
|
assert_parse_ok @parser_1, "acd", ['a', 'c', 'd']
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_3
|
||||||
|
assert_parse_ok @parser_1, "ad", ['a', null, 'd']
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_4
|
||||||
|
refute_parse_ok @parser_1, "aed"
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_5
|
||||||
|
refute_parse_ok @parser_1, "ab"
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_6
|
||||||
|
refute_parse_ok @parser_1, "ac"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class TestIgnore < Minitest::Test
|
||||||
|
def setup
|
||||||
|
super
|
||||||
|
h = Hammer::Parser
|
||||||
|
@parser_1 = h.sequence(h.ch('a'), h.ignore(h.ch('b')), h.ch('c'))
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_1
|
||||||
|
assert_parse_ok @parser_1, "abc", ['a', 'c']
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_2
|
||||||
|
refute_parse_ok @parser_1, "ac"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class TestSepBy < Minitest::Test
|
||||||
|
def setup
|
||||||
|
super
|
||||||
|
h = Hammer::Parser
|
||||||
|
@parser_1 = h.sepBy(h.choice(h.ch('1'), h.ch('2'), h.ch('3')), h.ch(','))
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_1
|
||||||
|
assert_parse_ok @parser_1, "1,2,3", ['1', '2', '3']
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_2
|
||||||
|
assert_parse_ok @parser_1, "1,3,2", ['1', '3', '2']
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_3
|
||||||
|
assert_parse_ok @parser_1, "1,3", ['1', '3']
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_4
|
||||||
|
assert_parse_ok @parser_1, "3", ['3']
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_5
|
||||||
|
assert_parse_ok @parser_1, "", []
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class TestSepBy1 < Minitest::Test
|
||||||
|
def setup
|
||||||
|
super
|
||||||
|
h = Hammer::Parser
|
||||||
|
@parser_1 = h.sepBy1(h.choice(h.ch('1'), h.ch('2'), h.ch('3')), h.ch(','))
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_1
|
||||||
|
assert_parse_ok @parser_1, "1,2,3", ['1', '2', '3']
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_2
|
||||||
|
assert_parse_ok @parser_1, "1,3,2", ['1', '3', '2']
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_3
|
||||||
|
assert_parse_ok @parser_1, "1,3", ['1', '3']
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_4
|
||||||
|
assert_parse_ok @parser_1, "3", ['3']
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_5
|
||||||
|
refute_parse_ok @parser_1, ""
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class TestAnd < Minitest::Test
|
||||||
|
def setup
|
||||||
|
super
|
||||||
|
h = Hammer::Parser
|
||||||
|
@parser_1 = h.sequence(h.and(h.ch('0')), h.ch('0'))
|
||||||
|
@parser_2 = h.sequence(h.and(h.ch('0')), h.ch('1'))
|
||||||
|
@parser_3 = h.sequence(h.ch('1'), h.and(h.ch('2')))
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_1
|
||||||
|
assert_parse_ok @parser_1, "0", ['0']
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_2
|
||||||
|
refute_parse_ok @parser_1, "1"
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_3
|
||||||
|
refute_parse_ok @parser_2, "0"
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_4
|
||||||
|
refute_parse_ok @parser_2, "1"
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_5
|
||||||
|
assert_parse_ok @parser_3, "12", ['1']
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_6
|
||||||
|
refute_parse_ok @parser_3, "13"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class TestNot < Minitest::Test
|
||||||
|
def setup
|
||||||
|
super
|
||||||
|
h = Hammer::Parser
|
||||||
|
@parser_1 = h.sequence(h.ch('a'), h.choice(h.token("+"), h.token("++")), h.ch('b'))
|
||||||
|
@parser_2 = h.sequence(h.ch('a'), h.choice(h.sequence(h.token("+"), h.not(h.ch('+'))), h.token("++")), h.ch('b'))
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_1
|
||||||
|
assert_parse_ok @parser_1, "a+b", ['a', "+", 'b']
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_2
|
||||||
|
refute_parse_ok @parser_1, "a++b"
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_3
|
||||||
|
assert_parse_ok @parser_2, "a+b", ['a', ["+"], 'b']
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_4
|
||||||
|
assert_parse_ok @parser_2, "a++b", ['a', "++", 'b']
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class TestRightrec < Minitest::Test
|
||||||
|
def setup
|
||||||
|
super
|
||||||
|
h = Hammer::Parser
|
||||||
|
@sp_rr = h.indirect
|
||||||
|
@sp_rr.bind h.choice(h.sequence(h.ch('a'), @sp_rr), h.epsilon_p)
|
||||||
|
@parser_1 = @sp_rr
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_1
|
||||||
|
assert_parse_ok @parser_1, "a", ['a']
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_2
|
||||||
|
assert_parse_ok @parser_1, "aa", ['a', ['a']]
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_3
|
||||||
|
assert_parse_ok @parser_1, "aaa", ['a', ['a', ['a']]]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class TestAmbiguous < Minitest::Test
|
||||||
|
def setup
|
||||||
|
super
|
||||||
|
h = Hammer::Parser
|
||||||
|
@sp_d = h.indirect
|
||||||
|
@sp_p = h.indirect
|
||||||
|
@sp_e = h.indirect
|
||||||
|
@sp_d.bind h.ch('d')
|
||||||
|
@sp_p.bind h.ch('+')
|
||||||
|
@sp_e.bind h.choice(h.sequence(@sp_e, @sp_p, @sp_e), @sp_d)
|
||||||
|
@parser_1 = @sp_e
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_1
|
||||||
|
assert_parse_ok @parser_1, "d", 'd'
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_2
|
||||||
|
assert_parse_ok @parser_1, "d+d", ['d', '+', 'd']
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_3
|
||||||
|
assert_parse_ok @parser_1, "d+d+d", [['d', '+', 'd'], '+', 'd']
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue