198 lines
4.4 KiB
Perl
198 lines
4.4 KiB
Perl
|
|
% -*- prolog -*-
|
||
|
|
|
||
|
|
% test suite grammar
|
||
|
|
:- module(tsparser,
|
||
|
|
[read_tc/1]).
|
||
|
|
:- expects_dialect(swi).
|
||
|
|
:- use_module(library(pure_input)).
|
||
|
|
|
||
|
|
|
||
|
|
nl --> "\r", !.
|
||
|
|
nl --> "\n", !.
|
||
|
|
ws --> " ", !.
|
||
|
|
ws --> "\t", !.
|
||
|
|
ws --> nl, !.
|
||
|
|
nonws --> ws, !, {fail}.
|
||
|
|
nonws --> [_]. % any character other than whitespace
|
||
|
|
tilEOL --> nl, !.
|
||
|
|
tilEOL --> [_], tilEOL.
|
||
|
|
comment --> "#", tilEOL.
|
||
|
|
layout1 --> ws, !; comment.
|
||
|
|
layout --> layout1, !, layout.
|
||
|
|
layout --> [].
|
||
|
|
eof([],[]).
|
||
|
|
|
||
|
|
idChar(Chr) -->
|
||
|
|
[Chr],
|
||
|
|
{memberchk(Chr, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")}.
|
||
|
|
idTailChar(Chr) --> idChar(Chr), !.
|
||
|
|
idTailChar(Chr) -->
|
||
|
|
[Chr],
|
||
|
|
{memberchk(Chr, "1234567890-_")}.
|
||
|
|
|
||
|
|
id(Name) --> % toplevel lexical token
|
||
|
|
idChar(Chr),
|
||
|
|
idTail(Rest),
|
||
|
|
{atom_codes(Name, [Chr|Rest])}.
|
||
|
|
idTail([Chr|Rest]) -->
|
||
|
|
idTailChar(Chr), !,
|
||
|
|
idTail(Rest).
|
||
|
|
idTail([]) --> [].
|
||
|
|
|
||
|
|
string(Str) --> "\"", qstring(Str), "\"", !.
|
||
|
|
string(Str) --> "<", hexstring(Str), ">".
|
||
|
|
|
||
|
|
qchar(C) --> "\\x", !, hexbyte(C).
|
||
|
|
qchar(C) --> [C], {C >= 0x20, C < 0x7F}.
|
||
|
|
qstring([], [34|R], [34|R]) :- !.
|
||
|
|
qstring([C|Rest]) -->
|
||
|
|
qchar(C), qstring(Rest).
|
||
|
|
qstring([]).
|
||
|
|
hexstring([C|Rest]) -->
|
||
|
|
hexbyte(C), !,
|
||
|
|
hexstring_post(Rest).
|
||
|
|
hexstring([]) -->
|
||
|
|
[].
|
||
|
|
hexstring_post([C|Rest]) -->
|
||
|
|
".", !,
|
||
|
|
hexbyte(C),
|
||
|
|
hexstring_post(Rest).
|
||
|
|
hexstring_post([]) --> [].
|
||
|
|
|
||
|
|
hexchr(C) --> [C0], {memberchk(C0, "0123456789"), C is C0 - 0x30}, !.
|
||
|
|
hexchr(C) --> [C0], {memberchk(C0, "abcdef"), C is C0 - 0x61 + 10}, !.
|
||
|
|
hexchr(C) --> [C0], {memberchk(C0, "ABCDEF"), C is C0 - 0x41 + 10}, !.
|
||
|
|
hexbyte(C) -->
|
||
|
|
hexchr(C0),
|
||
|
|
hexchr(C1),
|
||
|
|
{C is C0 * 16 + C1}.
|
||
|
|
hexnum(A) -->
|
||
|
|
hexchr(C0),
|
||
|
|
hexnum(A, C0).
|
||
|
|
hexnum(A, Acc) -->
|
||
|
|
hexchr(C0), !,
|
||
|
|
{AccP is Acc * 16 + C0},
|
||
|
|
hexnum(A, AccP).
|
||
|
|
hexnum(Acc, Acc) --> [].
|
||
|
|
|
||
|
|
|
||
|
|
parse_result_seq([A|Ar]) -->
|
||
|
|
parse_result(A), layout,
|
||
|
|
parse_result_seq_tail(Ar).
|
||
|
|
parse_result_seq([]) -->
|
||
|
|
layout.
|
||
|
|
parse_result_seq_tail([]) --> [].
|
||
|
|
parse_result_seq_tail([A|Ar]) -->
|
||
|
|
",", layout,
|
||
|
|
parse_result(A), layout,
|
||
|
|
parse_result_seq_tail(Ar).
|
||
|
|
|
||
|
|
parse_result(seq(A)) -->
|
||
|
|
"[", layout,
|
||
|
|
parse_result_seq(A), % eats trailing ws
|
||
|
|
"]", !.
|
||
|
|
parse_result(char(A)) -->
|
||
|
|
"'", qchar(A), "'", !.
|
||
|
|
parse_result(uint(A)) -->
|
||
|
|
"u0x", hexnum(A), !.
|
||
|
|
parse_result(sint(A)) -->
|
||
|
|
"s0x", hexnum(A), !.
|
||
|
|
parse_result(sint(A)) -->
|
||
|
|
"s-0x", hexnum(A0), {A is -A0}, !.
|
||
|
|
parse_result(string(A)) -->
|
||
|
|
string(A), !.
|
||
|
|
parse_result(none) --> "none".
|
||
|
|
|
||
|
|
parser_arg(A) --> parser(A), !.
|
||
|
|
parser_arg(string(A)) --> string(A), !.
|
||
|
|
parser_arg(char(A)) --> "'", qchar(A), "'", !.
|
||
|
|
parser_arg(num(A)) --> "0x", hexnum(A).
|
||
|
|
|
||
|
|
parser_arglist_tail([A0|As]) -->
|
||
|
|
% eats leading whitespace
|
||
|
|
",", !, layout,
|
||
|
|
parser_arg(A0), layout,
|
||
|
|
parser_arglist_tail(As).
|
||
|
|
parser_arglist_tail([]) --> [].
|
||
|
|
|
||
|
|
parser_arglist([]) --> [].
|
||
|
|
parser_arglist([A0|As]) -->
|
||
|
|
parser_arg(A0),
|
||
|
|
layout,
|
||
|
|
parser_arglist_tail(As). % eats trailing whitespace
|
||
|
|
|
||
|
|
|
||
|
|
parser(ref(Name)) -->
|
||
|
|
"$", !, id(Name).
|
||
|
|
parser(parser(Name, Args)) -->
|
||
|
|
id(Name), layout,
|
||
|
|
"(", layout,
|
||
|
|
parser_arglist(Args), % eats trailing whitespace
|
||
|
|
")".
|
||
|
|
|
||
|
|
testcase_elem(subparser(Name,Value)) -->
|
||
|
|
"subparser", layout1, layout, !,
|
||
|
|
"$", id(Name), layout,
|
||
|
|
"=", layout,
|
||
|
|
parser(Value), layout,
|
||
|
|
";".
|
||
|
|
testcase_elem(parser(Value)) -->
|
||
|
|
"parser", layout1, layout, !,
|
||
|
|
parser(Value), layout,
|
||
|
|
";".
|
||
|
|
testcase_elem(testFail(Input)) -->
|
||
|
|
"test", layout1, layout,
|
||
|
|
string(Input), layout,
|
||
|
|
"-->", layout,
|
||
|
|
"fail", layout,
|
||
|
|
";", !.
|
||
|
|
testcase_elem(test(Input, Expected)) -->
|
||
|
|
"test", layout1, layout,
|
||
|
|
string(Input), layout,
|
||
|
|
"-->", layout,
|
||
|
|
parse_result(Expected), layout,
|
||
|
|
";", !.
|
||
|
|
|
||
|
|
testcase_body([Elem|Rest]) -->
|
||
|
|
testcase_elem(Elem), layout, !,
|
||
|
|
testcase_body(Rest).
|
||
|
|
testcase_body([]) --> [].
|
||
|
|
|
||
|
|
testcase(testcase(Name,Content)) -->
|
||
|
|
id(Name),
|
||
|
|
layout,
|
||
|
|
"{",
|
||
|
|
layout,
|
||
|
|
testcase_body(Content),
|
||
|
|
layout,
|
||
|
|
"}".
|
||
|
|
|
||
|
|
testcases([]) -->
|
||
|
|
layout, eof, !.
|
||
|
|
testcases([TC|Rest]) -->
|
||
|
|
layout,
|
||
|
|
testcase(TC),
|
||
|
|
testcases(Rest).
|
||
|
|
testsuite(A) -->
|
||
|
|
testcases(A).
|
||
|
|
|
||
|
|
|
||
|
|
%slurp(File, Lst) :-
|
||
|
|
% get_code(File, C),
|
||
|
|
% (C == -1 ->
|
||
|
|
% Lst = [];
|
||
|
|
% slurp(File, Rest),
|
||
|
|
% Lst = [C|Rest]), !.
|
||
|
|
|
||
|
|
read_tc(A) :-
|
||
|
|
phrase_from_file(testsuite(A), 'test-suite').
|
||
|
|
|
||
|
|
%read_tc(A) :-
|
||
|
|
% read_tc('test-suite', A).
|
||
|
|
%read_tc(Name, A) :-
|
||
|
|
% open(Name, read, File),
|
||
|
|
% slurp(File, Contents),
|
||
|
|
% close(File), !,
|
||
|
|
% phrase(testsuite(A), Contents).
|
||
|
|
|