mirror of
https://gitlab.com/camelot/kickc.git
synced 2025-08-11 17:25:41 +00:00
Implementing JSON serialization of ICL
This commit is contained in:
14
.idea/libraries/com_fasterxml_jackson_core_jackson_core_2_8_9.xml
generated
Normal file
14
.idea/libraries/com_fasterxml_jackson_core_jackson_core_2_8_9.xml
generated
Normal file
@@ -0,0 +1,14 @@
|
||||
<component name="libraryTable">
|
||||
<library name="com.fasterxml.jackson.core:jackson-core:2.8.9" type="repository">
|
||||
<properties maven-id="com.fasterxml.jackson.core:jackson-core:2.8.9" />
|
||||
<CLASSES>
|
||||
<root url="jar://$PROJECT_DIR$/lib/jackson-core-2.8.9.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC>
|
||||
<root url="jar://$PROJECT_DIR$/lib/jackson-core-2.8.9-javadoc.jar!/" />
|
||||
</JAVADOC>
|
||||
<SOURCES>
|
||||
<root url="jar://$PROJECT_DIR$/lib/jackson-core-2.8.9-sources.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</component>
|
16
.idea/libraries/com_fasterxml_jackson_core_jackson_databind_2_8_9.xml
generated
Normal file
16
.idea/libraries/com_fasterxml_jackson_core_jackson_databind_2_8_9.xml
generated
Normal file
@@ -0,0 +1,16 @@
|
||||
<component name="libraryTable">
|
||||
<library name="com.fasterxml.jackson.core:jackson-databind:2.8.9" type="repository">
|
||||
<properties maven-id="com.fasterxml.jackson.core:jackson-databind:2.8.9" />
|
||||
<CLASSES>
|
||||
<root url="jar://$PROJECT_DIR$/lib/jackson-databind-2.8.9.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/lib/jackson-annotations-2.8.0.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/lib/jackson-core-2.8.9.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC>
|
||||
<root url="jar://$PROJECT_DIR$/lib/jackson-databind-2.8.9-javadoc.jar!/" />
|
||||
</JAVADOC>
|
||||
<SOURCES>
|
||||
<root url="jar://$PROJECT_DIR$/lib/jackson-databind-2.8.9-sources.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</component>
|
15
.idea/libraries/junit_junit_4_12.xml
generated
Normal file
15
.idea/libraries/junit_junit_4_12.xml
generated
Normal file
@@ -0,0 +1,15 @@
|
||||
<component name="libraryTable">
|
||||
<library name="junit:junit:4.12" type="repository">
|
||||
<properties maven-id="junit:junit:4.12" />
|
||||
<CLASSES>
|
||||
<root url="jar://$PROJECT_DIR$/lib/junit-4.12.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/lib/hamcrest-core-1.3.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC>
|
||||
<root url="jar://$PROJECT_DIR$/lib/junit-4.12-javadoc.jar!/" />
|
||||
</JAVADOC>
|
||||
<SOURCES>
|
||||
<root url="jar://$PROJECT_DIR$/lib/junit-4.12-sources.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</component>
|
@@ -8,5 +8,8 @@
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="org.antlr:antlr4:4.7" level="project" />
|
||||
<orderEntry type="library" name="com.fasterxml.jackson.core:jackson-core:2.8.9" level="project" />
|
||||
<orderEntry type="library" name="com.fasterxml.jackson.core:jackson-databind:2.8.9" level="project" />
|
||||
<orderEntry type="library" name="junit:junit:4.12" level="project" />
|
||||
</component>
|
||||
</module>
|
BIN
lib/hamcrest-core-1.3.jar
Normal file
BIN
lib/hamcrest-core-1.3.jar
Normal file
Binary file not shown.
BIN
lib/jackson-annotations-2.8.0.jar
Normal file
BIN
lib/jackson-annotations-2.8.0.jar
Normal file
Binary file not shown.
BIN
lib/jackson-core-2.8.9-javadoc.jar
Normal file
BIN
lib/jackson-core-2.8.9-javadoc.jar
Normal file
Binary file not shown.
BIN
lib/jackson-core-2.8.9-sources.jar
Normal file
BIN
lib/jackson-core-2.8.9-sources.jar
Normal file
Binary file not shown.
BIN
lib/jackson-core-2.8.9.jar
Normal file
BIN
lib/jackson-core-2.8.9.jar
Normal file
Binary file not shown.
BIN
lib/jackson-databind-2.8.9-javadoc.jar
Normal file
BIN
lib/jackson-databind-2.8.9-javadoc.jar
Normal file
Binary file not shown.
BIN
lib/jackson-databind-2.8.9-sources.jar
Normal file
BIN
lib/jackson-databind-2.8.9-sources.jar
Normal file
Binary file not shown.
BIN
lib/jackson-databind-2.8.9.jar
Normal file
BIN
lib/jackson-databind-2.8.9.jar
Normal file
Binary file not shown.
BIN
lib/junit-4.12-javadoc.jar
Normal file
BIN
lib/junit-4.12-javadoc.jar
Normal file
Binary file not shown.
BIN
lib/junit-4.12-sources.jar
Normal file
BIN
lib/junit-4.12-sources.jar
Normal file
Binary file not shown.
BIN
lib/junit-4.12.jar
Normal file
BIN
lib/junit-4.12.jar
Normal file
Binary file not shown.
@@ -66,7 +66,7 @@ public class Compiler {
|
||||
Pass1GenerateStatementSequence pass1GenerateStatementSequence = new Pass1GenerateStatementSequence(log);
|
||||
pass1GenerateStatementSequence.generate(file);
|
||||
StatementSequence statementSequence = pass1GenerateStatementSequence.getSequence();
|
||||
Scope programScope = pass1GenerateStatementSequence.getProgramScope();
|
||||
ProgramScope programScope = pass1GenerateStatementSequence.getProgramScope();
|
||||
Pass1TypeInference pass1TypeInference = new Pass1TypeInference();
|
||||
pass1TypeInference.inferTypes(statementSequence, programScope);
|
||||
|
||||
|
@@ -21,7 +21,7 @@ public class AsmFragment {
|
||||
/**
|
||||
* The symbol table.
|
||||
*/
|
||||
private Scope symbols;
|
||||
private ProgramScope symbols;
|
||||
|
||||
/**
|
||||
* Binding of named values in the fragment to values (constants, variables, ...) .
|
||||
@@ -33,26 +33,26 @@ public class AsmFragment {
|
||||
*/
|
||||
private String signature;
|
||||
|
||||
public AsmFragment(StatementConditionalJump conditionalJump, ControlFlowBlock block, Scope symbols, ControlFlowGraph graph) {
|
||||
public AsmFragment(StatementConditionalJump conditionalJump, ControlFlowBlock block, ProgramScope symbols, ControlFlowGraph graph) {
|
||||
this.bindings = new LinkedHashMap<>();
|
||||
this.symbols = symbols;
|
||||
String conditionalJumpSignature = conditionalJumpSignature(conditionalJump, block, graph);
|
||||
setSignature(conditionalJumpSignature);
|
||||
}
|
||||
|
||||
public AsmFragment(StatementAssignment assignment, Scope symbols) {
|
||||
public AsmFragment(StatementAssignment assignment, ProgramScope symbols) {
|
||||
this.bindings = new LinkedHashMap<>();
|
||||
this.symbols = symbols;
|
||||
setSignature(assignmentSignature(assignment.getLValue(), assignment.getRValue1(), assignment.getOperator(), assignment.getRValue2()));
|
||||
setSignature(assignmentSignature(assignment.getlValue(), assignment.getrValue1(), assignment.getOperator(), assignment.getrValue2()));
|
||||
}
|
||||
|
||||
public AsmFragment(LValue lValue, RValue rValue, Scope symbols) {
|
||||
public AsmFragment(LValue lValue, RValue rValue, ProgramScope symbols) {
|
||||
this.bindings = new LinkedHashMap<>();
|
||||
this.symbols = symbols;
|
||||
setSignature(assignmentSignature(lValue, null, null, rValue));
|
||||
}
|
||||
|
||||
public AsmFragment(StatementAssignment assignment, StatementAssignment assignmentAlu, Scope symbols) {
|
||||
public AsmFragment(StatementAssignment assignment, StatementAssignment assignmentAlu, ProgramScope symbols) {
|
||||
this.bindings = new LinkedHashMap<>();
|
||||
this.symbols = symbols;
|
||||
setSignature(assignmentWithAluSignature(assignment, assignmentAlu));
|
||||
@@ -60,21 +60,21 @@ public class AsmFragment {
|
||||
}
|
||||
|
||||
private String assignmentWithAluSignature(StatementAssignment assignment, StatementAssignment assignmentAlu) {
|
||||
RValue assignmentRValue2 = assignment.getRValue2();
|
||||
RValue assignmentRValue2 = assignment.getrValue2();
|
||||
RegisterAllocation.Register rVal2Register = symbols.getRegister((Variable) assignmentRValue2);
|
||||
if(!rVal2Register.getType().equals(RegisterAllocation.RegisterType.REG_ALU_BYTE)) {
|
||||
throw new RuntimeException("Error! ALU register only allowed as rValue2. "+assignment);
|
||||
}
|
||||
StringBuilder signature = new StringBuilder();
|
||||
signature.append(bind(assignment.getLValue()));
|
||||
signature.append(bind(assignment.getlValue()));
|
||||
signature.append("=");
|
||||
if (assignment.getRValue1() != null) {
|
||||
signature.append(bind(assignment.getRValue1()));
|
||||
if (assignment.getrValue1() != null) {
|
||||
signature.append(bind(assignment.getrValue1()));
|
||||
}
|
||||
if (assignment.getOperator() != null) {
|
||||
signature.append(getOperatorFragmentName(assignment.getOperator()));
|
||||
}
|
||||
signature.append(assignmentRightSideSignature(assignmentAlu.getRValue1(), assignmentAlu.getOperator(), assignmentAlu.getRValue2()));
|
||||
signature.append(assignmentRightSideSignature(assignmentAlu.getrValue1(), assignmentAlu.getOperator(), assignmentAlu.getrValue2()));
|
||||
return signature.toString();
|
||||
}
|
||||
|
||||
|
@@ -49,7 +49,7 @@ public class ControlFlowGraph {
|
||||
for (Statement statement : block.getStatements()) {
|
||||
if(statement instanceof StatementAssignment) {
|
||||
StatementAssignment assignment = (StatementAssignment) statement;
|
||||
if(assignment.getLValue().equals(variable)) {
|
||||
if(assignment.getlValue().equals(variable)) {
|
||||
return assignment;
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,5 @@
|
||||
package dk.camelot64.kickc.icl;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
|
||||
@@ -116,7 +115,7 @@ public class ControlFlowGraphCopyVisitor extends ControlFlowGraphBaseVisitor<Obj
|
||||
|
||||
@Override
|
||||
public StatementPhi visitPhi(StatementPhi phi) {
|
||||
VariableVersion lValue = phi.getLValue();
|
||||
VariableVersion lValue = phi.getlValue();
|
||||
StatementPhi copyPhi = new StatementPhi(lValue);
|
||||
for (StatementPhi.PreviousSymbol origPreviousVersion : phi.getPreviousVersions()) {
|
||||
RValue rValue = origPreviousVersion.getRValue();
|
||||
@@ -128,10 +127,10 @@ public class ControlFlowGraphCopyVisitor extends ControlFlowGraphBaseVisitor<Obj
|
||||
|
||||
@Override
|
||||
public StatementAssignment visitAssignment(StatementAssignment origAssignment) {
|
||||
LValue lValue = origAssignment.getLValue();
|
||||
RValue rValue1 = origAssignment.getRValue1();
|
||||
LValue lValue = origAssignment.getlValue();
|
||||
RValue rValue1 = origAssignment.getrValue1();
|
||||
Operator operator = origAssignment.getOperator();
|
||||
RValue rValue2 = origAssignment.getRValue2();
|
||||
RValue rValue2 = origAssignment.getrValue2();
|
||||
return new StatementAssignment(lValue, rValue1, operator, rValue2);
|
||||
}
|
||||
|
||||
@@ -158,7 +157,7 @@ public class ControlFlowGraphCopyVisitor extends ControlFlowGraphBaseVisitor<Obj
|
||||
|
||||
@Override
|
||||
public StatementCall visitCall(StatementCall callLValue) {
|
||||
LValue lValue = callLValue.getLValue();
|
||||
LValue lValue = callLValue.getlValue();
|
||||
String procedureName = callLValue.getProcedureName();
|
||||
List<RValue> parameters = callLValue.getParameters();
|
||||
return new StatementCall(lValue, procedureName, parameters);
|
||||
|
@@ -1,5 +1,9 @@
|
||||
package dk.camelot64.kickc.icl;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/** A jump label */
|
||||
public class Label implements Symbol {
|
||||
|
||||
@@ -17,6 +21,16 @@ public class Label implements Symbol {
|
||||
this.intermediate = intermediate;
|
||||
}
|
||||
|
||||
@JsonCreator
|
||||
public Label(
|
||||
@JsonProperty("name") String name,
|
||||
@JsonProperty("intermediate") boolean intermediate) {
|
||||
this.name = name;
|
||||
this.scope = null;
|
||||
this.intermediate = intermediate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLocalName() {
|
||||
return name;
|
||||
}
|
||||
@@ -26,6 +40,11 @@ public class Label implements Symbol {
|
||||
return scope;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setScope(Scope scope) {
|
||||
this.scope = scope;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getScopeDepth() {
|
||||
if(scope==null) {
|
||||
@@ -44,6 +63,7 @@ public class Label implements Symbol {
|
||||
return intermediate;
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public SymbolType getType() {
|
||||
return SymbolTypeBasic.LABEL;
|
||||
}
|
||||
@@ -61,13 +81,12 @@ public class Label implements Symbol {
|
||||
|
||||
if (intermediate != label.intermediate) return false;
|
||||
if (!name.equals(label.name)) return false;
|
||||
return scope != null ? scope.equals(label.scope) : label.scope == null;
|
||||
return getFullName().equals(label.getFullName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = name.hashCode();
|
||||
result = 31 * result + (scope != null ? scope.hashCode() : 0);
|
||||
int result = getFullName().hashCode();
|
||||
result = 31 * result + (intermediate ? 1 : 0);
|
||||
return result;
|
||||
}
|
||||
|
@@ -1,25 +1,52 @@
|
||||
package dk.camelot64.kickc.icl;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
/** Symbol describing a procedure/function */
|
||||
public class Procedure extends Scope {
|
||||
|
||||
private final SymbolType returnType;
|
||||
private List<Variable> parameters;
|
||||
private List<String> parameterNames;
|
||||
|
||||
public Procedure(String name, SymbolType returnType, Scope parentScope) {
|
||||
super(name, new SymbolTypeProcedure(returnType), parentScope);
|
||||
super(name, parentScope);
|
||||
this.returnType = returnType;
|
||||
}
|
||||
|
||||
public Procedure(
|
||||
@JsonProperty("name") String name,
|
||||
@JsonProperty("returntype") SymbolType returnType,
|
||||
@JsonProperty("parameterNames") List<String> parameterNames,
|
||||
@JsonProperty("symbols") HashMap<String, Symbol> symbols,
|
||||
@JsonProperty("intermediateVarCount") int intermediateVarCount,
|
||||
@JsonProperty("intermediateLabelCount") int intermediateLabelCount) {
|
||||
super(name, symbols, intermediateVarCount, intermediateLabelCount);
|
||||
this.returnType = returnType;
|
||||
this.parameterNames = parameterNames;
|
||||
}
|
||||
|
||||
public List<String> getParameterNames() {
|
||||
return parameterNames;
|
||||
}
|
||||
|
||||
public void setParameterNames(List<String> parameterNames) {
|
||||
this.parameterNames = parameterNames;
|
||||
}
|
||||
|
||||
public void setParameters(List<Variable> parameters) {
|
||||
this.parameters = parameters;
|
||||
this.parameterNames = new ArrayList<>();
|
||||
for (Variable parameter : parameters) {
|
||||
add(parameter);
|
||||
parameterNames.add(parameter.getLocalName());
|
||||
}
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public Label getLabel() {
|
||||
return new Label(getFullName(), getScope(), false);
|
||||
}
|
||||
@@ -28,7 +55,12 @@ public class Procedure extends Scope {
|
||||
return returnType;
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public List<Variable> getParameters() {
|
||||
ArrayList<Variable> parameters = new ArrayList<>();
|
||||
for (String name : parameterNames) {
|
||||
parameters.add(getScope().getVariable(name));
|
||||
}
|
||||
return parameters;
|
||||
}
|
||||
|
||||
@@ -44,8 +76,8 @@ public class Procedure extends Scope {
|
||||
res.append(getFullName());
|
||||
res.append("(");
|
||||
boolean first = true;
|
||||
if(parameters!=null) {
|
||||
for (Variable parameter : parameters) {
|
||||
if(parameterNames !=null) {
|
||||
for (Variable parameter : getParameters()) {
|
||||
if (!first) res.append(" , ");
|
||||
first = false;
|
||||
res.append(parameter.getTypedName());
|
||||
@@ -63,6 +95,22 @@ public class Procedure extends Scope {
|
||||
return res.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SymbolType getType() {
|
||||
return new SymbolTypeProcedure(returnType);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
RegisterAllocation getAllocation() {
|
||||
if(getScope()!=null) {
|
||||
return getScope().getAllocation();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getTypedName();
|
||||
|
36
src/dk/camelot64/kickc/icl/Program.java
Normal file
36
src/dk/camelot64/kickc/icl/Program.java
Normal file
@@ -0,0 +1,36 @@
|
||||
package dk.camelot64.kickc.icl;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/** A KickC Intermediate Compiler Language (ICL) Program */
|
||||
public class Program {
|
||||
/** The main scope. */
|
||||
private Scope scope;
|
||||
/** The control flow graph. */
|
||||
private ControlFlowGraph graph;
|
||||
|
||||
@JsonCreator
|
||||
public Program(
|
||||
@JsonProperty("scope") Scope scope,
|
||||
@JsonProperty("graph") ControlFlowGraph graph) {
|
||||
this.scope = scope;
|
||||
this.graph = graph;
|
||||
}
|
||||
|
||||
public Scope getScope() {
|
||||
return scope;
|
||||
}
|
||||
|
||||
public void setScope(Scope scope) {
|
||||
this.scope = scope;
|
||||
}
|
||||
|
||||
public ControlFlowGraph getGraph() {
|
||||
return graph;
|
||||
}
|
||||
|
||||
public void setGraph(ControlFlowGraph graph) {
|
||||
this.graph = graph;
|
||||
}
|
||||
}
|
73
src/dk/camelot64/kickc/icl/ProgramScope.java
Normal file
73
src/dk/camelot64/kickc/icl/ProgramScope.java
Normal file
@@ -0,0 +1,73 @@
|
||||
package dk.camelot64.kickc.icl;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
/** The program scope containing the symbols of a program */
|
||||
public class ProgramScope extends Scope {
|
||||
|
||||
private RegisterAllocation allocation;
|
||||
|
||||
public ProgramScope() {
|
||||
super("", null);
|
||||
}
|
||||
|
||||
@JsonCreator
|
||||
public ProgramScope(
|
||||
@JsonProperty("name") String name,
|
||||
@JsonProperty("symbols") HashMap<String, Symbol> symbols,
|
||||
@JsonProperty("intermediateVarCount") int intermediateVarCount,
|
||||
@JsonProperty("intermediateLabelCount") int intermediateLabelCount,
|
||||
@JsonProperty("allocation") RegisterAllocation allocation) {
|
||||
super(name, symbols, intermediateVarCount, intermediateLabelCount);
|
||||
this.allocation = allocation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SymbolType getType() {
|
||||
return new SymbolTypeProgram();
|
||||
}
|
||||
|
||||
public void setAllocation(RegisterAllocation allocation) {
|
||||
this.allocation = allocation;
|
||||
}
|
||||
|
||||
public RegisterAllocation.Register getRegister(Variable variable) {
|
||||
RegisterAllocation.Register register = null;
|
||||
if (allocation != null) {
|
||||
register = allocation.getRegister(variable);
|
||||
}
|
||||
return register;
|
||||
}
|
||||
|
||||
@Override
|
||||
RegisterAllocation getAllocation() {
|
||||
return allocation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
if (!super.equals(o)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ProgramScope that = (ProgramScope) o;
|
||||
|
||||
return allocation != null ? allocation.equals(that.allocation) : that.allocation == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = super.hashCode();
|
||||
result = 31 * result + (allocation != null ? allocation.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
}
|
@@ -8,7 +8,7 @@ import java.util.Map;
|
||||
/** Register Allocation for Variable Symbols */
|
||||
public class RegisterAllocation {
|
||||
|
||||
private Map<Variable, Register> allocation;
|
||||
private Map<String, Register> allocation;
|
||||
|
||||
public RegisterAllocation() {
|
||||
this.allocation = new LinkedHashMap<>();
|
||||
@@ -21,11 +21,18 @@ public class RegisterAllocation {
|
||||
* @return The allocated register.
|
||||
*/
|
||||
public Register getRegister(Variable variable) {
|
||||
return allocation.get(variable);
|
||||
return allocation.get(variable.getFullName());
|
||||
}
|
||||
|
||||
public Register getRegister(String varFullName) {
|
||||
return allocation.get(varFullName);
|
||||
}
|
||||
|
||||
|
||||
public void allocate(Variable variable, Register register) {
|
||||
allocation.put(variable, register);
|
||||
if(variable!=null) {
|
||||
allocation.put(variable.getFullName(), register);
|
||||
}
|
||||
}
|
||||
|
||||
/** A register used for storing a single variable. */
|
||||
@@ -287,9 +294,9 @@ public class RegisterAllocation {
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuffer out = new StringBuffer();
|
||||
for (Variable variable : allocation.keySet()) {
|
||||
Register register = getRegister(variable);
|
||||
out.append(variable+" : "+register+"\n");
|
||||
for (String varName: allocation.keySet()) {
|
||||
Register register = getRegister(varName);
|
||||
out.append(varName+" : "+register+"\n");
|
||||
}
|
||||
return out.toString();
|
||||
}
|
||||
|
@@ -1,34 +1,54 @@
|
||||
package dk.camelot64.kickc.icl;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Manages symbols (variables, labels)
|
||||
*/
|
||||
public class Scope implements Symbol {
|
||||
public abstract class Scope implements Symbol {
|
||||
|
||||
private String name;
|
||||
private SymbolType type;
|
||||
private Map<String, Symbol> symbols;
|
||||
private HashMap<String, Symbol> symbols;
|
||||
private int intermediateVarCount = 0;
|
||||
private int intermediateLabelCount = 1;
|
||||
private RegisterAllocation allocation;
|
||||
@JsonIgnore
|
||||
private Scope parentScope;
|
||||
|
||||
public Scope(String name, SymbolType type, Scope parentScope) {
|
||||
public Scope(String name, Scope parentScope) {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
this.parentScope = parentScope;
|
||||
this.symbols = new LinkedHashMap<>();
|
||||
}
|
||||
|
||||
@JsonCreator
|
||||
public Scope(
|
||||
@JsonProperty("name") String name,
|
||||
@JsonProperty("symbols") HashMap<String, Symbol> symbols,
|
||||
@JsonProperty("intermediateVarCount") int intermediateVarCount,
|
||||
@JsonProperty("intermediateLabelCount") int intermediateLabelCount) {
|
||||
this.name = name;
|
||||
this.symbols = symbols;
|
||||
this.intermediateVarCount = intermediateVarCount;
|
||||
this.intermediateLabelCount = intermediateLabelCount;
|
||||
for (Symbol symbol : symbols.values()) {
|
||||
symbol.setScope(this);
|
||||
}
|
||||
}
|
||||
|
||||
public Scope() {
|
||||
this.name = "";
|
||||
this.type = new SymbolTypeProgram();
|
||||
this.parentScope = null;
|
||||
this.symbols = new LinkedHashMap<>();
|
||||
}
|
||||
|
||||
public HashMap<String, Symbol> getSymbols() {
|
||||
return symbols;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLocalName() {
|
||||
return name;
|
||||
@@ -51,21 +71,23 @@ public class Scope implements Symbol {
|
||||
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Scope getScope() {
|
||||
return parentScope;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public String getTypedName() {
|
||||
return "(" + getType().getTypeName() + ") " + getFullName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SymbolType getType() {
|
||||
return type;
|
||||
}
|
||||
@JsonIgnore
|
||||
public abstract SymbolType getType();
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public int getScopeDepth() {
|
||||
if (parentScope == null) {
|
||||
return 0;
|
||||
@@ -127,7 +149,7 @@ public class Scope implements Symbol {
|
||||
return (Variable) getSymbol(name);
|
||||
}
|
||||
|
||||
|
||||
@JsonIgnore
|
||||
public Collection<Variable> getAllVariables() {
|
||||
Collection<Variable> vars = new ArrayList<>();
|
||||
for (Symbol symbol : symbols.values()) {
|
||||
@@ -174,28 +196,15 @@ public class Scope implements Symbol {
|
||||
}
|
||||
}
|
||||
|
||||
public void setAllocation(RegisterAllocation allocation) {
|
||||
this.allocation = allocation;
|
||||
for (Symbol symbol : symbols.values()) {
|
||||
if(symbol instanceof Scope) {
|
||||
((Scope) symbol).setAllocation(allocation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public RegisterAllocation.Register getRegister(Variable variable) {
|
||||
RegisterAllocation.Register register = null;
|
||||
if (allocation != null) {
|
||||
register = allocation.getRegister(variable);
|
||||
}
|
||||
return register;
|
||||
}
|
||||
abstract RegisterAllocation getAllocation();
|
||||
|
||||
@JsonIgnore
|
||||
public String getSymbolTableContents() {
|
||||
StringBuilder res = new StringBuilder();
|
||||
Set<String> names = symbols.keySet();
|
||||
List<String> sortedNames = new ArrayList<>(names);
|
||||
Collections.sort(sortedNames);
|
||||
RegisterAllocation allocation = getAllocation();
|
||||
for (String name : sortedNames) {
|
||||
Symbol symbol = symbols.get(name);
|
||||
if (symbol instanceof Scope) {
|
||||
@@ -203,8 +212,8 @@ public class Scope implements Symbol {
|
||||
} else {
|
||||
res.append(symbol.toString());
|
||||
}
|
||||
if (symbol instanceof Variable) {
|
||||
RegisterAllocation.Register register = getRegister((Variable) symbol);
|
||||
if (symbol instanceof Variable && allocation!=null) {
|
||||
RegisterAllocation.Register register = allocation.getRegister((Variable) symbol);
|
||||
if (register != null) {
|
||||
res.append(" " + register);
|
||||
}
|
||||
@@ -214,7 +223,47 @@ public class Scope implements Symbol {
|
||||
return res.toString();
|
||||
}
|
||||
|
||||
public Collection<Symbol> getSymbols() {
|
||||
@JsonIgnore
|
||||
public Collection<Symbol> getAllSymbols() {
|
||||
return symbols.values();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setScope(Scope scope) {
|
||||
this.parentScope = scope;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Scope scope = (Scope) o;
|
||||
|
||||
if (intermediateVarCount != scope.intermediateVarCount) {
|
||||
return false;
|
||||
}
|
||||
if (intermediateLabelCount != scope.intermediateLabelCount) {
|
||||
return false;
|
||||
}
|
||||
if (!name.equals(scope.name)) {
|
||||
return false;
|
||||
}
|
||||
if (!symbols.equals(scope.symbols)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = name.hashCode();
|
||||
result = 31 * result + intermediateVarCount;
|
||||
result = 31 * result + intermediateLabelCount;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,9 @@
|
||||
package dk.camelot64.kickc.icl;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
|
||||
|
||||
/**
|
||||
* Single Static Assignment Form Statement.
|
||||
* Intermediate form used for compiler optimization.
|
||||
@@ -8,11 +12,11 @@ package dk.camelot64.kickc.icl;
|
||||
* <br>
|
||||
* <i> lValue := rValue1 <operator> rValue2 </i>
|
||||
*/
|
||||
@JsonPropertyOrder({"lValue", "rValue1", "operator", "rValue2"})
|
||||
public class StatementAssignment implements StatementLValue {
|
||||
|
||||
/** The variable being assigned a value by the statement. */
|
||||
private LValue lValue;
|
||||
|
||||
private RValue rValue1;
|
||||
private Operator operator;
|
||||
private RValue rValue2;
|
||||
@@ -24,7 +28,12 @@ public class StatementAssignment implements StatementLValue {
|
||||
this.rValue2 = rValue2;
|
||||
}
|
||||
|
||||
public StatementAssignment(LValue lValue, RValue rValue1, Operator operator, RValue rValue2) {
|
||||
@JsonCreator
|
||||
public StatementAssignment(
|
||||
@JsonProperty("lValue1") LValue lValue,
|
||||
@JsonProperty("rValue1") RValue rValue1,
|
||||
@JsonProperty("operator") Operator operator,
|
||||
@JsonProperty("rValue2") RValue rValue2) {
|
||||
this.lValue = lValue;
|
||||
this.rValue1 = rValue1;
|
||||
this.operator = operator;
|
||||
@@ -38,19 +47,19 @@ public class StatementAssignment implements StatementLValue {
|
||||
this.rValue2 = rValue2;
|
||||
}
|
||||
|
||||
public LValue getLValue() {
|
||||
public LValue getlValue() {
|
||||
return lValue;
|
||||
}
|
||||
|
||||
public void setLValue(LValue lValue) {
|
||||
public void setlValue(LValue lValue) {
|
||||
this.lValue = lValue;
|
||||
}
|
||||
|
||||
public RValue getRValue1() {
|
||||
public RValue getrValue1() {
|
||||
return rValue1;
|
||||
}
|
||||
|
||||
public void setRValue1(RValue rValue1) {
|
||||
public void setrValue1(RValue rValue1) {
|
||||
this.rValue1 = rValue1;
|
||||
}
|
||||
|
||||
@@ -58,11 +67,11 @@ public class StatementAssignment implements StatementLValue {
|
||||
return operator;
|
||||
}
|
||||
|
||||
public RValue getRValue2() {
|
||||
public RValue getrValue2() {
|
||||
return rValue2;
|
||||
}
|
||||
|
||||
public void setRValue2(RValue rValue2) {
|
||||
public void setrValue2(RValue rValue2) {
|
||||
this.rValue2 = rValue2;
|
||||
}
|
||||
|
||||
|
@@ -23,11 +23,11 @@ public class StatementCall implements StatementLValue {
|
||||
this.parametersByAssignment = false;
|
||||
}
|
||||
|
||||
public LValue getLValue() {
|
||||
public LValue getlValue() {
|
||||
return lValue;
|
||||
}
|
||||
|
||||
public void setLValue(LValue lValue) {
|
||||
public void setlValue(LValue lValue) {
|
||||
this.lValue = lValue;
|
||||
}
|
||||
|
||||
|
@@ -5,8 +5,8 @@ package dk.camelot64.kickc.icl;
|
||||
*/
|
||||
public interface StatementLValue extends Statement {
|
||||
|
||||
LValue getLValue();
|
||||
LValue getlValue();
|
||||
|
||||
void setLValue(LValue lValue);
|
||||
void setlValue(LValue lValue);
|
||||
|
||||
}
|
||||
|
@@ -56,12 +56,12 @@ public class StatementPhi implements StatementLValue {
|
||||
}
|
||||
}
|
||||
|
||||
public VariableVersion getLValue() {
|
||||
public VariableVersion getlValue() {
|
||||
return lValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLValue(LValue lValue) {
|
||||
public void setlValue(LValue lValue) {
|
||||
if(!(lValue instanceof VariableVersion)) {
|
||||
throw new RuntimeException("Error modifying phi-statement lValue "+this.lValue+". Attempt to set to non-versioned variable "+lValue);
|
||||
}
|
||||
|
@@ -1,17 +1,26 @@
|
||||
package dk.camelot64.kickc.icl;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
|
||||
/** A Symbol (variable, jump label, etc.) */
|
||||
public interface Symbol extends Value {
|
||||
|
||||
@JsonIgnore
|
||||
String getLocalName();
|
||||
|
||||
@JsonIgnore
|
||||
String getFullName();
|
||||
|
||||
@JsonIgnore
|
||||
String getTypedName();
|
||||
|
||||
SymbolType getType();
|
||||
|
||||
@JsonIgnore
|
||||
Scope getScope();
|
||||
|
||||
@JsonIgnore
|
||||
int getScopeDepth();
|
||||
|
||||
void setScope(Scope scope);
|
||||
}
|
||||
|
@@ -1,8 +1,18 @@
|
||||
package dk.camelot64.kickc.icl;
|
||||
|
||||
/** Symbol Types */
|
||||
public interface SymbolType {
|
||||
import com.fasterxml.jackson.annotation.JsonSubTypes;
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
|
||||
/** Symbol Types */
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "@type")
|
||||
@JsonSubTypes({
|
||||
@JsonSubTypes.Type(value = SymbolTypeProgram.class, name = "program"),
|
||||
@JsonSubTypes.Type(value = SymbolTypeBasic.class, name = "basic"),
|
||||
@JsonSubTypes.Type(value = SymbolTypeArray.class, name = "array"),
|
||||
@JsonSubTypes.Type(value = SymbolTypePointer.class, name = "pointer"),
|
||||
@JsonSubTypes.Type(value = SymbolTypeProcedure.class, name = "procedure")
|
||||
})
|
||||
public interface SymbolType {
|
||||
public String getTypeName();
|
||||
|
||||
}
|
||||
|
@@ -1,21 +1,28 @@
|
||||
package dk.camelot64.kickc.icl;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/** Basic Symbol Types */
|
||||
public enum SymbolTypeBasic implements SymbolType {
|
||||
BYTE("byte"),
|
||||
WORD("word"),
|
||||
STRING("string"),
|
||||
BOOLEAN("boolean"),
|
||||
public class SymbolTypeBasic implements SymbolType {
|
||||
|
||||
public static final SymbolTypeBasic BYTE = new SymbolTypeBasic("byte");
|
||||
public static final SymbolTypeBasic WORD = new SymbolTypeBasic("word");
|
||||
public static final SymbolTypeBasic STRING = new SymbolTypeBasic("string");
|
||||
public static final SymbolTypeBasic BOOLEAN = new SymbolTypeBasic("boolean");
|
||||
// A label
|
||||
LABEL("label"),
|
||||
public static final SymbolTypeBasic LABEL = new SymbolTypeBasic("label");
|
||||
// Void type.
|
||||
VOID("void"),
|
||||
public static final SymbolTypeBasic VOID = new SymbolTypeBasic("void");
|
||||
// Unresolved type. Will be infered later
|
||||
VAR("var");
|
||||
public static final SymbolTypeBasic VAR = new SymbolTypeBasic("var");
|
||||
|
||||
private String typeName;
|
||||
|
||||
SymbolTypeBasic(String typeName) {
|
||||
@JsonCreator
|
||||
SymbolTypeBasic(
|
||||
@JsonProperty("typeName") String typeName) {
|
||||
this.typeName = typeName;
|
||||
}
|
||||
|
||||
@@ -34,5 +41,22 @@ public enum SymbolTypeBasic implements SymbolType {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SymbolTypeBasic that = (SymbolTypeBasic) o;
|
||||
|
||||
return typeName != null ? typeName.equals(that.typeName) : that.typeName == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return typeName != null ? typeName.hashCode() : 0;
|
||||
}
|
||||
}
|
||||
|
@@ -1,11 +1,17 @@
|
||||
package dk.camelot64.kickc.icl;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/** A function returning another type */
|
||||
public class SymbolTypeProcedure implements SymbolType {
|
||||
|
||||
private SymbolType returnType;
|
||||
|
||||
public SymbolTypeProcedure(SymbolType returnType) {
|
||||
@JsonCreator
|
||||
public SymbolTypeProcedure(
|
||||
@JsonProperty("returnType") SymbolType returnType) {
|
||||
this.returnType = returnType;
|
||||
}
|
||||
|
||||
@@ -14,6 +20,7 @@ public class SymbolTypeProcedure implements SymbolType {
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public String getTypeName() {
|
||||
return returnType.getTypeName() + "()";
|
||||
}
|
||||
|
@@ -1,5 +1,7 @@
|
||||
package dk.camelot64.kickc.icl;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
|
||||
/** A program */
|
||||
public class SymbolTypeProgram implements SymbolType {
|
||||
|
||||
@@ -8,7 +10,18 @@ public class SymbolTypeProgram implements SymbolType {
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public String getTypeName() {
|
||||
return "PROGRAM";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 331;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return (obj instanceof SymbolTypeProgram);
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,23 @@
|
||||
package dk.camelot64.kickc.icl;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonSubTypes;
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
|
||||
/** Any value (variable, constant, label) */
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "@type")
|
||||
@JsonSubTypes({
|
||||
@JsonSubTypes.Type(value = ConstantBool.class, name = "boolean"),
|
||||
@JsonSubTypes.Type(value = ConstantInteger.class, name = "integer"),
|
||||
@JsonSubTypes.Type(value = ConstantDouble.class, name = "double"),
|
||||
@JsonSubTypes.Type(value = ConstantString.class, name = "string"),
|
||||
@JsonSubTypes.Type(value = VariableUnversioned.class, name = "variable_unversioned"),
|
||||
@JsonSubTypes.Type(value = VariableVersion.class, name = "variable_versioned"),
|
||||
@JsonSubTypes.Type(value = VariableIntermediate.class, name = "variable_intermediate"),
|
||||
@JsonSubTypes.Type(value = Label.class, name = "label"),
|
||||
@JsonSubTypes.Type(value = PointerDereferenceIndexed.class, name = "pointer_indexed"),
|
||||
@JsonSubTypes.Type(value = PointerDereferenceSimple.class, name = "pointer_simple"),
|
||||
@JsonSubTypes.Type(value = ProgramScope.class, name = "program"),
|
||||
@JsonSubTypes.Type(value = Procedure.class, name = "procedure")
|
||||
})
|
||||
public interface Value {
|
||||
}
|
||||
|
@@ -1,5 +1,7 @@
|
||||
package dk.camelot64.kickc.icl;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
|
||||
/**
|
||||
* A Symbol (variable, jump label, etc.)
|
||||
*/
|
||||
@@ -13,6 +15,7 @@ public abstract class Variable implements Symbol, RValue, LValue {
|
||||
/**
|
||||
* Scope
|
||||
*/
|
||||
@JsonIgnore
|
||||
private Scope scope;
|
||||
|
||||
/**
|
||||
@@ -32,6 +35,7 @@ public abstract class Variable implements Symbol, RValue, LValue {
|
||||
this.inferredType = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLocalName() {
|
||||
return name;
|
||||
}
|
||||
@@ -42,6 +46,7 @@ public abstract class Variable implements Symbol, RValue, LValue {
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public String getTypedName() {
|
||||
return "(" + type.getTypeName() + (inferredType ? "~" : "") + ") " + getFullName();
|
||||
}
|
||||
@@ -50,7 +55,7 @@ public abstract class Variable implements Symbol, RValue, LValue {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setInferredType(SymbolType type) {
|
||||
public void setTypeInferred(SymbolType type) {
|
||||
this.type = type;
|
||||
this.inferredType = true;
|
||||
}
|
||||
@@ -59,27 +64,42 @@ public abstract class Variable implements Symbol, RValue, LValue {
|
||||
return inferredType;
|
||||
}
|
||||
|
||||
public void setInferredType(boolean inferredType) {
|
||||
this.inferredType = inferredType;
|
||||
}
|
||||
|
||||
public void setScope(Scope scope) {
|
||||
this.scope = scope;
|
||||
}
|
||||
|
||||
public void setType(SymbolType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public abstract boolean isVersioned();
|
||||
|
||||
@JsonIgnore
|
||||
public abstract boolean isIntermediate();
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
Variable variable = (Variable) o;
|
||||
|
||||
if (inferredType != variable.inferredType) return false;
|
||||
if (!name.equals(variable.name)) return false;
|
||||
if (scope != null ? !scope.equals(variable.scope) : variable.scope != null) return false;
|
||||
if (!getFullName().equals(variable.getFullName())) return false;
|
||||
return type.equals(variable.type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = name.hashCode();
|
||||
result = 31 * result + (scope != null ? scope.hashCode() : 0);
|
||||
int result = getFullName().hashCode();
|
||||
result = 31 * result + type.hashCode();
|
||||
result = 31 * result + (inferredType ? 1 : 0);
|
||||
return result;
|
||||
|
@@ -1,5 +1,9 @@
|
||||
package dk.camelot64.kickc.icl;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* A Symbol (variable, jump label, etc.)
|
||||
*/
|
||||
@@ -9,6 +13,13 @@ public class VariableIntermediate extends Variable {
|
||||
super(name, scope, type);
|
||||
}
|
||||
|
||||
@JsonCreator
|
||||
public VariableIntermediate(
|
||||
@JsonProperty("name") String name,
|
||||
@JsonProperty("type") SymbolType type) {
|
||||
super(name, null, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isIntermediate() {
|
||||
return true;
|
||||
@@ -18,4 +29,6 @@ public class VariableIntermediate extends Variable {
|
||||
public boolean isVersioned() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@@ -1,5 +1,8 @@
|
||||
package dk.camelot64.kickc.icl;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* A Symbol (variable, jump label, etc.)
|
||||
*/
|
||||
@@ -10,11 +13,23 @@ public class VariableUnversioned extends Variable {
|
||||
*/
|
||||
private Integer nextVersionNumber;
|
||||
|
||||
public VariableUnversioned(String name, Scope scope, SymbolType type) {
|
||||
public VariableUnversioned(
|
||||
String name,
|
||||
Scope scope,
|
||||
SymbolType type) {
|
||||
super(name, scope, type);
|
||||
this.nextVersionNumber = 0;
|
||||
}
|
||||
|
||||
@JsonCreator
|
||||
public VariableUnversioned(
|
||||
@JsonProperty("name") String name,
|
||||
@JsonProperty("type") SymbolType type,
|
||||
@JsonProperty("nextVersionNumber") Integer nextVersionNumber) {
|
||||
super(name, null, type);
|
||||
this.nextVersionNumber = nextVersionNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the version number of the next version. (if anyone versions the symbol).
|
||||
*/
|
||||
|
@@ -1,13 +1,26 @@
|
||||
package dk.camelot64.kickc.icl;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/** A Symbol (variable, jump label, etc.) */
|
||||
public class VariableVersion extends Variable {
|
||||
|
||||
private VariableUnversioned versionOf;
|
||||
private String versionOfName;
|
||||
|
||||
public VariableVersion(VariableUnversioned versionOf, int version) {
|
||||
super(versionOf.getLocalName()+"#"+version, versionOf.getScope(), versionOf.getType());
|
||||
this.versionOf = versionOf;
|
||||
this.versionOfName = versionOf.getLocalName();
|
||||
}
|
||||
|
||||
@JsonCreator
|
||||
public VariableVersion(
|
||||
@JsonProperty("name") String name,
|
||||
@JsonProperty("type") SymbolType type,
|
||||
@JsonProperty("versionOfName") String versionOfName) {
|
||||
super(name, null, type);
|
||||
this.versionOfName = versionOfName;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -20,25 +33,40 @@ public class VariableVersion extends Variable {
|
||||
return false;
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public VariableUnversioned getVersionOf() {
|
||||
return versionOf;
|
||||
return (VariableUnversioned) getScope().getVariable(versionOfName);
|
||||
}
|
||||
|
||||
public String getVersionOfName() {
|
||||
return versionOfName;
|
||||
}
|
||||
|
||||
public void setVersionOfName(String versionOfName) {
|
||||
this.versionOfName = versionOfName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
if (!super.equals(o)) return false;
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
if (!super.equals(o)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
VariableVersion that = (VariableVersion) o;
|
||||
|
||||
return versionOf != null ? versionOf.equals(that.versionOf) : that.versionOf == null;
|
||||
return versionOfName != null ? versionOfName.equals(that.versionOfName) : that.versionOfName == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = super.hashCode();
|
||||
result = 31 * result + (versionOf != null ? versionOf.hashCode() : 0);
|
||||
result = 31 * result + (versionOfName != null ? versionOfName.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
39
src/dk/camelot64/kickc/icl/jackson/IclJacksonFactory.java
Normal file
39
src/dk/camelot64/kickc/icl/jackson/IclJacksonFactory.java
Normal file
@@ -0,0 +1,39 @@
|
||||
package dk.camelot64.kickc.icl.jackson;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.PropertyAccessor;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.Module;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||
|
||||
/** Factory for Jackson JSON serialization of the KickC ICL */
|
||||
public class IclJacksonFactory {
|
||||
|
||||
private static ObjectMapper mapper;
|
||||
private static Module module;
|
||||
|
||||
static {
|
||||
mapper = new ObjectMapper();
|
||||
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true);
|
||||
mapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);
|
||||
mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
|
||||
SimpleModule jsonModule = new SimpleModule("KickC ICL Types");
|
||||
module = jsonModule;
|
||||
mapper.registerModule(jsonModule);
|
||||
}
|
||||
|
||||
|
||||
/** Get an ObjectMapper usable for serializing/deserializing KickC ICL to/from JSON */
|
||||
public static ObjectMapper getMapper() {
|
||||
return mapper;
|
||||
}
|
||||
|
||||
|
||||
/** Get a Jackson Module usable for serializing/deserializing KickC ICL to/from JSON */
|
||||
public static Module getModule() {
|
||||
return module;
|
||||
}
|
||||
|
||||
}
|
@@ -41,21 +41,21 @@ public class Pass1GenerateSingleStaticAssignmentForm {
|
||||
for (Statement statement : block.getStatements()) {
|
||||
if (statement instanceof StatementAssignment) {
|
||||
StatementAssignment assignment = (StatementAssignment) statement;
|
||||
LValue lValue = assignment.getLValue();
|
||||
LValue lValue = assignment.getlValue();
|
||||
if (lValue instanceof VariableUnversioned) {
|
||||
// Assignment to a non-versioned non-intermediary variable
|
||||
VariableUnversioned assignedSymbol = (VariableUnversioned) lValue;
|
||||
VariableVersion version = assignedSymbol.createVersion();
|
||||
assignment.setLValue(version);
|
||||
assignment.setlValue(version);
|
||||
}
|
||||
} else if(statement instanceof StatementCall) {
|
||||
StatementCall call = (StatementCall) statement;
|
||||
LValue lValue = call.getLValue();
|
||||
LValue lValue = call.getlValue();
|
||||
if (lValue instanceof VariableUnversioned) {
|
||||
// Assignment to a non-versioned non-intermediary variable
|
||||
VariableUnversioned assignedSymbol = (VariableUnversioned) lValue;
|
||||
VariableVersion version = assignedSymbol.createVersion();
|
||||
call.setLValue(version);
|
||||
call.setlValue(version);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -85,19 +85,19 @@ public class Pass1GenerateSingleStaticAssignmentForm {
|
||||
if (statement instanceof StatementAssignment) {
|
||||
StatementAssignment assignment = (StatementAssignment) statement;
|
||||
{
|
||||
VariableVersion version = findOrCreateVersion(assignment.getRValue1(), blockVersions, blockNewPhis);
|
||||
VariableVersion version = findOrCreateVersion(assignment.getrValue1(), blockVersions, blockNewPhis);
|
||||
if (version != null) {
|
||||
assignment.setRValue1(version);
|
||||
assignment.setrValue1(version);
|
||||
}
|
||||
}
|
||||
{
|
||||
VariableVersion version = findOrCreateVersion(assignment.getRValue2(), blockVersions, blockNewPhis);
|
||||
VariableVersion version = findOrCreateVersion(assignment.getrValue2(), blockVersions, blockNewPhis);
|
||||
if (version != null) {
|
||||
assignment.setRValue2(version);
|
||||
assignment.setrValue2(version);
|
||||
}
|
||||
}
|
||||
// Update map of versions encountered in the block
|
||||
LValue lValue = assignment.getLValue();
|
||||
LValue lValue = assignment.getlValue();
|
||||
if (lValue instanceof VariableVersion) {
|
||||
VariableVersion versioned = (VariableVersion) lValue;
|
||||
blockVersions.put(versioned.getVersionOf(), versioned);
|
||||
@@ -175,7 +175,7 @@ public class Pass1GenerateSingleStaticAssignmentForm {
|
||||
if (statement instanceof StatementPhi) {
|
||||
StatementPhi phi = (StatementPhi) statement;
|
||||
if (phi.getPreviousVersions().isEmpty()) {
|
||||
VariableVersion versioned = phi.getLValue();
|
||||
VariableVersion versioned = phi.getlValue();
|
||||
VariableUnversioned unversioned = versioned.getVersionOf();
|
||||
for (ControlFlowBlock predecessor : controlFlowGraph.getPredecessors(block)) {
|
||||
Label predecessorLabel = predecessor.getLabel();
|
||||
@@ -226,7 +226,7 @@ public class Pass1GenerateSingleStaticAssignmentForm {
|
||||
for (Statement statement : block.getStatements()) {
|
||||
if (statement instanceof StatementAssignment) {
|
||||
StatementAssignment assignment = (StatementAssignment) statement;
|
||||
LValue lValue = assignment.getLValue();
|
||||
LValue lValue = assignment.getlValue();
|
||||
if (lValue instanceof VariableVersion) {
|
||||
VariableVersion versioned = (VariableVersion) lValue;
|
||||
Label label = block.getLabel();
|
||||
@@ -240,7 +240,7 @@ public class Pass1GenerateSingleStaticAssignmentForm {
|
||||
}
|
||||
} else if (statement instanceof StatementPhi) {
|
||||
StatementPhi phi = (StatementPhi) statement;
|
||||
VariableVersion versioned = phi.getLValue();
|
||||
VariableVersion versioned = phi.getlValue();
|
||||
VariableUnversioned unversioned = versioned.getVersionOf();
|
||||
Label label = block.getLabel();
|
||||
Map<VariableUnversioned, VariableVersion> blockMap = symbolMap.get(label);
|
||||
@@ -251,7 +251,7 @@ public class Pass1GenerateSingleStaticAssignmentForm {
|
||||
blockMap.put(unversioned, versioned);
|
||||
} else if (statement instanceof StatementCall) {
|
||||
StatementCall call = (StatementCall) statement;
|
||||
LValue lValue = call.getLValue();
|
||||
LValue lValue = call.getlValue();
|
||||
if (lValue instanceof VariableVersion) {
|
||||
VariableVersion versioned = (VariableVersion) lValue;
|
||||
Label label = block.getLabel();
|
||||
|
@@ -18,19 +18,19 @@ import java.util.Stack;
|
||||
public class Pass1GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
||||
|
||||
private CompileLog log;
|
||||
private Scope programScope;
|
||||
private ProgramScope programScope;
|
||||
private Stack<Scope> scopeStack;
|
||||
private StatementSequence sequence;
|
||||
|
||||
public Pass1GenerateStatementSequence(CompileLog log) {
|
||||
this.log = log;
|
||||
this.programScope = new Scope();
|
||||
this.programScope = new ProgramScope();
|
||||
this.scopeStack = new Stack<>();
|
||||
scopeStack.push(programScope);
|
||||
this.sequence = new StatementSequence();
|
||||
}
|
||||
|
||||
public Scope getProgramScope() {
|
||||
public ProgramScope getProgramScope() {
|
||||
return programScope;
|
||||
}
|
||||
|
||||
|
@@ -41,10 +41,10 @@ public class Pass1ProcedureCallParameters extends ControlFlowGraphCopyVisitor {
|
||||
getCurrentBlock().setCallSuccessor(procedure.getLabel());
|
||||
splitCurrentBlock(scope.addLabelIntermediate());
|
||||
if(!SymbolTypeBasic.VOID.equals(procedure.getReturnType())) {
|
||||
addStatementToCurrentBlock(new StatementAssignment(origCall.getLValue(), procReturnVar));
|
||||
addStatementToCurrentBlock(new StatementAssignment(origCall.getlValue(), procReturnVar));
|
||||
} else {
|
||||
// No return type. Remove variable receiving the result.
|
||||
LValue lValue = origCall.getLValue();
|
||||
LValue lValue = origCall.getlValue();
|
||||
if(lValue instanceof Variable) {
|
||||
Variable lVar = (Variable) lValue;
|
||||
lVar.getScope().remove(lVar);
|
||||
|
@@ -47,7 +47,7 @@ public class Pass1ProcedureCallsReturnValue extends ControlFlowGraphCopyVisitor
|
||||
if (returnVarFinal == null) {
|
||||
throw new RuntimeException("Error! Cannot find final return variable for " + procedure.getFullName());
|
||||
}
|
||||
StatementAssignment returnAssignment = new StatementAssignment(origCall.getLValue(), returnVarFinal);
|
||||
StatementAssignment returnAssignment = new StatementAssignment(origCall.getlValue(), returnVarFinal);
|
||||
addStatementToCurrentBlock(returnAssignment);
|
||||
}
|
||||
return null;
|
||||
|
@@ -21,30 +21,30 @@ public class Pass1TypeInference {
|
||||
scopes.pop();
|
||||
} else if (statement instanceof StatementAssignment) {
|
||||
StatementAssignment assignment = (StatementAssignment) statement;
|
||||
LValue lValue = assignment.getLValue();
|
||||
LValue lValue = assignment.getlValue();
|
||||
if (lValue instanceof Variable) {
|
||||
Variable symbol = (Variable) lValue;
|
||||
if (SymbolTypeBasic.VAR.equals(symbol.getType())) {
|
||||
// Unresolved symbol - perform inference
|
||||
Operator operator = assignment.getOperator();
|
||||
if (operator == null || assignment.getRValue1() == null) {
|
||||
if (operator == null || assignment.getrValue1() == null) {
|
||||
// Copy operation or Unary operation
|
||||
RValue rValue = assignment.getRValue2();
|
||||
RValue rValue = assignment.getrValue2();
|
||||
SymbolType subType = inferType(rValue);
|
||||
SymbolType type = inferType(operator, subType);
|
||||
symbol.setInferredType(type);
|
||||
symbol.setTypeInferred(type);
|
||||
} else {
|
||||
// Binary operation
|
||||
SymbolType type1 = inferType(assignment.getRValue1());
|
||||
SymbolType type2 = inferType(assignment.getRValue2());
|
||||
SymbolType type1 = inferType(assignment.getrValue1());
|
||||
SymbolType type2 = inferType(assignment.getrValue2());
|
||||
SymbolType type = inferType(type1, operator, type2);
|
||||
symbol.setInferredType(type);
|
||||
symbol.setTypeInferred(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if(statement instanceof StatementCall) {
|
||||
StatementCall call = (StatementCall) statement;
|
||||
LValue lValue = call.getLValue();
|
||||
LValue lValue = call.getlValue();
|
||||
if(lValue instanceof Variable) {
|
||||
String procedureName = call.getProcedureName();
|
||||
Procedure procedure = scopes.peek().getProcedure(procedureName);
|
||||
@@ -52,7 +52,7 @@ public class Pass1TypeInference {
|
||||
if(procedure.getParameters().size()!=call.getParameters().size()) {
|
||||
throw new RuntimeException("Wrong number of parameters in call. Expected " +procedure.getParameters().size()+". "+statement.toString());
|
||||
}
|
||||
((Variable) lValue).setInferredType(procedure.getReturnType());
|
||||
((Variable) lValue).setTypeInferred(procedure.getReturnType());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -48,15 +48,15 @@ public class Pass2AliasElimination extends Pass2SsaOptimization {
|
||||
Statement statement = iterator.next();
|
||||
if (statement instanceof StatementAssignment) {
|
||||
StatementAssignment assignment = (StatementAssignment) statement;
|
||||
AliasSet aliasSet = aliases.findAliasSet(assignment.getLValue());
|
||||
AliasSet aliasSet = aliases.findAliasSet(assignment.getlValue());
|
||||
if (aliasSet != null) {
|
||||
if ((assignment.getRValue1() == null) && (assignment.getOperator() == null) && aliasSet.contains(assignment.getRValue2())) {
|
||||
if ((assignment.getrValue1() == null) && (assignment.getOperator() == null) && aliasSet.contains(assignment.getrValue2())) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
} else if (statement instanceof StatementPhi) {
|
||||
StatementPhi phi = (StatementPhi) statement;
|
||||
AliasSet aliasSet = aliases.findAliasSet(phi.getLValue());
|
||||
AliasSet aliasSet = aliases.findAliasSet(phi.getlValue());
|
||||
if (aliasSet != null) {
|
||||
if (phi.getPreviousVersions().size() == 1 && aliasSet.contains(phi.getPreviousVersion(0).getRValue())) {
|
||||
iterator.remove();
|
||||
@@ -241,7 +241,7 @@ public class Pass2AliasElimination extends Pass2SsaOptimization {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (aliasSet.contains(phi.getLValue())) {
|
||||
if (aliasSet.contains(phi.getlValue())) {
|
||||
lMatch[0] = true;
|
||||
}
|
||||
return null;
|
||||
@@ -261,11 +261,11 @@ public class Pass2AliasElimination extends Pass2SsaOptimization {
|
||||
ControlFlowGraphBaseVisitor<Void> visitor = new ControlFlowGraphBaseVisitor<Void>() {
|
||||
@Override
|
||||
public Void visitAssignment(StatementAssignment assignment) {
|
||||
if (assignment.getLValue() instanceof VariableVersion || assignment.getLValue() instanceof VariableIntermediate) {
|
||||
Variable variable = (Variable) assignment.getLValue();
|
||||
if (assignment.getRValue1() == null && assignment.getOperator() == null && assignment.getRValue2() instanceof Variable) {
|
||||
if (assignment.getlValue() instanceof VariableVersion || assignment.getlValue() instanceof VariableIntermediate) {
|
||||
Variable variable = (Variable) assignment.getlValue();
|
||||
if (assignment.getrValue1() == null && assignment.getOperator() == null && assignment.getrValue2() instanceof Variable) {
|
||||
// Alias assignment
|
||||
Variable alias = (Variable) assignment.getRValue2();
|
||||
Variable alias = (Variable) assignment.getrValue2();
|
||||
aliases.add(variable, alias);
|
||||
}
|
||||
}
|
||||
@@ -277,7 +277,7 @@ public class Pass2AliasElimination extends Pass2SsaOptimization {
|
||||
if (phi.getPreviousVersions().size() == 1) {
|
||||
StatementPhi.PreviousSymbol previousSymbol = phi.getPreviousVersions().get(0);
|
||||
if (previousSymbol.getRValue() instanceof Variable) {
|
||||
VariableVersion variable = phi.getLValue();
|
||||
VariableVersion variable = phi.getlValue();
|
||||
Variable alias = (Variable) previousSymbol.getRValue();
|
||||
aliases.add(variable, alias);
|
||||
}
|
||||
|
@@ -44,7 +44,7 @@ public class Pass2AssertSymbols extends Pass2SsaAssertion {
|
||||
|
||||
private HashSet<Symbol> getAllSymbols(Scope symbols) {
|
||||
HashSet<Symbol> allSymbols = new HashSet<>();
|
||||
for (Symbol symbol : symbols.getSymbols()) {
|
||||
for (Symbol symbol : symbols.getAllSymbols()) {
|
||||
allSymbols.add(symbol);
|
||||
if(symbol instanceof Scope) {
|
||||
HashSet<Symbol> subSymbols = getAllSymbols((Scope) symbol);
|
||||
@@ -110,9 +110,9 @@ public class Pass2AssertSymbols extends Pass2SsaAssertion {
|
||||
|
||||
@Override
|
||||
public Void visitAssignment(StatementAssignment assignment) {
|
||||
addSymbol(assignment.getLValue());
|
||||
addSymbol(assignment.getRValue1());
|
||||
addSymbol(assignment.getRValue2());
|
||||
addSymbol(assignment.getlValue());
|
||||
addSymbol(assignment.getrValue1());
|
||||
addSymbol(assignment.getrValue2());
|
||||
return super.visitAssignment(assignment);
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@ public class Pass2AssertSymbols extends Pass2SsaAssertion {
|
||||
|
||||
@Override
|
||||
public Void visitCall(StatementCall callLValue) {
|
||||
addSymbol(callLValue.getLValue());
|
||||
addSymbol(callLValue.getlValue());
|
||||
addSymbol(callLValue.getProcedure());
|
||||
if(callLValue.getParameters()!=null) {
|
||||
for (RValue param : callLValue.getParameters()) {
|
||||
@@ -142,7 +142,7 @@ public class Pass2AssertSymbols extends Pass2SsaAssertion {
|
||||
|
||||
@Override
|
||||
public Void visitPhi(StatementPhi phi) {
|
||||
addSymbol(phi.getLValue());
|
||||
addSymbol(phi.getlValue());
|
||||
for (StatementPhi.PreviousSymbol previousSymbol : phi.getPreviousVersions()) {
|
||||
addSymbol(previousSymbol.getRValue());
|
||||
}
|
||||
|
@@ -54,9 +54,9 @@ public class Pass2ConditionalJumpSimplification extends Pass2SsaOptimization {
|
||||
case "=<":
|
||||
case ">=":
|
||||
case "=>":
|
||||
conditionalJump.setRValue1(conditionAssignment.getRValue1());
|
||||
conditionalJump.setRValue1(conditionAssignment.getrValue1());
|
||||
conditionalJump.setOperator(conditionAssignment.getOperator());
|
||||
conditionalJump.setRValue2(conditionAssignment.getRValue2());
|
||||
conditionalJump.setRValue2(conditionAssignment.getrValue2());
|
||||
simpleConditionVars.add(conditionVar);
|
||||
log.append("Simple Condition " + conditionVar + " " + conditionalJump);
|
||||
break;
|
||||
|
@@ -39,7 +39,7 @@ public class Pass2ConstantAdditionElimination extends Pass2SsaOptimization {
|
||||
for (Statement statement : block.getStatements()) {
|
||||
if (statement instanceof StatementAssignment) {
|
||||
StatementAssignment assignment = (StatementAssignment) statement;
|
||||
if(assignment.getLValue() instanceof PointerDereferenceIndexed) {
|
||||
if(assignment.getlValue() instanceof PointerDereferenceIndexed) {
|
||||
optimized |= optimizePointerDereferenceIndexed(assignment);
|
||||
}
|
||||
Operator operator = assignment.getOperator();
|
||||
@@ -60,13 +60,13 @@ public class Pass2ConstantAdditionElimination extends Pass2SsaOptimization {
|
||||
}
|
||||
|
||||
private boolean optimizePointerDereferenceIndexed(StatementAssignment assignment) {
|
||||
PointerDereferenceIndexed pointerDereferenceIndexed = (PointerDereferenceIndexed) assignment.getLValue();
|
||||
PointerDereferenceIndexed pointerDereferenceIndexed = (PointerDereferenceIndexed) assignment.getlValue();
|
||||
if(pointerDereferenceIndexed.getPointer() instanceof ConstantInteger && pointerDereferenceIndexed.getIndex() instanceof Constant) {
|
||||
ConstantInteger ptrConstant = (ConstantInteger) pointerDereferenceIndexed.getPointer();
|
||||
ConstantInteger idxConstant = (ConstantInteger) pointerDereferenceIndexed.getIndex();
|
||||
int newPtr = ptrConstant.getNumber() + idxConstant.getNumber();
|
||||
assignment.setLValue(new PointerDereferenceSimple(new ConstantInteger(newPtr)));
|
||||
log.append("Consolidated assigned array index constant in assignment " + assignment.getLValue());
|
||||
assignment.setlValue(new PointerDereferenceSimple(new ConstantInteger(newPtr)));
|
||||
log.append("Consolidated assigned array index constant in assignment " + assignment.getlValue());
|
||||
return true;
|
||||
}
|
||||
if(pointerDereferenceIndexed.getPointer() instanceof ConstantInteger && pointerDereferenceIndexed.getIndex() instanceof Variable) {
|
||||
@@ -76,7 +76,7 @@ public class Pass2ConstantAdditionElimination extends Pass2SsaOptimization {
|
||||
ConstantInteger ptrConstant = (ConstantInteger) pointerDereferenceIndexed.getPointer();
|
||||
int newPtr = ptrConstant.getNumber() + consolidated.getNumber();
|
||||
pointerDereferenceIndexed.setPointer(new ConstantInteger(newPtr));
|
||||
log.append("Consolidated assigned array index constant in assignment " + assignment.getLValue());
|
||||
log.append("Consolidated assigned array index constant in assignment " + assignment.getlValue());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -84,24 +84,24 @@ public class Pass2ConstantAdditionElimination extends Pass2SsaOptimization {
|
||||
}
|
||||
|
||||
private boolean optimizeArrayDeref(StatementAssignment assignment) {
|
||||
if (assignment.getRValue1() instanceof ConstantInteger && assignment.getRValue2() instanceof ConstantInteger) {
|
||||
ConstantInteger ptrConstant = (ConstantInteger) assignment.getRValue1();
|
||||
ConstantInteger idxConstant = (ConstantInteger) assignment.getRValue2();
|
||||
if (assignment.getrValue1() instanceof ConstantInteger && assignment.getrValue2() instanceof ConstantInteger) {
|
||||
ConstantInteger ptrConstant = (ConstantInteger) assignment.getrValue1();
|
||||
ConstantInteger idxConstant = (ConstantInteger) assignment.getrValue2();
|
||||
int newPtr = ptrConstant.getNumber() + idxConstant.getNumber();
|
||||
assignment.setRValue1(null);
|
||||
assignment.setrValue1(null);
|
||||
assignment.setOperator(new Operator("*"));
|
||||
assignment.setRValue2(new ConstantInteger(newPtr));
|
||||
log.append("Consolidated referenced array index constant in assignment " + assignment.getLValue());
|
||||
assignment.setrValue2(new ConstantInteger(newPtr));
|
||||
log.append("Consolidated referenced array index constant in assignment " + assignment.getlValue());
|
||||
return true;
|
||||
}
|
||||
if (assignment.getRValue1() instanceof ConstantInteger && assignment.getRValue2() instanceof Variable) {
|
||||
Variable variable = (Variable) assignment.getRValue2();
|
||||
if (assignment.getrValue1() instanceof ConstantInteger && assignment.getrValue2() instanceof Variable) {
|
||||
Variable variable = (Variable) assignment.getrValue2();
|
||||
ConstantInteger consolidated = consolidateSubConstants(variable);
|
||||
if (consolidated != null) {
|
||||
ConstantInteger ptrConstant = (ConstantInteger) assignment.getRValue1();
|
||||
ConstantInteger ptrConstant = (ConstantInteger) assignment.getrValue1();
|
||||
int newPtr = ptrConstant.getNumber() + consolidated.getNumber();
|
||||
assignment.setRValue1(new ConstantInteger(newPtr));
|
||||
log.append("Consolidated referenced array index constant in assignment " + assignment.getLValue());
|
||||
assignment.setrValue1(new ConstantInteger(newPtr));
|
||||
log.append("Consolidated referenced array index constant in assignment " + assignment.getlValue());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -109,28 +109,28 @@ public class Pass2ConstantAdditionElimination extends Pass2SsaOptimization {
|
||||
}
|
||||
|
||||
private boolean optimizePlus(StatementAssignment assignment) {
|
||||
if (assignment.getRValue1() instanceof ConstantInteger && assignment.getRValue2() instanceof Variable) {
|
||||
Variable variable = (Variable) assignment.getRValue2();
|
||||
if (assignment.getrValue1() instanceof ConstantInteger && assignment.getrValue2() instanceof Variable) {
|
||||
Variable variable = (Variable) assignment.getrValue2();
|
||||
ConstantInteger consolidated = consolidateSubConstants(variable);
|
||||
if (consolidated != null) {
|
||||
ConstantInteger const1 = (ConstantInteger) assignment.getRValue1();
|
||||
assignment.setRValue1(new ConstantInteger(const1.getNumber() + consolidated.getNumber()));
|
||||
log.append("Consolidated constant in assignment " + assignment.getLValue());
|
||||
ConstantInteger const1 = (ConstantInteger) assignment.getrValue1();
|
||||
assignment.setrValue1(new ConstantInteger(const1.getNumber() + consolidated.getNumber()));
|
||||
log.append("Consolidated constant in assignment " + assignment.getlValue());
|
||||
return true;
|
||||
}
|
||||
} else if (assignment.getRValue1() instanceof Variable && assignment.getRValue2() instanceof ConstantInteger) {
|
||||
Variable variable = (Variable) assignment.getRValue1();
|
||||
} else if (assignment.getrValue1() instanceof Variable && assignment.getrValue2() instanceof ConstantInteger) {
|
||||
Variable variable = (Variable) assignment.getrValue1();
|
||||
ConstantInteger consolidated = consolidateSubConstants(variable);
|
||||
if (consolidated != null) {
|
||||
ConstantInteger const2 = (ConstantInteger) assignment.getRValue2();
|
||||
ConstantInteger const2 = (ConstantInteger) assignment.getrValue2();
|
||||
int newNumber = const2.getNumber() + consolidated.getNumber();
|
||||
if (newNumber < 0) {
|
||||
assignment.setRValue2(new ConstantInteger(-newNumber));
|
||||
assignment.setrValue2(new ConstantInteger(-newNumber));
|
||||
assignment.setOperator(new Operator("-"));
|
||||
} else {
|
||||
assignment.setRValue2(new ConstantInteger(newNumber));
|
||||
assignment.setrValue2(new ConstantInteger(newNumber));
|
||||
}
|
||||
log.append("Consolidated constant in assignment " + assignment.getLValue());
|
||||
log.append("Consolidated constant in assignment " + assignment.getlValue());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -150,25 +150,25 @@ public class Pass2ConstantAdditionElimination extends Pass2SsaOptimization {
|
||||
}
|
||||
StatementAssignment assignment = getGraph().getAssignment(variable);
|
||||
if (assignment != null && assignment.getOperator() != null && "+".equals(assignment.getOperator().getOperator())) {
|
||||
if (assignment.getRValue1() instanceof ConstantInteger) {
|
||||
ConstantInteger constant = (ConstantInteger) assignment.getRValue1();
|
||||
assignment.setRValue1(null);
|
||||
if (assignment.getrValue1() instanceof ConstantInteger) {
|
||||
ConstantInteger constant = (ConstantInteger) assignment.getrValue1();
|
||||
assignment.setrValue1(null);
|
||||
assignment.setOperator(null);
|
||||
return constant;
|
||||
} else if (assignment.getRValue2() instanceof ConstantInteger) {
|
||||
ConstantInteger constant = (ConstantInteger) assignment.getRValue2();
|
||||
assignment.setRValue2(assignment.getRValue1());
|
||||
} else if (assignment.getrValue2() instanceof ConstantInteger) {
|
||||
ConstantInteger constant = (ConstantInteger) assignment.getrValue2();
|
||||
assignment.setrValue2(assignment.getrValue1());
|
||||
assignment.setOperator(null);
|
||||
assignment.setRValue1(null);
|
||||
assignment.setrValue1(null);
|
||||
return constant;
|
||||
} else {
|
||||
ConstantInteger const1 = null;
|
||||
if (assignment.getRValue1() instanceof Variable) {
|
||||
const1 = consolidateSubConstants((Variable) assignment.getRValue1());
|
||||
if (assignment.getrValue1() instanceof Variable) {
|
||||
const1 = consolidateSubConstants((Variable) assignment.getrValue1());
|
||||
}
|
||||
ConstantInteger const2 = null;
|
||||
if (assignment.getRValue2() instanceof Variable) {
|
||||
const2 = consolidateSubConstants((Variable) assignment.getRValue2());
|
||||
if (assignment.getrValue2() instanceof Variable) {
|
||||
const2 = consolidateSubConstants((Variable) assignment.getrValue2());
|
||||
}
|
||||
ConstantInteger result = null;
|
||||
if (const1 != null) {
|
||||
@@ -183,24 +183,24 @@ public class Pass2ConstantAdditionElimination extends Pass2SsaOptimization {
|
||||
}
|
||||
}
|
||||
if (assignment != null && assignment.getOperator() != null && "-".equals(assignment.getOperator().getOperator())) {
|
||||
if (assignment.getRValue1() instanceof ConstantInteger) {
|
||||
ConstantInteger constant = (ConstantInteger) assignment.getRValue1();
|
||||
assignment.setRValue1(null);
|
||||
if (assignment.getrValue1() instanceof ConstantInteger) {
|
||||
ConstantInteger constant = (ConstantInteger) assignment.getrValue1();
|
||||
assignment.setrValue1(null);
|
||||
return constant;
|
||||
} else if (assignment.getRValue2() instanceof ConstantInteger) {
|
||||
ConstantInteger constant = (ConstantInteger) assignment.getRValue2();
|
||||
assignment.setRValue2(assignment.getRValue1());
|
||||
} else if (assignment.getrValue2() instanceof ConstantInteger) {
|
||||
ConstantInteger constant = (ConstantInteger) assignment.getrValue2();
|
||||
assignment.setrValue2(assignment.getrValue1());
|
||||
assignment.setOperator(null);
|
||||
assignment.setRValue1(null);
|
||||
assignment.setrValue1(null);
|
||||
return new ConstantInteger(-constant.getNumber());
|
||||
} else {
|
||||
ConstantInteger const1 = null;
|
||||
if (assignment.getRValue1() instanceof Variable) {
|
||||
const1 = consolidateSubConstants((Variable) assignment.getRValue1());
|
||||
if (assignment.getrValue1() instanceof Variable) {
|
||||
const1 = consolidateSubConstants((Variable) assignment.getrValue1());
|
||||
}
|
||||
ConstantInteger const2 = null;
|
||||
if (assignment.getRValue2() instanceof Variable) {
|
||||
const2 = consolidateSubConstants((Variable) assignment.getRValue2());
|
||||
if (assignment.getrValue2() instanceof Variable) {
|
||||
const2 = consolidateSubConstants((Variable) assignment.getrValue2());
|
||||
}
|
||||
ConstantInteger result = null;
|
||||
if (const1 != null) {
|
||||
|
@@ -39,26 +39,26 @@ public class Pass2ConstantPropagation extends Pass2SsaOptimization {
|
||||
ControlFlowGraphBaseVisitor<Void> visitor = new ControlFlowGraphBaseVisitor<Void>() {
|
||||
@Override
|
||||
public Void visitAssignment(StatementAssignment assignment) {
|
||||
if (assignment.getLValue() instanceof VariableVersion || assignment.getLValue() instanceof VariableIntermediate) {
|
||||
Variable variable = (Variable) assignment.getLValue();
|
||||
if (assignment.getRValue1() == null && assignment.getRValue2() instanceof Constant) {
|
||||
if (assignment.getlValue() instanceof VariableVersion || assignment.getlValue() instanceof VariableIntermediate) {
|
||||
Variable variable = (Variable) assignment.getlValue();
|
||||
if (assignment.getrValue1() == null && assignment.getrValue2() instanceof Constant) {
|
||||
if (assignment.getOperator() == null) {
|
||||
// Constant assignment
|
||||
Constant constant = (Constant) assignment.getRValue2();
|
||||
Constant constant = (Constant) assignment.getrValue2();
|
||||
constants.put(variable, constant);
|
||||
} else {
|
||||
// Constant unary expression
|
||||
Constant constant = calculateUnary(assignment.getOperator(), (Constant) assignment.getRValue2());
|
||||
Constant constant = calculateUnary(assignment.getOperator(), (Constant) assignment.getrValue2());
|
||||
if(constant!=null) {
|
||||
constants.put(variable, constant);
|
||||
}
|
||||
}
|
||||
} else if (assignment.getRValue1() instanceof Constant && assignment.getRValue2() instanceof Constant) {
|
||||
} else if (assignment.getrValue1() instanceof Constant && assignment.getrValue2() instanceof Constant) {
|
||||
// Constant binary expression
|
||||
Constant constant = calculateBinary(
|
||||
assignment.getOperator(),
|
||||
(Constant) assignment.getRValue1(),
|
||||
(Constant) assignment.getRValue2());
|
||||
(Constant) assignment.getrValue1(),
|
||||
(Constant) assignment.getrValue2());
|
||||
if(constant!=null) {
|
||||
constants.put(variable, constant);
|
||||
}
|
||||
@@ -72,7 +72,7 @@ public class Pass2ConstantPropagation extends Pass2SsaOptimization {
|
||||
if (phi.getPreviousVersions().size() == 1) {
|
||||
StatementPhi.PreviousSymbol previousSymbol = phi.getPreviousVersions().get(0);
|
||||
if (previousSymbol.getRValue() instanceof Constant) {
|
||||
VariableVersion variable = phi.getLValue();
|
||||
VariableVersion variable = phi.getlValue();
|
||||
Constant constant = (Constant) previousSymbol.getRValue();
|
||||
constants.put(variable, constant);
|
||||
}
|
||||
|
@@ -51,7 +51,7 @@ public class Pass2RedundantPhiElimination extends Pass2SsaOptimization {
|
||||
}
|
||||
}
|
||||
if(found) {
|
||||
VariableVersion variable = phi.getLValue();
|
||||
VariableVersion variable = phi.getlValue();
|
||||
if(phiRValue==null) {phiRValue = VOID;}
|
||||
aliases.put(variable, phiRValue);
|
||||
}
|
||||
|
@@ -26,10 +26,10 @@ public class Pass2SelfPhiElimination extends Pass2SsaOptimization {
|
||||
public Void visitPhi(StatementPhi phi) {
|
||||
for (Iterator<StatementPhi.PreviousSymbol> iterator = phi.getPreviousVersions().iterator(); iterator.hasNext(); ) {
|
||||
StatementPhi.PreviousSymbol previousSymbol = iterator.next();
|
||||
if (previousSymbol.getRValue().equals(phi.getLValue())) {
|
||||
if (previousSymbol.getRValue().equals(phi.getlValue())) {
|
||||
iterator.remove();
|
||||
optimized[0] = Boolean.TRUE;
|
||||
log.append("Self Phi Eliminated "+phi.getLValue());
|
||||
log.append("Self Phi Eliminated "+phi.getlValue());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
@@ -59,20 +59,20 @@ public abstract class Pass2SsaOptimization {
|
||||
ControlFlowGraphBaseVisitor<Void> visitor = new ControlFlowGraphBaseVisitor<Void>() {
|
||||
@Override
|
||||
public Void visitAssignment(StatementAssignment assignment) {
|
||||
LValue lValue = assignment.getLValue();
|
||||
LValue lValue = assignment.getlValue();
|
||||
if (getAlias(aliases, lValue) != null) {
|
||||
RValue alias = getAlias(aliases, lValue);
|
||||
if (alias instanceof LValue) {
|
||||
assignment.setLValue((LValue) alias);
|
||||
assignment.setlValue((LValue) alias);
|
||||
} else {
|
||||
throw new RuntimeException("Error replacing LValue variable " + lValue + " with " + alias);
|
||||
}
|
||||
}
|
||||
if (getAlias(aliases, assignment.getRValue1()) != null) {
|
||||
assignment.setRValue1(getAlias(aliases, assignment.getRValue1()));
|
||||
if (getAlias(aliases, assignment.getrValue1()) != null) {
|
||||
assignment.setrValue1(getAlias(aliases, assignment.getrValue1()));
|
||||
}
|
||||
if (getAlias(aliases, assignment.getRValue2()) != null) {
|
||||
assignment.setRValue2(getAlias(aliases, assignment.getRValue2()));
|
||||
if (getAlias(aliases, assignment.getrValue2()) != null) {
|
||||
assignment.setrValue2(getAlias(aliases, assignment.getrValue2()));
|
||||
}
|
||||
// Handle pointer dereference in LValue
|
||||
if (lValue instanceof PointerDereferenceSimple) {
|
||||
@@ -136,10 +136,10 @@ public abstract class Pass2SsaOptimization {
|
||||
|
||||
@Override
|
||||
public Void visitPhi(StatementPhi phi) {
|
||||
if (getAlias(aliases, phi.getLValue()) != null) {
|
||||
RValue alias = getAlias(aliases, phi.getLValue());
|
||||
if (getAlias(aliases, phi.getlValue()) != null) {
|
||||
RValue alias = getAlias(aliases, phi.getlValue());
|
||||
if (alias instanceof LValue) {
|
||||
phi.setLValue((Variable) alias);
|
||||
phi.setlValue((Variable) alias);
|
||||
}
|
||||
}
|
||||
for (Iterator<StatementPhi.PreviousSymbol> iterator = phi.getPreviousVersions().iterator(); iterator.hasNext(); ) {
|
||||
@@ -254,12 +254,12 @@ public abstract class Pass2SsaOptimization {
|
||||
Statement statement = iterator.next();
|
||||
if (statement instanceof StatementAssignment) {
|
||||
StatementAssignment assignment = (StatementAssignment) statement;
|
||||
if (variables.contains(assignment.getLValue())) {
|
||||
if (variables.contains(assignment.getlValue())) {
|
||||
iterator.remove();
|
||||
}
|
||||
} else if (statement instanceof StatementPhi) {
|
||||
StatementPhi phi = (StatementPhi) statement;
|
||||
if (variables.contains(phi.getLValue())) {
|
||||
if (variables.contains(phi.getlValue())) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
@@ -283,7 +283,7 @@ public abstract class Pass2SsaOptimization {
|
||||
ControlFlowGraphBaseVisitor<Void> visitor = new ControlFlowGraphBaseVisitor<Void>() {
|
||||
@Override
|
||||
public Void visitAssignment(StatementAssignment assignment) {
|
||||
assignments.put(assignment.getLValue(), assignment);
|
||||
assignments.put(assignment.getlValue(), assignment);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
@@ -296,8 +296,8 @@ public abstract class Pass2SsaOptimization {
|
||||
ControlFlowGraphBaseVisitor<Void> visitor = new ControlFlowGraphBaseVisitor<Void>() {
|
||||
@Override
|
||||
public Void visitAssignment(StatementAssignment assignment) {
|
||||
addUsage(assignment.getRValue1(), assignment);
|
||||
addUsage(assignment.getRValue2(), assignment);
|
||||
addUsage(assignment.getrValue1(), assignment);
|
||||
addUsage(assignment.getrValue2(), assignment);
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -354,8 +354,8 @@ public abstract class Pass2SsaOptimization {
|
||||
|
||||
@Override
|
||||
public Object visitAssignment(StatementAssignment assignment) {
|
||||
addUsage(assignment.getRValue1());
|
||||
addUsage(assignment.getRValue2());
|
||||
addUsage(assignment.getrValue1());
|
||||
addUsage(assignment.getrValue2());
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@@ -11,9 +11,9 @@ import java.util.*;
|
||||
public class Pass3CodeGeneration {
|
||||
|
||||
private ControlFlowGraph graph;
|
||||
private Scope symbols;
|
||||
private ProgramScope symbols;
|
||||
|
||||
public Pass3CodeGeneration(ControlFlowGraph graph, Scope symbols) {
|
||||
public Pass3CodeGeneration(ControlFlowGraph graph, ProgramScope symbols) {
|
||||
this.graph = graph;
|
||||
this.symbols = symbols;
|
||||
}
|
||||
@@ -46,7 +46,7 @@ public class Pass3CodeGeneration {
|
||||
if (!(statement instanceof StatementPhi)) {
|
||||
if (statement instanceof StatementAssignment) {
|
||||
StatementAssignment assignment = (StatementAssignment) statement;
|
||||
LValue lValue = assignment.getLValue();
|
||||
LValue lValue = assignment.getlValue();
|
||||
boolean isAlu = false;
|
||||
if (lValue instanceof Variable) {
|
||||
RegisterAllocation.Register lValRegister = symbols.getRegister((Variable) lValue);
|
||||
@@ -124,7 +124,7 @@ public class Pass3CodeGeneration {
|
||||
});
|
||||
for (StatementPhi.PreviousSymbol previousSymbol : previousVersions) {
|
||||
if (previousSymbol.getBlock().equals(fromBlock.getLabel())) {
|
||||
genAsmMove(asm, phi.getLValue(), previousSymbol.getRValue());
|
||||
genAsmMove(asm, phi.getlValue(), previousSymbol.getRValue());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@@ -8,10 +8,10 @@ import dk.camelot64.kickc.icl.*;
|
||||
public class Pass3RegisterAllocation {
|
||||
|
||||
private ControlFlowGraph graph;
|
||||
private Scope symbols;
|
||||
private ProgramScope symbols;
|
||||
int currentZp = 2;
|
||||
|
||||
public Pass3RegisterAllocation(ControlFlowGraph graph, Scope symbols) {
|
||||
public Pass3RegisterAllocation(ControlFlowGraph graph, ProgramScope symbols) {
|
||||
this.graph = graph;
|
||||
this.symbols = symbols;
|
||||
}
|
||||
@@ -159,7 +159,7 @@ public class Pass3RegisterAllocation {
|
||||
}
|
||||
|
||||
private void performAllocation(Scope scope, RegisterAllocation allocation) {
|
||||
for (Symbol symbol : scope.getSymbols()) {
|
||||
for (Symbol symbol : scope.getAllSymbols()) {
|
||||
if (symbol instanceof Scope) {
|
||||
performAllocation((Scope) symbol, allocation);
|
||||
} else if (symbol instanceof VariableIntermediate || symbol instanceof VariableVersion) {
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package dk.camelot64.kickc.test;
|
||||
|
||||
import dk.camelot64.kickc.Compiler;
|
||||
import junit.framework.TestCase;
|
||||
import org.antlr.v4.runtime.CharStream;
|
||||
import org.antlr.v4.runtime.CharStreams;
|
||||
|
||||
@@ -16,7 +17,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/** Compile a number of source files and compare the resulting assembler with expected output*/
|
||||
public class TestCompilationOutput {
|
||||
public class TestCompilationOutput extends TestCase {
|
||||
|
||||
private Path tempDir;
|
||||
private String testPath;
|
||||
@@ -28,12 +29,14 @@ public class TestCompilationOutput {
|
||||
tempDir = Files.createTempDirectory("kickc-output");
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws IOException, URISyntaxException {
|
||||
public void testFlipper() throws IOException, URISyntaxException {
|
||||
TestCompilationOutput tester = new TestCompilationOutput();
|
||||
//tester.testFile("fibmem");
|
||||
tester.testFile("flipper-rex2");
|
||||
}
|
||||
|
||||
public void testBresenham() throws IOException, URISyntaxException {
|
||||
TestCompilationOutput tester = new TestCompilationOutput();
|
||||
tester.testFile("bresenham");
|
||||
//tester.testFile("unused");
|
||||
}
|
||||
|
||||
private void testFile(String fileName) throws IOException, URISyntaxException {
|
||||
|
63
src/dk/camelot64/kickc/test/TestIclJson.java
Normal file
63
src/dk/camelot64/kickc/test/TestIclJson.java
Normal file
@@ -0,0 +1,63 @@
|
||||
package dk.camelot64.kickc.test;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.ObjectReader;
|
||||
import com.fasterxml.jackson.databind.ObjectWriter;
|
||||
import dk.camelot64.kickc.icl.*;
|
||||
import dk.camelot64.kickc.icl.jackson.IclJacksonFactory;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/** Test JSON serialization of the KickC ICL */
|
||||
public class TestIclJson extends TestCase {
|
||||
|
||||
public void testJsonVariable() throws IOException {
|
||||
VariableUnversioned v1 = new VariableUnversioned("v1", null, SymbolTypeBasic.BYTE);
|
||||
String json = "{\"@type\":\"variable_unversioned\",\"name\":\"v1\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"nextVersionNumber\":0,\"inferredType\":false}";
|
||||
assertJsonSerialization(v1, json, Variable.class);
|
||||
}
|
||||
|
||||
public void testJsonScopeSimple() throws IOException {
|
||||
Scope scope = new ProgramScope();
|
||||
VariableUnversioned v1 = scope.addVariable("v1", SymbolTypeBasic.BYTE);
|
||||
v1.createVersion();
|
||||
scope.addVariableIntermediate();
|
||||
scope.addLabel("main");
|
||||
scope.addLabelIntermediate();
|
||||
String json = "{\"@type\":\"program\",\"name\":\"\",\"symbols\":{\"v1\":{\"@type\":\"variable_unversioned\",\"name\":\"v1\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"nextVersionNumber\":1,\"inferredType\":false},\"v1#0\":{\"@type\":\"variable_versioned\",\"name\":\"v1#0\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"v1\",\"inferredType\":false},\"$0\":{\"@type\":\"variable_intermediate\",\"name\":\"$0\",\"type\":{\"@type\":\"basic\",\"typeName\":\"var\"},\"inferredType\":false},\"main\":{\"@type\":\"label\",\"name\":\"main\",\"intermediate\":false},\"@1\":{\"@type\":\"label\",\"name\":\"@1\",\"intermediate\":true}},\"intermediateVarCount\":1,\"intermediateLabelCount\":2,\"allocation\":null}";
|
||||
assertJsonSerialization(scope, json, Scope.class);
|
||||
}
|
||||
|
||||
public void testJsonScopeProcedure() throws IOException {
|
||||
Scope scope = new ProgramScope();
|
||||
scope.addVariable("v1", SymbolTypeBasic.BYTE);
|
||||
Procedure procedure = scope.addProcedure("main", SymbolTypeBasic.VOID);
|
||||
procedure.addVariable("v2", SymbolTypeBasic.BYTE);
|
||||
ArrayList<Variable> parameters = new ArrayList<>();
|
||||
parameters.add(new VariableUnversioned("p1", procedure, SymbolTypeBasic.BYTE));
|
||||
parameters.add(new VariableUnversioned("p2", procedure, SymbolTypeBasic.BYTE));
|
||||
procedure.setParameters(parameters);
|
||||
String json = "{\"@type\":\"program\",\"name\":\"\",\"symbols\":{\"v1\":{\"@type\":\"variable_unversioned\",\"name\":\"v1\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"nextVersionNumber\":0,\"inferredType\":false},\"main\":{\"@type\":\"procedure\",\"name\":\"main\",\"parameterNames\":[\"p1\",\"p2\"],\"symbols\":{\"v2\":{\"@type\":\"variable_unversioned\",\"name\":\"v2\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"nextVersionNumber\":0,\"inferredType\":false},\"p1\":{\"@type\":\"variable_unversioned\",\"name\":\"p1\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"nextVersionNumber\":0,\"inferredType\":false},\"p2\":{\"@type\":\"variable_unversioned\",\"name\":\"p2\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"nextVersionNumber\":0,\"inferredType\":false}},\"intermediateVarCount\":0,\"intermediateLabelCount\":1,\"returnType\":{\"@type\":\"basic\",\"typeName\":\"void\"}}},\"intermediateVarCount\":0,\"intermediateLabelCount\":1,\"allocation\":null}";
|
||||
assertJsonSerialization(scope, json, Scope.class);
|
||||
}
|
||||
|
||||
|
||||
public static void assertJsonSerialization(
|
||||
Object object,
|
||||
String json,
|
||||
Class deserializeClass) throws IOException {
|
||||
ObjectMapper jsonMapper = IclJacksonFactory.getMapper();
|
||||
ObjectWriter jsonWriter = jsonMapper.writer();
|
||||
String serialized = jsonWriter.writeValueAsString(object);
|
||||
System.out.println(serialized);
|
||||
TestCase.assertEquals("Serialized Object and Reference Serialized", json, serialized);
|
||||
ObjectReader reader = jsonMapper.readerFor(deserializeClass);
|
||||
Object deserialized = reader.readValue(json);
|
||||
TestCase.assertEquals("Deserialized Object and Reference Object", object, deserialized);
|
||||
Object redeserialized = reader.readValue(serialized);
|
||||
TestCase.assertEquals("Re-serialized Object and Reference Object", object, redeserialized);
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user