github.com/jshiv/can-go@v0.2.1-0.20210224011015-069e90e90bdf/pkg/dbc/parser.go (about) 1 package dbc 2 3 import ( 4 "bytes" 5 "fmt" 6 "strconv" 7 "strings" 8 "text/scanner" 9 "unicode/utf8" 10 ) 11 12 const defaultScannerMode = scanner.ScanIdents | scanner.ScanFloats 13 14 const ( 15 defaultWhitespace = scanner.GoWhitespace 16 significantNewline = defaultWhitespace & ^uint64(1<<'\n') 17 significantTab = defaultWhitespace & ^uint64(1<<'\t') 18 ) 19 20 type token struct { 21 typ rune 22 pos scanner.Position 23 txt string 24 } 25 26 type Parser struct { 27 sc scanner.Scanner 28 curr token 29 lookahead token 30 hasLookahead bool 31 data []byte 32 defs []Def 33 } 34 35 func NewParser(filename string, data []byte) *Parser { 36 p := &Parser{data: data} 37 p.sc.Init(bytes.NewReader(data)) 38 p.sc.Mode = defaultScannerMode 39 p.sc.Whitespace = defaultWhitespace 40 p.sc.Filename = filename 41 p.sc.Error = func(sc *scanner.Scanner, msg string) { 42 p.failf(sc.Pos(), msg) 43 } 44 return p 45 } 46 47 func (p *Parser) Defs() []Def { 48 return p.defs 49 } 50 51 func (p *Parser) File() *File { 52 return &File{ 53 Name: p.sc.Filename, 54 Data: p.data, 55 Defs: p.defs, 56 } 57 } 58 59 func (p *Parser) Parse() (err Error) { 60 defer func() { 61 if r := recover(); r != nil { 62 // recover from parse errors only 63 if errParse, ok := r.(*parseError); ok { 64 err = errParse 65 } else { 66 panic(r) 67 } 68 } 69 }() 70 for p.peekToken().typ != scanner.EOF { 71 var def Def 72 switch p.peekKeyword() { 73 case KeywordVersion: 74 def = &VersionDef{} 75 case KeywordBitTiming: 76 def = &BitTimingDef{} 77 case KeywordNewSymbols: 78 def = &NewSymbolsDef{} 79 case KeywordNodes: 80 def = &NodesDef{} 81 case KeywordMessage: 82 def = &MessageDef{} 83 case KeywordSignal: 84 def = &SignalDef{} 85 case KeywordEnvironmentVariable: 86 def = &EnvironmentVariableDef{} 87 case KeywordComment: 88 def = &CommentDef{} 89 case KeywordAttribute: 90 def = &AttributeDef{} 91 case KeywordAttributeDefault: 92 def = &AttributeDefaultValueDef{} 93 case KeywordAttributeValue: 94 def = &AttributeValueForObjectDef{} 95 case KeywordValueDescriptions: 96 def = &ValueDescriptionsDef{} 97 case KeywordValueTable: 98 def = &ValueTableDef{} 99 case KeywordSignalValueType: 100 def = &SignalValueTypeDef{} 101 case KeywordMessageTransmitters: 102 def = &MessageTransmittersDef{} 103 case KeywordEnvironmentVariableData: 104 def = &EnvironmentVariableDataDef{} 105 default: 106 def = &UnknownDef{} 107 } 108 def.parseFrom(p) 109 p.defs = append(p.defs, def) 110 } 111 return nil 112 } 113 114 func (p *Parser) failf(pos scanner.Position, format string, a ...interface{}) { 115 panic(&parseError{pos: pos, reason: fmt.Sprintf(format, a...)}) 116 } 117 118 // 119 // Whitespace 120 // 121 122 func (p *Parser) useWhitespace(whitespace uint64) { 123 p.sc.Whitespace = whitespace 124 } 125 126 // 127 // Characters 128 // 129 130 func (p *Parser) nextRune() rune { 131 if p.hasLookahead { 132 if utf8.RuneCountInString(p.lookahead.txt) > 1 { 133 p.failf(p.lookahead.pos, "cannot get next rune when lookahead contains a token") 134 } 135 p.hasLookahead = false 136 r, _ := utf8.DecodeRuneInString(p.lookahead.txt) 137 return r 138 } 139 return p.sc.Next() 140 } 141 142 func (p *Parser) peekRune() rune { 143 if p.hasLookahead { 144 if utf8.RuneCountInString(p.lookahead.txt) > 1 { 145 p.failf(p.lookahead.pos, "cannot peek next rune when lookahead contains a token") 146 } 147 r, _ := utf8.DecodeRuneInString(p.lookahead.txt) 148 return r 149 } 150 return p.sc.Peek() 151 } 152 153 func (p *Parser) discardLine() { 154 p.useWhitespace(significantNewline) 155 defer p.useWhitespace(defaultWhitespace) 156 for p.nextToken().typ != '\n' && p.nextToken().typ != scanner.EOF { 157 // skip all non-newline tokens 158 } 159 } 160 161 // 162 // Tokens 163 // 164 165 func (p *Parser) nextToken() token { 166 if p.hasLookahead { 167 p.hasLookahead = false 168 p.curr = p.lookahead 169 return p.lookahead 170 } 171 p.curr = token{typ: p.sc.Scan(), pos: p.sc.Position, txt: p.sc.TokenText()} 172 return p.curr 173 } 174 175 func (p *Parser) peekToken() token { 176 if p.hasLookahead { 177 return p.lookahead 178 } 179 p.hasLookahead = true 180 p.lookahead = token{typ: p.sc.Scan(), pos: p.sc.Position, txt: p.sc.TokenText()} 181 return p.lookahead 182 } 183 184 // 185 // Data types 186 // 187 188 // string parses a string that may contain newlines. 189 func (p *Parser) string() string { 190 tok := p.nextToken() 191 if tok.typ != '"' { 192 p.failf(tok.pos, `expected token "`) 193 } 194 var b strings.Builder 195 ReadLoop: 196 for { 197 switch r := p.nextRune(); r { 198 case scanner.EOF: 199 p.failf(tok.pos, "unterminated string") 200 case '"': 201 break ReadLoop 202 case '\n': 203 if _, err := b.WriteRune(' '); err != nil { 204 p.failf(tok.pos, err.Error()) 205 } 206 case '\\': 207 if p.peekRune() == '"' { 208 _ = p.nextRune() // include escaped quotes in string 209 if _, err := b.WriteString(`\"`); err != nil { 210 p.failf(tok.pos, err.Error()) 211 } 212 continue 213 } 214 fallthrough 215 default: 216 if _, err := b.WriteRune(r); err != nil { 217 p.failf(tok.pos, err.Error()) 218 } 219 } 220 } 221 return b.String() 222 } 223 224 func (p *Parser) identifier() Identifier { 225 tok := p.nextToken() 226 if tok.typ != scanner.Ident { 227 p.failf(tok.pos, "expected ident") 228 } 229 id := Identifier(tok.txt) 230 if err := id.Validate(); err != nil { 231 p.failf(tok.pos, err.Error()) 232 } 233 return id 234 } 235 236 func (p *Parser) stringIdentifier() Identifier { 237 tok := p.peekToken() 238 id := Identifier(p.string()) 239 if err := id.Validate(); err != nil { 240 p.failf(tok.pos, err.Error()) 241 } 242 return id 243 } 244 245 func (p *Parser) keyword(kw Keyword) token { 246 if p.peekKeyword() != kw { 247 p.failf(p.peekToken().pos, "expected keyword: %v", kw) 248 } 249 return p.nextToken() 250 } 251 252 func (p *Parser) peekKeyword() Keyword { 253 tok := p.peekToken() 254 if tok.typ != scanner.Ident { 255 p.failf(p.peekToken().pos, "expected ident") 256 } 257 return Keyword(tok.txt) 258 } 259 260 func (p *Parser) token(typ rune) { 261 if tok := p.nextToken(); tok.typ != typ { 262 p.failf( 263 p.peekToken().pos, 264 "expected token: %v, found: %v (%v)", 265 scanner.TokenString(typ), 266 scanner.TokenString(tok.typ), 267 tok.txt, 268 ) 269 } 270 } 271 272 func (p *Parser) optionalToken(typ rune) { 273 if p.peekToken().typ == typ { 274 p.token(typ) 275 } 276 } 277 278 func (p *Parser) enumValue(values []string) string { 279 tok := p.peekToken() 280 if tok.typ == scanner.Int { 281 // SPECIAL-CASE: Enum values by index encountered in the wild 282 i := p.uint() 283 if i >= uint64(len(values)) { 284 p.failf(tok.pos, "enum index out of bounds") 285 } 286 return values[i] 287 } 288 return p.string() 289 } 290 291 func (p *Parser) float() float64 { 292 var isNegative bool 293 if p.peekToken().typ == '-' { 294 p.token('-') 295 isNegative = true 296 } 297 tok := p.nextToken() 298 if tok.typ != scanner.Int && tok.typ != scanner.Float { 299 p.failf(p.peekToken().pos, "expected int or float") 300 } 301 f, err := strconv.ParseFloat(tok.txt, 64) 302 if err != nil { 303 p.failf(tok.pos, "invalid float") 304 } 305 if isNegative { 306 f *= -1 307 } 308 return f 309 } 310 311 func (p *Parser) int() int64 { 312 var isNegative bool 313 if p.peekToken().typ == '-' { 314 p.token('-') 315 isNegative = true 316 } 317 tok := p.nextToken() 318 if tok.typ != scanner.Int { 319 p.failf(tok.pos, "expected int") 320 } 321 i, err := strconv.ParseInt(tok.txt, 10, 64) 322 if err != nil { 323 p.failf(tok.pos, "invalid int") 324 } 325 if isNegative { 326 i *= -1 327 } 328 return i 329 } 330 331 func (p *Parser) uint() uint64 { 332 tok := p.nextToken() 333 if tok.typ != scanner.Int { 334 p.failf(tok.pos, "expected int") 335 } 336 i, err := strconv.ParseUint(tok.txt, 10, 64) 337 if err != nil { 338 p.failf(tok.pos, "invalid uint") 339 } 340 return i 341 } 342 343 func (p *Parser) intInRange(min, max int) int { 344 var isNegative bool 345 if p.peekToken().typ == '-' { 346 p.token('-') 347 isNegative = true 348 } 349 tok := p.nextToken() 350 i, err := strconv.Atoi(tok.txt) 351 if err != nil { 352 p.failf(tok.pos, "invalid int") 353 } 354 if isNegative { 355 i *= -1 356 } 357 if i < min || i > max { 358 p.failf(tok.pos, "invalid value") 359 } 360 return i 361 } 362 363 func (p *Parser) optionalUint() uint64 { 364 if p.peekToken().typ != scanner.Int { 365 return 0 366 } 367 tok := p.nextToken() 368 i, err := strconv.ParseUint(tok.txt, 10, 64) 369 if err != nil { 370 p.failf(tok.pos, "invalid uint") 371 } 372 return i 373 } 374 375 func (p *Parser) anyOf(tokenTypes ...rune) rune { 376 tok := p.nextToken() 377 for _, tokenType := range tokenTypes { 378 if tok.typ == tokenType { 379 return tok.typ 380 } 381 } 382 p.failf(tok.pos, "unexpected token") 383 return 0 384 } 385 386 func (p *Parser) optionalObjectType() ObjectType { 387 tok := p.peekToken() 388 if tok.typ != scanner.Ident { 389 return ObjectTypeUnspecified 390 } 391 objectType := ObjectType(p.identifier()) 392 if err := objectType.Validate(); err != nil { 393 p.failf(tok.pos, err.Error()) 394 } 395 return objectType 396 } 397 398 func (p *Parser) messageID() MessageID { 399 tok := p.peekToken() 400 messageID := MessageID(p.uint()) 401 if err := messageID.Validate(); err != nil { 402 p.failf(tok.pos, err.Error()) 403 } 404 return messageID 405 } 406 407 func (p *Parser) signalValueType() SignalValueType { 408 tok := p.peekToken() 409 signalValueType := SignalValueType(p.uint()) 410 if err := signalValueType.Validate(); err != nil { 411 p.failf(tok.pos, err.Error()) 412 } 413 return signalValueType 414 } 415 416 func (p *Parser) environmentVariableType() EnvironmentVariableType { 417 tok := p.peekToken() 418 environmentVariableType := EnvironmentVariableType(p.uint()) 419 if err := environmentVariableType.Validate(); err != nil { 420 p.failf(tok.pos, err.Error()) 421 } 422 return environmentVariableType 423 } 424 425 func (p *Parser) attributeValueType() AttributeValueType { 426 tok := p.peekToken() 427 attributeValueType := AttributeValueType(p.identifier()) 428 if err := attributeValueType.Validate(); err != nil { 429 p.failf(tok.pos, err.Error()) 430 } 431 return attributeValueType 432 } 433 434 func (p *Parser) accessType() AccessType { 435 tok := p.peekToken() 436 accessType := AccessType(p.identifier()) 437 if err := accessType.Validate(); err != nil { 438 p.failf(tok.pos, "invalid access type") 439 } 440 return accessType 441 }