mirror of https://github.com/tbklang/tlang.git
482 lines
10 KiB
D
482 lines
10 KiB
D
module compiler.codegen.instruction;
|
|
|
|
import std.conv : to;
|
|
import compiler.typecheck.dependency.core : Context;
|
|
import std.string : cmp;
|
|
import compiler.symbols.data : SymbolType;
|
|
import compiler.symbols.check : getCharacter;
|
|
import gogga;
|
|
import compiler.symbols.typing.core : Type;
|
|
|
|
public class Instruction
|
|
{
|
|
/* Context for the Instruction (used in emitter for name resolution) */
|
|
public Context context;
|
|
|
|
protected string addInfo;
|
|
|
|
this()
|
|
{
|
|
// this.instructionName = instructionName;
|
|
}
|
|
|
|
public final override string toString()
|
|
{
|
|
return "[Instruction: "~this.classinfo.name~":"~addInfo~"]";
|
|
}
|
|
|
|
public final Context getContext()
|
|
{
|
|
return context;
|
|
}
|
|
}
|
|
|
|
public class FetchInst : Instruction
|
|
{
|
|
|
|
}
|
|
|
|
public class Value : Instruction
|
|
{
|
|
|
|
}
|
|
|
|
public class StorageDeclaration : Instruction
|
|
{
|
|
|
|
}
|
|
|
|
public class ClassStaticInitAllocate : Instruction
|
|
{
|
|
this(string className)
|
|
{
|
|
addInfo = "classStaticInitAllocate: "~className;
|
|
}
|
|
}
|
|
|
|
public class VariableAssignmentInstr : Instruction
|
|
{
|
|
/* Name of variable being declared */
|
|
public string varName; /*TODO: Might not be needed */
|
|
|
|
public const Instruction data;
|
|
|
|
this(string varName, Instruction data)
|
|
{
|
|
this.varName = varName;
|
|
this.data = data;
|
|
|
|
addInfo = "assignTo: "~varName~", valInstr: "~data.toString();
|
|
}
|
|
}
|
|
|
|
public final class VariableDeclaration : StorageDeclaration
|
|
{
|
|
/* Name of variable being declared */
|
|
public const string varName;
|
|
|
|
/* Length */
|
|
public const byte length;
|
|
|
|
/* Type of the variable being declared */
|
|
public const Type varType;
|
|
|
|
/* VariableAssignmentInstr-instruction to be assigned */
|
|
private VariableAssignmentInstr varAssInstr;
|
|
|
|
//TODO: This must take in type information
|
|
this(string varName, byte len, Type varType, VariableAssignmentInstr varAssInstr)
|
|
{
|
|
this.varName = varName;
|
|
this.length = len;
|
|
this.varType = varType;
|
|
|
|
this.varAssInstr = varAssInstr;
|
|
|
|
addInfo = "varName: "~varName;
|
|
}
|
|
|
|
public VariableAssignmentInstr getAssignmentInstr()
|
|
{
|
|
return varAssInstr;
|
|
}
|
|
|
|
}
|
|
|
|
public final class FetchValueVar : Value
|
|
{
|
|
/* Name of variable to fetch from */
|
|
public string varName;
|
|
|
|
/* Length */
|
|
public byte length;
|
|
|
|
this(string varName, byte len)
|
|
{
|
|
this.varName = varName;
|
|
this.length = len;
|
|
|
|
addInfo = "fetchVarValName: "~varName~", VarLen: "~to!(string)(length);
|
|
}
|
|
}
|
|
|
|
/* Used for integers */
|
|
public final class LiteralValue : Value
|
|
{
|
|
/* Data */
|
|
public ulong data;
|
|
public byte len;
|
|
|
|
this(ulong data, byte len)
|
|
{
|
|
this.data = data;
|
|
this.len = len;
|
|
|
|
addInfo = "Data: "~to!(string)(data)~", Length: "~to!(string)(len);
|
|
}
|
|
}
|
|
|
|
public final class LiteralValueFloat : Value
|
|
{
|
|
/* Data */
|
|
public double data; /* TODO: Is this best way to store? Consirring floats/doubles */
|
|
public byte len;
|
|
|
|
this(double data, byte len)
|
|
{
|
|
this.data = data;
|
|
this.len = len;
|
|
|
|
addInfo = "Data: "~to!(string)(data)~", Length: "~to!(string)(len);
|
|
}
|
|
}
|
|
|
|
/* FIXME: Implement this */
|
|
/**
|
|
* TODO: This should take in:
|
|
*
|
|
* 1. The string literal
|
|
* 2. It should assign it to an interning pool and get the ID (associate one with the string literal if equal/in-the-pool)
|
|
*/
|
|
public final class StringLiteral : Value
|
|
{
|
|
/* String interning pool */
|
|
private static int[string] internmentCamp;
|
|
private static int rollCount = 0;
|
|
private string stringLiteral;
|
|
|
|
|
|
this(string stringLiteral)
|
|
{
|
|
this.stringLiteral = stringLiteral;
|
|
|
|
/* Intern the string */
|
|
intern(stringLiteral);
|
|
|
|
addInfo = "StrLit: `"~stringLiteral~"`, InternID: "~to!(string)(intern(stringLiteral));
|
|
}
|
|
|
|
public static int intern(string strLit)
|
|
{
|
|
/* Search for the string (if it exists return it's pool ID) */
|
|
foreach(string curStrLit; internmentCamp.keys())
|
|
{
|
|
if(cmp(strLit, curStrLit) == 0)
|
|
{
|
|
return internmentCamp[strLit];
|
|
}
|
|
}
|
|
|
|
/* If not, create a new entry (pool it) and return */
|
|
internmentCamp[strLit] = rollCount;
|
|
rollCount++; /* TODO: Overflow check */
|
|
|
|
return rollCount-1;
|
|
}
|
|
|
|
public string getStringLiteral()
|
|
{
|
|
return stringLiteral;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* BinOpInstr instruction
|
|
*
|
|
* Any sort of Binary Operator
|
|
*/
|
|
public class BinOpInstr : Value
|
|
{
|
|
public const Instruction lhs;
|
|
public const Instruction rhs;
|
|
public const SymbolType operator;
|
|
|
|
this(Instruction lhs, Instruction rhs, SymbolType operator)
|
|
{
|
|
this.lhs = lhs;
|
|
this.rhs = rhs;
|
|
this.operator = operator;
|
|
|
|
addInfo = "BinOpType: "~to!(string)(operator)~", LhsValInstr: "~lhs.toString()~", RhsValInstr: "~rhs.toString();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* UnaryOpInstr instruction
|
|
*
|
|
* Any sort of Unary Operator
|
|
*/
|
|
public class UnaryOpInstr : Value
|
|
{
|
|
private Instruction exp;
|
|
private SymbolType operator;
|
|
|
|
this(Instruction exp, SymbolType operator)
|
|
{
|
|
this.exp = exp;
|
|
this.operator = operator;
|
|
|
|
addInfo = "UnaryOpType: "~to!(string)(operator)~", Instr: "~exp.toString();
|
|
}
|
|
|
|
public SymbolType getOperator()
|
|
{
|
|
return operator;
|
|
}
|
|
|
|
public Instruction getOperand()
|
|
{
|
|
return exp;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 2022 New things
|
|
*
|
|
*/
|
|
|
|
//public class CallInstr : Instruction
|
|
public class CallInstr : Value
|
|
{
|
|
|
|
}
|
|
|
|
public class FuncCallInstr : CallInstr
|
|
{
|
|
/* Per-argument instrructions */
|
|
private Value[] evaluationInstructions;
|
|
|
|
public const string functionName;
|
|
|
|
this(string functionName, ulong argEvalInstrsSize)
|
|
{
|
|
this.functionName = functionName;
|
|
evaluationInstructions.length = argEvalInstrsSize;
|
|
|
|
updateAddInfo();
|
|
}
|
|
|
|
/**
|
|
* FuncCallInstr is built-bit-by-bit so toString information will change
|
|
*/
|
|
private void updateAddInfo()
|
|
{
|
|
addInfo = "FunctionName: "~functionName ~" EvalInstrs: "~ to!(string)(getEvaluationInstructions());
|
|
}
|
|
|
|
public void setEvalInstr(ulong argPos, Value instr)
|
|
{
|
|
evaluationInstructions[argPos] = instr;
|
|
updateAddInfo();
|
|
}
|
|
|
|
public Value[] getEvaluationInstructions()
|
|
{
|
|
return evaluationInstructions;
|
|
}
|
|
}
|
|
|
|
|
|
public final class ReturnInstruction : Instruction
|
|
{
|
|
private Value returnExprInstr;
|
|
|
|
this(Value returnExprInstr)
|
|
{
|
|
this.returnExprInstr = returnExprInstr;
|
|
}
|
|
|
|
public Value getReturnExpInstr()
|
|
{
|
|
return returnExprInstr;
|
|
}
|
|
}
|
|
|
|
public final class IfStatementInstruction : Instruction
|
|
{
|
|
private BranchInstruction[] branchInstructions;
|
|
|
|
this(BranchInstruction[] branchInstructions)
|
|
{
|
|
this.branchInstructions = branchInstructions;
|
|
|
|
addInfo = "Branches: "~to!(string)(branchInstructions);
|
|
}
|
|
|
|
public BranchInstruction[] getBranchInstructions()
|
|
{
|
|
return branchInstructions;
|
|
}
|
|
}
|
|
|
|
public final class WhileLoopInstruction : Instruction
|
|
{
|
|
private BranchInstruction branchInstruction;
|
|
|
|
this(BranchInstruction branchInstruction)
|
|
{
|
|
this.branchInstruction = branchInstruction;
|
|
|
|
addInfo = "Branch: "~to!(string)(branchInstruction);
|
|
}
|
|
|
|
public BranchInstruction getBranchInstruction()
|
|
{
|
|
return branchInstruction;
|
|
}
|
|
}
|
|
|
|
public final class ForLoopInstruction : Instruction
|
|
{
|
|
private Instruction preRunInstruction;
|
|
private BranchInstruction branchInstruction;
|
|
private bool hasPostIterate;
|
|
|
|
this(BranchInstruction branchInstruction, Instruction preRunInstruction = null, bool hasPostIterate = false)
|
|
{
|
|
this.branchInstruction = branchInstruction;
|
|
this.preRunInstruction = preRunInstruction;
|
|
|
|
addInfo = (hasPreRunInstruction() ? "PreRun: "~to!(string)(preRunInstruction)~", " : "")~"Branch: "~to!(string)(branchInstruction);
|
|
|
|
this.hasPostIterate = hasPostIterate;
|
|
}
|
|
|
|
public bool hasPostIterationInstruction()
|
|
{
|
|
return hasPostIterate;
|
|
}
|
|
|
|
public Instruction getPreRunInstruction()
|
|
{
|
|
return preRunInstruction;
|
|
}
|
|
|
|
public bool hasPreRunInstruction()
|
|
{
|
|
return !(preRunInstruction is null);
|
|
}
|
|
|
|
public BranchInstruction getBranchInstruction()
|
|
{
|
|
return branchInstruction;
|
|
}
|
|
}
|
|
|
|
public final class BranchInstruction : Instruction
|
|
{
|
|
private Value branchConditionInstr;
|
|
private Instruction[] bodyInstructions;
|
|
|
|
this(Value conditionInstr, Instruction[] bodyInstructions)
|
|
{
|
|
this.branchConditionInstr = conditionInstr;
|
|
this.bodyInstructions = bodyInstructions;
|
|
|
|
addInfo = "CondInstr: "~to!(string)(branchConditionInstr)~", BBodyInstrs: "~to!(string)(bodyInstructions);
|
|
}
|
|
|
|
public bool hasConditionInstr()
|
|
{
|
|
return !(branchConditionInstr is null);
|
|
}
|
|
|
|
public Value getConditionInstr()
|
|
{
|
|
return branchConditionInstr;
|
|
}
|
|
|
|
public Instruction[] getBodyInstructions()
|
|
{
|
|
return bodyInstructions;
|
|
}
|
|
}
|
|
|
|
|
|
public final class PointerDereferenceAssignmentInstruction : Instruction
|
|
{
|
|
private Value pointerEvalInstr;
|
|
private Value assigmnetExprInstr;
|
|
private ulong derefCount;
|
|
|
|
this(Value pointerEvalInstr, Value assigmnetExprInstr, ulong derefCount)
|
|
{
|
|
this.pointerEvalInstr = pointerEvalInstr;
|
|
this.assigmnetExprInstr = assigmnetExprInstr;
|
|
this.derefCount = derefCount;
|
|
}
|
|
|
|
public Value getPointerEvalInstr()
|
|
{
|
|
return pointerEvalInstr;
|
|
}
|
|
|
|
public Value getAssExprInstr()
|
|
{
|
|
return assigmnetExprInstr;
|
|
}
|
|
|
|
public ulong getDerefCount()
|
|
{
|
|
return derefCount;
|
|
}
|
|
}
|
|
|
|
public final class DiscardInstruction : Instruction
|
|
{
|
|
private Value exprInstr;
|
|
|
|
this(Value exprInstr)
|
|
{
|
|
this.exprInstr = exprInstr;
|
|
}
|
|
|
|
public Value getExpressionInstruction()
|
|
{
|
|
return exprInstr;
|
|
}
|
|
}
|
|
|
|
public final class CastedValueInstruction : Value
|
|
{
|
|
/* The uncasted original instruction that must be executed-then-trimmed (casted) */
|
|
private Value uncastedValue;
|
|
|
|
private Type castToType;
|
|
|
|
this(Value uncastedValue, Type castToType)
|
|
{
|
|
this.uncastedValue = uncastedValue;
|
|
this.castToType = castToType;
|
|
}
|
|
|
|
public Value getEmbeddedInstruction()
|
|
{
|
|
return uncastedValue;
|
|
}
|
|
|
|
public Type getCastToType()
|
|
{
|
|
return castToType;
|
|
}
|
|
} |