Skip to content

Commit b6ce1b9

Browse files
lvan100lianghuan
authored andcommitted
feat(tidl): support oneof defination
1 parent 70ba534 commit b6ce1b9

File tree

12 files changed

+1124
-530
lines changed

12 files changed

+1124
-530
lines changed

lib/tidl/TLexer.g4

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ channels {WS_CHAN, SL_COMMENT_CHAN, ML_COMMENT_CHAN}
1313
KW_CONST : 'const';
1414
KW_ENUM : 'enum';
1515
KW_TYPE : 'type';
16+
KW_ONEOF : 'oneof';
1617
KW_RPC : 'rpc';
1718
KW_TRUE : 'true';
1819
KW_FALSE : 'false';
@@ -46,6 +47,7 @@ RIGHT_BRACE : '}';
4647
EQUAL : '=';
4748
COMMA : ',';
4849
QUESTION : '?';
50+
AT : '@';
4951

5052
// --------------------
5153
// String literal

lib/tidl/TParser.g4

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ document
1616
// Definition types: const, enum, type, rpc
1717
// --------------------
1818
definition
19-
: const_def | enum_def | type_def | rpc_def
19+
: const_def | enum_def | type_def | oneof_def | rpc_def
2020
;
2121

2222
// --------------------
@@ -27,7 +27,7 @@ const_def
2727
: KW_CONST const_type IDENTIFIER EQUAL const_value
2828
;
2929

30-
// Allowed constant types: bool, int, float, or string.
30+
// Allowed constant types: bool, int, float, or string
3131
const_type
3232
: TYPE_BOOL | TYPE_INT | TYPE_FLOAT | TYPE_STRING
3333
;
@@ -52,19 +52,21 @@ enum_field
5252
// B?
5353
// string? field = "1" ( go.type="string" )
5454
// }
55+
// type Alias Map<string,User>
5556
// --------------------
5657
type_def
57-
: KW_TYPE IDENTIFIER (LESS_THAN IDENTIFIER GREATER_THAN)? LEFT_BRACE type_field* RIGHT_BRACE | KW_TYPE IDENTIFIER IDENTIFIER LESS_THAN generic_type GREATER_THAN
58+
: KW_TYPE IDENTIFIER (LESS_THAN IDENTIFIER GREATER_THAN)? LEFT_BRACE type_field* RIGHT_BRACE
59+
| KW_TYPE IDENTIFIER IDENTIFIER LESS_THAN generic_type GREATER_THAN
5860
;
5961

60-
// A type field can be an embedded type or a normal typed field
62+
// A type field can be either an embedded type or a named typed field
6163
type_field
6264
: common_type_field | embed_type_field
6365
;
6466

65-
// Embedded field: just a user-defined type (optionally nullable with ?)
67+
// Embedded field: user-defined type (optionally nullable with '?')
6668
embed_type_field
67-
: user_type
69+
: '@'user_type
6870
;
6971

7072
// Common field: type + name + optional default value + optional annotations
@@ -81,6 +83,7 @@ common_field_type
8183
| TYPE_BINARY
8284
;
8385

86+
// Generic type
8487
generic_type
8588
: base_type | user_type | container_type
8689
;
@@ -93,21 +96,39 @@ type_annotations
9396
: LEFT_PAREN annotation (COMMA annotation)* RIGHT_PAREN
9497
;
9598

99+
// --------------------
100+
// OneOf definition
101+
// Example:
102+
// oneof Value {
103+
// A? a
104+
// B? b
105+
// }
106+
// --------------------
107+
oneof_def
108+
: KW_ONEOF IDENTIFIER LEFT_BRACE oneof_field* RIGHT_BRACE
109+
;
110+
111+
// OneOf fields must be normal named fields
112+
oneof_field
113+
: common_type_field
114+
;
115+
96116
// --------------------
97117
// RPC definition
98-
// Example: rpc GetUser (ReqType) RespType { method="GET" }
118+
// Example:
119+
// rpc GetUser (ReqType) RespType { method="GET" }
99120
// --------------------
100121
rpc_def
101122
: KW_RPC IDENTIFIER LEFT_PAREN rpc_req RIGHT_PAREN rpc_resp rpc_annotations
102123
;
103124

104-
// RPC request type
125+
// RPC request type: always an identifier
105126
rpc_req
106127
: IDENTIFIER
107128
;
108129

109-
// RPC response type
110-
// Either an identifier, generic form (Type<T>), or stream<T>
130+
// RPC response type:
131+
// Either an identifier, a generic form (Type<T>), or a stream<T>
111132
rpc_resp
112133
: IDENTIFIER
113134
| TYPE_STREAM LESS_THAN user_type GREATER_THAN
@@ -118,20 +139,21 @@ rpc_annotations
118139
: LEFT_BRACE annotation* RIGHT_BRACE
119140
;
120141

121-
// Annotation for type or rpc
142+
// Annotation for type or RPC
143+
// Example: method="GET"
122144
annotation
123145
: IDENTIFIER (EQUAL const_value)?
124146
;
125147

126148
// --------------------
127149
// Base types
128-
// Support nullable modifier `?`
150+
// Primitive base types with optional nullable modifier '?'
129151
// --------------------
130152
base_type
131153
: (TYPE_BOOL | TYPE_INT | TYPE_FLOAT | TYPE_STRING) QUESTION?
132154
;
133155

134-
// User-defined type (identifier, optionally nullable with ?)
156+
// User-defined type (identifier, optionally nullable with '?')
135157
user_type
136158
: IDENTIFIER QUESTION?
137159
;
@@ -173,4 +195,4 @@ value_type
173195
// --------------------
174196
const_value
175197
: KW_TRUE | KW_FALSE | INTEGER | FLOAT | STRING | IDENTIFIER
176-
;
198+
;

lib/tidl/format.go

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,15 @@ func dumpDocument(doc Document, sb *strings.Builder) {
111111
})
112112
}
113113

114+
// Process oneOfs
115+
for _, o := range doc.OneOfs {
116+
items = append(items, docItem{
117+
kind: docItemKindType,
118+
pos: o.Position.Start,
119+
buf: dumpOneOf(o),
120+
})
121+
}
122+
114123
// Process types
115124
for _, t := range doc.Types {
116125
items = append(items, docItem{
@@ -188,7 +197,7 @@ func dumpEnum(e Enum) string {
188197
sb.WriteString(s.Text)
189198
sb.WriteString("\n")
190199
}
191-
sb.WriteString("\n\t")
200+
sb.WriteString("\n ")
192201
sb.WriteString(f.Name)
193202
sb.WriteString(" = ")
194203
sb.WriteString(strconv.FormatInt(f.Value, 10))
@@ -223,7 +232,7 @@ func dumpType(t Type) string {
223232
}
224233
sb.WriteString(" {")
225234
for _, f := range t.Fields {
226-
sb.WriteString("\n\t")
235+
sb.WriteString("\n ")
227236
dumpTypeField(f, &sb)
228237
}
229238
sb.WriteString("\n}")
@@ -236,7 +245,7 @@ func dumpType(t Type) string {
236245
func dumpTypeField(f TypeField, sb *strings.Builder) {
237246
for _, s := range f.Comments.Top {
238247
sb.WriteString(s.Text)
239-
sb.WriteString("\n\t")
248+
sb.WriteString("\n ")
240249
}
241250
sb.WriteString(f.FieldType.Text())
242251
if _, ok := f.FieldType.(EmbedType); !ok {
@@ -268,6 +277,25 @@ func dumpTypeField(f TypeField, sb *strings.Builder) {
268277
}
269278
}
270279

280+
// dumpOneOf converts an OneOf node into textual representation,
281+
// including field definitions and top-level comments.
282+
func dumpOneOf(o OneOf) string {
283+
var sb strings.Builder
284+
for _, s := range o.Comments.Top {
285+
sb.WriteString(s.Text)
286+
sb.WriteString("\n")
287+
}
288+
sb.WriteString("oneof ")
289+
sb.WriteString(o.Name)
290+
sb.WriteString(" {")
291+
for _, f := range o.Fields {
292+
sb.WriteString("\n ")
293+
dumpTypeField(f, &sb)
294+
}
295+
sb.WriteString("\n}")
296+
return sb.String()
297+
}
298+
271299
// dumpRPC converts an RPC node into textual representation,
272300
// including its annotations and comments.
273301
func dumpRPC(r RPC) string {
@@ -284,7 +312,7 @@ func dumpRPC(r RPC) string {
284312
sb.WriteString(r.Response.Text())
285313
sb.WriteString(" {")
286314
for _, a := range r.Annotations {
287-
sb.WriteString("\n\t")
315+
sb.WriteString("\n ")
288316
for _, s := range a.Comments.Top {
289317
sb.WriteString("\n")
290318
sb.WriteString(s.Text)

lib/tidl/parser.go

Lines changed: 75 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ func (l *ParseTreeListener) parseCompleteType(ctx *Type_defContext, t *Type) {
211211
}
212212
} else if f.Common_type_field() != nil {
213213
// Regular field
214-
typeField.FieldType = parseCommonFieldType(f.Common_type_field().Common_field_type())
214+
typeField.FieldType = l.parseCommonFieldType(f.Common_type_field().Common_field_type())
215215
typeField.Name = f.Common_type_field().IDENTIFIER().GetText()
216216

217217
// Default value
@@ -243,6 +243,7 @@ func (l *ParseTreeListener) parseCompleteType(ctx *Type_defContext, t *Type) {
243243
}
244244
}
245245

246+
// parseRedefinedType handles redefined types, including generic types.
246247
func (l *ParseTreeListener) parseRedefinedType(ctx *Type_defContext, t *Type) {
247248
t.Redefined = &RedefinedType{
248249
Name: ctx.IDENTIFIER(1).GetText(),
@@ -263,13 +264,13 @@ func (l *ParseTreeListener) parseRedefinedType(ctx *Type_defContext, t *Type) {
263264
if g.Container_type() != nil {
264265
if g.Container_type().Map_type() != nil {
265266
kt := g.Container_type().Map_type().Key_type().GetText()
266-
vt := parseValueType(g.Container_type().Map_type().Value_type())
267+
vt := l.parseValueType(g.Container_type().Map_type().Value_type())
267268
t.Redefined.GenericType = MapType{
268269
Key: kt,
269270
Value: vt,
270271
}
271272
} else if g.Container_type().List_type() != nil {
272-
vt := parseValueType(g.Container_type().List_type().Value_type())
273+
vt := l.parseValueType(g.Container_type().List_type().Value_type())
273274
t.Redefined.GenericType = ListType{
274275
Item: vt,
275276
}
@@ -283,7 +284,7 @@ func (l *ParseTreeListener) parseRedefinedType(ctx *Type_defContext, t *Type) {
283284

284285
// parseCommonFieldType resolves type definitions inside type fields.
285286
// It distinguishes between built-in types, user-defined types, and containers.
286-
func parseCommonFieldType(ctx ICommon_field_typeContext) TypeDefinition {
287+
func (l *ParseTreeListener) parseCommonFieldType(ctx ICommon_field_typeContext) TypeDefinition {
287288
if ctx.TYPE_ANY() != nil {
288289
return AnyType{}
289290
}
@@ -305,13 +306,13 @@ func parseCommonFieldType(ctx ICommon_field_typeContext) TypeDefinition {
305306
if ctx.Container_type() != nil {
306307
if ctx.Container_type().Map_type() != nil {
307308
kt := ctx.Container_type().Map_type().Key_type().GetText()
308-
vt := parseValueType(ctx.Container_type().Map_type().Value_type())
309+
vt := l.parseValueType(ctx.Container_type().Map_type().Value_type())
309310
return MapType{
310311
Key: kt,
311312
Value: vt,
312313
}
313314
} else if ctx.Container_type().List_type() != nil {
314-
vt := parseValueType(ctx.Container_type().List_type().Value_type())
315+
vt := l.parseValueType(ctx.Container_type().List_type().Value_type())
315316
return ListType{
316317
Item: vt,
317318
}
@@ -321,7 +322,7 @@ func parseCommonFieldType(ctx ICommon_field_typeContext) TypeDefinition {
321322
}
322323

323324
// parseValueType resolves value types inside container types.
324-
func parseValueType(ctx IValue_typeContext) TypeDefinition {
325+
func (l *ParseTreeListener) parseValueType(ctx IValue_typeContext) TypeDefinition {
325326
if ctx.Base_type() != nil {
326327
return BaseType{
327328
Name: strings.TrimRight(ctx.Base_type().GetText(), "?"),
@@ -337,13 +338,13 @@ func parseValueType(ctx IValue_typeContext) TypeDefinition {
337338
if ctx.Container_type() != nil {
338339
if ctx.Container_type().Map_type() != nil {
339340
kt := ctx.Container_type().Map_type().Key_type().GetText()
340-
vt := parseValueType(ctx.Container_type().Map_type().Value_type())
341+
vt := l.parseValueType(ctx.Container_type().Map_type().Value_type())
341342
return MapType{
342343
Key: kt,
343344
Value: vt,
344345
}
345346
} else if ctx.Container_type().List_type() != nil {
346-
vt := parseValueType(ctx.Container_type().List_type().Value_type())
347+
vt := l.parseValueType(ctx.Container_type().List_type().Value_type())
347348
return ListType{
348349
Item: vt,
349350
}
@@ -352,6 +353,71 @@ func parseValueType(ctx IValue_typeContext) TypeDefinition {
352353
panic(fmt.Errorf("unknown type: %s", ctx.GetText()))
353354
}
354355

356+
func (l *ParseTreeListener) ExitOneof_def(ctx *Oneof_defContext) {
357+
o := OneOf{
358+
Name: ctx.IDENTIFIER().GetText(),
359+
Position: Position{
360+
Start: ctx.GetStart().GetLine(),
361+
Stop: ctx.GetStop().GetLine(),
362+
},
363+
Comments: Comments{
364+
Top: l.topComment(ctx.GetStart()),
365+
},
366+
}
367+
368+
l.parseOneOfType(ctx, &o)
369+
370+
l.Document.OneOfs = append(l.Document.OneOfs, o)
371+
}
372+
373+
// parseOneOfType handles oneof types, including fields and annotations.
374+
func (l *ParseTreeListener) parseOneOfType(ctx *Oneof_defContext, o *OneOf) {
375+
376+
// Process all oneof fields
377+
for _, f := range ctx.AllOneof_field() {
378+
typeField := TypeField{
379+
Position: Position{
380+
Start: f.GetStart().GetLine(),
381+
Stop: f.GetStop().GetLine(),
382+
},
383+
Comments: Comments{
384+
Top: l.topComment(f.GetStart()),
385+
Right: l.rightComment(f.GetStop()),
386+
},
387+
}
388+
389+
// Regular field
390+
typeField.FieldType = l.parseCommonFieldType(f.Common_type_field().Common_field_type())
391+
typeField.Name = f.Common_type_field().IDENTIFIER().GetText()
392+
393+
// Default value
394+
if f.Common_type_field().Const_value() != nil {
395+
s := f.Common_type_field().Const_value().GetText()
396+
typeField.Default = &s
397+
}
398+
399+
// Annotations
400+
if f.Common_type_field().Type_annotations() != nil {
401+
for _, aCtx := range f.Common_type_field().Type_annotations().AllAnnotation() {
402+
a := Annotation{
403+
Key: aCtx.IDENTIFIER().GetText(),
404+
Position: Position{
405+
Start: aCtx.GetStart().GetLine(),
406+
Stop: aCtx.GetStop().GetLine(),
407+
},
408+
}
409+
if aCtx.Const_value() != nil {
410+
s := aCtx.Const_value().GetText()
411+
a.Value = &s
412+
}
413+
typeField.Annotations = append(typeField.Annotations, a)
414+
}
415+
}
416+
417+
o.Fields = append(o.Fields, typeField)
418+
}
419+
}
420+
355421
// ExitRpc_def handles RPC definitions, including request/response
356422
// types and annotations.
357423
func (l *ParseTreeListener) ExitRpc_def(ctx *Rpc_defContext) {

0 commit comments

Comments
 (0)