github.com/unigraph-dev/dgraph@v1.1.1-0.20200923154953-8b52b426f765/schema/state.go (about)

     1  /*
     2   * Copyright 2016-2018 Dgraph Labs, Inc. and Contributors
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package schema
    18  
    19  import (
    20  	"github.com/dgraph-io/dgraph/lex"
    21  )
    22  
    23  // Constants representing type of different graphql lexed items.
    24  const (
    25  	itemText       lex.ItemType = 5 + iota // plain text
    26  	itemLeftCurl                           // left curly bracket
    27  	itemRightCurl                          // right curly bracket
    28  	itemColon                              // colon
    29  	itemLeftRound                          // left round bracket
    30  	itemRightRound                         // right round bracket
    31  	itemAt
    32  	itemComma
    33  	itemNewLine
    34  	itemDot
    35  	itemLeftSquare
    36  	itemRightSquare
    37  	itemExclamationMark
    38  )
    39  
    40  func lexText(l *lex.Lexer) lex.StateFn {
    41  Loop:
    42  	for {
    43  		switch r := l.Next(); {
    44  		case r == lex.EOF:
    45  			break Loop
    46  		case isNameBegin(r):
    47  			l.Backup()
    48  			return lexWord
    49  		case isSpace(r):
    50  			l.Ignore()
    51  		case lex.IsEndOfLine(r):
    52  			l.Emit(itemNewLine)
    53  		case r == '.':
    54  			l.Emit(itemDot)
    55  		case r == '#':
    56  			return lexTextComment
    57  		case r == ',':
    58  			l.Emit(itemComma)
    59  		case r == '<':
    60  			if err := lex.IRIRef(l, itemText); err != nil {
    61  				return l.Errorf("Invalid schema: %v", err)
    62  			}
    63  		case r == '{':
    64  			l.Emit(itemLeftCurl)
    65  		case r == '}':
    66  			l.Emit(itemRightCurl)
    67  		case r == '(':
    68  			l.Emit(itemLeftRound)
    69  		case r == ')':
    70  			l.Emit(itemRightRound)
    71  		case r == ':':
    72  			l.Emit(itemColon)
    73  		case r == '@':
    74  			l.Emit(itemAt)
    75  		case r == '[':
    76  			l.Emit(itemLeftSquare)
    77  		case r == ']':
    78  			l.Emit(itemRightSquare)
    79  		case r == '!':
    80  			l.Emit(itemExclamationMark)
    81  		case r == '_':
    82  			// Predicates can start with _.
    83  			return lexWord
    84  		default:
    85  			return l.Errorf("Invalid schema. Unexpected %s", l.Input[l.Start:l.Pos])
    86  		}
    87  	}
    88  	if l.Pos > l.Start {
    89  		l.Emit(itemText)
    90  	}
    91  	l.Emit(lex.ItemEOF)
    92  	return nil
    93  }
    94  
    95  func lexWord(l *lex.Lexer) lex.StateFn {
    96  	for {
    97  		// The caller already checked isNameBegin, and absorbed one rune.
    98  		r := l.Next()
    99  		if isNameSuffix(r) {
   100  			continue
   101  		}
   102  		l.Backup()
   103  		l.Emit(itemText)
   104  		break
   105  	}
   106  	return lexText
   107  }
   108  
   109  // lexTextComment lexes a comment text inside a schema.
   110  func lexTextComment(l *lex.Lexer) lex.StateFn {
   111  	for {
   112  		r := l.Next()
   113  		if r == lex.EOF {
   114  			l.Ignore()
   115  			l.Emit(lex.ItemEOF)
   116  			break
   117  		}
   118  		if !lex.IsEndOfLine(r) {
   119  			continue
   120  		}
   121  		l.Ignore()
   122  		l.Emit(itemNewLine)
   123  		break
   124  	}
   125  	return lexText
   126  }
   127  
   128  // isNameBegin returns true if the rune is an alphabet.
   129  func isNameBegin(r rune) bool {
   130  	switch {
   131  	case r >= 'a' && r <= 'z':
   132  		return true
   133  	case r >= 'A' && r <= 'Z':
   134  		return true
   135  	default:
   136  		return false
   137  	}
   138  }
   139  
   140  func isNameSuffix(r rune) bool {
   141  	if isNameBegin(r) {
   142  		return true
   143  	}
   144  	if r >= '0' && r <= '9' {
   145  		return true
   146  	}
   147  	if r == '_' || r == '.' || r == '-' { // Use by freebase.
   148  		return true
   149  	}
   150  	return false
   151  }
   152  
   153  // isSpace returns true if the rune is a tab or space.
   154  func isSpace(r rune) bool {
   155  	return r == '\u0009' || r == '\u0020'
   156  }