All pastes #186895 Raw Edit

Pylisp lexer

public text v1 · immutable
#186895 ·published 2006-09-30 16:04 UTC
rendered paste body
#!/usr/bin/env python
# -*- coding: utf-8 -*-

#error, debug and warning
from functions import *

#The lexer/tokeniser object
class Lexer(object):
	u"""
	The lexer/tokeniser class. use the tokenise(string) method to return a list of tokens
	Theoretically bug-free, it's hard to produce a hard to find bug in so few lines of code and it's been extensively tested
	"""
	def __init__(self):
		u"""
		Just sets up a couple of constants
		"""
		self.__forbidden_in_identifiers = ['"', "'", "[", "]", "(", ")", "{", "}"]

	def tokenise(self, string):
		u"""
		Returns a list of all tokens in a string.
		Token format is [a, b] where:
		a is a character representing the token type
		b (when present) is the token itself
		"""
		ret = []
		tokens = []
		ret = self.__next_token(string)
		while ret != []:
			tokens.append(ret[1:])
			string = ret[0]
			ret = self.__next_token(string)
		return tokens

	def __next_token(self, string):
		u"""
		Returns the next token in the string and
		the string with the token trimmed off the front
		"""
		if len(string) == 0: return []
		#Skip whitespace
		while ord(string[0]) < 33:
			string = string[1:]
		ch = string[0]
		#What is it?
		if ch == "(":
			return [string[1:], "("]
		elif ch == ")":
			return [string[1:], ")"]
		elif ch == "[":
			return [string[1:], "["]
		elif ch == "]":
			return [string[1:], "]"]
		elif ch == "{":
			return [string[1:], "{"]
		elif ch == "}":
			return [string[1:], "}"]
		elif ch == '"':
			[collectedstring, remnants] = self.__collect_string(string[1:], '"')
			return [remnants, '"', collectedstring]
		elif ch == "'":
			[collectedstring, remnants] = self.__collect_string(string[1:], "'")
			return [remnants, "'", collectedstring]
		elif ch == ":":
			return [string[1:], "'"]
		else:
			[collectedidentifier, remnants] = self.__collect_identifier(string) 
			return [remnants, "i", collectedidentifier]
			
	def __collect_string(self, string, quote):
		u"""
		Returns the contents of the string we started collecting
		Also returns the tail
		"""
		escape = False
		chars = []
		count = 1
		for ch in string:
			count += 1
			if escape:
				if ch == quote:
					chars.append(quote)
				else:
					warning("Unrecognised string escape sequence: \\%s" % (ch))
				escape = False
			elif ch == quote:
				return ["".join(chars), string[count:]]
			elif ch == '\\':
				escape = True
			else:
				chars.append(ch)
		#Crap, we ran out of string
		error("Ran out of string to collect, incomplete statement")
			

	def __collect_identifier(self, string):
		u"""
		Returns the rest of an identifier name and the trailing string
		Identifiers can be anything but:
		-whitespace
		-brackets (of any sort)
		-quote symbols (all sorts)
		"""
		chars = []
		count = 0
		for ch in string:
			count += 1
			if self.__forbidden_in_identifiers.count(ch) > 0:
				return ["".join(chars), string[count-1:]]
			elif ord(ch) > 32:
				chars.append(ch)
			else:
				return ["".join(chars), string[count:]]
		return ["".join(chars), string[count:]]