github.com/cloudflare/circl@v1.5.0/abe/cpabe/tkn20/internal/dsl/lexer.go (about)

     1  package dsl
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"strings"
     7  )
     8  
     9  var keywords = map[string]string{
    10  	"and": And,
    11  	"or":  Or,
    12  	"not": Not,
    13  }
    14  
    15  type Lexer struct {
    16  	source   string
    17  	tokens   []Token
    18  	start    int
    19  	curr     int
    20  	line     int
    21  	hadError bool
    22  }
    23  
    24  func newLexer(source string) Lexer {
    25  	return Lexer{
    26  		source:   source,
    27  		tokens:   nil,
    28  		start:    0,
    29  		curr:     0,
    30  		line:     1,
    31  		hadError: false,
    32  	}
    33  }
    34  
    35  func (l *Lexer) scanTokens() error {
    36  	errMsg := "unexpected character(s): "
    37  	for l.curr < len(l.source) {
    38  		l.start = l.curr
    39  		c := l.source[l.curr]
    40  		l.curr++
    41  		switch c {
    42  		case '(':
    43  			l.addToken(LeftParen)
    44  		case ')':
    45  			l.addToken(RightParen)
    46  		case ':':
    47  			l.addToken(Colon)
    48  		case ' ', '\r', '\t':
    49  		case '\n':
    50  			l.line++
    51  		default:
    52  			if isAlphaNumeric(c) {
    53  				l.identifier()
    54  			} else {
    55  				errMsg += fmt.Sprintf("'%s' ", string(c))
    56  				l.hadError = true
    57  			}
    58  		}
    59  	}
    60  	l.addToken(EOF)
    61  	if l.hadError {
    62  		return errors.New(strings.TrimSpace(errMsg))
    63  	}
    64  	return nil
    65  }
    66  
    67  func (l *Lexer) addToken(tokenType string) {
    68  	token := Token{
    69  		tokenType,
    70  		l.source[l.start:l.curr],
    71  		l.line,
    72  	}
    73  	l.tokens = append(l.tokens, token)
    74  }
    75  
    76  func (l *Lexer) identifier() {
    77  	for l.curr < len(l.source) {
    78  		if isAlphaNumeric(l.source[l.curr]) {
    79  			l.curr++
    80  		} else {
    81  			break
    82  		}
    83  	}
    84  	tokenType, ok := keywords[l.source[l.start:l.curr]]
    85  	if !ok {
    86  		tokenType = Identifier
    87  	}
    88  	l.addToken(tokenType)
    89  }