def lexQuote(l: lexer) -> Optional[stateFn]: """lexQuote scans a quoted string.""" while True: x = l.next() if x == '\\': r = l.next() if r != eof and r != '\n': break if x == 'eof' or x == '\n': raise ParseError('unterminated quoted string') elif x == 'eof' or x == '\n': raise ParseError('unterminated quoted string') elif x == '"': break l.emit(itemType.itemString) return lexInsideAction
def lexComment(l: lexer) -> Optional[stateFn]: l.pos += len(leftComment) i = l.input[l.pos:].find(rightComment) if i < 0: raise ParseError('Unclosed comment') l.pos += i + len(rightComment) delim, trimSpace = l.atRightDelim() if not delim: raise ParseError('comment ends before closing delimiter') if l.emitComment: l.emit(itemType.itemComment) if trimSpace: l.pos += trimMarkerLen l.pos += len(l.rightDelim) if trimSpace: l.pos += leftTrimLength(l.input[l.pos:]) l.ignore() return lexText
def lexRawQuote(l: lexer) -> Optional[stateFn]: """lexRawQuote scans a raw quoted string.""" while True: x = l.next() if x == eof: raise ParseError('unterminated raw quoted string') elif x == '`': break l.emit(itemType.itemRawString) return lexInsideAction
def lexChar(l: lexer) -> Optional[stateFn]: """ lexChar scans a character constant. The initial quote is already scanned. Syntax checking is done by the parser. """ while True: x = l.next() if x == '\\': r = l.next() if r != eof and r != '\n': break if x == eof or x == '\n': raise ParseError('unterminated character constant') elif x == eof or x == '\n': raise ParseError('unterminated character constant') elif x == "'": break l.emit(itemType.itemCharConstant) return lexInsideAction
def lexNumber(l: lexer) -> Optional[stateFn]: """ lexNumber scans a number: decimal, octal, hex, float, or imaginary. This isn't a perfect number scanner - for instance it accepts "." and "0x0.2" and "089" - but when it's wrong the input is invalid and the parser (via strconv) will notice. """ if not l.scanNumber(): raise ParseError('bad number syntax: {}'.format( l.input[l.start:l.pos])) sign = l.peek() if sign == '+' or sign == '-': # Complex: 1+2i. No spaces, must end in 'i'. if not l.scanNumber() or l.input[l.pos - 1] != 'i': raise ParseError('bad number syntax: {}'.format( l.input[l.start:l.pos])) l.emit(itemType.itemComplex) else: l.emit(itemType.itemNumber) return lexInsideAction
def IsEmptyTree(n: Optional[Node]) -> bool: if n is None: return True elif isinstance(n, ActionNode) or isinstance(n, CommentNode): return True elif isinstance(n, IfNode) or isinstance(n, ListNode): for node in n.Nodes: if not IsEmptyTree(node): return False return True elif isinstance(n, RangeNode) or isinstance(n, TemplateNode) or isinstance( n, TextNode): return len(n.Text.strip()) == 0 # elif isinstance(n, WithNode): else: raise ParseError('unknown node: {}'.format(n.String()))
def lexFieldOrVariable(l: lexer, typ: itemType) -> Optional[stateFn]: """ lexVariable scans a field or variable: [.$]Alphanumeric. The . or $ has been scanned. """ if l.atTerminator(): # Nothing interesting follows -> "." or "$". if typ == itemType.itemVariable: l.emit(itemType.itemVariable) else: l.emit(itemType.itemDot) return lexInsideAction while True: r = l.next() if not isAlphaNumeric(r): l.backup() break if not l.atTerminator(): raise ParseError('bad character {}'.format(r)) l.emit(typ) return lexInsideAction
def lexIdentifier(l: lexer) -> Optional[stateFn]: """lexIdentifier scans an alphanumeric.""" while True: r = l.next() if isAlphaNumeric(r): pass # absorb. else: l.backup() word = l.input[l.start:l.pos] if not l.atTerminator(): raise ParseError('bad character {}'.format(r)) if key[word] > itemType.itemKeyword: l.emit(key[word]) elif word[0] == '.': l.emit(itemType.itemField) elif word == 'true' or word == 'false': l.emit(itemType.itemBool) else: l.emit(itemType.itemIdentifier) break return lexInsideAction
def recover(self, errp: Any): raise ParseError('Recover not supported')
def errorf(self, format: str, *args: Any) -> None: """errorf formats the error and terminates processing.""" self.Root = None format = "template: %s:%d: %s".format(self.ParseName, self.token[0].line, format) raise ParseError(format.format(*args))
def lexInsideAction(l: lexer) -> Optional[stateFn]: """lexInsideAction scans the elements inside action delimiters.""" # Either number, quoted string, or identifier. # Spaces separate arguments; runs of spaces turn into itemSpace. # Pipe symbols separate and are emitted. delim, _ = l.atRightDelim() if delim: if l.parenDepth == 0: return lexRightDelim raise ParseError('unclosed left paren') r = l.next() if r == eof: raise ParseError('unclosed action') elif isSpace(r): l.backup() # Put space back in case we have " -}}". return lexSpace elif r == '=': l.emit(itemType.itemAssign) elif r == ':': if l.next() != '=': raise ParseError('expected :=') l.emit(itemType.itemDeclare) elif r == '|': l.emit(itemType.itemPipe) elif r == '"': return lexQuote elif r == '`': return lexRawQuote elif r == '$': return lexVariable elif r == "'": return lexChar elif r == '.': # special look-ahead for ".field" so we don't break l.backup(). if l.pos < len(l.input): r = l.input[l.pos] if r < '0' or '9' < r: return lexField # '.' can start a number. if r == '+' or r == '-' or ('0' <= r and r <= '9'): l.backup() return lexNumber elif r == '+' or r == '-' or ('0' <= r and r <= '9'): l.backup() return lexNumber elif isAlphaNumeric(r): l.backup() return lexIdentifier elif r == '(': l.emit(itemType.itemLeftParen) l.parenDepth += 1 elif r == ')': l.emit(itemType.itemRightParen) l.parenDepth -= 1 if l.parenDepth < 0: raise ParseError('unexpected right paren {}'.format(r)) elif r <= MaxASCII and r.isprintable(): l.emit(itemType.itemChar) else: raise ParseError('unrecognized character in action: {}'.format(r)) return lexInsideAction