-
-
Notifications
You must be signed in to change notification settings - Fork 68
/
Copy pathgherkin-ruby.razor
222 lines (190 loc) · 6.06 KB
/
gherkin-ruby.razor
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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
@using Berp;
@helper CallProduction(ProductionRule production, string extraIndent)
{
switch(production.Type)
{
case ProductionRuleType.Start:
@:@(extraIndent) start_rule(context, :@production.RuleName);
break;
case ProductionRuleType.End:
@:@(extraIndent) end_rule(context, :@production.RuleName);
break;
case ProductionRuleType.Process:
@:@(extraIndent) build(context, token);
break;
}
}
@helper HandleParserError(IEnumerable<string> expectedTokens, State state)
{<text>
state_comment = "State: @state.Id - @Raw(state.Comment)"
token.detach
expected_tokens = ["@Raw(string.Join("\", \"", expectedTokens))"]
error = token.eof? ? UnexpectedEOFException.new(token, expected_tokens, state_comment) : UnexpectedTokenException.new(token, expected_tokens, state_comment)
raise error if (stop_at_first_error)
add_error(context, error)
return @state.Id</text>}
@helper MatchToken(TokenType tokenType)
{<text>match_@(tokenType)(context, token)</text>}
# This file is generated. Do not edit! Edit gherkin-ruby.razor instead.
require_relative 'ast_builder'
require_relative 'token_matcher'
require_relative 'token_scanner'
require_relative 'errors'
module Gherkin
RULE_TYPE = [
:None,
@foreach(var rule in Model.RuleSet.Where(r => !r.TempRule))
{<text> :@rule.Name.Replace("#", "_"), # @rule.ToString(true)
</text>}
]
class ParserContext
attr_reader :token_scanner, :token_matcher, :token_queue, :errors
def initialize(token_scanner, token_matcher, token_queue, errors)
@@token_scanner = token_scanner
@@token_matcher = token_matcher
@@token_queue = token_queue
@@errors = errors
end
end
class @Model.ParserClassName
attr_accessor :stop_at_first_error
def initialize(ast_builder = AstBuilder.new(Cucumber::Messages::Helpers::IdGenerator::UUID.new))
@@ast_builder = ast_builder
end
def parse(token_scanner, token_matcher=TokenMatcher.new)
token_scanner = token_scanner.is_a?(TokenScanner) ? token_scanner : TokenScanner.new(token_scanner)
@@ast_builder.reset
token_matcher.reset
context = ParserContext.new(
token_scanner,
token_matcher,
[],
[]
)
start_rule(context, :@Model.RuleSet.StartRule.Name);
state = 0
token = nil
begin
token = read_token(context)
state = match_token(state, token, context)
end until(token.eof?)
end_rule(context, :@Model.RuleSet.StartRule.Name)
raise CompositeParserException.new(context.errors) if context.errors.any?
get_result()
end
def build(context, token)
handle_ast_error(context) do
@@ast_builder.build(token)
end
end
def add_error(context, error)
context.errors.push(error) unless context.errors.map { |e| e.message }.include?(error.message)
raise CompositeParserException, context.errors if context.errors.length > 10
end
def start_rule(context, rule_type)
handle_ast_error(context) do
@@ast_builder.start_rule(rule_type)
end
end
def end_rule(context, rule_type)
handle_ast_error(context) do
@@ast_builder.end_rule(rule_type)
end
end
def get_result()
@@ast_builder.get_result
end
def read_token(context)
context.token_queue.any? ? context.token_queue.shift : context.token_scanner.read
end
@foreach(var rule in Model.RuleSet.TokenRules)
{<text>
def match_@(rule.Name.Replace("#", ""))( context, token)
@if (rule.Name != "#EOF")
{
@:return false if token.eof?
}
return handle_external_error(context, false) do
context.token_matcher.match_@(rule.Name.Replace("#", ""))(token)
end
end
</text>
}
def match_token(state, token, context)
case state
@foreach(var state in Model.States.Values.Where(s => !s.IsEndState))
{
@:when @state.Id
@:match_token_at_state@(state.Id)(token, context)
}
else
raise InvalidOperationException, "Unknown state: #{state}"
end
end
@foreach(var state in Model.States.Values.Where(s => !s.IsEndState))
{<text>
# @Raw(state.Comment)
def match_token_at_state@(state.Id)(token, context)
@foreach(var transition in state.Transitions)
{
@:if @MatchToken(transition.TokenType)
var extraIndent = "";
if (transition.LookAheadHint != null)
{
extraIndent = " ";
@:@("if lookahead")@(transition.LookAheadHint.Id)(context, token)
}
foreach(var production in transition.Productions)
{
@CallProduction(production, extraIndent)
}
@:@(extraIndent)return @transition.TargetState
if (transition.LookAheadHint != null)
{
@:end
}
@:end
}
@HandleParserError(state.Transitions.Select(t => "#" + t.TokenType.ToString()).Distinct(), state)
end</text>
}
@foreach(var lookAheadHint in Model.RuleSet.LookAheadHints)
{
<text>
def lookahead@(lookAheadHint.Id)(context, current_token)
current_token.detach
token = nil
queue = []
match = false
loop do
token = read_token(context)
token.detach
queue.push(token)
if (false @foreach(var tokenType in lookAheadHint.ExpectedTokens) {<text>|| @MatchToken(tokenType)</text>})
match = true
break
end
break unless (false @foreach(var tokenType in lookAheadHint.Skip) {<text>|| @MatchToken(tokenType)</text>})
end
context.token_queue.concat(queue)
return match
end
</text>
}
private
def handle_ast_error(context, &action)
handle_external_error(context, true, &action)
end
def handle_external_error(context, default_value, &action)
return action.call if stop_at_first_error
begin
return action.call
rescue CompositeParserException => e
e.errors.each { |error| add_error(context, error) }
rescue ParserException => e
add_error(context, e)
end
default_value
end
end
end