Instruction

- Implemented new instruction `CastedValueInstruction`
- Added import for `Type`

DGen

- Implemented primitive type casting code generation in `transform()`
- Added import for `Type` and `Primitive`

Parser

- Implemented `parseCast()` which is called by `parseExpression()`

Check

- Added new symbol type `SymbolType.CAST`

Expressions

- Implemented new expression type `CastedExpression`

Typechecker

- Implemented processing of `CastedExpression` in the expression section, along with correct type/instruction pushes and pops

Dependency

- Implemented dependency generation of `CastedExpression` in `expressionPass()`

Test cases

- Added test file `simple_cast.t`
This commit is contained in:
Tristan B. Velloza Kildaire 2023-01-14 18:40:08 +02:00
parent c1ba609609
commit 113386ebe2
8 changed files with 184 additions and 0 deletions

View File

@ -17,6 +17,7 @@ import compiler.codegen.mapper : SymbolMapper;
import compiler.symbols.data : SymbolType, Variable, Function, VariableParameter;
import compiler.symbols.check : getCharacter;
import misc.utils : Stack;
import compiler.symbols.typing.core : Type, Primitive;
public final class DCodeEmitter : CodeEmitter
{
@ -401,6 +402,42 @@ public final class DCodeEmitter : CodeEmitter
/* Transform the expression */
emit ~= transform(valueInstruction)~";";
return emit;
}
/**
* Type casting instruction (CastedValueInstruction)
*/
else if(cast(CastedValueInstruction)instruction)
{
CastedValueInstruction castedValueInstruction = cast(CastedValueInstruction)instruction;
Type castingTo = castedValueInstruction.getCastToType();
// TODO: Dependent on type being casted one must handle different types, well differently (as is case for atleast OOP)
Value uncastedInstruction = castedValueInstruction.getEmbeddedInstruction();
string emit;
/* Handling of primitive types */
if(cast(Primitive)castingTo)
{
/* Add the actual cast */
emit ~= "("~to!(string)(castingTo)~")";
/* The expression being casted */
emit ~= transform(uncastedInstruction);
}
else
{
// TODO: Implement this
gprintln("Non-primitive type casting not yet implemented", DebugType.ERROR);
assert(false);
}
return emit;
}

View File

@ -6,6 +6,7 @@ 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
{
@ -454,4 +455,28 @@ public final class DiscardInstruction : Instruction
{
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;
}
}

View File

@ -986,6 +986,36 @@ public final class Parser
*/
private CastedExpression parseCast()
{
CastedExpression castedExpression;
/* Consume the `cast` */
nextToken();
/* Expect an `(` open brace */
expect(SymbolType.LBRACE, getCurrentToken());
nextToken();
/* Expect a type */
expect(SymbolType.IDENT_TYPE, getCurrentToken());
string toType = getCurrentToken().getToken();
nextToken();
/* Expect a `)` closing brace */
expect(SymbolType.RBRACE, getCurrentToken());
nextToken();
/* Get the expression to cast */
Expression uncastedExpression = parseExpression();
castedExpression = new CastedExpression(toType, uncastedExpression);
return castedExpression;
}
/**
* Parses an expression
*
@ -1065,6 +1095,12 @@ public final class Parser
/* Get the next token */
nextToken();
}
/* If it is a cast operator */
else if(symbol == SymbolType.CAST)
{
CastedExpression castedExpression = parseCast();
addRetExp(castedExpression);
}
/* If it is a maths operator */
/* TODO: Handle all operators here (well most), just include bit operators */
else if (isMathOp(getCurrentToken()) || isBinaryOp(getCurrentToken()))

View File

@ -58,6 +58,7 @@ public enum SymbolType
SMALLER_THAN,
GREATER_THAN_OR_EQUALS,
SMALLER_THAN_OR_EQUALS,
CAST,
UNKNOWN
}
@ -326,6 +327,11 @@ public SymbolType getSymbolType(Token tokenIn)
{
return SymbolType.NEW;
}
/* cast keyword */
else if(cmp(token, "cast") == 0)
{
return SymbolType.CAST;
}
/* discard keyword */
else if(cmp(token, "discard") == 0)
{

View File

@ -138,4 +138,26 @@ public final class NewExpression : Expression
{
return funcCall;
}
}
public final class CastedExpression : Expression
{
private Expression uncastedExpression;
private string toType;
this(string toType, Expression uncastedExpression)
{
this.toType = toType;
this.uncastedExpression = uncastedExpression;
}
public string getToType()
{
return toType;
}
public Expression getEmbeddedExpression()
{
return uncastedExpression;
}
}

View File

@ -737,6 +737,40 @@ public final class TypeChecker
addInstr(funcCallInstr);
addType(getType(func.parentOf(), func.getType()));
}
/* Type cast operator */
else if(cast(CastedExpression)statement)
{
CastedExpression castedExpression = cast(CastedExpression)statement;
gprintln("Context: "~to!(string)(castedExpression.context));
gprintln("ParentOf: "~to!(string)(castedExpression.parentOf()));
Type castToType = getType(castedExpression.context.container, castedExpression.getToType());
/* Pop the type associated with the embedded expression */
Type typeBeingCasted = popType(); // TODO: Is there anything we would want to do with this?
gprintln("TypeCast [FromType: "~to!(string)(typeBeingCasted)~", ToType: "~to!(string)(castToType)~"]");
/* Push the type to cast to onto the stack such that we typify the associated instruction */
addType(castToType);
/**
* Codegen
*
* 1. Pop off the current value instruction corresponding to the embedding
* 2. Create a new CastedValueInstruction instruction
* 3. Set the context
* 4. Add to front of code queue
*/
Value uncastedInstruction = cast(Value)popInstr();
assert(uncastedInstruction);
printCodeQueue();
printTypeQueue();
CastedValueInstruction castedValueInstruction = new CastedValueInstruction(uncastedInstruction, castToType);
castedValueInstruction.context = castedExpression.context;
addInstr(castedValueInstruction);
}
}
/* VariableAssigbmentDNode */
else if(cast(compiler.typecheck.dependency.variables.VariableAssignmentNode)dnode)

View File

@ -1095,6 +1095,22 @@ public class DNodeGenerator
/* TODO: Add specific DNode type dependent on the type of operator */
dnode.needs(expressionNode);
}
/**
* Type cast operator (CastedExpression)
*/
else if(cast(CastedExpression)exp)
{
CastedExpression castedExpression = cast(CastedExpression)exp;
// Set the context as we need to grab it later in the typechecker
castedExpression.context = context;
/* Extract the embedded expression and pass it */
Expression uncastedExpression = castedExpression.getEmbeddedExpression();
DNode uncastedExpressionDNode = expressionPass(uncastedExpression, context);
dnode.needs(uncastedExpressionDNode);
}
else
{
// dnode = new DNode(this, exp);

View File

@ -0,0 +1,8 @@
module simple_cast;
int myInt;
void function()
{
byte myByte = cast(byte)myInt;
}