1package schema
2
3import (
4	"fmt"
5	"io"
6	"regexp"
7	"strconv"
8)
9
10var (
11	userTypeNameRE = regexp.MustCompile(`[A-Z][A-Za-z0-9]*`)
12	userEnumNameRE = regexp.MustCompile(`[A-Z][A-Za-z0-9]*`)
13	fieldNameRE = regexp.MustCompile(`[a-z][A-Za-z0-9]*`)
14	enumValueRE = regexp.MustCompile(`[A-Z][A-Z0-9_]*`)
15)
16
17// Returned when the lexer encounters an unexpected token
18type ErrUnexpectedToken struct {
19	token    Token
20	expected string
21}
22
23func (e *ErrUnexpectedToken) Error() string {
24	return fmt.Sprintf("Unexpected token '%s'; expected %s",
25		e.token.String(), e.expected)
26}
27
28// Parses a BARE schema definition language document from the given reader and
29// returns a list of the user-defined types it specifies.
30func Parse(reader io.Reader) ([]SchemaType, error) {
31	scanner := NewScanner(reader)
32	var stypes []SchemaType
33	for {
34		st, err := parseSchemaType(scanner)
35		if err == io.EOF {
36			break
37		} else if err != nil {
38			return nil, err
39		}
40		stypes = append(stypes, st)
41	}
42	return stypes, nil
43}
44
45func parseSchemaType(scanner *Scanner) (SchemaType, error) {
46	tok, err := scanner.Next()
47	if err != nil {
48		return nil, err
49	}
50
51	switch tok.Token {
52	case TTYPE:
53		scanner.PushBack(tok)
54		return parseUserType(scanner)
55	case TENUM:
56		scanner.PushBack(tok)
57		return parseUserEnum(scanner)
58	}
59
60	return nil, &ErrUnexpectedToken{tok, "'type' or 'enum'"}
61}
62
63func parseUserType(scanner *Scanner) (SchemaType, error) {
64	tok, err := scanner.Next()
65	if err != nil {
66		return nil, err
67	}
68	if tok.Token != TTYPE {
69		return nil, &ErrUnexpectedToken{tok, "type"}
70	}
71
72	tok, err = scanner.Next()
73	if err != nil {
74		return nil, err
75	}
76	if tok.Token != TNAME {
77		return nil, &ErrUnexpectedToken{tok, "type name"}
78	}
79
80	udt := &UserDefinedType{name: tok.Value}
81	udt.type_, err = parseType(scanner)
82	if err != nil {
83		return nil, err
84	}
85
86	if !userTypeNameRE.MatchString(udt.Name()) {
87		return nil, fmt.Errorf("Invalid name for user type %s", udt.Name())
88	}
89
90	return udt, nil
91}
92
93func parseUserEnum(scanner *Scanner) (SchemaType, error) {
94	tok, err := scanner.Next()
95	if err != nil {
96		return nil, err
97	}
98	if tok.Token != TENUM {
99		return nil, &ErrUnexpectedToken{tok, "enum"}
100	}
101
102	var name string
103	tok, err = scanner.Next()
104	if err != nil {
105		return nil, err
106	}
107	if tok.Token != TNAME {
108		return nil, &ErrUnexpectedToken{tok, "enum name"}
109	}
110	name = tok.Value
111
112	var kind TypeKind
113	tok, err = scanner.Next()
114	if err != nil {
115		return nil, err
116	}
117	switch tok.Token {
118	case TU8:
119		kind = U8
120	case TU16:
121		kind = U16
122	case TU32:
123		kind = U32
124	case TU64:
125		kind = U64
126	default:
127		kind = UINT
128		scanner.PushBack(tok)
129	}
130
131	tok, err = scanner.Next()
132	if err != nil {
133		return nil, err
134	}
135	if tok.Token != TLBRACE {
136		return nil, &ErrUnexpectedToken{tok, "{"}
137	}
138
139	var value uint
140	var evs []EnumValue
141	for {
142		tok, err = scanner.Next()
143		if err != nil {
144			return nil, err
145		}
146		if tok.Token != TNAME {
147			return nil, &ErrUnexpectedToken{tok, "value name"}
148		}
149
150		var ev EnumValue
151		ev.name = tok.Value
152		if !enumValueRE.MatchString(ev.name) {
153			return nil, fmt.Errorf("Invalid name for enum value %s", ev.name)
154		}
155
156		tok, err = scanner.Next()
157		if err != nil {
158			return nil, err
159		}
160		if tok.Token == TEQUAL {
161			tok, err = scanner.Next()
162			if err != nil {
163				return nil, err
164			}
165			if tok.Token != TINTEGER {
166				return nil, &ErrUnexpectedToken{tok, "integer"}
167			}
168
169			v, _ := strconv.ParseUint(tok.Value, 10, 32)
170			value = uint(v)
171			ev.value = value
172		} else {
173			ev.value = value
174			value += 1
175			scanner.PushBack(tok)
176		}
177
178		evs = append(evs, ev)
179
180		tok, err = scanner.Next()
181		if err != nil {
182			return nil, err
183		}
184
185		if tok.Token == TRBRACE {
186			break
187		} else if tok.Token == TNAME {
188			scanner.PushBack(tok)
189		} else {
190			return nil, &ErrUnexpectedToken{tok, "value name"}
191		}
192	}
193
194	if !userEnumNameRE.MatchString(name) {
195		return nil, fmt.Errorf("Invalid name for user enum %s", name)
196	}
197
198	return &UserDefinedEnum{name, kind, evs}, nil
199}
200
201func parseType(scanner *Scanner) (Type, error) {
202	tok, err := scanner.Next()
203	if err != nil {
204		return nil, err
205	}
206
207	switch tok.Token {
208	case TUINT:
209		return &PrimitiveType{UINT}, nil
210	case TU8:
211		return &PrimitiveType{U8}, nil
212	case TU16:
213		return &PrimitiveType{U16}, nil
214	case TU32:
215		return &PrimitiveType{U32}, nil
216	case TU64:
217		return &PrimitiveType{U64}, nil
218	case TINT:
219		return &PrimitiveType{INT}, nil
220	case TI8:
221		return &PrimitiveType{I8}, nil
222	case TI16:
223		return &PrimitiveType{I16}, nil
224	case TI32:
225		return &PrimitiveType{I32}, nil
226	case TI64:
227		return &PrimitiveType{I64}, nil
228	case TF32:
229		return &PrimitiveType{F32}, nil
230	case TF64:
231		return &PrimitiveType{F64}, nil
232	case TBOOL:
233		return &PrimitiveType{Bool}, nil
234	case TSTRING:
235		return &PrimitiveType{String}, nil
236	case TVOID:
237		return &PrimitiveType{Void}, nil
238	case TOPTIONAL:
239		scanner.PushBack(tok)
240		return parseOptionalType(scanner)
241	case TDATA:
242		scanner.PushBack(tok)
243		return parseDataType(scanner)
244	case TMAP:
245		scanner.PushBack(tok)
246		return parseMapType(scanner)
247	case TLBRACKET:
248		scanner.PushBack(tok)
249		return parseArrayType(scanner)
250	case TLPAREN:
251		scanner.PushBack(tok)
252		return parseUnionType(scanner)
253	case TLBRACE:
254		scanner.PushBack(tok)
255		return parseStructType(scanner)
256	case TNAME:
257		return &NamedUserType{name: tok.Value}, nil
258	}
259
260	return nil, &ErrUnexpectedToken{tok, "type"}
261}
262
263func parseOptionalType(scanner *Scanner) (Type, error) {
264	tok, err := scanner.Next()
265	if err != nil {
266		return nil, err
267	}
268	if tok.Token != TOPTIONAL {
269		return nil, &ErrUnexpectedToken{tok, "optional"}
270	}
271
272	tok, err = scanner.Next()
273	if err != nil {
274		return nil, err
275	}
276	if tok.Token != TLANGLE {
277		return nil, &ErrUnexpectedToken{tok, "<"}
278	}
279
280	st, err := parseType(scanner)
281	if err != nil {
282		return nil, err
283	}
284
285	tok, err = scanner.Next()
286	if err != nil {
287		return nil, err
288	}
289	if tok.Token != TRANGLE {
290		return nil, &ErrUnexpectedToken{tok, ">"}
291	}
292	return &OptionalType{subtype: st}, nil
293}
294
295func parseDataType(scanner *Scanner) (Type, error) {
296	tok, err := scanner.Next()
297	if err != nil {
298		return nil, err
299	}
300	if tok.Token != TDATA {
301		return nil, &ErrUnexpectedToken{tok, "data"}
302	}
303
304	tok, err = scanner.Next()
305	if err != nil {
306		return nil, err
307	}
308	if tok.Token != TLANGLE {
309		scanner.PushBack(tok)
310		return &DataType{0}, nil
311	}
312
313	tok, err = scanner.Next()
314	if err != nil {
315		return nil, err
316	}
317	if tok.Token != TINTEGER {
318		return nil, &ErrUnexpectedToken{tok, "integer"}
319	}
320	length, _ := strconv.ParseUint(tok.Value, 10, 32)
321
322	tok, err = scanner.Next()
323	if err != nil {
324		return nil, err
325	}
326	if tok.Token != TRANGLE {
327		return nil, &ErrUnexpectedToken{tok, ">"}
328	}
329
330	return &DataType{uint(length)}, nil
331}
332
333func parseMapType(scanner *Scanner) (Type, error) {
334	tok, err := scanner.Next()
335	if err != nil {
336		return nil, err
337	}
338	if tok.Token != TMAP {
339		return nil, &ErrUnexpectedToken{tok, "map"}
340	}
341
342	tok, err = scanner.Next()
343	if err != nil {
344		return nil, err
345	}
346	if tok.Token != TLBRACKET {
347		return nil, &ErrUnexpectedToken{tok, "["}
348	}
349
350	key, err := parseType(scanner)
351	if err != nil {
352		return nil, err
353	}
354
355	tok, err = scanner.Next()
356	if err != nil {
357		return nil, err
358	}
359	if tok.Token != TRBRACKET {
360		return nil, &ErrUnexpectedToken{tok, "]"}
361	}
362
363	value, err := parseType(scanner)
364	if err != nil {
365		return nil, err
366	}
367
368	return &MapType{key, value}, nil
369}
370
371func parseArrayType(scanner *Scanner) (Type, error) {
372	tok, err := scanner.Next()
373	if err != nil {
374		return nil, err
375	}
376	if tok.Token != TLBRACKET {
377		return nil, &ErrUnexpectedToken{tok, "["}
378	}
379
380	tok, err = scanner.Next()
381	if err != nil {
382		return nil, err
383	}
384
385	var length uint
386	switch tok.Token {
387	case TINTEGER:
388		l, _ := strconv.ParseUint(tok.Value, 10, 32)
389		length = uint(l)
390
391		tok, err := scanner.Next()
392		if err != nil {
393			return nil, err
394		}
395		if tok.Token != TRBRACKET {
396			return nil, &ErrUnexpectedToken{tok, "]"}
397		}
398		break
399	case TRBRACKET:
400		break
401	default:
402		return nil, &ErrUnexpectedToken{tok, "]"}
403	}
404
405	member, err := parseType(scanner)
406	if err != nil {
407		return nil, err
408	}
409
410	return &ArrayType{member, length}, nil
411}
412
413func parseUnionType(scanner *Scanner) (Type, error) {
414	tok, err := scanner.Next()
415	if err != nil {
416		return nil, err
417	}
418	if tok.Token != TLPAREN {
419		return nil, &ErrUnexpectedToken{tok, "("}
420	}
421
422	var (
423		types []UnionSubtype
424		tag   uint64
425	)
426	for {
427		ty, err := parseType(scanner)
428		if err != nil {
429			return nil, err
430		}
431
432		tok, err = scanner.Next()
433		if err != nil {
434			return nil, err
435		}
436		if tok.Token == TEQUAL {
437			tok, err := scanner.Next()
438			if err != nil {
439				return nil, err
440			}
441			if tok.Token != TINTEGER {
442				return nil, &ErrUnexpectedToken{tok, "integer"}
443			}
444			tag, _ = strconv.ParseUint(tok.Value, 10, 64)
445		} else {
446			scanner.PushBack(tok)
447		}
448
449		types = append(types, UnionSubtype{
450			subtype: ty,
451			tag:     tag,
452		})
453		tag++
454
455		tok, err = scanner.Next()
456		if err != nil {
457			return nil, err
458		}
459
460		if tok.Token == TPIPE {
461			continue
462		} else if tok.Token == TRPAREN {
463			break
464		} else {
465			return nil, &ErrUnexpectedToken{tok, "'|' or ')'"}
466		}
467	}
468
469	return &UnionType{types}, nil
470}
471
472func parseStructType(scanner *Scanner) (Type, error) {
473	tok, err := scanner.Next()
474	if err != nil {
475		return nil, err
476	}
477	if tok.Token != TLBRACE {
478		return nil, &ErrUnexpectedToken{tok, "["}
479	}
480
481	var fields []StructField
482	for {
483		var sf StructField
484
485		tok, err := scanner.Next()
486		if err != nil {
487			return nil, err
488		}
489		if tok.Token == TRBRACE {
490			break
491		}
492		if tok.Token != TNAME {
493			return nil, &ErrUnexpectedToken{tok, "field name"}
494		}
495
496		sf.name = tok.Value
497		if !fieldNameRE.MatchString(sf.name) {
498			return nil, fmt.Errorf("Invalid name for field %s", sf.name)
499		}
500
501		tok, err = scanner.Next()
502		if err != nil {
503			return nil, err
504		}
505		if tok.Token != TCOLON {
506			return nil, &ErrUnexpectedToken{tok, ":"}
507		}
508
509		sf.type_, err = parseType(scanner)
510		if err != nil {
511			return nil, err
512		}
513
514		fields = append(fields, sf)
515	}
516
517	return &StructType{fields}, nil
518}
519