HomeForumSourceResearchGuide
Sign in to contribute to source. how it works
Component util.compiler.AssignGraphBuilder by barry
expand copy to clipboardexpand
uses HWI

data AssignInstanceDest {
	AssignVar toVar
	const byte AT_DIRECT = 0
	const byte AT_FIELD = 1
	const byte AT_ALL_FIELDS = 2
	byte assignType
	int fieldIndex
}

data OpStack {
	OpToken op
}

const bool DEBUG = false

//this pass derives typing, literals, and control-flow, plus scoping and variables, "store" status, and giving an execution-order instruction list
component provides AssignGraphBuilder requires data.query.Search search, data.adt.Stack, io.Output out, data.IntUtil iu, TypeUtil typeUtil, DNCUtil dncUtil {

	AssignVar getVariable(AssignGraph agr, int index)
		{
		for (int i = 0; i < agr.vars.arrayLength; i++)
			{
			if (agr.vars[i].varIndex == index)
				return agr.vars[i]
			}

		return null
		}
	
	AssignInstanceDest getAssignInstances(AssignGraph agr, OpToken op, DanaType types[])
		{
		//the instruction "op" should be pointing at an assignment left-hand-side, which should be a get-variable operation of some sort
		// - we're only interested in local variables, so we return "null" in any other case...

		AssignInstanceDest result = null

		if (op.type == HWI.OP_ID_GET_REF
			|| op.type == HWI.OP_ID_GET_PTR
			|| op.type == HWI.OP_ID_GET_PTR_HND)
			{
			if (op.parameters[1].type == HWI.OP_ID_LOCALS)
				{
				result = new AssignInstanceDest()
				result.toVar = getVariable(agr, op.variableIndex)
				}
				else if (op.parameters[1].type == HWI.OP_ID_MEMBER_ACCESS)
				{
				result = getAssignInstances(agr, op.parameters[1], types)

				//out.println("member access on $(op.lineNumber)")
				//if (result == null)
				//	{
				//	out.println(" - yielded null")
				//	}
				//	else
				//	{
				//	out.println(" - yielded mpt-null")
				//	}

				//if (result != null)
				//	{
				//	result.assignType = AssignInstanceDest.AT_FIELD
				//	result.fieldIndex = op.variableIndex
				//	}
				}
			}
			else if (op.type == HWI.OP_ID_MEMBER_ACCESS)
			{
			result = getAssignInstances(agr, op.parameters[1], types)

			//if (result != null)
			//	{
			//	result.assignType = AssignInstanceDest.AT_FIELD
			//	result.fieldIndex = op.variableIndex
			//	}
			}
			else if (op.type == HWI.OP_ID_GET_INDEX_TO_ASSIGN)
			{
			result = getAssignInstances(agr, op.parameters[1], types)

			//if (result != null)
			//	{
			//	result.assignType = AssignInstanceDest.AT_FIELD
			//	result.fieldIndex = 0
			//	}
			}
			else if (op.type == HWI.OP_ID_GET_FIELD_TO_ASSIGN)
			{
			result = getAssignInstances(agr, op.parameters[1], types)

			//if (result != null)
			//	{
			//	result.assignType = AssignInstanceDest.AT_ALL_FIELDS
			//	result.fieldIndex = 0
			//	}
			}

		return result
		}
	
	bool isPrimitiveArrayType(DanaType t, DanaType types[])
		{
		if (t.class == DanaType.ARRAY)
			{
			DanaType arrayType = types.findFirst(DanaType.[name], new DanaType(name = t.fields[0].type))
			if (arrayType.class == DanaType.INTEGER)
				{
				return true
				}
			}
		
		return false
		}

	AssignInstance[] AssignGraphBuilder:getInstances(AssignGraph agr, OpToken op, DanaType types[])
		{
		AssignInstance result[] = null

		if (op.type == HWI.OP_ID_GET_LITERAL_PTR)
			{
			return new AssignInstance[](result, new AssignInstance(null, AssignInstance.SC_NEUTRAL))
			}

		if (op.type == HWI.OP_ID_GET_REF
			|| op.type == HWI.OP_ID_GET_PTR
			|| op.type == HWI.OP_ID_GET_PTR_HND)
			{
			if (op.parameters[1].type == HWI.OP_ID_LOCALS)
				{
				AssignVar v = getVariable(agr, op.variableIndex)
				result = new AssignInstance[](result, v.instances)
				}
				else if (op.parameters[1].type == HWI.OP_ID_PRIVATE_IVS)
				{
				//TODO: we do need to resolve the type here...
				result = new AssignInstance[](result, new AssignInstance(null, AssignInstance.SC_STORE))
				}
				else if (op.parameters[1].type == HWI.OP_ID_GLOBALS)
				{
				//TODO: we do need to resolve the type here...
				result = new AssignInstance[](result, new AssignInstance(null, AssignInstance.SC_STORE))
				}
				else if (op.parameters[1].type == HWI.OP_ID_MEMBER_ACCESS)
				{
				return getInstances(agr, op.parameters[1], types)
				}
				else
				{
				if (DEBUG) out.println("RHS p-stack NL $(op.type)/$(op.parameters[1].type) on line $(op.lineNumber)")

				return null
				}
			
			//out.println("RHS p-stack JO $(parentStack.op.type).$(op.type)")
			}
			//else if (op.type == HWI.OP_ID_STACK_FRAME_INIT_OBJECT)
			else if (op.type == HWI.OP_ID_STACK_FRAME_LAUNCH_LIB_P || op.type == HWI.OP_ID_STACK_FRAME_LAUNCH_LIB_R)
			{
			result = new AssignInstance(op.returnType, AssignInstance.SC_NEUTRAL)
			return result
			}
			else if (op.type == HWI.OP_ID_ELEMENT_FINISH)
			{
			if (DEBUG) out.println("EL_FINISH on line $(op.lineNumber)")

			if (isPrimitiveArrayType(op.returnType, types))
				{
				return null
				}

			//TODO: this is supposed to add every instance of every field, from every parameter ...?
			for (int i = 0; i < op.parameters.arrayLength; i++)
				{
				if (DEBUG) out.println(" -- parameter $i is $(op.parameters[i].type)")
				result = new AssignInstance[](result, getInstances(agr, op.parameters[i], types))
				if (DEBUG) out.println("   -- now $(result.arrayLength) ais cells")
				}
			
			return result
			}
			else if (op.type == HWI.OP_ID_GET_INDEX_R || op.type == HWI.OP_ID_GET_INDEX_P)
			{
			return getInstances(agr, op.parameters[1], types)
			}
			else if (op.type == HWI.OP_ID_NEW_ARRAY_INIT)
			{
			return getInstances(agr, op.parameters[1], types)
			}
			else if (op.type == HWI.OP_ID_NEW_ARRAY_INIT_FROM)
			{
			return getInstances(agr, op.parameters[1], types)
			}
			else if (op.type == HWI.OP_ID_NEW_ARRAY_APPEND)
			{
			return getInstances(agr, op.parameters[1], types)
			}
			else if (op.type == HWI.OP_ID_MEMBER_ACCESS)
			{
			if (DEBUG) out.println(" -- member access on line $(op.lineNumber) of field index $(op.variableIndex)")

			DanaType currentType = op.parameters[1].returnType
			DanaTypeField tfield = typeUtil.getDataFieldAt(currentType, op.variableIndex)
			DanaType fieldType = types.findFirst(DanaType.[name], new DanaType(name = tfield.type))
			if (fieldType.class == DanaType.ARRAY)
				{
				DanaType arrayType = types.findFirst(DanaType.[name], new DanaType(name = fieldType.fields[0].type))
				if (arrayType.class == DanaType.INTEGER)
					{
					if (DEBUG) out.println(" -- member access of primitive array type $(fieldType.name)")
					return null
					}
					else
					{
					return getInstances(agr, op.parameters[1], types)
					}
				}
				else
				{
				return getInstances(agr, op.parameters[1], types)
				}
			}
			else if (op.type == HWI.OP_ID_CLONE_DATA || op.type == HWI.OP_ID_CLONE_ARRAY || op.type == HWI.OP_ID_RCLONE)
			{
			return getInstances(agr, op.parameters[1], types)
			}
			else if (op.type == HWI.OP_ID_ASSIGN_DATA_POINTER)
			{
			//out.println(" -- ASS.DP on line $(op.lineNumber), sub of $(op.parameters[1].type)")
			//TODO: the legacy compiler checks what param index this is to the data type, and if it's a primitive array, returns null
			return getInstances(agr, op.parameters[1], types)
			}
			else if (op.type == HWI.OP_ID_GET_FIELD)
			{
			result = getInstances(agr, op.parameters[1], types)
			}

		return result
		}
	
	bool referenceIn(AssignInstance ref, AssignInstance list[])
		{
		for (int i = 0; i < list.arrayLength; i++)
			{
			if (ref === list[i]) return true
			}
		
		return false
		}

	//return "b", but with duplicates removed, and no duplicates of anything in "a"
	AssignInstance[] filterReferenceList(AssignInstance a[], AssignInstance b[])
		{
		AssignInstance result[] = null

		for (int i = 0; i < b.arrayLength; i++)
			{
			if (!referenceIn(b[i], result) && !referenceIn(b[i], a))
				result = new AssignInstance[](result, b[i])
			}

		return result
		}
	
	void buildAssignmentGraphFor(AssignGraph agr, OpToken op, DanaType types[])
		{
		for (int i = 0; i < op.parameters.arrayLength; i ++)
			{
			buildAssignmentGraphFor(agr, op.parameters[i], types)
			}
		
		if (op.type == HWI.OP_ID_ASSIGN_POINTER)
			{
			if (DEBUG) out.println(":found assign, of $(op.parameters[1].type) -> $(op.parameters[1].parameters[1].type), line $(op.lineNumber)")

			//out.println("-IG-BA")
			AssignInstanceDest aid = getAssignInstances(agr, op.parameters[1], types)
			AssignInstance ais[] = getInstances(agr, op.parameters[2], types)

			//aid is non-null only if the LHS is a local variable of this function
			if (aid != null)
				{
				//TODO, associate the instances of ais with aid, in whichever mode we need to
				// - (direct-variable, specific-field, all-fields)
				if (DEBUG)
					{
					out.println(": - is local v, at index $(aid.toVar.varIndex); ais array is $(ais.arrayLength) cells")

					for (int i = 0; i < ais.arrayLength; i++)
						{
						if (ais[i].type != null)
							out.println(" - AIS $i has type $(ais[i].type.name), s.class $(ais[i].storeClass)")
							else
							out.println(" - AIS $i has type , s.class $(ais[i].storeClass)")
						}
					}
				
				if (aid.assignType == AssignInstanceDest.AT_DIRECT)
					{
					//if (!referenceInList(aid.toVar.instances, ais))

					AssignInstance filtered[] = filterReferenceList(aid.toVar.instances, ais)
					aid.toVar.instances = new AssignInstance[](aid.toVar.instances, filtered)
					}
					else if (aid.assignType == AssignInstanceDest.AT_FIELD)
					{
					for (int j = 0; j < aid.toVar.instances.arrayLength; j++)
						{
						//our instance list can have sub-field instances on it, e.g. from a data construction, so we check for only things of matching type...
						if (aid.toVar.instances[j].type === aid.toVar.type)
							{
							if (aid.fieldIndex >= aid.toVar.instances[j].fields.arrayLength)
								{
								out.println("field index $(aid.fieldIndex) exceeds count $(aid.toVar.instances[j].fields.arrayLength) for type $(aid.toVar.type.name):$(aid.toVar.instances[j].type.name) on line $(op.lineNumber)")
								}
							AssignInstance filtered[] = filterReferenceList(aid.toVar.instances[j].fields[aid.fieldIndex].instances, ais)
							aid.toVar.instances[j].fields[aid.fieldIndex].instances = new AssignInstance[](aid.toVar.instances[j].fields[aid.fieldIndex].instances, filtered)
							}
						}
					}
					else if (aid.assignType == AssignInstanceDest.AT_ALL_FIELDS)
					{
					for (int j = 0; j < aid.toVar.instances.arrayLength; j++)
						{
						for (int i = 0; i < aid.toVar.instances[j].fields.arrayLength; i++)
							{
							AssignInstance filtered[] = filterReferenceList(aid.toVar.instances[j].fields[i].instances, ais)
							aid.toVar.instances[j].fields[i].instances = new AssignInstance[](aid.toVar.instances[j].fields[i].instances, filtered)
							}
						}
					}
				}
			}
			else if (op.type == HWI.OP_ID_VASSIGN)
			{
			if (DEBUG) out.println(":found vassign, of $(op.parameters[1].type) -> $(op.parameters[1].parameters[1].type), line $(op.lineNumber)")
			AssignInstanceDest aid = getAssignInstances(agr, op.parameters[1], types)
			AssignInstance ais[] = getInstances(agr, op.parameters[2], types)

			if (DEBUG) out.println(": - check local v")

			if (aid != null)
				{
				if (DEBUG) 
					{
					out.println(": - is local v, at index $(aid.toVar.varIndex); ais array is $(ais.arrayLength) cells")

					for (int i = 0; i < ais.arrayLength; i++)
						{
						out.println(" - AIS $i has type $(ais[i].type.name), s.class $(ais[i].storeClass)")
						}
					}
				
				for (int j = 0; j < aid.toVar.instances.arrayLength; j++)
					{
					for (int i = 0; i < aid.toVar.instances[j].fields.arrayLength; i++)
						{
						if (DEBUG) out.println(": - updating field")
						AssignInstance filtered[] = filterReferenceList(aid.toVar.instances[j].fields[i].instances, ais)
						aid.toVar.instances[j].fields[i].instances = new AssignInstance[](aid.toVar.instances[j].fields[i].instances, filtered)
						}
					}
				}
			}
		}
	
	AssignGraph AssignGraphBuilder:buildAssignmentGraph(OpFunction function, DanaType types[])
		{
		AssignGraph agr = new AssignGraph()

		agr.vars = new AssignVar[function.variables.fields.arrayLength]
		int vIndex = 0

		//make instances for the function's parameters
		for (int i = 0; i < function.parameters.arrayLength; i++)
			{
			DanaTypeField field = function.variables.fields[i+1]
			DanaType fieldType = types.findFirst(DanaType.[name], new DanaType(name = field.type))
			DanaType subFieldType = null

			if (fieldType.class == DanaType.ARRAY)
				{
				subFieldType = types.findFirst(DanaType.[name], new DanaType(name = fieldType.fields[0].type))
				}
			
			AssignVar avr = new AssignVar(i+1)
			avr.type = fieldType

			AssignInstance ai = new AssignInstance()
			ai.type = fieldType
			ai.fields = new AssignField[fieldType.fields.arrayLength]

			for (int j = 0; j < ai.fields.arrayLength; j ++)
				{
				ai.fields[j] = new AssignField()
				}

			if (function.parameters[i].qualifier == Parameter.Q_STORE)
				{
				ai.storeClass = AssignInstance.SC_STORE
				}
				else if (fieldType.class == DanaType.ARRAY && subFieldType.class == DanaType.INTEGER)
				{
				ai.storeClass = AssignInstance.SC_NEUTRAL
				}
				else
				{
				ai.storeClass = AssignInstance.SC_LOCAL
				}
			
			if (DEBUG) out.println("param $i has store class $(ai.storeClass)")

			avr.instances = ai

			agr.vars[vIndex] = avr
			vIndex ++
			}
		
		//...and for all of the local variables
		int baseIndex = function.parameters.arrayLength

		for (int i = baseIndex; i < function.variables.fields.arrayLength; i++)
			{
			DanaTypeField field = function.variables.fields[i]
			DanaType fieldType = dncUtil.findType(types, field.type)
			DanaType subFieldType = null

			if (fieldType.class == DanaType.ARRAY)
				{
				subFieldType = dncUtil.findType(types, fieldType.fields[0].type)
				}
			
			AssignVar avr = new AssignVar(i)
			avr.type = fieldType

			AssignInstance ai = new AssignInstance()
			ai.type = fieldType
			ai.fields = new AssignField[fieldType.fields.arrayLength]
			for (int j = 0; j < ai.fields.arrayLength; j ++)
				{
				ai.fields[j] = new AssignField()
				}

			avr.instances = ai

			agr.vars[vIndex] = avr
			vIndex ++
			}
		
		//build instance graph for all local variables
		// - scan over all instructions, looking for assign_pointer, and update instance graph for each one
		for (int i = 0; i < function.instructions.arrayLength; i ++)
			{
			buildAssignmentGraphFor(agr, function.instructions[i], types)
			}

		return agr
		}
	
	}
Revision history
To propose a new revision to this entity, use dana source put -uc your/new/version.dn -n util.compiler.AssignGraphBuilder -m "reason for update" -u yourUsername
Version 1 (this version) by barry
Notes for this version: New compiler components