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. * *

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 { , , , }. * 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 dispatch(NodeAnalyzer 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 fromJSON(String json, Class 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 fromJSON(JsonNode tree, Class 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); } }