/
binaryparsers.pas
124 lines (100 loc) · 2.65 KB
/
binaryparsers.pas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
unit BinaryParsers;
{$mode Delphi}
interface
uses
Parsers, ParseResult, Tokenizers;
type
TBinaryParser<L, R, T> = class(TParser<T>)
private
FLeft: TParser<L>;
FRight: TParser<R>;
public
constructor Create(Left: TParser<L>; Right: TParser<R>);
destructor Destroy; override;
end;
TAbstractAndParser<L, R, T> = class(TBinaryParser<L, R, T>)
protected
function Combine(Left: L; Right: R): T; virtual; abstract;
public
function Parse(Source: TUndoTokenizer): TParseResult<T>; override;
end;
(* And *)
TPair<L, R> = record
Left: L;
Right: R;
end;
TAndParser<L, R> = class(TAbstractAndParser<L, R, TPair<L, R>>)
protected
function Combine(Left: L; Right: R): TPair<L, R>; override;
public
procedure Undo(Source: TUndoTokenizer; Data: TPair<L, R>); override;
end;
function Seq<L, R>(Left: TParser<L>; Right: TParser<R>): TParser<TPair<L, R>>; overload;
type
(* Or *)
TOrParser<T> = class(TBinaryParser<T, T, T>)
public
function Parse(Source: TUndoTokenizer): TParseResult<T>; override;
procedure Undo(Source: TUndoTokenizer; Data: T); override;
end;
implementation
(* Binary *)
constructor TBinaryParser<L, R, T>.Create(Left: TParser<L>; Right: TParser<R>);
begin
FLeft := Left;
FRight := Right;
end;
destructor TBinaryParser<L, R, T>.Destroy;
begin
FLeft.Free;
FRight.Free;
inherited Destroy;
end;
(* AbstractAnd *)
function TAbstractAndParser<L, R, T>.Parse(Source: TUndoTokenizer): TParseResult<T>;
var
Left: TParseResult<L>;
Right: TParseResult<R>;
begin
Left := FLeft.Parse(Source);
if Left.Success then
begin
Right := FRight.Parse(Source);
if Right.Success then
Result := SuccessParseResult<T>(Combine(Left.Data, Right.Data))
else
begin
FLeft.Undo(Source, Left.Data);
Result := FailedParseResult<T>();
end
end
else
Result := FailedParseResult<T>()
end;
(* And *)
function TAndParser<L, R>.Combine(Left: L; Right: R): TPair<L, R>;
begin
Result.Left := Left;
Result.Right := Right;
end;
procedure TAndParser<L, R>.Undo(Source: TUndoTokenizer; Data: TPair<L, R>);
begin
FRight.Undo(Source, Data.Right);
FLeft.Undo(Source, Data.Left);
end;
function Seq<L, R>(Left: TParser<L>; Right: TParser<R>): TParser<TPair<L, R>>; overload;
begin
Result := TAndParser<L, R>.Create(Left, Right);
end;
(* Or *)
function TOrParser<T>.Parse(Source: TUndoTokenizer): TParseResult<T>;
begin
Result := FLeft.Parse(Source);
if not Result.Success then
Result := FRight.Parse(Source);
end;
procedure TOrParser<T>.Undo(Source: TUndoTokenizer; Data: T);
begin
FLeft.Undo(Source, Data); // TODO: remember which parser was actually used?
end;
end.