Example #1
0
	def setDocblock(self, text):
		
		if not text:
			return

		if isinstance(text, Docblock):
			self.docblock = text
		else:
			self.docblock = Docblock(text)

		self.setType(self.docblock.getType())
Example #2
0
	def __init__(self, parentfile, obj):

		parentfile.statements.append(self)
		
		self.statement = obj
		self.parentfile = parentfile

		# The original line nr
		self.lineNr = obj['line']

		# The parent statement (the block this is a part of)
		#self.parent = parentStatement

		# The filename this statement is in
		self.filename = parentfile.fileName

		# The docblock of this statement
		self.docblock = Docblock(obj['docblock'])

		# The type of this statement (assignment or expression)
		self.type = obj['openType']

		# The type name
		self.typeName = obj['openName']

		# The scope id
		self.scopeId = obj['scopeId']

		# The scope
		self.scope = parentfile.scopes[self.scopeId]

		# The possible params (function)
		self.params = {}

		# The possible properties
		self.properties = {}

		# Modified variables
		self.variables = {}

		self.process()
Example #3
0
class WittyStatement:

	def __init__(self, parentfile, obj):

		parentfile.statements.append(self)
		
		self.statement = obj
		self.parentfile = parentfile

		# The original line nr
		self.lineNr = obj['line']

		# The parent statement (the block this is a part of)
		#self.parent = parentStatement

		# The filename this statement is in
		self.filename = parentfile.fileName

		# The docblock of this statement
		self.docblock = Docblock(obj['docblock'])

		# The type of this statement (assignment or expression)
		self.type = obj['openType']

		# The type name
		self.typeName = obj['openName']

		# The scope id
		self.scopeId = obj['scopeId']

		# The scope
		self.scope = parentfile.scopes[self.scopeId]

		# The possible params (function)
		self.params = {}

		# The possible properties
		self.properties = {}

		# Modified variables
		self.variables = {}

		self.process()

		# Add all the variables to the scope
		# for name in obj['variables']:
		# 	tempName = name.replace('[\'', '.')
		# 	tempName = tempName.replace('\']', '')

		# 	#@todo: What to do with things like [i] or ['zever_'.i]

		# 	pieces = tempName.split('.')

		# 	workingPiece = self.variables

		# 	for index, piece in enumerate(pieces):
		# 		# If this is the first piece, it's the var name
		# 		if index == 0:
		# 			if not piece in self.variables:
		# 				self.variables[piece] = {'name': piece, 'properties': {}}
		# 			workingPiece = self.variables[piece]
		# 		else:
		# 			if not piece in workingPiece['properties']:
		# 				workingPiece['properties'][piece] = {'name': piece, 'properties': {}}
		
			#thisScope['variables'][name] = {'type': '?', 'name': name, 'description': ''}

		# These should not be added to this scope, but the child scope
		#self.properties = self.docblock.getProperties()
		#self.params = self.docblock.getParams()

		#for pName, pValue in self.params.items():
		#	thisScope['variables'].append(pName)

	## Get a statement docblock attribute
	def getAttribute(self, attributeName):
		return self.docblock.getAttribute(attributeName)

	## See if a docblock attribute is present
	def hasAttribute(self, attributeName):
		return self.docblock.hasAttribute(attributeName)

	def process(self):

		if self.typeName == 'var':
			self.processVar()
		elif self.typeName == 'function':
			self.processFunction()
		elif self.type == 'statement':
			self.processStatement()
		elif self.typeName == 'expression':
			self.processExpression()
		elif self.type == 'scope':
			pass
		else:
			pr(self.type)
			pr(self.statement)
			die()

	## Create an empty variable dict
	def createEmpty(self, name, type):
		return {
			'name': name,
			'type': type,
			'docblock': None,
			'declared': False,
			'value': None,
			'description': None,
			'reference': False,
			'options': {},
			'properties': {}
		}

	def touchProperty(self, parent, name, type = None):

		if name in parent['properties']:
			prop = parent['properties'][name]
			if type: prop['type'] = type
		else:
			prop = self.createEmpty(name, type)
			prop['type'] = type
			prop['declared'] = 'property'
			parent['properties'][name] = prop

		return prop

	## Touch a variable, possibly creating it in the process
	#  @param   self           The object pointer
	#  @param   name           The name of the variable
	#  @param   type           The type of the variable
	def touchVar(self, name, type = None):

		if name in self.variables:
			newVar = self.variables[name]
			if type: newVar['type'] = type
		else:
			newVar = self.createEmpty(name, type)
			self.variables[name] = newVar

		# this is always declared
		if name == 'this' or name == 'arguments':
			newVar['declared'] = True

		return newVar

	def processStatement(self):

		result = self.statement['result'][0]

		# Recursively go through all the statements in this file
		if 'block' in result:
			for stat in result['block']['parsed']:
				WittyStatement(self.parentfile, stat)

		

	def processExpression(self):
		
		# @todo: When there are functions in the expressions,
		# they're not assigned to the variable if that is needed!

		# If it's not an assignment, just ignore it
		if not self.statement['result']['assignment']:

			# If there are functions assigned ...
			# @todo: This would still declare the function if it had a name,
			# which function expressions don't do!
			if self.statement['result']['functions']:
				for fnc in self.statement['result']['functions']:
					self.processFunction(fnc)

			return

		# Get the raw expression
		expression = wf.normalizeExpression(self.statement['result']['text'])

		targetVar = False
		targetVars = []
		prop = False

		for target in expression['target']:

			if not 'name' in target:
				continue

			targetVar = self.touchVar(target['name'])

			prop = targetVar

			# Now go over every property
			for part in target['parts']:
				prop = self.touchProperty(prop, part['text'])

			# If there's a type, set it to the last prop
			# We don't parse the value yet, so just set it to unknwon
			if prop != targetVar: prop['type'] = 'unknown'

			# If there is a docblock here, set that
			if self.statement['docblock']:
				prop['docblock'] = self.statement['docblock']

			targetVars.append(prop)

		# If there are functions assigned ...
		if self.statement['result']['functions']:
			for fnc in self.statement['result']['functions']:
				if prop:
					self.processFunction(fnc, prop)

		# @todo: We need to add assign this function to the other targets, too!!


	# Process a var statement
	def processVar(self):

		# Go over every assignment
		for index, entry in enumerate(self.statement['result']):

			newVar = self.touchVar(entry['name']['name'], 'undefined')

			# Since we used the var statement, it's declared
			newVar['declared'] = True

			if '=' in entry and 'expression' in entry:

				if entry['expression']['functions']:
					self.processFunction(entry['expression']['functions'][0], newVar)
				else:
					# @todo: what goes on in this expression?
					newVar['value'] = entry['expression']

			if entry['docblock']:

				newVar['docblock'] = Docblock(entry['docblock'])
				dbtype = newVar['docblock'].getType()
				if dbtype:
					newVar['type'] = dbtype


	# Process a function statement
	def processFunction(self, result = None, newVar = None):

		if not result:
			result = self.statement['result'][0]

		#if not scopeId:
		#scopeId = self.statement['subscopeId']
		if 'scopeId' in result:
			scopeId = result['scopeId']
		else:
			scopeId = self.statement['subscopeId']

		# Add the function variable to this scope
		if not newVar and 'name' in result:
			newVar = self.touchVar(result['name']['name'], 'Function')
			newVar['declared'] = True

		newVar['type'] = 'Function'

		# Create a new statement for inside the next scope
		scopeStat = WittyStatement(self.parentfile, {
			'line': self.lineNr,
			'docblock': None,
			'openType': 'scope',
			'openName': 'scope',
			'scopeId': scopeId,
			})

		# Process variable in the parens,
		# Add them to the subscope
		parenVars = result['paren']['content'].split(',')

		paraminfo = self.docblock.getParams()

		for varName in parenVars:

			# Strip out any spaces or newlines
			varName = varName.strip()

			if varName:
				parVar = scopeStat.touchVar(varName.strip())
				parVar['declared'] = True # Parameters are declared variables

				if varName in paraminfo:
					parVar['type'] = paraminfo[varName]['type']
					parVar['description'] = paraminfo[varName]['description']

		# Add the function name as a variable to the current scope
		if 'name' in result:
			parVar = scopeStat.touchVar(result['name']['name'])
			parVar['declared'] = True
			parVar['reference'] = newVar['name']

		# Recursively go through all the statements in this file
		for stat in result['block']['parsed']:
			WittyStatement(self.parentfile, stat)
Example #4
0
class WittyVariable:

	# Every variable has a unique id
	id = None

	# Extra options
	options = None

	# What is the scope of this variable?
	# This does NOT equal to where it was declared
	# As global variables can be declared elsewhere
	scope = None

	# In what statement was this variable declared?
	statement = None

	# Where was this variable used?
	statements = None

	# Properties of this variable
	properties = None
	propArray = None

	docblock = None

	name = None
	type = None
	types = None

	## Constructor
	#  @param   self        The object pointer
	#  @param   statement   The statement of declaration
	#  @param   scope       The parent WittyScope
	def __init__(self):
		self.statements = []
		self.propArray = []
		self.properties = {}
		self.options = {}

	def setDocblock(self, text):
		
		if not text:
			return

		if isinstance(text, Docblock):
			self.docblock = text
		else:
			self.docblock = Docblock(text)

		self.setType(self.docblock.getType())

	def getAttribute(self, name):

		if self.docblock:
			return self.docblock.getAttribute(name)
		else:
			return None

	def setType(self, type):
		if type:
			self.type = type
			self.types = type.split(',')


	## Get the properties of the types
	def getTypeProperties(self):

		# Initial value is empty
		variables = {}

		# Go over every type this variable has
		for typeName in self.types:

			# Don't do ourselves, that'll cause a loop
			if typeName == self.name:
				continue

			# Get the variable for the given type
			typeVar = self.scope.findVariable(typeName)

			# Update the result value with the found prototype properties
			if typeVar: variables.update(typeVar.getPrototypeProperties())
		
		return variables

	def getPrototypeProperties(self, typePrototype = True):
		result = {}

		if 'prototype' in self.properties:
			result = self.properties['prototype'].properties
		
		if typePrototype:
			result.update(self.getTypeProperties())

		return result

	## Get all the properties of this variable
	#  @param   self                     The object pointer
	#  @param   includeTypeProperties    Include the prototypal properties of the type
	def getProperties(self, includeTypeProperties=True):

		pr('Getting properties of ' + self.name)

		variables = {}

		# Now get the prototype properties of the foundVar's type
		if includeTypeProperties and self.types:

			# Create empty object
			variables = self.getTypeProperties()

			pr(self.properties)

			# Now overwrite anything with our own properties
			variables.update(self.properties)
		else:
			if self.properties:
				return self.properties
		
		return variables

	def getReturn(self):
		if self.docblock:
			return self.docblock.getReturn()
		else:
			return None

	def setBase(self, variable):

		# Store info
		self.info = variable

		if 'name' in variable:
			self.setName(variable['name'])

		# Set the type
		self.setType(variable['type'])

		if 'docblock' in variable and variable['docblock']:
			self.setDocblock(variable['docblock'])

		if not self.type or self.type in ['undefined', 'unknown']:

			valueResult = None

			if variable['value'] and 'result' in variable['value']:
				valueResult = variable['value']['result']
			elif self.statement:
				# @todo: This shouldn't really go here, and be solved much earlier!
				valueResult = self.statement.statement['result']
				tempTest = valueResult['text'].replace('===', '_EQ_')
				tempTest = tempTest.replace('==', '_EQ_')

				if len(tempTest):
					valueResult['text'] = tempTest[len(tempTest)-1].strip()
				else:
					valueResult = None

			if valueResult:
				# See if there is a value assignment
				value = valueResult['text']

				# Remove trailing semicolon
				if value[-1:] == ';':
					value = value[:-1]

				if not len(value):
					pass # Do nothing if there is no text
				elif value[:4] == 'new ':
					# Constructor form is used!
					className = value[4:].split('(')[0].strip()
					self.type = className
				elif value[0] == '"' or value[0] == "'":
					self.type = 'String'
				elif value in ['true', 'false', 'true;', 'false;']:
					self.type = 'Boolean'
				elif value[0] == '{':
					self.type = 'Object'
				elif value[0] == '[':
					self.type = 'Array'
				elif value.isdigit():
					self.type = 'Number'
				elif '(' in value:
					# It might be a function call
					functionName = value.split('(')[0].strip()

					existing = self.scope.findVariable(functionName)

					if existing:
						# Get the type this function returns!
						returnInfo = existing.getReturn()

						if returnInfo:
							self.setType(returnInfo['type'])

				elif self.scope:

					# See if it's an existing variable somewhere
					existing = self.scope.findVariable(value)

					if existing:
						self.makeReference(existing)

	## Make a reference to the given variable
	#  @param   self        The object pointer
	#  @param   existing    The given variable
	def makeReference(self, existing, forceAll = False):

		if forceAll or existing.type in ['Function', 'Object', 'Array']:
			self.properties = existing.properties
			self.propArray = existing.propArray
			self.options = existing.options

		self.setType(existing.type)

	## Set the name of this variable
	#  @param   self        The object pointer
	#  @param   name        The name of the variable
	def setName(self, name):

		self.name = name

	## Set the scope
	#  @param   scope       The parent WittyScope
	def setScope(self, scope):
		self.scope = scope

	## Set the statement
	#  @param   statement   The statement of declaration
	def setStatement(self, statement):
		self.statement = statement

	## Indicate the variable was used here
	#  @param   self        The object pointer
	#  @param   scope       The scope where we appeared
	#  @param   statement   The statement where we appeared
	def addAppearance(self, scope, statement):
		self.statements.append(statement)

	## Look for properties inside this variable
	def findProperties(self, properties):

		if isinstance(properties, str):
			properties = properties.split('.')

		if not len(properties):
			return False

		findNext = properties.pop(0)

		if findNext in self.properties:

			if len(properties):
				return self.properties[findNext].findProperties(properties)
			else:
				return self.properties[findNext]

		else:
			return False



	def touchProperties(self, properties, statement = None):

		for name, prop in properties.items():
			self.addProperty(prop['name'], prop, statement)


	## Add a property to this variable
	def addProperty(self, name, info, statement = None):

		# If the property already exist, fetch it
		if name in self.properties:
			prop = self.properties[name]

			# If there is a new type set
			if info['type']:
				prop.type = info['type']
		else:
			prop = WittyVariable()

			# Add some basic info
			prop.id = 0
			prop.setScope(self.scope)

			# Set the current statement
			prop.setStatement(statement)

			# Set the name
			prop.setName(name)

			# Set basic info
			prop.setBase(info)

			self.properties[name] = prop
			self.propArray.append(prop)

		# See if there are any sub properties we need to touch
		if 'properties' in info:
			# Recursively add deeper properties
			prop.touchProperties(info['properties'], statement)

		# If the property is added to a globalizer, it becomes a global!
		if 'globalizer' in self.options and self.options['globalizer']:

			rootScope = self.scope.getRoot()

			newGlob = rootScope.intel.createEmptyVariable()
			newGlob.setScope(rootScope)
			newGlob.setStatement(statement)
			newGlob.setName(name)

			newGlob.makeReference(prop, True)

			rootScope.registerVariable(newGlob)