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
}
}