package chocopy.common.codegen; import chocopy.common.astnodes.*; import java.util.HashMap; import java.util.Map; /** * A store for caching and re-using program constants that are represented as immutable objects. * *

Constants are emitted in assembly in the DATA section, and therefore are represented by their * labels. */ public class Constants { /** A counter used to generate unique label names for constants. */ protected int nextLabelSuffix = 0; /** The constant representing the boolean `False`. */ final Label falseConstant = generateConstantLabel(); /** * The constant representing the boolean `True`. This immediately follows falseConstant in * static memory. */ final Label trueConstant = generateConstantLabel(); /** A cache for integer-valued constants. */ final Map intConstants = new HashMap<>(); /** A cache for string-valued constants. */ final Map strConstants = new HashMap<>(); /** * Returns the next unique label suffix for constants. * * @return the next unique label suffix for constants */ protected int getNextLabelSuffix() { return nextLabelSuffix++; } /** * Generates a fresh label for constants. * *

This label is guaranteed to be unique amongst labels generated by invoking this method. * All such labels have a prefix of `const_`. * * @return a fresh label */ public Label generateConstantLabel() { return new Label(String.format("const_%d", getNextLabelSuffix())); } /** * Returns the label for a `bool` constant. * * @param value the boolean value * @return the label for the boolean value */ public Label getBoolConstant(boolean value) { return value ? trueConstant : falseConstant; } /** * Returns the label for am `int` constant. * * @param value the integer value * @return the label for the integer value */ public Label getIntConstant(int value) { if (intConstants.containsKey(value)) { return intConstants.get(value); } else { Label newLabel = generateConstantLabel(); intConstants.put(value, newLabel); return newLabel; } } /** * Returns the label for a `str` constant. * * @param value the string value * @return the label for the string value */ public Label getStrConstant(String value) { if (strConstants.containsKey(value)) { return strConstants.get(value); } else { Label newLabel = generateConstantLabel(); strConstants.put(value, newLabel); return newLabel; } } /** * Converts a constant literal in the AST to a constant for code generation. * * @param literal the literal expression in the AST * @return a {@link Label} representing a constant int/str/bool, or `null` representing the None * literal */ public Label fromLiteral(Literal literal) { if (literal instanceof IntegerLiteral) { return getIntConstant(((IntegerLiteral) literal).value); } else if (literal instanceof StringLiteral) { return getStrConstant(((StringLiteral) literal).value); } else if (literal instanceof BooleanLiteral) { return getBoolConstant(((BooleanLiteral) literal).value); } else { assert literal == null || literal instanceof NoneLiteral; return null; } } }