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  }