You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

205 lines
6.3 KiB

package chocopy.common.astnodes;
import chocopy.common.analysis.NodeAnalyzer;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;
import java_cup.runtime.ComplexSymbolFactory.Location;
import java.io.IOException;
/**
* Root of the AST class hierarchy. Every node has a left and right
* location, indicating the start and end of the represented construct
* in the source text.
* <p>
* Every node can be marked with an error message, which serves two purposes:
* 1. It indicates that an error message has been issued for this
* Node, allowing tne program to reduce cascades of error
* messages.
* 2. It aids in debugging by making it convenient to see which
* Nodes have caused an error.
*/
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.EXISTING_PROPERTY,
property = "kind")
/* List of all concrete subclasses of Node. */
@JsonSubTypes({
@JsonSubTypes.Type(AssignStmt.class),
@JsonSubTypes.Type(BinaryExpr.class),
@JsonSubTypes.Type(BooleanLiteral.class),
@JsonSubTypes.Type(CallExpr.class),
@JsonSubTypes.Type(ClassDef.class),
@JsonSubTypes.Type(ClassType.class),
@JsonSubTypes.Type(CompilerError.class),
@JsonSubTypes.Type(Errors.class),
@JsonSubTypes.Type(ExprStmt.class),
@JsonSubTypes.Type(ForStmt.class),
@JsonSubTypes.Type(FuncDef.class),
@JsonSubTypes.Type(GlobalDecl.class),
@JsonSubTypes.Type(Identifier.class),
@JsonSubTypes.Type(IfExpr.class),
@JsonSubTypes.Type(IfStmt.class),
@JsonSubTypes.Type(IndexExpr.class),
@JsonSubTypes.Type(IntegerLiteral.class),
@JsonSubTypes.Type(ListExpr.class),
@JsonSubTypes.Type(ListType.class),
@JsonSubTypes.Type(MemberExpr.class),
@JsonSubTypes.Type(MethodCallExpr.class),
@JsonSubTypes.Type(NoneLiteral.class),
@JsonSubTypes.Type(NonLocalDecl.class),
@JsonSubTypes.Type(Program.class),
@JsonSubTypes.Type(ReturnStmt.class),
@JsonSubTypes.Type(StringLiteral.class),
@JsonSubTypes.Type(TypedVar.class),
@JsonSubTypes.Type(UnaryExpr.class),
@JsonSubTypes.Type(VarDef.class),
@JsonSubTypes.Type(WhileStmt.class),
})
public abstract class Node {
/**
* Node-type indicator for JSON form.
*/
public final String kind;
/**
* Source position information: 0: line number of start, 1: column number
* of start, 2: line number of end, 3: column number of end.
*/
private final int[] location = new int[4];
/**
* First error message "blamed" on this Node. When non-null, indicates
* that an error has been found in this Node.
*/
@JsonInclude(JsonInclude.Include.NON_EMPTY)
private String errorMsg;
/**
* A Node corresponding to source text between LEFT and RIGHT.
*/
public Node(Location left, Location right) {
if (left != null) {
location[0] = left.getLine();
location[1] = left.getColumn();
}
if (right != null) {
location[2] = right.getLine();
location[3] = right.getColumn();
}
this.kind = getClass().getSimpleName();
this.errorMsg = null;
}
/**
* Return my source location as
* { <first line>, <first column>, <last line>, <last column> }.
* Result should not be modified, and contents will change after
* setLocation().
*/
public int[] getLocation() {
return location;
}
/**
* Copy LOCATION as getLocation().
*/
public void setLocation(final int[] location) {
System.arraycopy(location, 0, this.location, 0, 4);
}
public String getErrorMsg() {
return errorMsg;
}
public void setErrorMsg(String msg) {
this.errorMsg = msg;
}
/**
* Return true iff I have been marked with an error message.
*/
@JsonIgnore
public boolean hasError() {
return this.errorMsg != null;
}
/**
* Invoke ANALYZER on me as a node of static type T. See the comment
* on NodeAnalyzer. Returns modified Node.
*/
public abstract <T> T dispatch(NodeAnalyzer<T> analyzer);
/**
* Print out the AST in JSON format.
*/
@Override
public String toString() {
try {
return toJSON();
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
/**
* Return a serialization of this node in JSON format.
*/
public String toJSON() throws JsonProcessingException {
return mapper.writeValueAsString(this);
}
/**
* Mapper to-and-from serialized JSON.
*/
private static final ObjectMapper mapper = new ObjectMapper();
static {
mapper.enable(SerializationFeature.INDENT_OUTPUT);
mapper.registerModule(new ParameterNamesModule());
}
/**
* Returns a T from JSON, a JSON-serialized T value with class
* CLAS.
*/
public static <T> T fromJSON(String json, Class<T> clas)
throws IOException {
return mapper.readValue(json, clas);
}
/**
* Returns the result of converting JSON, a JSon-serialization of
* a Node value, into the value it serializes.
*/
public static Node fromJSON(String json)
throws IOException {
return fromJSON(json, Node.class);
}
/**
* Returns the result of converting TREE to the value of type T
* that it represents, where CLAS reflects T.
*/
public static <T> T fromJSON(JsonNode tree, Class<T> clas)
throws IOException {
return mapper.treeToValue(tree, clas);
}
/**
* Returns the translation of serialized value SRC into the
* corresponding JSON tree.
*/
public static JsonNode readTree(String src) throws IOException {
return mapper.readTree(src);
}
}