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