github.com/hasnat/dolt/go@v0.0.0-20210628190320-9eb5d843fbb7/store/nomdl/lexer.go (about)

     1  // Copyright 2019 Dolthub, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  //
    15  // This file incorporates work covered by the following copyright and
    16  // permission notice:
    17  //
    18  // Copyright 2017 Attic Labs, Inc. All rights reserved.
    19  // Licensed under the Apache License, version 2.0:
    20  // http://www.apache.org/licenses/LICENSE-2.0
    21  
    22  package nomdl
    23  
    24  import (
    25  	"fmt"
    26  	"text/scanner"
    27  )
    28  
    29  type lexer struct {
    30  	scanner   *scanner.Scanner
    31  	peekToken rune
    32  }
    33  
    34  func (lex *lexer) next() rune {
    35  	if lex.peekToken != 0 {
    36  		tok := lex.peekToken
    37  		lex.peekToken = 0
    38  		return tok
    39  	}
    40  
    41  	return lex.scanner.Scan()
    42  }
    43  
    44  func (lex *lexer) peek() rune {
    45  	if lex.peekToken != 0 {
    46  		return lex.peekToken
    47  	}
    48  	tok := lex.scanner.Scan()
    49  	lex.peekToken = tok
    50  	return tok
    51  }
    52  
    53  func (lex *lexer) pos() scanner.Position {
    54  	if lex.peekToken != 0 {
    55  		panic("Cannot use pos after peek")
    56  	}
    57  	return lex.scanner.Pos()
    58  }
    59  
    60  func (lex *lexer) tokenText() string {
    61  	if lex.peekToken != 0 {
    62  		panic("Cannot use tokenText after peek")
    63  	}
    64  	return lex.scanner.TokenText()
    65  }
    66  
    67  func (lex *lexer) eat(expected rune) rune {
    68  	tok := lex.next()
    69  	lex.check(expected, tok)
    70  	return tok
    71  }
    72  
    73  func (lex *lexer) eatIf(expected rune) bool {
    74  	tok := lex.peek()
    75  	if tok == expected {
    76  		lex.next()
    77  		return true
    78  	}
    79  	return false
    80  }
    81  
    82  func (lex *lexer) check(expected, actual rune) {
    83  	if actual != expected {
    84  		lex.tokenMismatch(expected, actual)
    85  	}
    86  }
    87  
    88  func (lex *lexer) tokenMismatch(expected, actual rune) {
    89  	raiseSyntaxError(fmt.Sprintf("Unexpected token %s, expected %s", scanner.TokenString(actual), scanner.TokenString(expected)), lex.pos())
    90  }
    91  
    92  func (lex *lexer) unexpectedToken(actual rune) {
    93  	raiseSyntaxError(fmt.Sprintf("Unexpected token %s", scanner.TokenString(actual)), lex.pos())
    94  }
    95  
    96  func raiseSyntaxError(msg string, pos scanner.Position) {
    97  	panic(syntaxError{
    98  		msg: msg,
    99  		pos: pos,
   100  	})
   101  }
   102  
   103  type syntaxError struct {
   104  	msg string
   105  	pos scanner.Position
   106  }
   107  
   108  func (e syntaxError) Error() string {
   109  	return fmt.Sprintf("%s, %s", e.msg, e.pos)
   110  }
   111  
   112  func catchSyntaxError(f func()) (errRes error) {
   113  	defer func() {
   114  		if err := recover(); err != nil {
   115  			if err, ok := err.(syntaxError); ok {
   116  				errRes = err
   117  				return
   118  			}
   119  			panic(err)
   120  		}
   121  	}()
   122  
   123  	f()
   124  	return
   125  }