2023-02-05 18:21:26 +00:00
module tlang.compiler.codegen.emit.dgen ;
2021-11-02 08:41:03 +00:00
2023-02-05 18:21:26 +00:00
import tlang.compiler.codegen.emit.core : CodeEmitter ;
import tlang.compiler.typecheck.core ;
2021-11-02 13:13:44 +00:00
import std.container.slist : SList ;
2023-02-05 18:21:26 +00:00
import tlang.compiler.codegen.instruction ;
2021-11-02 13:13:44 +00:00
import std.stdio ;
import std.file ;
2021-11-02 15:03:38 +00:00
import std.conv : to ;
import std.string : cmp ;
2021-11-02 15:24:08 +00:00
import gogga ;
2022-12-11 15:52:36 +00:00
import std.range : walkLength ;
2022-12-11 19:00:48 +00:00
import std.string : wrap ;
2022-12-11 19:41:15 +00:00
import std.process : spawnProcess , Pid , ProcessException , wait ;
2023-02-05 18:21:26 +00:00
import tlang.compiler.typecheck.dependency.core : Context , FunctionData , DNode ;
import tlang.compiler.codegen.mapper.core : SymbolMapper ;
import tlang.compiler.symbols.data : SymbolType , Variable , Function , VariableParameter ;
import tlang.compiler.symbols.check : getCharacter ;
2022-12-12 14:40:45 +00:00
import misc.utils : Stack ;
2023-02-05 18:21:26 +00:00
import tlang.compiler.symbols.typing.core : Type , Primitive , Integer , Void , Pointer ;
import tlang.compiler.configuration : CompilerConfiguration ;
2021-11-02 13:27:17 +00:00
2021-11-02 08:41:03 +00:00
public final class DCodeEmitter : CodeEmitter
2023-02-04 10:41:30 +00:00
{
2023-01-23 18:44:35 +00:00
// NOTE: In future store the mapper in the config please
this ( TypeChecker typeChecker , File file , CompilerConfiguration config , SymbolMapper mapper )
2021-11-02 13:13:44 +00:00
{
2023-01-23 18:44:35 +00:00
super ( typeChecker , file , config , mapper ) ;
2021-11-09 13:30:37 +00:00
}
2022-12-19 13:37:55 +00:00
private ulong transformDepth = 0 ;
private string genTabs ( ulong count )
{
string tabStr ;
2023-01-19 19:06:20 +00:00
/* Only generate tabs if enabled in compiler config */
2023-01-28 16:12:49 +00:00
if ( config . getConfig ( "dgen:pretty_code" ) . getBoolean ( ) )
2022-12-19 13:37:55 +00:00
{
2023-01-19 19:06:20 +00:00
for ( ulong i = 0 ; i < count ; i + + )
{
tabStr ~ = "\t" ;
}
2022-12-19 13:37:55 +00:00
}
2023-01-19 19:06:20 +00:00
2022-12-19 13:37:55 +00:00
return tabStr ;
}
2023-01-15 10:36:54 +00:00
/ * *
* Given an instance of a Type this will transform it to a string
*
* Params :
* typeIn = The Type to transform
*
* Returns : The string representation of the transformed type
* /
public string typeTransform ( Type typeIn )
{
string stringRepr ;
// TODO: Some types will ident transform
2023-01-15 10:49:28 +00:00
/* Pointer types */
if ( cast ( Pointer ) typeIn )
{
/* Extract type being pointed to */
Pointer pointerType = cast ( Pointer ) typeIn ;
2023-01-15 10:59:41 +00:00
Type referType = pointerType . getReferredType ( ) ;
2023-01-15 10:49:28 +00:00
/* The type is then `transform(<refertype>)*` */
return typeTransform ( referType ) ~ "*" ;
}
2023-01-15 10:36:54 +00:00
/* Integral types transformation */
2023-01-15 10:49:28 +00:00
else if ( cast ( Integer ) typeIn )
2023-01-15 10:36:54 +00:00
{
Integer integralType = cast ( Integer ) typeIn ;
/* u<>_t or <>_t (Determine signedness) */
string typeString = integralType . isSigned ( ) ? "int" : "uint" ;
/* Width of integer */
typeString ~ = to ! ( string ) ( integralType . getSize ( ) * 8 ) ;
/* Trailing `_t` */
typeString ~ = "_t" ;
return typeString ;
}
/* Void type */
else if ( cast ( Void ) typeIn )
{
return "void" ;
}
gprintln ( "Type transform unimplemented" ) ;
assert ( false ) ;
// return stringRepr;
}
2022-12-12 13:36:07 +00:00
public override string transform ( const Instruction instruction )
2022-12-11 19:41:15 +00:00
{
2022-12-16 12:53:33 +00:00
writeln ( "\n" ) ;
2022-12-14 17:49:08 +00:00
gprintln ( "transform(): " ~ to ! ( string ) ( instruction ) ) ;
2022-12-19 13:37:55 +00:00
transformDepth + + ;
// At any return decrement the depth
scope ( exit )
{
transformDepth - - ;
}
2022-12-14 17:49:08 +00:00
2022-12-12 13:36:07 +00:00
/* VariableAssignmentInstr */
if ( cast ( VariableAssignmentInstr ) instruction )
2022-12-11 19:41:15 +00:00
{
2022-12-16 12:53:33 +00:00
gprintln ( "type: VariableAssignmentInstr" ) ;
2022-12-12 13:36:07 +00:00
VariableAssignmentInstr varAs = cast ( VariableAssignmentInstr ) instruction ;
Context context = varAs . getContext ( ) ;
2022-12-11 19:41:15 +00:00
2022-12-12 13:36:07 +00:00
gprintln ( "Is ContextNull?: " ~ to ! ( string ) ( context is null ) ) ;
2022-12-16 12:53:33 +00:00
gprintln ( "Wazza contect: " ~ to ! ( string ) ( context . container ) ) ;
2023-01-23 18:44:35 +00:00
auto typedEntityVariable = typeChecker . getResolver ( ) . resolveBest ( context . getContainer ( ) , varAs . varName ) ; //TODO: Remove `auto`
2023-01-30 17:08:48 +00:00
gprintln ( "Hi" ~ to ! ( string ) ( varAs ) ) ;
gprintln ( "Hi" ~ to ! ( string ) ( varAs . data ) ) ;
2023-02-01 12:55:23 +00:00
gprintln ( "Hi" ~ to ! ( string ) ( varAs . data . getInstrType ( ) ) ) ;
2023-01-30 17:08:48 +00:00
// NOTE: For tetsing issue #94 coercion (remove when done)
2023-02-01 12:55:23 +00:00
string typeName = ( cast ( Type ) varAs . data . getInstrType ( ) ) . getName ( ) ;
2023-01-30 17:08:48 +00:00
gprintln ( "VariableAssignmentInstr: The data to assign's type is: " ~ typeName ) ;
2022-12-11 19:41:15 +00:00
2022-12-12 13:36:07 +00:00
2023-01-19 07:03:19 +00:00
/* If it is not external */
if ( ! typedEntityVariable . isExternal ( ) )
2022-12-12 14:56:54 +00:00
{
2023-01-23 18:44:35 +00:00
string renamedSymbol = mapper . symbolLookup ( typedEntityVariable ) ;
2022-12-12 17:12:39 +00:00
2023-01-19 07:03:19 +00:00
return renamedSymbol ~ " = " ~ transform ( varAs . data ) ~ ";" ;
}
/* If it is external */
else
{
return typedEntityVariable . getName ( ) ~ " = " ~ transform ( varAs . data ) ~ ";" ;
}
2022-12-11 19:41:15 +00:00
}
2022-12-12 13:36:07 +00:00
/* VariableDeclaration */
else if ( cast ( VariableDeclaration ) instruction )
2022-12-11 19:41:15 +00:00
{
2022-12-16 12:53:33 +00:00
gprintln ( "type: VariableDeclaration" ) ;
2022-12-12 13:36:07 +00:00
VariableDeclaration varDecInstr = cast ( VariableDeclaration ) instruction ;
Context context = varDecInstr . getContext ( ) ;
2023-01-23 18:44:35 +00:00
Variable typedEntityVariable = cast ( Variable ) typeChecker . getResolver ( ) . resolveBest ( context . getContainer ( ) , varDecInstr . varName ) ; //TODO: Remove `auto`
2022-12-12 13:36:07 +00:00
2023-01-19 07:03:19 +00:00
/* If the variable is not external */
if ( ! typedEntityVariable . isExternal ( ) )
2022-12-12 17:12:39 +00:00
{
2023-01-19 07:03:19 +00:00
//NOTE: We should remove all dots from generated symbol names as it won't be valid C (I don't want to say C because
// a custom CodeEmitter should be allowed, so let's call it a general rule)
//
//simple_variables.x -> simple_variables_x
//NOTE: We may need to create a symbol table actually and add to that and use that as these names
//could get out of hand (too long)
// NOTE: Best would be identity-mapping Entity's to a name
2023-01-23 18:44:35 +00:00
string renamedSymbol = mapper . symbolLookup ( typedEntityVariable ) ;
2022-12-19 13:37:55 +00:00
2022-12-12 17:12:39 +00:00
2023-01-19 07:03:19 +00:00
// Check to see if this declaration has an assignment attached
if ( typedEntityVariable . getAssignment ( ) )
{
2023-02-04 10:41:30 +00:00
Value varAssInstr = varDecInstr . getAssignmentInstr ( ) ;
2023-02-04 12:25:39 +00:00
gprintln ( "VarDec(with assignment): My assignment type is: " ~ varAssInstr . getInstrType ( ) . getName ( ) ) ;
2023-01-19 07:03:19 +00:00
// Generate the code to emit
return typeTransform ( cast ( Type ) varDecInstr . varType ) ~ " " ~ renamedSymbol ~ " = " ~ transform ( varAssInstr ) ~ ";" ;
}
2022-12-12 14:40:45 +00:00
2023-01-19 07:03:19 +00:00
return typeTransform ( cast ( Type ) varDecInstr . varType ) ~ " " ~ renamedSymbol ~ ";" ;
}
/* If the variable is external */
else
{
return "extern " ~ typeTransform ( cast ( Type ) varDecInstr . varType ) ~ " " ~ typedEntityVariable . getName ( ) ~ ";" ;
2022-12-12 17:12:39 +00:00
}
2022-12-12 14:40:45 +00:00
2022-12-12 13:36:07 +00:00
}
/* LiteralValue */
else if ( cast ( LiteralValue ) instruction )
{
2022-12-16 12:53:33 +00:00
gprintln ( "type: LiteralValue" ) ;
2022-12-12 13:36:07 +00:00
LiteralValue literalValueInstr = cast ( LiteralValue ) instruction ;
2023-02-04 12:25:39 +00:00
return to ! ( string ) ( literalValueInstr . getLiteralValue ( ) ) ;
2022-12-13 09:46:40 +00:00
}
/* FetchValueVar */
else if ( cast ( FetchValueVar ) instruction )
{
2022-12-16 12:53:33 +00:00
gprintln ( "type: FetchValueVar" ) ;
2022-12-13 09:51:44 +00:00
FetchValueVar fetchValueVarInstr = cast ( FetchValueVar ) instruction ;
Context context = fetchValueVarInstr . getContext ( ) ;
2022-12-13 09:46:40 +00:00
2023-01-23 18:44:35 +00:00
Variable typedEntityVariable = cast ( Variable ) typeChecker . getResolver ( ) . resolveBest ( context . getContainer ( ) , fetchValueVarInstr . varName ) ; //TODO: Remove `auto`
2022-12-13 09:51:44 +00:00
2023-01-19 07:03:19 +00:00
/* If it is not external */
if ( ! typedEntityVariable . isExternal ( ) )
{
//TODO: THis is giving me kak (see issue #54), it's generating name but trying to do it for the given container, relative to it
//TODO: We might need a version of generateName that is like generatenamebest (currently it acts like generatename, within)
2022-12-17 11:41:00 +00:00
2023-01-23 18:44:35 +00:00
string renamedSymbol = mapper . symbolLookup ( typedEntityVariable ) ;
2022-12-13 09:51:44 +00:00
2023-01-19 07:03:19 +00:00
return renamedSymbol ;
}
/* If it is external */
else
{
return typedEntityVariable . getName ( ) ;
}
2022-12-12 13:36:07 +00:00
}
/* BinOpInstr */
else if ( cast ( BinOpInstr ) instruction )
{
2022-12-16 12:53:33 +00:00
gprintln ( "type: BinOpInstr" ) ;
2022-12-12 13:36:07 +00:00
BinOpInstr binOpInstr = cast ( BinOpInstr ) instruction ;
2022-12-11 19:41:15 +00:00
2022-12-19 13:37:55 +00:00
// TODO: I like having `lhs == rhs` for `==` or comparators but not spaces for `lhs+rhs`
2022-12-12 13:36:07 +00:00
return transform ( binOpInstr . lhs ) ~ to ! ( string ) ( getCharacter ( binOpInstr . operator ) ) ~ transform ( binOpInstr . rhs ) ;
2022-12-11 19:41:15 +00:00
}
2022-12-16 12:53:33 +00:00
/* FuncCallInstr */
else if ( cast ( FuncCallInstr ) instruction )
{
gprintln ( "type: FuncCallInstr" ) ;
FuncCallInstr funcCallInstr = cast ( FuncCallInstr ) instruction ;
Context context = funcCallInstr . getContext ( ) ;
assert ( context ) ;
2023-01-23 18:44:35 +00:00
Function functionToCall = cast ( Function ) typeChecker . getResolver ( ) . resolveBest ( context . getContainer ( ) , funcCallInstr . functionName ) ; //TODO: Remove `auto`
2022-12-16 12:53:33 +00:00
// TODO: SymbolLookup?
string emit = functionToCall . getName ( ) ~ "(" ;
//TODO: Insert argument passimng code here
//NOTE: Typechecker must have checked for passing arguments to a function that doesn't take any, for example
//NOTE (Behaviour): We may want to actually have an preinliner for these arguments
//such to enforce a certain ordering. I believe this should be done in the emitter stage,
//so it is best placed here
if ( functionToCall . hasParams ( ) )
{
Value [ ] argumentInstructions = funcCallInstr . getEvaluationInstructions ( ) ;
string argumentString ;
for ( ulong argIdx = 0 ; argIdx < argumentInstructions . length ; argIdx + + )
{
Value currentArgumentInstr = argumentInstructions [ argIdx ] ;
argumentString ~ = transform ( currentArgumentInstr ) ;
if ( argIdx ! = ( argumentInstructions . length - 1 ) )
{
argumentString ~ = ", " ;
}
}
emit ~ = argumentString ;
}
emit ~ = ")" ;
return emit ;
}
2022-12-17 17:02:14 +00:00
/* ReturnInstruction */
else if ( cast ( ReturnInstruction ) instruction )
{
gprintln ( "type: ReturnInstruction" ) ;
ReturnInstruction returnInstruction = cast ( ReturnInstruction ) instruction ;
Context context = returnInstruction . getContext ( ) ;
assert ( context ) ;
/* Get the return expression instruction */
Value returnExpressionInstr = returnInstruction . getReturnExpInstr ( ) ;
return "return " ~ transform ( returnExpressionInstr ) ~ ";" ;
}
2022-12-19 13:37:55 +00:00
/ * *
* If statements ( IfStatementInstruction )
* /
else if ( cast ( IfStatementInstruction ) instruction )
{
IfStatementInstruction ifStatementInstruction = cast ( IfStatementInstruction ) instruction ;
BranchInstruction [ ] branchInstructions = ifStatementInstruction . getBranchInstructions ( ) ;
gprintln ( "Holla" ~ to ! ( string ) ( branchInstructions ) ) ;
string emit ;
for ( ulong i = 0 ; i < branchInstructions . length ; i + + )
{
BranchInstruction curBranchInstr = branchInstructions [ i ] ;
if ( curBranchInstr . hasConditionInstr ( ) )
{
Value conditionInstr = cast ( Value ) curBranchInstr . getConditionInstr ( ) ;
string hStr = ( i = = 0 ) ? "if" : genTabs ( transformDepth ) ~ "else if" ;
emit ~ = hStr ~ "(" ~ transform ( conditionInstr ) ~ ")\n" ;
emit ~ = genTabs ( transformDepth ) ~ "{\n" ;
foreach ( Instruction branchBodyInstr ; curBranchInstr . getBodyInstructions ( ) )
{
emit ~ = genTabs ( transformDepth ) ~ "\t" ~ transform ( branchBodyInstr ) ~ "\n" ;
}
emit ~ = genTabs ( transformDepth ) ~ "}\n" ;
}
else
{
emit ~ = genTabs ( transformDepth ) ~ "else\n" ;
emit ~ = genTabs ( transformDepth ) ~ "{\n" ;
foreach ( Instruction branchBodyInstr ; curBranchInstr . getBodyInstructions ( ) )
{
emit ~ = genTabs ( transformDepth ) ~ "\t" ~ transform ( branchBodyInstr ) ~ "\n" ;
}
emit ~ = genTabs ( transformDepth ) ~ "}\n" ;
}
}
return emit ;
}
2023-01-04 10:03:50 +00:00
/ * *
* While loops ( WhileLoopInstruction )
2023-01-11 08:43:29 +00:00
*
* TODO : Add do - while check
2023-01-04 10:03:50 +00:00
* /
else if ( cast ( WhileLoopInstruction ) instruction )
{
WhileLoopInstruction whileLoopInstr = cast ( WhileLoopInstruction ) instruction ;
BranchInstruction branchInstr = whileLoopInstr . getBranchInstruction ( ) ;
Value conditionInstr = branchInstr . getConditionInstr ( ) ;
Instruction [ ] bodyInstructions = branchInstr . getBodyInstructions ( ) ;
string emit ;
/* Generate the `while(<expr>)` and opening curly brace */
emit = "while(" ~ transform ( conditionInstr ) ~ ")\n" ;
emit ~ = genTabs ( transformDepth ) ~ "{\n" ;
/* Transform each body statement */
foreach ( Instruction curBodyInstr ; bodyInstructions )
{
emit ~ = genTabs ( transformDepth ) ~ "\t" ~ transform ( curBodyInstr ) ~ "\n" ;
}
/* Closing curly brace */
emit ~ = genTabs ( transformDepth ) ~ "}" ;
return emit ;
}
2023-01-11 08:43:29 +00:00
/ * *
* For loops ( ForLoopInstruction )
* /
else if ( cast ( ForLoopInstruction ) instruction )
{
ForLoopInstruction forLoopInstr = cast ( ForLoopInstruction ) instruction ;
BranchInstruction branchInstruction = forLoopInstr . getBranchInstruction ( ) ;
Value conditionInstr = branchInstruction . getConditionInstr ( ) ;
Instruction [ ] bodyInstructions = branchInstruction . getBodyInstructions ( ) ;
string emit = "for(" ;
// Emit potential pre-run instruction
emit ~ = forLoopInstr . hasPreRunInstruction ( ) ? transform ( forLoopInstr . getPreRunInstruction ( ) ) : ";" ;
// Condition
emit ~ = transform ( conditionInstr ) ~ ";" ;
// NOTE: We are leaving the post-iteration blank due to us including it in the body
// TODO: We can hoist bodyInstructions[$] maybe if we want to generate it as C-for-loops
// if(forLoopInstr.hasPostIterationInstruction())
emit ~ = ")\n" ;
// Open curly (begin body)
emit ~ = genTabs ( transformDepth ) ~ "{\n" ;
/* Transform each body statement */
foreach ( Instruction curBodyInstr ; bodyInstructions )
{
emit ~ = genTabs ( transformDepth ) ~ "\t" ~ transform ( curBodyInstr ) ~ "\n" ;
}
// Close curly (body end)
emit ~ = genTabs ( transformDepth ) ~ "}" ;
2023-01-12 08:53:48 +00:00
return emit ;
}
/ * *
* Unary operators ( UnaryOpInstr )
* /
else if ( cast ( UnaryOpInstr ) instruction )
{
UnaryOpInstr unaryOpInstr = cast ( UnaryOpInstr ) instruction ;
Value operandInstruction = cast ( Value ) unaryOpInstr . getOperand ( ) ;
assert ( operandInstruction ) ;
string emit ;
/* The operator's symbol */
emit ~ = getCharacter ( unaryOpInstr . getOperator ( ) ) ;
/* Transform the operand */
emit ~ = transform ( operandInstruction ) ;
return emit ;
}
/ * *
* Pointer dereference assignment ( PointerDereferenceAssignmentInstruction )
* /
else if ( cast ( PointerDereferenceAssignmentInstruction ) instruction )
{
PointerDereferenceAssignmentInstruction pointerDereferenceAssignmentInstruction = cast ( PointerDereferenceAssignmentInstruction ) instruction ;
Value lhsPtrAddrExprInstr = pointerDereferenceAssignmentInstruction . getPointerEvalInstr ( ) ;
assert ( lhsPtrAddrExprInstr ) ;
Value rhsAssExprInstr = pointerDereferenceAssignmentInstruction . getAssExprInstr ( ) ;
assert ( rhsAssExprInstr ) ;
string emit ;
/* Star followed by transformation of the pointer address expression */
string starsOfLiberty ;
for ( ulong i = 0 ; i < pointerDereferenceAssignmentInstruction . getDerefCount ( ) ; i + + )
{
starsOfLiberty ~ = "*" ;
}
2023-04-17 15:50:11 +01:00
emit ~ = starsOfLiberty ~ "(" ~ transform ( lhsPtrAddrExprInstr ) ~ ")" ;
2023-01-12 08:53:48 +00:00
/* Assignment operator follows */
emit ~ = " = " ;
/* Expression to be assigned on the right hand side */
emit ~ = transform ( rhsAssExprInstr ) ~ ";" ;
2023-01-13 08:49:47 +00:00
return emit ;
}
/ * *
* Discard instruction ( DiscardInstruction )
* /
else if ( cast ( DiscardInstruction ) instruction )
{
DiscardInstruction discardInstruction = cast ( DiscardInstruction ) instruction ;
Value valueInstruction = discardInstruction . getExpressionInstruction ( ) ;
string emit ;
/* Transform the expression */
emit ~ = transform ( valueInstruction ) ~ ";" ;
2023-01-14 16:40:08 +00:00
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 */
2023-01-15 10:36:54 +00:00
emit ~ = "(" ~ typeTransform ( castingTo ) ~ ")" ;
2023-01-14 16:40:08 +00:00
/* The expression being casted */
emit ~ = transform ( uncastedInstruction ) ;
}
else
{
// TODO: Implement this
gprintln ( "Non-primitive type casting not yet implemented" , DebugType . ERROR ) ;
assert ( false ) ;
}
2023-01-11 08:43:29 +00:00
return emit ;
}
2023-01-15 18:48:40 +00:00
// TODO: MAAAAN we don't even have this yet
// else if(cast(StringExpression))
2022-12-13 09:45:45 +00:00
2022-12-13 09:46:40 +00:00
return "<TODO: Base emit: " ~ to ! ( string ) ( instruction ) ~ ">" ;
2022-12-11 19:41:15 +00:00
}
2022-12-12 13:36:07 +00:00
2021-11-02 08:41:03 +00:00
public override void emit ( )
{
2022-12-11 19:00:48 +00:00
// Emit header comment (NOTE: Change this to a useful piece of text)
emitHeaderComment ( "Place any extra information by code generator here" ) ; // NOTE: We can pass a string with extra information to it if we want to
2022-12-11 15:52:36 +00:00
2023-01-15 10:36:54 +00:00
// Emit standard integer header import
emitStdint ( ) ;
2022-12-17 12:31:03 +00:00
// Emit static allocation code
2022-12-12 17:12:39 +00:00
emitStaticAllocations ( ) ;
2022-12-11 15:52:36 +00:00
2022-12-17 12:31:03 +00:00
// Emit globals
2022-12-16 12:53:33 +00:00
emitCodeQueue ( ) ;
2022-12-17 12:31:03 +00:00
// Emit function definitions
2023-01-13 09:22:47 +00:00
emitFunctionPrototypes ( ) ;
2022-12-14 17:49:08 +00:00
emitFunctionDefinitions ( ) ;
2023-01-19 19:06:20 +00:00
// If enabled (default: yes) then emit entry point (TODO: change later)
2023-01-28 16:12:49 +00:00
if ( config . getConfig ( "dgen:emit_entrypoint_test" ) . getBoolean ( ) )
2023-01-19 19:06:20 +00:00
{
//TODO: Emit main (entry point)
emitEntryPoint ( ) ;
}
2022-12-11 15:52:36 +00:00
}
2022-12-11 15:58:33 +00:00
/ * *
* Emits the header comment which contains information about the source
* file and the generated code file
*
* Params :
* headerPhrase = Optional additional string information to add to the header comment
* /
2022-12-11 15:52:36 +00:00
private void emitHeaderComment ( string headerPhrase = "" )
{
2022-12-11 16:01:54 +00:00
// NOTE: We could maybe fetch input fiel info too? Although it would have to be named similiarly in any case
// so perhaps just appending a `.t` to the module name below would be fine
2022-12-11 15:57:16 +00:00
string moduleName = typeChecker . getResolver ( ) . generateName ( typeChecker . getModule ( ) , typeChecker . getModule ( ) ) ; //TODO: Lookup actual module name (I was lazy)
2022-12-11 15:52:36 +00:00
string outputCFilename = file . name ( ) ;
2022-12-11 16:09:56 +00:00
file . write ( ` / * *
2022-12-11 15:52:36 +00:00
* TLP compiler generated code
*
* Module name : ` ) ;
file . writeln ( moduleName ) ;
file . write ( " * Output C file: " ) ;
file . writeln ( outputCFilename ) ;
2022-12-11 15:55:18 +00:00
if ( headerPhrase . length )
{
2022-12-11 19:00:48 +00:00
file . write ( wrap ( headerPhrase , 40 , " *\n * " , " * " ) ) ;
2022-12-11 15:55:18 +00:00
}
2022-12-11 15:52:36 +00:00
2022-12-11 19:00:48 +00:00
file . write ( " */\n" ) ;
2022-12-11 15:52:36 +00:00
}
/ * *
* Emits the static allocations provided
*
* Params :
* initQueue = The allocation queue to emit static allocations from
* /
2022-12-12 17:12:39 +00:00
private void emitStaticAllocations ( )
2022-12-11 15:52:36 +00:00
{
2022-12-14 17:49:08 +00:00
selectQueue ( QueueType . ALLOC_QUEUE ) ;
gprintln ( "Static allocations needed: " ~ to ! ( string ) ( getQueueLength ( ) ) ) ;
2022-12-16 12:53:33 +00:00
file . writeln ( ) ;
2022-12-14 17:49:08 +00:00
}
/ * *
2023-01-13 09:22:47 +00:00
* Emits the function prototypes
* /
private void emitFunctionPrototypes ( )
{
gprintln ( "Function definitions needed: " ~ to ! ( string ) ( getFunctionDefinitionsCount ( ) ) ) ;
Instruction [ ] [ string ] functionBodyInstrs = typeChecker . getFunctionBodyCodeQueues ( ) ;
string [ ] functionNames = getFunctionDefinitionNames ( ) ;
gprintln ( "WOAH: " ~ to ! ( string ) ( functionNames ) ) ;
foreach ( string currentFunctioName ; functionNames )
{
emitFunctionPrototype ( currentFunctioName ) ;
file . writeln ( ) ;
}
}
/ * *
* Emits the function definitions
2022-12-14 17:49:08 +00:00
* /
private void emitFunctionDefinitions ( )
{
2022-12-16 12:53:33 +00:00
gprintln ( "Function definitions needed: " ~ to ! ( string ) ( getFunctionDefinitionsCount ( ) ) ) ;
2022-12-14 17:49:08 +00:00
Instruction [ ] [ string ] functionBodyInstrs = typeChecker . getFunctionBodyCodeQueues ( ) ;
string [ ] functionNames = getFunctionDefinitionNames ( ) ;
gprintln ( "WOAH: " ~ to ! ( string ) ( functionNames ) ) ;
foreach ( string currentFunctioName ; functionNames )
{
emitFunctionDefinition ( currentFunctioName ) ;
2022-12-16 12:53:33 +00:00
file . writeln ( ) ;
2023-01-13 09:22:47 +00:00
}
2022-12-14 17:49:08 +00:00
}
private string generateSignature ( Function func )
{
string signature ;
2023-01-15 10:40:42 +00:00
// Extract the Function's return Type
2023-01-15 10:36:54 +00:00
Type returnType = typeChecker . getType ( func . context . container , func . getType ( ) ) ;
2022-12-14 17:49:08 +00:00
// <type> <functionName> (
2023-01-15 10:36:54 +00:00
signature = typeTransform ( returnType ) ~ " " ~ func . getName ( ) ~ "(" ;
2022-12-14 17:49:08 +00:00
// Generate parameter list
if ( func . hasParams ( ) )
{
2022-12-17 12:00:16 +00:00
VariableParameter [ ] parameters = func . getParams ( ) ;
2022-12-14 17:49:08 +00:00
string parameterString ;
for ( ulong parIdx = 0 ; parIdx < parameters . length ; parIdx + + )
{
Variable currentParameter = parameters [ parIdx ] ;
2022-12-17 12:00:16 +00:00
2023-01-15 10:40:42 +00:00
// Extract the variable's type
Type parameterType = typeChecker . getType ( currentParameter . context . container , currentParameter . getType ( ) ) ;
2022-12-17 12:00:16 +00:00
// Generate the symbol-mapped names for the parameters
Variable typedEntityVariable = cast ( Variable ) typeChecker . getResolver ( ) . resolveBest ( func , currentParameter . getName ( ) ) ; //TODO: Remove `auto`
2023-01-23 18:44:35 +00:00
string renamedSymbol = mapper . symbolLookup ( typedEntityVariable ) ;
2022-12-17 12:00:16 +00:00
// Generate <type> <parameter-name (symbol mapped)>
2023-01-15 10:40:42 +00:00
parameterString ~ = typeTransform ( parameterType ) ~ " " ~ renamedSymbol ;
2022-12-14 17:49:08 +00:00
if ( parIdx ! = ( parameters . length - 1 ) )
{
parameterString ~ = ", " ;
}
}
signature ~ = parameterString ;
}
// )
signature ~ = ")" ;
2023-01-15 18:48:40 +00:00
// If the function is marked as external then place `extern` infront
if ( func . isExternal ( ) )
{
signature = "extern " ~ signature ;
}
2022-12-14 17:49:08 +00:00
return signature ;
}
2023-01-13 09:22:47 +00:00
private void emitFunctionPrototype ( string functionName )
{
selectQueue ( QueueType . FUNCTION_DEF_QUEUE , functionName ) ;
gprintln ( "emotFunctionDefinition(): Function: " ~ functionName ~ ", with " ~ to ! ( string ) ( getSelectedQueueLength ( ) ) ~ " many instructions" ) ;
//TODO: Look at nested definitions or nah? (Context!!)
//TODO: And what about methods defined in classes? Those should technically be here too
Function functionEntity = cast ( Function ) typeChecker . getResolver ( ) . resolveBest ( typeChecker . getModule ( ) , functionName ) ; //TODO: Remove `auto`
// Emit the function signature
file . writeln ( generateSignature ( functionEntity ) ~ ";" ) ;
}
2022-12-14 17:49:08 +00:00
private void emitFunctionDefinition ( string functionName )
{
selectQueue ( QueueType . FUNCTION_DEF_QUEUE , functionName ) ;
2022-12-16 12:53:33 +00:00
gprintln ( "emotFunctionDefinition(): Function: " ~ functionName ~ ", with " ~ to ! ( string ) ( getSelectedQueueLength ( ) ) ~ " many instructions" ) ;
2022-12-14 17:49:08 +00:00
//TODO: Look at nested definitions or nah? (Context!!)
//TODO: And what about methods defined in classes? Those should technically be here too
Function functionEntity = cast ( Function ) typeChecker . getResolver ( ) . resolveBest ( typeChecker . getModule ( ) , functionName ) ; //TODO: Remove `auto`
2023-01-15 18:48:40 +00:00
// If the Entity is NOT external then emit the signature+body
if ( ! functionEntity . isExternal ( ) )
{
// Emit the function signature
file . writeln ( generateSignature ( functionEntity ) ) ;
2022-12-14 17:49:08 +00:00
2023-01-15 18:48:40 +00:00
// Emit opening curly brace
file . writeln ( getCharacter ( SymbolType . OCURLY ) ) ;
2022-12-11 15:52:36 +00:00
2023-01-15 18:48:40 +00:00
// Emit body
while ( hasInstructions ( ) )
{
Instruction curFuncBodyInstr = getCurrentInstruction ( ) ;
2022-12-14 17:49:08 +00:00
2023-01-15 18:48:40 +00:00
string emit = transform ( curFuncBodyInstr ) ;
gprintln ( "emitFunctionDefinition(" ~ functionName ~ "): Emit: " ~ emit ) ;
file . writeln ( "\t" ~ emit ) ;
nextInstruction ( ) ;
}
2022-12-14 17:49:08 +00:00
2023-01-15 18:48:40 +00:00
// Emit closing curly brace
file . writeln ( getCharacter ( SymbolType . CCURLY ) ) ;
}
// If the Entity IS external then don't emit anything as the signature would have been emitted via a prorotype earlier with `emitPrototypes()`
else
{
// Do nothing
}
2021-11-02 08:41:03 +00:00
}
2022-12-11 16:04:53 +00:00
2022-12-12 17:12:39 +00:00
private void emitCodeQueue ( )
2022-12-11 16:04:53 +00:00
{
2022-12-14 17:49:08 +00:00
selectQueue ( QueueType . GLOBALS_QUEUE ) ;
gprintln ( "Code emittings needed: " ~ to ! ( string ) ( getQueueLength ( ) ) ) ;
while ( hasInstructions ( ) )
2022-12-11 16:06:10 +00:00
{
2022-12-14 17:49:08 +00:00
Instruction currentInstruction = getCurrentInstruction ( ) ;
2022-12-12 13:36:07 +00:00
file . writeln ( transform ( currentInstruction ) ) ;
2022-12-12 17:12:39 +00:00
2022-12-14 17:49:08 +00:00
nextInstruction ( ) ;
2022-12-11 16:06:10 +00:00
}
2022-12-16 12:53:33 +00:00
file . writeln ( ) ;
2022-12-11 16:04:53 +00:00
}
2022-12-11 19:41:15 +00:00
2023-01-15 10:36:54 +00:00
private void emitStdint ( )
{
file . writeln ( "#include<stdint.h>" ) ;
}
2022-12-11 19:41:15 +00:00
private void emitEntryPoint ( )
{
2023-01-24 17:57:27 +00:00
// TODO: Implement me
2022-12-11 19:41:15 +00:00
2023-01-04 10:03:50 +00:00
// Test for `simple_functions.t` (function call testing)
2022-12-19 13:37:55 +00:00
if ( cmp ( typeChecker . getModule ( ) . getName ( ) , "simple_functions" ) = = 0 )
{
2023-01-04 10:03:50 +00:00
file . writeln ( `
2022-12-16 12:53:33 +00:00
# include < stdio . h >
2023-01-04 10:03:50 +00:00
# include < assert . h >
2022-12-11 19:41:15 +00:00
int main ( )
{
2023-01-04 10:03:50 +00:00
assert ( t_7b6d477c5859059f16bc9da72fc8cc3b = = 22 ) ;
2022-12-17 12:31:03 +00:00
printf ( "k: %u\n" , t_7b6d477c5859059f16bc9da72fc8cc3b ) ;
2023-01-04 10:03:50 +00:00
2022-12-16 12:53:33 +00:00
banana ( 1 ) ;
2023-01-04 10:03:50 +00:00
assert ( t_7b6d477c5859059f16bc9da72fc8cc3b = = 72 ) ;
2022-12-17 12:31:03 +00:00
printf ( "k: %u\n" , t_7b6d477c5859059f16bc9da72fc8cc3b ) ;
2023-01-04 10:03:50 +00:00
return 0 ;
} ` ) ;
}
else if ( cmp ( typeChecker . getModule ( ) . getName ( ) , "simple_while" ) = = 0 )
{
file . writeln ( `
2023-01-11 08:43:29 +00:00
# include < stdio . h >
# include < assert . h >
int main ( )
{
int result = function ( 3 ) ;
printf ( "result: %d\n" , result ) ;
assert ( result = = 3 ) ;
return 0 ;
} ` ) ;
}
else if ( cmp ( typeChecker . getModule ( ) . getName ( ) , "simple_for_loops" ) = = 0 )
{
file . writeln ( `
2023-01-04 10:03:50 +00:00
# include < stdio . h >
# include < assert . h >
int main ( )
{
int result = function ( 3 ) ;
printf ( "result: %d\n" , result ) ;
assert ( result = = 3 ) ;
2023-01-12 08:53:48 +00:00
return 0 ;
} ` ) ;
}
else if ( cmp ( typeChecker . getModule ( ) . getName ( ) , "simple_pointer" ) = = 0 )
{
file . writeln ( `
# include < stdio . h >
# include < assert . h >
int main ( )
{
2023-01-14 10:39:37 +00:00
int retValue = thing ( ) ;
2023-01-12 08:53:48 +00:00
assert ( t_87bc875d0b65f741b69fb100a0edebc7 = = 4 ) ;
2023-01-14 10:39:37 +00:00
assert ( retValue = = 6 ) ;
2023-01-12 08:53:48 +00:00
2023-04-17 15:50:11 +01:00
return 0 ;
} ` ) ;
}
else if ( cmp ( typeChecker . getModule ( ) . getName ( ) , "simple_pointer_cast_le" ) = = 0 )
{
file . writeln ( `
# include < stdio . h >
# include < assert . h >
int main ( )
{
int retValue = thing ( ) ;
assert ( t_e159019f766be1a175186a13f16bcfb7 = = 256 + 4 ) ;
assert ( retValue = = 256 + 4 + 2 ) ;
return 0 ;
} ` ) ;
}
else if ( cmp ( typeChecker . getModule ( ) . getName ( ) , "simple_pointer_malloc" ) = = 0 )
{
file . writeln ( `
# include < stdio . h >
# include < assert . h >
int main ( )
{
test ( ) ;
// TODO: Test the value
2023-01-15 18:48:40 +00:00
return 0 ;
} ` ) ;
}
else if ( cmp ( typeChecker . getModule ( ) . getName ( ) , "simple_extern" ) = = 0 )
{
file . writeln ( `
# include < stdio . h >
# include < assert . h >
int main ( )
{
test ( ) ;
2022-12-11 19:41:15 +00:00
return 0 ;
} ` ) ;
2022-12-19 13:37:55 +00:00
}
else
{
file . writeln ( `
int main ( )
{
return 0 ;
}
` ) ;
}
2022-12-11 19:41:15 +00:00
}
2022-12-12 13:36:07 +00:00
public override void finalize ( )
{
try
{
//NOTE: Change to system compiler (maybe, we need to choose a good C compiler)
2023-01-28 16:12:49 +00:00
string [ ] compileArgs = [ "clang" , "-o" , "tlang.out" , file . name ( ) ] ;
// Check for object files to be linked in
string [ ] objectFilesLink ;
if ( config . hasConfig ( "linker:link_files" ) )
{
objectFilesLink = config . getConfig ( "linker:link_files" ) . getArray ( ) ;
gprintln ( "Object files to be linked in: " ~ to ! ( string ) ( objectFilesLink ) ) ;
}
else
{
gprintln ( "No files to link in" ) ;
}
Pid ccPID = spawnProcess ( compileArgs ~ objectFilesLink ) ;
2022-12-12 13:36:07 +00:00
int code = wait ( ccPID ) ;
if ( code )
{
//NOTE: Make this a TLang exception
2022-12-16 12:53:33 +00:00
throw new Exception ( "The CC exited with a non-zero exit code (" ~ to ! ( string ) ( code ) ~ ")" ) ;
2022-12-12 13:36:07 +00:00
}
}
catch ( ProcessException e )
{
gprintln ( "NOTE: Case where it exited and Pid now inavlid (if it happens it would throw processexception surely)?" , DebugType . ERROR ) ;
assert ( false ) ;
}
}
2021-11-02 08:41:03 +00:00
}