/
expr.y
410 lines (361 loc) · 20.8 KB
/
expr.y
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
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
%{
package traceql
import (
"time"
)
%}
%start root
%union {
root RootExpr
groupOperation GroupOperation
coalesceOperation CoalesceOperation
selectOperation SelectOperation
attributeList []Attribute
spansetExpression SpansetExpression
spansetPipelineExpression SpansetExpression
wrappedSpansetPipeline Pipeline
spansetPipeline Pipeline
spansetFilter *SpansetFilter
scalarFilter ScalarFilter
scalarFilterOperation Operator
scalarPipelineExpressionFilter ScalarFilter
scalarPipelineExpression ScalarExpression
scalarExpression ScalarExpression
wrappedScalarPipeline Pipeline
scalarPipeline Pipeline
aggregate Aggregate
metricsAggregation *MetricsAggregate
fieldExpression FieldExpression
static Static
intrinsicField Attribute
attributeField Attribute
attribute Attribute
scopedIntrinsicField Attribute
binOp Operator
staticInt int
staticStr string
staticFloat float64
staticDuration time.Duration
numericList []float64
hint *Hint
hintList []*Hint
hints *Hints
}
%type <RootExpr> root
%type <groupOperation> groupOperation
%type <coalesceOperation> coalesceOperation
%type <selectOperation> selectOperation
%type <attributeList> attributeList
%type <spansetExpression> spansetExpression
%type <spansetPipelineExpression> spansetPipelineExpression
%type <wrappedSpansetPipeline> wrappedSpansetPipeline
%type <spansetPipeline> spansetPipeline
%type <spansetFilter> spansetFilter
%type <scalarFilter> scalarFilter
%type <scalarFilterOperation> scalarFilterOperation
%type <metricsAggregation> metricsAggregation
%type <scalarPipelineExpressionFilter> scalarPipelineExpressionFilter
%type <scalarPipelineExpression> scalarPipelineExpression
%type <scalarExpression> scalarExpression
%type <wrappedScalarPipeline> wrappedScalarPipeline
%type <scalarPipeline> scalarPipeline
%type <aggregate> aggregate
%type <fieldExpression> fieldExpression
%type <static> static
%type <intrinsicField> intrinsicField
%type <attributeField> attributeField
%type <scopedIntrinsicField> scopedIntrinsicField
%type <attribute> attribute
%type <numericList> numericList
%type <hint> hint
%type <hintList> hintList
%type <hints> hints
%token <staticStr> IDENTIFIER STRING
%token <staticInt> INTEGER
%token <staticFloat> FLOAT
%token <staticDuration> DURATION
%token <val> DOT OPEN_BRACE CLOSE_BRACE OPEN_PARENS CLOSE_PARENS COMMA
NIL TRUE FALSE STATUS_ERROR STATUS_OK STATUS_UNSET
KIND_UNSPECIFIED KIND_INTERNAL KIND_SERVER KIND_CLIENT KIND_PRODUCER KIND_CONSUMER
IDURATION CHILDCOUNT NAME STATUS STATUS_MESSAGE PARENT KIND ROOTNAME ROOTSERVICENAME
ROOTSERVICE TRACEDURATION NESTEDSETLEFT NESTEDSETRIGHT NESTEDSETPARENT
PARENT_DOT RESOURCE_DOT SPAN_DOT TRACE_COLON SPAN_COLON
COUNT AVG MAX MIN SUM
BY COALESCE SELECT
END_ATTRIBUTE
RATE COUNT_OVER_TIME QUANTILE_OVER_TIME HISTOGRAM_OVER_TIME
WITH
// Operators are listed with increasing precedence.
%left <binOp> PIPE
%left <binOp> AND OR
%left <binOp> EQ NEQ LT LTE GT GTE NRE RE DESC ANCE SIBL NOT_CHILD NOT_PARENT NOT_DESC NOT_ANCE UNION_CHILD UNION_PARENT UNION_DESC UNION_ANCE UNION_SIBL
%left <binOp> ADD SUB
%left <binOp> NOT
%left <binOp> MUL DIV MOD
%right <binOp> POW
%%
// **********************
// Pipeline
// **********************
root:
spansetPipeline { yylex.(*lexer).expr = newRootExpr($1) }
| spansetPipelineExpression { yylex.(*lexer).expr = newRootExpr($1) }
| scalarPipelineExpressionFilter { yylex.(*lexer).expr = newRootExpr($1) }
| spansetPipeline PIPE metricsAggregation { yylex.(*lexer).expr = newRootExprWithMetrics($1, $3) }
| root hints { yylex.(*lexer).expr.withHints($2) }
;
// **********************
// Spanset Expressions
// **********************
spansetPipelineExpression: // shares the same operators as spansetExpression. split out for readability
OPEN_PARENS spansetPipelineExpression CLOSE_PARENS { $$ = $2 }
| spansetPipelineExpression AND spansetPipelineExpression { $$ = newSpansetOperation(OpSpansetAnd, $1, $3) }
| spansetPipelineExpression GT spansetPipelineExpression { $$ = newSpansetOperation(OpSpansetChild, $1, $3) }
| spansetPipelineExpression LT spansetPipelineExpression { $$ = newSpansetOperation(OpSpansetParent, $1, $3) }
| spansetPipelineExpression DESC spansetPipelineExpression { $$ = newSpansetOperation(OpSpansetDescendant, $1, $3) }
| spansetPipelineExpression ANCE spansetPipelineExpression { $$ = newSpansetOperation(OpSpansetAncestor, $1, $3) }
| spansetPipelineExpression OR spansetPipelineExpression { $$ = newSpansetOperation(OpSpansetUnion, $1, $3) }
| spansetPipelineExpression SIBL spansetPipelineExpression { $$ = newSpansetOperation(OpSpansetSibling, $1, $3) }
| spansetPipelineExpression NOT_CHILD spansetPipelineExpression { $$ = newSpansetOperation(OpSpansetNotChild, $1, $3) }
| spansetPipelineExpression NOT_PARENT spansetPipelineExpression { $$ = newSpansetOperation(OpSpansetNotParent, $1, $3) }
| spansetPipelineExpression NOT_DESC spansetPipelineExpression { $$ = newSpansetOperation(OpSpansetNotDescendant, $1, $3) }
| spansetPipelineExpression NOT_ANCE spansetPipelineExpression { $$ = newSpansetOperation(OpSpansetNotAncestor, $1, $3) }
| spansetPipelineExpression NRE spansetPipelineExpression { $$ = newSpansetOperation(OpSpansetNotSibling, $1, $3) }
| spansetPipelineExpression UNION_CHILD spansetPipelineExpression { $$ = newSpansetOperation(OpSpansetUnionChild, $1, $3) }
| spansetPipelineExpression UNION_PARENT spansetPipelineExpression { $$ = newSpansetOperation(OpSpansetUnionParent, $1, $3) }
| spansetPipelineExpression UNION_DESC spansetPipelineExpression { $$ = newSpansetOperation(OpSpansetUnionDescendant, $1, $3) }
| spansetPipelineExpression UNION_ANCE spansetPipelineExpression { $$ = newSpansetOperation(OpSpansetUnionAncestor, $1, $3) }
| spansetPipelineExpression UNION_SIBL spansetPipelineExpression { $$ = newSpansetOperation(OpSpansetUnionSibling, $1, $3) }
| wrappedSpansetPipeline { $$ = $1 }
;
wrappedSpansetPipeline:
OPEN_PARENS spansetPipeline CLOSE_PARENS { $$ = $2 }
spansetPipeline:
spansetExpression { $$ = newPipeline($1) }
| scalarFilter { $$ = newPipeline($1) }
| groupOperation { $$ = newPipeline($1) }
| selectOperation { $$ = newPipeline($1) }
| spansetPipeline PIPE spansetExpression { $$ = $1.addItem($3) }
| spansetPipeline PIPE scalarFilter { $$ = $1.addItem($3) }
| spansetPipeline PIPE groupOperation { $$ = $1.addItem($3) }
| spansetPipeline PIPE coalesceOperation { $$ = $1.addItem($3) }
| spansetPipeline PIPE selectOperation { $$ = $1.addItem($3) }
;
groupOperation:
BY OPEN_PARENS fieldExpression CLOSE_PARENS { $$ = newGroupOperation($3) }
;
coalesceOperation:
COALESCE OPEN_PARENS CLOSE_PARENS { $$ = newCoalesceOperation() }
;
selectOperation:
SELECT OPEN_PARENS attributeList CLOSE_PARENS { $$ = newSelectOperation($3) }
;
attribute:
intrinsicField { $$ = $1 }
| attributeField { $$ = $1 }
| scopedIntrinsicField { $$ = $1 }
;
attributeList:
attribute { $$ = []Attribute{$1} }
| attributeList COMMA attribute { $$ = append($1, $3) }
;
// Comma-separated list of numeric values. Casts all to floats
numericList:
FLOAT { $$ = []float64{$1} }
| INTEGER { $$ = []float64{float64($1)}}
| numericList COMMA FLOAT { $$ = append($1, $3) }
| numericList COMMA INTEGER { $$ = append($1, float64($3))}
;
spansetExpression: // shares the same operators as scalarPipelineExpression. split out for readability
OPEN_PARENS spansetExpression CLOSE_PARENS { $$ = $2 }
| spansetExpression AND spansetExpression { $$ = newSpansetOperation(OpSpansetAnd, $1, $3) }
| spansetExpression GT spansetExpression { $$ = newSpansetOperation(OpSpansetChild, $1, $3) }
| spansetExpression LT spansetExpression { $$ = newSpansetOperation(OpSpansetParent, $1, $3) }
| spansetExpression DESC spansetExpression { $$ = newSpansetOperation(OpSpansetDescendant, $1, $3) }
| spansetExpression ANCE spansetExpression { $$ = newSpansetOperation(OpSpansetAncestor, $1, $3) }
| spansetExpression OR spansetExpression { $$ = newSpansetOperation(OpSpansetUnion, $1, $3) }
| spansetExpression SIBL spansetExpression { $$ = newSpansetOperation(OpSpansetSibling, $1, $3) }
| spansetExpression NOT_CHILD spansetExpression { $$ = newSpansetOperation(OpSpansetNotChild, $1, $3) }
| spansetExpression NOT_PARENT spansetExpression { $$ = newSpansetOperation(OpSpansetNotParent, $1, $3) }
| spansetExpression NRE spansetExpression { $$ = newSpansetOperation(OpSpansetNotSibling, $1, $3) }
| spansetExpression NOT_ANCE spansetExpression { $$ = newSpansetOperation(OpSpansetNotAncestor, $1, $3) }
| spansetExpression NOT_DESC spansetExpression { $$ = newSpansetOperation(OpSpansetNotDescendant, $1, $3) }
| spansetExpression UNION_CHILD spansetExpression { $$ = newSpansetOperation(OpSpansetUnionChild, $1, $3) }
| spansetExpression UNION_PARENT spansetExpression { $$ = newSpansetOperation(OpSpansetUnionParent, $1, $3) }
| spansetExpression UNION_SIBL spansetExpression { $$ = newSpansetOperation(OpSpansetUnionSibling, $1, $3) }
| spansetExpression UNION_ANCE spansetExpression { $$ = newSpansetOperation(OpSpansetUnionAncestor, $1, $3) }
| spansetExpression UNION_DESC spansetExpression { $$ = newSpansetOperation(OpSpansetUnionDescendant, $1, $3) }
| spansetFilter { $$ = $1 }
;
spansetFilter:
OPEN_BRACE CLOSE_BRACE { $$ = newSpansetFilter(NewStaticBool(true)) }
| OPEN_BRACE fieldExpression CLOSE_BRACE { $$ = newSpansetFilter($2) }
;
scalarFilter:
scalarExpression scalarFilterOperation scalarExpression { $$ = newScalarFilter($2, $1, $3) }
;
scalarFilterOperation:
EQ { $$ = OpEqual }
| NEQ { $$ = OpNotEqual }
| LT { $$ = OpLess }
| LTE { $$ = OpLessEqual }
| GT { $$ = OpGreater }
| GTE { $$ = OpGreaterEqual }
;
// **********************
// Scalar Expressions
// **********************
scalarPipelineExpressionFilter:
scalarPipelineExpression scalarFilterOperation scalarPipelineExpression { $$ = newScalarFilter($2, $1, $3) }
| scalarPipelineExpression scalarFilterOperation static { $$ = newScalarFilter($2, $1, $3) }
;
scalarPipelineExpression: // shares the same operators as scalarExpression. split out for readability
OPEN_PARENS scalarPipelineExpression CLOSE_PARENS { $$ = $2 }
| scalarPipelineExpression ADD scalarPipelineExpression { $$ = newScalarOperation(OpAdd, $1, $3) }
| scalarPipelineExpression SUB scalarPipelineExpression { $$ = newScalarOperation(OpSub, $1, $3) }
| scalarPipelineExpression MUL scalarPipelineExpression { $$ = newScalarOperation(OpMult, $1, $3) }
| scalarPipelineExpression DIV scalarPipelineExpression { $$ = newScalarOperation(OpDiv, $1, $3) }
| scalarPipelineExpression MOD scalarPipelineExpression { $$ = newScalarOperation(OpMod, $1, $3) }
| scalarPipelineExpression POW scalarPipelineExpression { $$ = newScalarOperation(OpPower, $1, $3) }
| wrappedScalarPipeline { $$ = $1 }
;
wrappedScalarPipeline:
OPEN_PARENS scalarPipeline CLOSE_PARENS { $$ = $2 }
;
scalarPipeline:
spansetPipeline PIPE aggregate { $$ = $1.addItem($3) }
;
scalarExpression: // shares the same operators as scalarPipelineExpression. split out for readability
OPEN_PARENS scalarExpression CLOSE_PARENS { $$ = $2 }
| scalarExpression ADD scalarExpression { $$ = newScalarOperation(OpAdd, $1, $3) }
| scalarExpression SUB scalarExpression { $$ = newScalarOperation(OpSub, $1, $3) }
| scalarExpression MUL scalarExpression { $$ = newScalarOperation(OpMult, $1, $3) }
| scalarExpression DIV scalarExpression { $$ = newScalarOperation(OpDiv, $1, $3) }
| scalarExpression MOD scalarExpression { $$ = newScalarOperation(OpMod, $1, $3) }
| scalarExpression POW scalarExpression { $$ = newScalarOperation(OpPower, $1, $3) }
| aggregate { $$ = $1 }
| INTEGER { $$ = NewStaticInt($1) }
| FLOAT { $$ = NewStaticFloat($1) }
| DURATION { $$ = NewStaticDuration($1) }
| SUB INTEGER { $$ = NewStaticInt(-$2) }
| SUB FLOAT { $$ = NewStaticFloat(-$2) }
| SUB DURATION { $$ = NewStaticDuration(-$2) }
;
aggregate:
COUNT OPEN_PARENS CLOSE_PARENS { $$ = newAggregate(aggregateCount, nil) }
| MAX OPEN_PARENS fieldExpression CLOSE_PARENS { $$ = newAggregate(aggregateMax, $3) }
| MIN OPEN_PARENS fieldExpression CLOSE_PARENS { $$ = newAggregate(aggregateMin, $3) }
| AVG OPEN_PARENS fieldExpression CLOSE_PARENS { $$ = newAggregate(aggregateAvg, $3) }
| SUM OPEN_PARENS fieldExpression CLOSE_PARENS { $$ = newAggregate(aggregateSum, $3) }
;
// **********************
// Metrics
// **********************
metricsAggregation:
RATE OPEN_PARENS CLOSE_PARENS { $$ = newMetricsAggregate(metricsAggregateRate, nil) }
| RATE OPEN_PARENS CLOSE_PARENS BY OPEN_PARENS attributeList CLOSE_PARENS { $$ = newMetricsAggregate(metricsAggregateRate, $6) }
| COUNT_OVER_TIME OPEN_PARENS CLOSE_PARENS { $$ = newMetricsAggregate(metricsAggregateCountOverTime, nil) }
| COUNT_OVER_TIME OPEN_PARENS CLOSE_PARENS BY OPEN_PARENS attributeList CLOSE_PARENS { $$ = newMetricsAggregate(metricsAggregateCountOverTime, $6) }
| QUANTILE_OVER_TIME OPEN_PARENS attribute COMMA numericList CLOSE_PARENS { $$ = newMetricsAggregateQuantileOverTime($3, $5, nil) }
| QUANTILE_OVER_TIME OPEN_PARENS attribute COMMA numericList CLOSE_PARENS BY OPEN_PARENS attributeList CLOSE_PARENS { $$ = newMetricsAggregateQuantileOverTime($3, $5, $9) }
| HISTOGRAM_OVER_TIME OPEN_PARENS attribute CLOSE_PARENS { $$ = newMetricsAggregateHistogramOverTime($3, nil) }
| HISTOGRAM_OVER_TIME OPEN_PARENS attribute CLOSE_PARENS BY OPEN_PARENS attributeList CLOSE_PARENS { $$ = newMetricsAggregateHistogramOverTime($3, $7) }
;
// **********************
// Hints
// **********************
hint:
IDENTIFIER EQ static { $$ = newHint($1,$3) }
;
hints:
WITH OPEN_PARENS hintList CLOSE_PARENS { $$ = newHints($3) }
;
hintList:
hint { $$ = []*Hint{$1} }
| hintList COMMA hint { $$ = append($1, $3) }
;
// **********************
// FieldExpressions
// **********************
fieldExpression:
OPEN_PARENS fieldExpression CLOSE_PARENS { $$ = $2 }
| fieldExpression ADD fieldExpression { $$ = newBinaryOperation(OpAdd, $1, $3) }
| fieldExpression SUB fieldExpression { $$ = newBinaryOperation(OpSub, $1, $3) }
| fieldExpression MUL fieldExpression { $$ = newBinaryOperation(OpMult, $1, $3) }
| fieldExpression DIV fieldExpression { $$ = newBinaryOperation(OpDiv, $1, $3) }
| fieldExpression MOD fieldExpression { $$ = newBinaryOperation(OpMod, $1, $3) }
| fieldExpression EQ fieldExpression { $$ = newBinaryOperation(OpEqual, $1, $3) }
| fieldExpression NEQ fieldExpression { $$ = newBinaryOperation(OpNotEqual, $1, $3) }
| fieldExpression LT fieldExpression { $$ = newBinaryOperation(OpLess, $1, $3) }
| fieldExpression LTE fieldExpression { $$ = newBinaryOperation(OpLessEqual, $1, $3) }
| fieldExpression GT fieldExpression { $$ = newBinaryOperation(OpGreater, $1, $3) }
| fieldExpression GTE fieldExpression { $$ = newBinaryOperation(OpGreaterEqual, $1, $3) }
| fieldExpression RE fieldExpression { $$ = newBinaryOperation(OpRegex, $1, $3) }
| fieldExpression NRE fieldExpression { $$ = newBinaryOperation(OpNotRegex, $1, $3) }
| fieldExpression POW fieldExpression { $$ = newBinaryOperation(OpPower, $1, $3) }
| fieldExpression AND fieldExpression { $$ = newBinaryOperation(OpAnd, $1, $3) }
| fieldExpression OR fieldExpression { $$ = newBinaryOperation(OpOr, $1, $3) }
| SUB fieldExpression { $$ = newUnaryOperation(OpSub, $2) }
| NOT fieldExpression { $$ = newUnaryOperation(OpNot, $2) }
| static { $$ = $1 }
| intrinsicField { $$ = $1 }
| attributeField { $$ = $1 }
| scopedIntrinsicField { $$ = $1 }
;
// **********************
// Statics
// **********************
static:
STRING { $$ = NewStaticString($1) }
| INTEGER { $$ = NewStaticInt($1) }
| FLOAT { $$ = NewStaticFloat($1) }
| TRUE { $$ = NewStaticBool(true) }
| FALSE { $$ = NewStaticBool(false) }
| NIL { $$ = NewStaticNil() }
| DURATION { $$ = NewStaticDuration($1) }
| STATUS_OK { $$ = NewStaticStatus(StatusOk) }
| STATUS_ERROR { $$ = NewStaticStatus(StatusError) }
| STATUS_UNSET { $$ = NewStaticStatus(StatusUnset) }
| KIND_UNSPECIFIED { $$ = NewStaticKind(KindUnspecified)}
| KIND_INTERNAL { $$ = NewStaticKind(KindInternal) }
| KIND_SERVER { $$ = NewStaticKind(KindServer) }
| KIND_CLIENT { $$ = NewStaticKind(KindClient) }
| KIND_PRODUCER { $$ = NewStaticKind(KindProducer) }
| KIND_CONSUMER { $$ = NewStaticKind(KindConsumer) }
;
// ** DO NOT ADD MORE FEATURES **
// Going forward with scoped intrinsics only
intrinsicField:
IDURATION { $$ = NewIntrinsic(IntrinsicDuration) }
| CHILDCOUNT { $$ = NewIntrinsic(IntrinsicChildCount) }
| NAME { $$ = NewIntrinsic(IntrinsicName) }
| STATUS { $$ = NewIntrinsic(IntrinsicStatus) }
| STATUS_MESSAGE { $$ = NewIntrinsic(IntrinsicStatusMessage) }
| KIND { $$ = NewIntrinsic(IntrinsicKind) }
| PARENT { $$ = NewIntrinsic(IntrinsicParent) }
| ROOTNAME { $$ = NewIntrinsic(IntrinsicTraceRootSpan) }
| ROOTSERVICENAME { $$ = NewIntrinsic(IntrinsicTraceRootService) }
| TRACEDURATION { $$ = NewIntrinsic(IntrinsicTraceDuration) }
| NESTEDSETLEFT { $$ = NewIntrinsic(IntrinsicNestedSetLeft) }
| NESTEDSETRIGHT { $$ = NewIntrinsic(IntrinsicNestedSetRight) }
| NESTEDSETPARENT { $$ = NewIntrinsic(IntrinsicNestedSetParent) }
;
scopedIntrinsicField:
// trace:
TRACE_COLON IDURATION { $$ = NewIntrinsic(IntrinsicTraceDuration) }
| TRACE_COLON ROOTNAME { $$ = NewIntrinsic(IntrinsicTraceRootSpan) }
| TRACE_COLON ROOTSERVICE { $$ = NewIntrinsic(IntrinsicTraceRootService) }
// span:
| SPAN_COLON IDURATION { $$ = NewIntrinsic(IntrinsicDuration) }
| SPAN_COLON NAME { $$ = NewIntrinsic(IntrinsicName) }
| SPAN_COLON KIND { $$ = NewIntrinsic(IntrinsicKind) }
| SPAN_COLON STATUS { $$ = NewIntrinsic(IntrinsicStatus) }
| SPAN_COLON STATUS_MESSAGE { $$ = NewIntrinsic(IntrinsicStatusMessage) }
attributeField:
DOT IDENTIFIER END_ATTRIBUTE { $$ = NewAttribute($2) }
| RESOURCE_DOT IDENTIFIER END_ATTRIBUTE { $$ = NewScopedAttribute(AttributeScopeResource, false, $2) }
| SPAN_DOT IDENTIFIER END_ATTRIBUTE { $$ = NewScopedAttribute(AttributeScopeSpan, false, $2) }
| PARENT_DOT IDENTIFIER END_ATTRIBUTE { $$ = NewScopedAttribute(AttributeScopeNone, true, $2) }
| PARENT_DOT RESOURCE_DOT IDENTIFIER END_ATTRIBUTE { $$ = NewScopedAttribute(AttributeScopeResource, true, $3) }
| PARENT_DOT SPAN_DOT IDENTIFIER END_ATTRIBUTE { $$ = NewScopedAttribute(AttributeScopeSpan, true, $3) }
;