diff --git a/.github/workflows/d.yml b/.github/workflows/d.yml index 9638613..3cbd14b 100644 --- a/.github/workflows/d.yml +++ b/.github/workflows/d.yml @@ -129,6 +129,62 @@ jobs: exit 1 fi + # Array support + - name: Simple array + run: ./tlang typecheck source/tlang/testing/simple_arrays.t + - name: Simple array 2 + run: ./tlang typecheck source/tlang/testing/simple_arrays2.t + - name: Simple array 4 + run: ./tlang typecheck source/tlang/testing/simple_arrays4.t + + - name: Stack-based array coercion + run: ./tlang typecheck source/tlang/testing/simple_stack_array_coerce.t + - name: Complex stack-based arrays + run: ./tlang typecheck source/tlang/testing/complex_stack_arrays1.t + - name: Stack-based array coercion (type mismatch) + run: | + set +e + ./tlang compile source/tlang/testing/simple_stack_array_coerce_wrong.t + if [ $? = 255 ] + then + exit 0 + else + exit 1 + fi + + - name: Stack-based array coercion (good permutations)) + run: | + ./tlang typecheck source/tlang/testing/complex_stack_array_coerce_permutation_good.t + - name: Stack-based array coercion (type mismatch - bad permutation 1) + run: | + set +e + ./tlang compile source/tlang/testing/complex_stack_array_coerce_bad1.t + if [ $? = 255 ] + then + exit 0 + else + exit 1 + fi + - name: Stack-based array coercion (type mismatch - bad permutation 2) + run: | + set +e + ./tlang compile source/tlang/testing/complex_stack_array_coerce_bad2.t + if [ $? = 255 ] + then + exit 0 + else + exit 1 + fi + - name: Stack-based array coercion (type mismatch - bad permutation 3) + run: | + set +e + ./tlang compile source/tlang/testing/complex_stack_array_coerce_bad3.t + if [ $? = 255 ] + then + exit 0 + else + exit 1 + fi - name: Collide container module1 run: | @@ -313,10 +369,57 @@ jobs: run: | chmod +x extern_test.sh ./extern_test.sh + + + # Array support + - name: Stack-based arrays simple + run: | + ./tlang compile source/tlang/testing/simple_stack_arrays4.t + ./tlang.out + - name: Stack-based array coercion (array syntax) + run: | + ./tlang compile source/tlang/testing/simple_stack_array_coerce.t + ./tlang.out + - name: Stack-based array coercion (pointer syntax) + run: | + ./tlang compile source/tlang/testing/simple_stack_array_coerce_ptr_syntax.t + ./tlang.out + - name: Stack-based array with normal array coercion (complex) + run: | + ./tlang compile source/tlang/testing/complex_stack_array_coerce.t + ./tlang.out + + + # TODO: Actually add semantic tests for these + - name: Complex stack-based arrays + run: | + ./tlang compile source/tlang/testing/complex_stack_arrays1.t + ./tlang.out + - name: Simple array + run: | + ./tlang compile source/tlang/testing/simple_arrays.t + ./tlang.out + - name: Simple array 2 + run: | + ./tlang compile source/tlang/testing/simple_arrays2.t + ./tlang.out + - name: Simple array 4 + run: | + ./tlang compile source/tlang/testing/simple_arrays4.t + ./tlang.out + + - name: Simple pointer (malloc and free) run: | chmod +x malloc_test.sh ./malloc_test.sh + - name: Simple pointer (array syntax) + run: | + ./tlang compile source/tlang/testing/simple_pointer_array_syntax.t + ./tlang.out + + + ################################## ####### Deployment section ####### ################################## diff --git a/branding/logo.png b/branding/logo.png new file mode 100644 index 0000000..0ed63c5 Binary files /dev/null and b/branding/logo.png differ diff --git a/branding/logo.xcf b/branding/logo.xcf new file mode 100644 index 0000000..90771cc Binary files /dev/null and b/branding/logo.xcf differ diff --git a/source/tlang/compiler/codegen/emit/dgen.d b/source/tlang/compiler/codegen/emit/dgen.d index 6959bde..ce68ba8 100644 --- a/source/tlang/compiler/codegen/emit/dgen.d +++ b/source/tlang/compiler/codegen/emit/dgen.d @@ -17,7 +17,7 @@ import tlang.compiler.codegen.mapper.core : SymbolMapper; import tlang.compiler.symbols.data : SymbolType, Variable, Function, VariableParameter; import tlang.compiler.symbols.check : getCharacter; import misc.utils : Stack; -import tlang.compiler.symbols.typing.core : Type, Primitive, Integer, Void, Pointer; +import tlang.compiler.symbols.typing.core; import tlang.compiler.configuration : CompilerConfiguration; public final class DCodeEmitter : CodeEmitter @@ -91,6 +91,18 @@ public final class DCodeEmitter : CodeEmitter { return "void"; } + /* Stack-based array type */ + else if(cast(StackArray)typeIn) + { + // TODO: Still implement stakc-based arrays + // we won't be able to tyoe transform just here + // ... as we need [] + // ... hence this must be performed in avriable declaration + StackArray stackArray = cast(StackArray)typeIn; + + return typeTransform(stackArray.getComponentType()); + // return "KAK TODO"; + } gprintln("Type transform unimplemented"); assert(false); @@ -166,6 +178,14 @@ public final class DCodeEmitter : CodeEmitter string renamedSymbol = mapper.symbolLookup(typedEntityVariable); + // Check if the type is a stack-based array + // ... if so then take make symbolName := `[]` + if(cast(StackArray)varDecInstr.varType) + { + StackArray stackArray = cast(StackArray)varDecInstr.varType; + renamedSymbol~="["~to!(string)(stackArray.getAllocatedSize())~"]"; + } + // Check to see if this declaration has an assignment attached if(typedEntityVariable.getAssignment()) { @@ -505,6 +525,176 @@ public final class DCodeEmitter : CodeEmitter + return emit; + } + /** + * Array indexing (pointer-based arrays) + * + * Handles `myArray[]` where `myArray` is + * of type `int[]` (i.e. `int*`) + */ + else if(cast(ArrayIndexInstruction)instruction) + { + ArrayIndexInstruction arrAssInstr = cast(ArrayIndexInstruction)instruction; + + gprintln("TODO: Implement Pointer-array index emit", DebugType.ERROR); + + gprintln("ArrayInstr: "~arrAssInstr.getIndexedToInstr().toString()); + gprintln("ArrayIndexInstr: "~to!(string)(arrAssInstr.getIndexInstr())); + + + /* Obtain the entity being indexed */ + Value indexed = arrAssInstr.getIndexedToInstr(); + + /* Obtain the index */ + Value index = arrAssInstr.getIndexInstr(); + + + /** + * Emit *(+) + */ + string emit; + emit ~= "*("; + + + emit ~= transform(indexed); + emit ~= "+"; + emit ~= transform(index); + emit ~= ")"; + + + + // return "*("~transform(indexed)~"+"~transform(index)~")"; + return emit; + } + /** + * Array assignments (pointer-based arrays) + * + * Handles `myArray[] = ` where `myArray` + * is of type `int[]` (i.e. `int*`) + */ + else if(cast(ArrayIndexAssignmentInstruction)instruction) + { + ArrayIndexAssignmentInstruction arrayAssignmentInstr = cast(ArrayIndexAssignmentInstruction)instruction; + + /** + * Obtain the array pointer evaluation + */ + ArrayIndexInstruction arrayPtrEval = arrayAssignmentInstr.getArrayPtrEval(); + + // NOTE: See above + // /** + // * Obtain the index being assigned at + // */ + // Value index = arrayAssignmentInstr.getIndexInstr(); + + /** + * Obtain the expression being assigned + */ + Value assignmentInstr = arrayAssignmentInstr.getAssignmentInstr(); + + + /** + * Emit *(+) = ; + */ + string emit; + // NOTE: Below is done by ArrayIndexInstruction + // emit ~= "*("; + // emit ~= transform(arrayPtrEval); + // emit ~= "+"; + // emit ~= transform(index); + // emit ~= ")"; + emit ~= transform(arrayPtrEval); + + emit ~= " = "; + emit ~= transform(assignmentInstr); + emit ~= ";"; + + + return emit; + } + /** + * Array indexing (stack-based arrays) + * + * Handles `myArray[]` where `myArray` is + * of type `int[]` (i.e. a stack-array) + */ + else if(cast(StackArrayIndexInstruction)instruction) + { + StackArrayIndexInstruction stackArrInstr = cast(StackArrayIndexInstruction)instruction; + Context context = stackArrInstr.getContext(); + + /* Obtain the stack array variable being indexed */ + // TODO: Investigate, nroamlly we do a `FetchValueVar` as like the instr which is fine actually + FetchValueVar array = cast(FetchValueVar)stackArrInstr.getIndexedToInstr(); + assert(array); + Variable arrayVariable = cast(Variable)typeChecker.getResolver().resolveBest(context.getContainer(), array.varName); + + /* Perform symbol mapping */ + string arrayName = mapper.symbolLookup(arrayVariable); + + /* Obtain the index expression */ + Value indexInstr = stackArrInstr.getIndexInstr(); + + /** + * Emit [] + */ + string emit = arrayName; + emit ~= "["; + emit ~= transform(indexInstr); + emit ~= "]"; + + + gprintln("TODO: Implement Stack-array index emit", DebugType.ERROR); + + + + + // return "(TODO: Stack-array index emit)"; + return emit; + } + /** + * Array assignments (stack-based arrays) + * + * Handles `myArray[] = ` where `myArray` + * is of type `int[]` (i.e. a stack-array) + */ + else if(cast(StackArrayIndexAssignmentInstruction)instruction) + { + StackArrayIndexAssignmentInstruction stackArrAssInstr = cast(StackArrayIndexAssignmentInstruction)instruction; + Context context = stackArrAssInstr.getContext(); + assert(context); + + /** + * Obtain the stack array being assigned to + */ + string arrayName = stackArrAssInstr.getArrayName(); + Variable arrayVariable = cast(Variable)typeChecker.getResolver().resolveBest(context.getContainer(), arrayName); + + /* Perform symbol mapping */ + string arrayNameMapped = mapper.symbolLookup(arrayVariable); + + /* Obtain the index expression */ + Value indexInstr = stackArrAssInstr.getIndexInstr(); + + /* Obtain the expresison being assigned */ + Value assignmentInstr = stackArrAssInstr.getAssignedValue(); + + /** + * Emit [] = ; + */ + string emit = arrayNameMapped; + emit ~= "["; + emit ~= transform(indexInstr); + emit ~= "]"; + + emit ~= " = "; + emit ~= transform(assignmentInstr); + emit ~= ";"; + + + // return "(StackArrAssignmentInstr: TODO)"; + return emit; } // TODO: MAAAAN we don't even have this yet @@ -815,6 +1005,20 @@ int main() assert(t_87bc875d0b65f741b69fb100a0edebc7 == 4); assert(retValue == 6); + return 0; +}`); + } + else if(cmp(typeChecker.getModule().getName(), "simple_pointer_array_syntax") == 0) + { + file.writeln(` +#include +#include +int main() +{ + int retValue = thing(); + assert(t_9d01d71b858651e520c9b503122a1b7a == 4); + assert(retValue == 6); + return 0; }`); } @@ -857,6 +1061,64 @@ int main() + return 0; +}`); + } + else if(cmp(typeChecker.getModule().getName(), "simple_stack_array_coerce") == 0) + { + file.writeln(` +#include +#include +int main() +{ + int result = function(); + assert(result == 420+69); + printf("stackArr sum: %d\n", result); + + return 0; +}`); + } + else if(cmp(typeChecker.getModule().getName(), "complex_stack_array_coerce") == 0) + { + file.writeln(` +#include +#include +int main() +{ + int result = function(); + assert(result == 69+420); + + printf("val1: %d\n", t_596f49b2a2784a3c1b073ccfe174caa0); + printf("val2: %d\n", t_4233b83329676d70ab4afaa00b504564); + printf("stackArr sum: %d\n", result); + + return 0; +}`); + } + else if(cmp(typeChecker.getModule().getName(), "simple_stack_array_coerce_ptr_syntax") == 0) + { + file.writeln(` +#include +#include +int main() +{ + int result = function(); + assert(result == 420+69); + printf("stackArr sum: %d\n", result); + + return 0; +}`); + } + else if(cmp(typeChecker.getModule().getName(), "simple_stack_arrays4") == 0) + { + file.writeln(` +#include +#include +int main() +{ + int result = function(); + assert(result == 61); + return 0; }`); } diff --git a/source/tlang/compiler/codegen/instruction.d b/source/tlang/compiler/codegen/instruction.d index 5864c41..208da01 100644 --- a/source/tlang/compiler/codegen/instruction.d +++ b/source/tlang/compiler/codegen/instruction.d @@ -511,4 +511,142 @@ public final class CastedValueInstruction : Value { return type; } +} + +public final class ArrayIndexInstruction : Value +{ + /* Index-to instruction */ + private Value indexTo; + + /* The index */ + private Value index; + + this(Value indexTo, Value index) + { + this.indexTo = indexTo; + this.index = index; + } + + public Value getIndexInstr() + { + return index; + } + + public Value getIndexedToInstr() + { + return indexTo; + } + + public override string toString() + { + return "ArrayIndexInstr [IndexTo: "~indexTo.toString()~", Index: "~index.toString()~"]"; + } +} + +//TODO: ArrayIndexAssignmentInstruction +public final class ArrayIndexAssignmentInstruction : Instruction +{ + // TODO: We then need the left hand side array evaluation instruction (a pointer value basically) + // private Value arrayPtrEval; + + // TODO: We then also need a `Value` field for the index expression instruction + // private Value index; + + // NOTE: We now to the above to using an ArrayIndexInstruction + private ArrayIndexInstruction arrayPtrEval; + + // TODO: We then also need another `Value` field for the expression instruction + // ... being assigned into the pointer-array + private Value assignment; + + this(ArrayIndexInstruction arrayPtrEval, Value assignment) + { + this.arrayPtrEval = arrayPtrEval; + // this.index = index; + this.assignment = assignment; + } + + public ArrayIndexInstruction getArrayPtrEval() + { + return arrayPtrEval; + } + + public Value getAssignmentInstr() + { + return assignment; + } +} + +// TODO: StackArrayIndexInstruction +public final class StackArrayIndexInstruction : Value +{ + /* Index-to instruction */ + private Value indexTo; + + /* The index */ + private Value index; + + this(Value indexTo, Value index) + { + this.indexTo = indexTo; + this.index = index; + } + + public Value getIndexInstr() + { + return index; + } + + public Value getIndexedToInstr() + { + return indexTo; + } + + public override string toString() + { + return "StackArrayIndexInstr [IndexTo: "~indexTo.toString()~", Index: "~index.toString()~"]"; + } +} + +// TODO: StackArrayIndexAssignmentInstruction +public final class StackArrayIndexAssignmentInstruction : Instruction +{ + // TODO: We need a `string` field here which is looked up with the + // ... associated context of this instruction and refers to the + // ... stack-array being index-assigned into + private string arrayName; + + // TODO: We then also need a `Value` field for the index expression instruction + private Value index; + + // TODO: We then also need another `Value` field for the expression instruction + // ... being assigned into the stack-array at said index + private Value assignment; + + this(string arrayName, Value index, Value assignment) + { + this.arrayName = arrayName; + this.index = index; + this.assignment = assignment; + } + + public string getArrayName() + { + return arrayName; + } + + public Value getIndexInstr() + { + return index; + } + + public Value getAssignedValue() + { + return assignment; + } + + public override string toString() + { + return "StackArrayASSIGN [name: "~arrayName~", index: "~index.toString()~", Assignment: "~assignment.toString()~"]"; + } } \ No newline at end of file diff --git a/source/tlang/compiler/parsing/core.d b/source/tlang/compiler/parsing/core.d index 134ad62..abc082e 100644 --- a/source/tlang/compiler/parsing/core.d +++ b/source/tlang/compiler/parsing/core.d @@ -455,9 +455,10 @@ public final class Parser * * 1. `int ptr` (and we looked ahead to `ptr`) * 2. `int* ptr` (and we looked ahead to `*`) + * 3. `int[] thing` (and we looked ahead to `[`) */ /* If we have an identifier/type then declaration */ - else if(type == SymbolType.IDENT_TYPE || type == SymbolType.STAR) + else if(type == SymbolType.IDENT_TYPE || type == SymbolType.STAR || type == SymbolType.OBRACKET) { previousToken(); ret = parseTypedDeclaration(); @@ -474,6 +475,13 @@ public final class Parser expect(SymbolType.SEMICOLON, getCurrentToken()); nextToken(); } + /* If it is an arrau assignment */ + else if(cast(ArrayAssignment)ret) + { + /* Expect a semicolon and consume it */ + expect(SymbolType.SEMICOLON, getCurrentToken()); + nextToken(); + } /* This should never happen */ else { @@ -907,7 +915,7 @@ public final class Parser if(getSymbolType(getCurrentToken()) == SymbolType.IDENT_TYPE) { /* Get the type */ - TypedEntity bogusEntity = parseTypedDeclaration(false, false, false, true); + TypedEntity bogusEntity = cast(TypedEntity)parseTypedDeclaration(false, false, false, true); string type = bogusEntity.getType(); /* Get the identifier (This CAN NOT be dotted) */ @@ -1041,7 +1049,8 @@ public final class Parser * which means we can call `getType()` and extract * the type string */ - TypedEntity bogusEntity = parseTypedDeclaration(false, false, false, true); + TypedEntity bogusEntity = cast(TypedEntity)parseTypedDeclaration(false, false, false, true); + assert(bogusEntity); string toType = bogusEntity.getType(); /* Expect a `)` closing brace */ @@ -1057,7 +1066,6 @@ public final class Parser return castedExpression; } - /** * Parses an expression * @@ -1315,6 +1323,23 @@ public final class Parser /* Get the next token */ nextToken(); } + /* If we have a `[` (array index/access) */ + else if(symbol == SymbolType.OBRACKET) + { + // Pop off an expression which will be `indexTo` + Expression indexTo = removeExp(); + gprintln("indexTo: "~indexTo.toString()); + + /* Get the index expression */ + nextToken(); + Expression index = parseExpression(); + nextToken(); + gprintln("IndexExpr: "~index.toString()); + // gprintln(getCurrentToken()); + + ArrayIndex arrayIndexExpr = new ArrayIndex(indexTo, index); + addRetExp(arrayIndexExpr); + } /* If it is an identifier */ else if (symbol == SymbolType.IDENT_TYPE) { @@ -1348,7 +1373,9 @@ public final class Parser addRetExp(toAdd); } /* Detect if this expression is coming to an end, then return */ - else if (symbol == SymbolType.SEMICOLON || symbol == SymbolType.RBRACE || symbol == SymbolType.COMMA || symbol == SymbolType.ASSIGN) + else if (symbol == SymbolType.SEMICOLON || symbol == SymbolType.RBRACE || + symbol == SymbolType.COMMA || symbol == SymbolType.ASSIGN || + symbol == SymbolType.CBRACKET) { break; } @@ -1436,29 +1463,93 @@ public final class Parser return retExpression[0]; } - private TypedEntity parseTypedDeclaration(bool wantsBody = true, bool allowVarDec = true, bool allowFuncDef = true, bool onlyType = false) + + + // TODO: Update to `Statement` as this can return an ArrayAssignment now + private Statement parseTypedDeclaration(bool wantsBody = true, bool allowVarDec = true, bool allowFuncDef = true, bool onlyType = false) { gprintln("parseTypedDeclaration(): Enter", DebugType.WARNING); /* Generated object */ - TypedEntity generated; + Statement generated; /* TODO: Save type */ string type = getCurrentToken().getToken(); string identifier; - - - // TODO: Insert pointer `*`-handling code here nextToken(); - ulong derefCount = 0; - /* If we have a star */ - while(getSymbolType(getCurrentToken()) == SymbolType.STAR) + + + /* Potential array index expressions (assignment) */ + // Think myArray[i][1] -> [`i`, `1`] + Expression[] arrayIndexExprs; + + // We are currently 1 past the "type" (the identifier) so go back one + ulong arrayAssignTokenBeginPos = getCursor()-1; + + /* Potential stack-array type size (declaration) */ + string potentialStackSize; + + /* Handling of pointer and array types */ + while(getSymbolType(getCurrentToken()) == SymbolType.STAR || getSymbolType(getCurrentToken()) == SymbolType.OBRACKET) { - derefCount+=1; - type=type~"*"; + /* If we have `[` then expect a number and/or a `]` */ + if(getSymbolType(getCurrentToken()) == SymbolType.OBRACKET) + { + nextToken(); + SymbolType nextType = getSymbolType(getCurrentToken()); + + + /* Check if the next symbol is NOT a `]` */ + if(nextType != SymbolType.CBRACKET) + { + + + arrayIndexExprs ~= parseExpression(); + + /** + * If it is the case it is a number literal then save it + * anyways just for the case whereby we may be declaring + * a stack-array type + * + * TODO: Double check any error checking here which should be deferred to later + */ + if(nextType == SymbolType.NUMBER_LITERAL) + { + // TODO: Ensure the returned thing is a number + // TODO: Ensure said number is non-negative + // TODO: May as well now start adding `]` as a seperator or stopper or something + IntegerLiteral stackArraySize = cast(IntegerLiteral)arrayIndexExprs[$-1]; + + // If the expression is an integer (which it should be) + if(stackArraySize) + { + gprintln("StackArraySize: "~stackArraySize.toString()); + potentialStackSize = stackArraySize.getNumber(); + } + // If not, then error + else + { + gprintln("Expected an integer as stack-array size but got iets ander", DebugType.ERROR); + // TODO: Rather throw a parsing error + assert(false); + } + } + } + + + + expect(SymbolType.CBRACKET, getCurrentToken()); + type=type~"["~potentialStackSize~"]"; + } + /* If we have `*` */ + else + { + type=type~"*"; + } + nextToken(); } @@ -1470,17 +1561,39 @@ public final class Parser return generated; } - - /* Expect an identifier (CAN NOT be dotted) */ - expect(SymbolType.IDENT_TYPE, getCurrentToken()); - if(!isIdentifier_NoDot(getCurrentToken())) - { - expect("Identifier cannot be dotted"); - } - identifier = getCurrentToken().getToken(); - nextToken(); - gprintln("ParseTypedDec: DecisionBtwn FuncDef/VarDef: " ~ getCurrentToken().getToken()); + /* If we are going to be assigning into an array (indexed) */ + bool arrayIndexing = false; + + + /* If the current token is ASSIGN then array indexing is occuring */ + if(getSymbolType(getCurrentToken()) == SymbolType.ASSIGN) + { + // Then we are doing an array-indexed assignment + arrayIndexing = true; + } + /* If we have an identifier the a declaration is occuring */ + else if(getSymbolType(getCurrentToken()) == SymbolType.IDENT_TYPE) + { + /* Expect an identifier (CAN NOT be dotted) */ + expect(SymbolType.IDENT_TYPE, getCurrentToken()); + if(!isIdentifier_NoDot(getCurrentToken())) + { + expect("Identifier cannot be dotted"); + } + identifier = getCurrentToken().getToken(); + + nextToken(); + gprintln("ParseTypedDec: DecisionBtwn FuncDef/VarDef: " ~ getCurrentToken().getToken()); + } + /* Anything else is an error */ + else + { + expect("Either a identity or an assignment symbol is expected"); + } + + + /* Check if it is `(` (func dec) */ SymbolType symbolType = getSymbolType(getCurrentToken()); @@ -1528,7 +1641,7 @@ public final class Parser } } /* Check for `=` (var dec) */ - else if (symbolType == SymbolType.ASSIGN) + else if (symbolType == SymbolType.ASSIGN && (arrayIndexing == false)) { // Only continue if variable declarations are allowed if(allowVarDec) @@ -1564,6 +1677,47 @@ public final class Parser expect("Variables declarations are not allowed."); } } + /* Check for `=` (array indexed assignment) */ + else if (symbolType == SymbolType.ASSIGN && (arrayIndexing == true)) + { + // Set the token pointer back to the beginning + setCursor(arrayAssignTokenBeginPos); + gprintln("Looking at: "~to!(string)(getCurrentToken())); + + // TODO: Move all below code to the branch below that handles this case + gprintln("We have an array assignment, here is the indexers: "~to!(string)(arrayIndexExprs), DebugType.WARNING); + + // Our identifier will be some weird malformed-looking `mrArray[][1]` (because os atck array size declarations no-number literal) + // ... expressions don't make it in (we have arrayIndexExprs for that). Therefore what we must do is actually + // strip the array bracket syntax away to get the name + import std.string : indexOf; + long firstBracket = indexOf(type, "["); + assert(firstBracket > -1); + identifier = type[0..firstBracket]; + gprintln("Then identifier is type actually: "~identifier); + + + gprintln("We are still implenenting array assignments", DebugType.ERROR); + + ArrayIndex muhIndex = cast(ArrayIndex)parseExpression(); + gprintln("Expback: "~muhIndex.toString()); + + /* Expect a `=` and consume it */ + gprintln(getCurrentToken()); + expect(SymbolType.ASSIGN, getCurrentToken()); + nextToken(); + + /* Parse the expression being assigned followed by a semi-colon `;` */ + Expression expressionBeingAssigned = parseExpression(); + expect(SymbolType.SEMICOLON, getCurrentToken()); + + // TODO: Get the expression after the `=` + ArrayAssignment arrayAssignment = new ArrayAssignment(muhIndex, expressionBeingAssigned); + gprintln("Created array assignment: "~arrayAssignment.toString()); + // assert(false); + + generated = arrayAssignment; + } else { expect("Expected one of the following: (, ; or ="); @@ -1964,14 +2118,20 @@ public final class Parser // We now parse function definition but with `wantsBody` set to false // indicating no body should be allowed. - pseudoEntity = parseTypedDeclaration(false, false, true); + pseudoEntity = cast(TypedEntity)parseTypedDeclaration(false, false, true); + + // TODO: Add a check for this cast (AND parse wise if it is evan possible) + assert(pseudoEntity); } /* External variable symbol */ else if(externType == SymbolType.EXTERN_EVAR) { // We now parse a variable declaration but with the `wantsBody` set to false // indicating no assignment should be allowed. - pseudoEntity = parseTypedDeclaration(false, true, false); + pseudoEntity = cast(TypedEntity)parseTypedDeclaration(false, true, false); + + // TODO: Add a check for this cast (AND parse wise if it is evan possible) + assert(pseudoEntity); } /* Anything else is invalid */ else diff --git a/source/tlang/compiler/symbols/check.d b/source/tlang/compiler/symbols/check.d index 2fa77e7..d18c50c 100644 --- a/source/tlang/compiler/symbols/check.d +++ b/source/tlang/compiler/symbols/check.d @@ -58,6 +58,8 @@ public enum SymbolType SMALLER_THAN, GREATER_THAN_OR_EQUALS, SMALLER_THAN_OR_EQUALS, + OBRACKET, + CBRACKET, CAST, EXTERN, EXTERN_EFUNC, @@ -418,6 +420,16 @@ public SymbolType getSymbolType(Token tokenIn) { return SymbolType.CCURLY; } + /* Left-bracket checl */ + else if(token[0] == '[') + { + return SymbolType.OBRACKET; + } + /* Right-bracket check */ + else if(token[0] == ']') + { + return SymbolType.CBRACKET; + } /* Comma check */ else if (token[0] == ',') { diff --git a/source/tlang/compiler/symbols/data.d b/source/tlang/compiler/symbols/data.d index c2ef9da..a11d37b 100644 --- a/source/tlang/compiler/symbols/data.d +++ b/source/tlang/compiler/symbols/data.d @@ -458,6 +458,48 @@ public class VariableAssignmentStdAlone : Statement } } +// TODO: Add an ArrayAssignment thing here, would be similiar to PointerDeference +// mmmh, we would also need to ensure during typechecking/codegen/emit that we don't +// do pointer arithmetic. Makes sense we would have a ArrayAssign and expression for indexers +// but during codegen we check WHO was being assigned to and their type and based on that +// generate the correct INSTRUCTION +public final class ArrayAssignment : Statement +{ + private Expression assignmentExpression; + + /** + * The left hand side of: + * e.g. myArray[i][1] = 2; + * + * Therefore the `myArray[i][1]` part + */ + private ArrayIndex leftHandExpression; + + this(ArrayIndex leftHandExpression, Expression assignmentExpression) + { + this.leftHandExpression = leftHandExpression; + this.assignmentExpression = assignmentExpression; + + /* Weighted as 2 */ + weight = 2; + } + + public ArrayIndex getArrayLeft() + { + return leftHandExpression; + } + + public Expression getAssignmentExpression() + { + return assignmentExpression; + } + + public override string toString() + { + return "ArrayAssignment [leftHand: "~leftHandExpression.toString()~", assignmentExpr: "~assignmentExpression.toString()~"]"; + } +} + public class PointerDereferenceAssignment : Statement { diff --git a/source/tlang/compiler/symbols/expressions.d b/source/tlang/compiler/symbols/expressions.d index 2d62764..9e9ba2b 100644 --- a/source/tlang/compiler/symbols/expressions.d +++ b/source/tlang/compiler/symbols/expressions.d @@ -199,4 +199,34 @@ public final class CastedExpression : Expression { return uncastedExpression; } +} + +public final class ArrayIndex : Expression +{ + /* The expression to index of */ + private Expression indexInto; + + /* The expression used as the index */ + private Expression index; + + this(Expression indexInto, Expression index) + { + this.indexInto = indexInto; + this.index = index; + } + + public Expression getIndexed() + { + return indexInto; + } + + public Expression getIndex() + { + return index; + } + + public override string toString() + { + return "ArrayIndex [to: "~indexInto.toString()~", idx: "~index.toString()~"]"; + } } \ No newline at end of file diff --git a/source/tlang/compiler/symbols/typing/builtins.d b/source/tlang/compiler/symbols/typing/builtins.d index 271f576..85672a7 100644 --- a/source/tlang/compiler/symbols/typing/builtins.d +++ b/source/tlang/compiler/symbols/typing/builtins.d @@ -4,6 +4,7 @@ import tlang.compiler.symbols.typing.core; import std.string : cmp, indexOf, lastIndexOf; import gogga; import tlang.compiler.typecheck.core; +import std.conv : to; /** * TODO: We should write spec here like I want int and stuff of proper size so imma hard code em @@ -12,6 +13,8 @@ import tlang.compiler.typecheck.core; */ public Type getBuiltInType(TypeChecker tc, string typeString) { + gprintln("getBuiltInType("~typeString~")"); + /* `int`, signed (2-complement) */ if(cmp(typeString, "int") == 0) { @@ -75,36 +78,62 @@ public Type getBuiltInType(TypeChecker tc, string typeString) { return new Integer("ubyte", 1, false); } - - - /** - * FIXME: For the below we need to find which is the RIGHT-MOST and THEN - * go from there - * - * This is so that we can support things such as: - * - * `char*[]` - */ - - - /* Pointer handling `*` */ - else if(lastIndexOf(typeString, "*") > -1) + /* Stack-based array handling `[]` */ + else if(isStackArray(typeString)) { - long ptrTypePos = lastIndexOf(typeString, "*"); + // TODO: Construct this by dissecting `typeString` + StackArray stackArray; + + // Find the last occuring `[` + long lastOBracketPos = lastIndexOf(typeString, "["); + assert(lastOBracketPos > -1); + + // Find the component type (everything before `lastOBracketPos`) + string componentTypeString = typeString[0..lastOBracketPos]; + gprintln("StackArray (component type): "~componentTypeString); + + // Determine the size of the array (from `pos('[')+1` to typeString.length-2) + string arraySizeString = typeString[lastOBracketPos+1..$-1]; + ulong arraySize = to!(ulong)(arraySizeString); + gprintln("StackArray (stack size): "~to!(string)(arraySize)); + + + gprintln("typeString: "~typeString); + + stackArray = new StackArray(tc.getType(tc.getModule(), componentTypeString), arraySize); + + gprintln("Stack-based array types are still being implemented", DebugType.ERROR); + // assert(false); + return stackArray; + } + /* Pointer handling `*` and Array handling `*` */ + else if((lastIndexOf(typeString, "*") > -1) || (lastIndexOf(typeString, "[]") > -1)) + { + // Find the `*` (if any) + long starPos = lastIndexOf(typeString, "*"); + + // Find the `[]` (if any) + long brackPos = lastIndexOf(typeString, "[]"); + + // Determine which one is the rightmost + long rightmostTypePos; + if(starPos > brackPos) + { + rightmostTypePos = starPos; + } + else + { + rightmostTypePos = brackPos; + } + + long ptrTypePos = rightmostTypePos; string ptrType = typeString[0..(ptrTypePos)]; - gprintln("Pointer to '"~ptrType~"'"); + gprintln("TypeStr: "~typeString); + gprintln("Pointer to '"~ptrType~"'", DebugType.ERROR); return new Pointer(tc.getType(tc.getModule(), ptrType)); } - /* Array handling `[]` */ - else if(lastIndexOf(typeString, "[]") > -1) - { - long arrayTypePos = lastIndexOf(typeString, "[]"); - string arrayType = typeString[0..(arrayTypePos)]; - gprintln("Array of '"~arrayType~"'"); - - return new Array(tc.getType(tc.getModule(), arrayType)); - } + /* TODO: Add all remaining types, BUGS probabloy occur on failed looks ups when hitting this */ @@ -113,8 +142,36 @@ public Type getBuiltInType(TypeChecker tc, string typeString) { - + gprintln("getBuiltInType("~typeString~"): Failed to map to a built-in type", DebugType.ERROR); return null; } +} + +/** + * Given a type string this returns true if the provided + * type string is infact a stack array type + * + * Params: + * typeString = the type string to check + * Returns: a true if it is s atck array, false + * otherwise. + */ +private bool isStackArray(string typeString) +{ + // FIXME: THis below will be picked up by `int[]` before us + // e.g. int[][222] (a stack array of size 222 of `int[]` (a.k.a. `int*`)) + + // TODO: Also how will we fix: int[222][] which is int[222]*, ak..a a pojnter to a stack array of size 222 which + // ... is simply not a thing it would just be int[][] (int[]*) - irrespective of where the array is (on stack or heap) + + // TODO: Length check? Or parser would have caught? + + // Ensure `<...>[ ]` + if(typeString[$-1] == ']' && typeString[$-2] != '[') + { + return true; + } + + return false; } \ No newline at end of file diff --git a/source/tlang/compiler/symbols/typing/core.d b/source/tlang/compiler/symbols/typing/core.d index 188edfb..1ae7aa8 100644 --- a/source/tlang/compiler/symbols/typing/core.d +++ b/source/tlang/compiler/symbols/typing/core.d @@ -116,23 +116,32 @@ public class Pointer : Integer } /** -* Array type -* -* TODO: Might need investigation +* Stack-based Array type */ -public class Array : Type +public class StackArray : Type { + /* Size of the stack array to allocate */ + private ulong arraySize; + + /* Component type */ private Type elementType; - this(Type elementType) + this(Type elementType, ulong arraySize) { - /* The name should be `elementType[]` */ - - // super(name, ) - - /* TODO: Differentiate between stack arrays and heap */ - super(to!(string)(elementType)~"[]"); + /* The name should be `elementType[arraySize]` */ + super(to!(string)(elementType)~"["~to!(string)(arraySize)~"]"); this.elementType = elementType; + this.arraySize = arraySize; + } + + public Type getComponentType() + { + return elementType; + } + + public ulong getAllocatedSize() + { + return arraySize; } } \ No newline at end of file diff --git a/source/tlang/compiler/typecheck/core.d b/source/tlang/compiler/typecheck/core.d index e78863d..4519ac4 100644 --- a/source/tlang/compiler/typecheck/core.d +++ b/source/tlang/compiler/typecheck/core.d @@ -691,6 +691,95 @@ public final class TypeChecker } /** + * Determines whether the provided Value-instruction refers + * to a StackArray. This is used for array indexing checks, + * to disambiguate between pointer-arrays and stack-based + * arrays. + * + * Params: + * valInstr = the Value-based instruction to inspect + * Returns: true if the FetchValInstr refers to a stack-array, + * false otherwise + */ + private bool isStackArrayIndex(Value valInstr) + { + // TODO: Rename + Value indexToInstr = valInstr; + + /* We need a `FetchValueInstruction` as the first condition */ + FetchValueVar potFVV = cast(FetchValueVar)indexToInstr; + if(potFVV) + { + /** + * Obtain the array variable being referred to + * and obtain it's declared type + */ + Context potFVVCtx = potFVV.getContext(); + Variable potStackArrVar = cast(Variable)resolver.resolveBest(potFVVCtx.getContainer(), potFVV.varName); + Type variableDeclaredType = getType(potFVVCtx.getContainer(), potStackArrVar.getType()); + + /** + * If the type is `StackArray` + */ + if(cast(StackArray)variableDeclaredType) + { + return true; + } + } + + return false; + } + + /** + * Used to check if the type of the argument being passed into + * a function call is a stack array and if the function's parameter + * type is a pointer then this will check if the component type + * of the stack array is the same as that of the pointer + * + * Params: + * parameterType = the function's parameter typoe + * argumentType = the argument's type + * outputType = variable to place updated type into + * + * Returns: true if the so, false otherwise + */ + private bool canCoerceStackArray(Type parameterType, Type argumentType, ref Type outputType) + { + // If the argument being passed in is a stack array + if(cast(StackArray)argumentType) + { + StackArray stackArrayType = cast(StackArray)argumentType; + + // Get the component type of the stack array + Type stackArrCompType = stackArrayType.getComponentType(); + + // Now check if the parameter is a pointer type + if(cast(Pointer)parameterType) + { + Pointer parameterPointerCompType = cast(Pointer)parameterType; + + // Now create a new type for the stack array which is + // effectively * + Type stackArrayTypeCoerced = new Pointer(stackArrCompType); + outputType = stackArrayTypeCoerced; + + // If the coerced stack array's component type is the same as the pointer's component type + return isSameType(parameterPointerCompType, stackArrayTypeCoerced); + } + // If not, then return false immedtaiely + else + { + return false; + } + } + // If not, then immediately return false + else + { + return false; + } + } + + /** * Given two Value-based instructions this will firstly check if * at least one of the two is of type Pointer, then checks if the * remaining instruction is an of type Integer - the remaining instruction @@ -1112,6 +1201,9 @@ public final class TypeChecker // gprintln("FuncCall(Formal): "~parmType.getName()); // gprintln("FuncCall(Actual): "~valueInstr.toString()); + /* Scratch type used only for stack-array coercion */ + Type coercionScratchType; + /* Match up types */ //if(argType == parmType) @@ -1123,6 +1215,22 @@ public final class TypeChecker funcCallInstr.setEvalInstr(parmCount, valueInstr); gprintln(funcCallInstr.getEvaluationInstructions()); } + /* Stack-array argument to pointer parameter coercion check */ + else if(canCoerceStackArray(parmType, argType, coercionScratchType)) + { + // TODO: Add stack coercion check here + gprintln("Stack-based array has been coerced for function call"); + + // Update the fetch-var instruction's type to the coerced + // TODO: Should we have applied this technically earlier then fallen through to + // ... the branch above? That would have worked and been neater - we should do + // ... that to avoid duplicating any code + valueInstr.setInstrType(coercionScratchType); + + /* Add the instruction into the FunctionCallInstr */ + funcCallInstr.setEvalInstr(parmCount, valueInstr); + gprintln(funcCallInstr.getEvaluationInstructions()); + } else { printCodeQueue(); @@ -1203,6 +1311,125 @@ public final class TypeChecker /* The type of the cats expression is that of the type it casts to */ castedValueInstruction.setInstrType(castToType); } + /* ArrayIndex */ + else if(cast(ArrayIndex)statement) + { + ArrayIndex arrayIndex = cast(ArrayIndex)statement; + Type accessType; + + /* Pop the thing being indexed (the indexTo expression) */ + Value indexToInstr = cast(Value)popInstr(); + Type indexToType = indexToInstr.getInstrType(); + assert(indexToType); + gprintln("ArrayIndex: Type of `indexToInstr`: "~indexToType.toString()); + + /* Pop the index instruction (the index expression) */ + Value indexInstr = cast(Value)popInstr(); + Type indexType = indexInstr.getInstrType(); + assert(indexType); + + + // TODO: Type check here the `indexToInstr` ensure that it is an array + // TODO: Type check the indexInstr and ensure it is an integral type (index can not be anything else) + + // TODO: We need iets different for stack-arrays here + + + + /* Final Instruction generated */ + Instruction generatedInstruction; + + + // // TODO: We need to add a check here for if the `arrayRefInstruction` is a name + // // ... and if so if its type is `StackArray`, else we will enter the wrong thing below + + // TODO: Look up based on the name of the `FetchValueInstruction` (so if it is) + // ... AND if it refers to a stack array + bool isStackArray = isStackArrayIndex(indexToInstr); + gprintln("isStackArray (being indexed-on)?: "~to!(string)(isStackArray), DebugType.ERROR); + + + + // /* The type of what is being indexed on */ + // Type indexingOnType = arrayRefInstruction.getInstrType(); + // gprintln("Indexing-on type: "~indexingOnType.toString(), DebugType.WARNING); + + + /* Stack-array type `[]` */ + if(isStackArray) + { + StackArray stackArray = cast(StackArray)indexToType; + accessType = stackArray.getComponentType(); + gprintln("ArrayIndex: Stack-array access"); + + + gprintln("<<<<<<<< STCK ARRAY INDEX CODE GEN >>>>>>>>", DebugType.ERROR); + + + + /** + * Codegen and type checking + * + * 1. Set the type (TODO) + * 2. Set the context (TODO) + */ + StackArrayIndexInstruction stackArrayIndexInstr = new StackArrayIndexInstruction(indexToInstr, indexInstr); + stackArrayIndexInstr.setInstrType(accessType); + stackArrayIndexInstr.setContext(arrayIndex.context); + + gprintln("IndexTo: "~indexToInstr.toString(), DebugType.ERROR); + gprintln("Index: "~indexInstr.toString(), DebugType.ERROR); + gprintln("Stack ARray type: "~stackArray.getComponentType().toString(), DebugType.ERROR); + + + + // assert(false); + generatedInstruction = stackArrayIndexInstr; + } + /* Array type `[]` */ + else if(cast(Pointer)indexToType) + { + gprintln("ArrayIndex: Pointer access"); + + Pointer pointer = cast(Pointer)indexToType; + accessType = pointer.getReferredType(); + + /** + * Codegen and type checking + * + * 1. Embed the index instruction and indexed-to instruction + * 2. Set the type of this instruction to the type of the array's component type + * 3. (TODO) Set the context + */ + ArrayIndexInstruction arrayIndexInstr = new ArrayIndexInstruction(indexToInstr, indexInstr); + arrayIndexInstr.setInstrType(accessType); + + generatedInstruction = arrayIndexInstr; + } + else + { + // TODO: Throw an error here + // throw new TypeMismatchException() + gprintln("Indexing to an entity other than a stack array or pointer!", DebugType.ERROR); + assert(false); + } + + + + // TODO: context (arrayIndex) + + gprintln("ArrayIndex: [toInstr: "~indexToInstr.toString()~", indexInstr: "~indexInstr.toString()~"]"); + + gprintln("Array index not yet supported", DebugType.ERROR); + // assert(false); + + addInstr(generatedInstruction); + } + else + { + gprintln("This ain't it chief", DebugType.ERROR); + assert(false); + } } /* VariableAssigbmentDNode */ else if(cast(tlang.compiler.typecheck.dependency.variables.VariableAssignmentNode)dnode) @@ -1634,6 +1861,129 @@ public final class TypeChecker discardInstruction.setContext(discardStatement.context); addInstrB(discardInstruction); } + /** + * Array assignments (ArrayAssignment) + */ + else if(cast(ArrayAssignment)statement) + { + ArrayAssignment arrayAssignment = cast(ArrayAssignment)statement; + + gprintln("Note, dependency processing of ArrayAssignment is not yet implemented, recall seggy", DebugType.ERROR); + printCodeQueue(); + + // TODO: We need to implement this, what should we put here + // ... we also should be setting the correct types if need be + + /** + * At this point the code queue top of stack should look like this + * (as a requirement for Array assignments) (top-to-bottom) + * + * 1. Index instruction + * 2. Array name instruction + * 3. Assigment expression instruction + */ + Value indexInstruction = cast(Value)popInstr(); + + + // FIXME: Actually this may not always be the case, the name fetching makes sense + // ... for stack arrays but not pointer ones where the arrayRef may be generated + // ... from something else. + Value arrayRefInstruction = cast(Value)popInstr(); + Value assignmentInstr = cast(Value)popInstr(); + + gprintln("indexInstruction: "~indexInstruction.toString(), DebugType.WARNING); + gprintln("arrayRefInstruction: "~arrayRefInstruction.toString(), DebugType.WARNING); + gprintln("assignmentInstr: "~assignmentInstr.toString(), DebugType.WARNING); + + + /* Final Instruction generated */ + Instruction generatedInstruction; + + + // TODO: We need to add a check here for if the `arrayRefInstruction` is a name + // ... and if so if its type is `StackArray`, else we will enter the wrong thing below + bool isStackArray = isStackArrayIndex(arrayRefInstruction); + gprintln("isStackArray (being assigned to)?: "~to!(string)(isStackArray), DebugType.ERROR); + + + + /* The type of what is being indexed on */ + Type indexingOnType = arrayRefInstruction.getInstrType(); + gprintln("Indexing-on type: "~indexingOnType.toString(), DebugType.WARNING); + gprintln("Indexing-on type: "~indexingOnType.classinfo.toString(), DebugType.WARNING); + + + /* Stack-array type `[]` */ + if(isStackArray) + { + // TODO: Crashing here currently with `simple_stack_arrays2.t` + // gprint("arrayRefInstruction: "); + // gprintln(arrayRefInstruction); + + // StackArrayIndexInstruction stackArrayIndex = cast(StackArrayIndexInstruction)arrayRefInstruction; + + FetchValueVar arrayFetch = cast(FetchValueVar)arrayRefInstruction; + + /** + * Hoist out the declared stack array variable + */ + Context stackVarContext = arrayFetch.getContext(); + assert(stackVarContext); //TODO: We must set the Context when we make the `StackArrayIndexInstruction` + + Variable arrayVariable = cast(Variable)resolver.resolveBest(stackVarContext.container, arrayFetch.varName); + Type arrayVariableDeclarationType = getType(stackVarContext.container, arrayVariable.getType()); + + gprintln("TODO: We are still working on generating an assignment instruction for assigning to stack arrays", DebugType.ERROR); + gprintln("TODO: Implement instruction generation for stack-based arrays", DebugType.ERROR); + + // TODO: Use StackArrayIndexAssignmentInstruction + StackArrayIndexAssignmentInstruction stackAssignmentInstr = new StackArrayIndexAssignmentInstruction(arrayFetch.varName, indexInstruction, assignmentInstr); + + // TODO: See issue on `Stack-array support` for what to do next + // assert(false); + generatedInstruction = stackAssignmentInstr; + + // TODO: Set context + /* Set the context */ + stackAssignmentInstr.setContext(arrayAssignment.getContext()); + + + gprintln(">>>>> "~stackAssignmentInstr.toString()); + gprintln("Assigning into this array: "~to!(string)(assignmentInstr)); + // assert(false); + } + /* Array type `[]` */ + else if(cast(Pointer)indexingOnType) + { + // TODO: Update this and don't use pointer dereference assignment + /** + * Create a new pointer dereference assignment instruction + * + * 1. The deref is level 1 (as array index == one `*`) + * 2. The left-hand side is to be `new ArrayIndexInstruction(arrayRefInstruction, indexInstruction)` + * 3. Assignment expression is to be `assignmentInstr` + */ + // NOTE: We couple arrBasePtr+offset (index) using an ArrayIndexInstruction (optimization/code-reuse) + ArrayIndexInstruction arrIndex = new ArrayIndexInstruction(arrayRefInstruction, indexInstruction); + ArrayIndexAssignmentInstruction arrDerefAssInstr = new ArrayIndexAssignmentInstruction(arrIndex, assignmentInstr); + + gprintln("TODO: Implement instruction generation for pointer-based arrays", DebugType.ERROR); + generatedInstruction = arrDerefAssInstr; + // assert(false); + + // TODO: Set context + } + // TODO: handle this error (if even possible?) + else + { + assert(false); + } + + assert(generatedInstruction !is null); + + /* Add the instruction */ + addInstrB(generatedInstruction); + } /* Case of no matches */ else { diff --git a/source/tlang/compiler/typecheck/dependency/core.d b/source/tlang/compiler/typecheck/dependency/core.d index 9182fdf..ddca33f 100644 --- a/source/tlang/compiler/typecheck/dependency/core.d +++ b/source/tlang/compiler/typecheck/dependency/core.d @@ -1156,6 +1156,31 @@ public class DNodeGenerator dnode.needs(uncastedExpressionDNode); } + /** + * Array indexing (ArrayIndex) + */ + else if(cast(ArrayIndex)exp) + { + gprintln("Working on expressionPass'ing of ArrayIndex", DebugType.ERROR); + + ArrayIndex arrayIndex = cast(ArrayIndex)exp; + + // Set the context as we need to grab it later in the typechecker + arrayIndex.context = context; + + /* The index's expression */ + Expression indexExp = arrayIndex.getIndex(); + DNode indexExpDNode = expressionPass(indexExp, context); + dnode.needs(indexExpDNode); + + /* The thing being indexeds' expression */ + Expression indexedExp = arrayIndex.getIndexed(); + DNode indexedExpDNode = expressionPass(indexedExp, context); + dnode.needs(indexedExpDNode); + + + // assert(false); + } else { // dnode = new DNode(this, exp); @@ -1266,11 +1291,41 @@ public class DNodeGenerator else if(cast(Struct)variableType) { + } + /* Stack-based array-type */ + else if(cast(StackArray)variableType) + { + // TODO: For array support not all too sure what I shoudl put here, perhap nothing? + StackArray arrayType = cast(StackArray)variableType; + + // TODO: We might need to do pointer magic + + // (TODO) Check component type + Type componentType = arrayType.getComponentType(); + + // If the component type is a primitive type + if(cast(Primitive)componentType) + { + /* Do nothing (I presume?) */ + } + // If not + else + { + // TODO: Add more advanced handling here + gprintln("Advanced component types l;ike arrays of arrays or arrays of classes etc not yet supported", DebugType.ERROR); + assert(false); + } + + gprintln("Arrays (and these are stack arrays) are not yet supported", DebugType.ERROR); + // assert(false); } /* Anything else */ else { /* This should never happen */ + gprintln(variableType); + gprintln(variableType.classinfo); + gprintln("#ThisShouldNeverHappen Fault: A variable declaration with a kind-of type we don't know", DebugType.ERROR); assert(false); } @@ -1341,6 +1396,46 @@ public class DNodeGenerator } } /** + * Array assignments + */ + else if(cast(ArrayAssignment)entity) + { + ArrayAssignment arrayAssignment = cast(ArrayAssignment)entity; + arrayAssignment.setContext(context); + DNode arrayAssDerefDNode = pool(arrayAssignment); + + /* Pass the expression to be assigned */ + Expression assignedExpression = arrayAssignment.getAssignmentExpression(); + DNode assignmentExpressionDNode = expressionPass(assignedExpression, context); + arrayAssDerefDNode.needs(assignmentExpressionDNode); + + /** + * Extract the ArrayIndex expression + * + * This consists of two parts (e.g. `myArray[i]`): + * + * 1. The indexTo `myArray` + * 2. The index `i` + */ + ArrayIndex arrayIndexExpression = arrayAssignment.getArrayLeft(); + Expression indexTo = arrayIndexExpression.getIndexed(); + Expression index = arrayIndexExpression.getIndex(); + + DNode indexToExpression = expressionPass(indexTo, context); + arrayAssDerefDNode.needs(indexToExpression); + + DNode indexExpression = expressionPass(index, context); + arrayAssDerefDNode.needs(indexExpression); + + + + + gprintln("Please implement array assignment dependency generation", DebugType.ERROR); + // assert(false); + + return arrayAssDerefDNode; + } + /** * Function definitions */ else if(cast(Function)entity) diff --git a/source/tlang/testing/complex_stack_array_coerce.t b/source/tlang/testing/complex_stack_array_coerce.t new file mode 100644 index 0000000..01ad4ff --- /dev/null +++ b/source/tlang/testing/complex_stack_array_coerce.t @@ -0,0 +1,21 @@ +module complex_stack_array_coerce; + +int val1; +int val2; + +void coerce(int** in) +{ + in[0][0] = 69; + in[1][0] = 420; +} + +int function() +{ + int[][2] stackArr; + stackArr[0] = &val1; + stackArr[1] = &val2; + + discard coerce(stackArr); + + return val1+val2; +} \ No newline at end of file diff --git a/source/tlang/testing/complex_stack_array_coerce_bad1.t b/source/tlang/testing/complex_stack_array_coerce_bad1.t new file mode 100644 index 0000000..2583d0e --- /dev/null +++ b/source/tlang/testing/complex_stack_array_coerce_bad1.t @@ -0,0 +1,17 @@ +module complex_stack_array_coerce_bad1; + +int val1; +int val2; + +void coerce_bad1(int* in) {} + +int function() +{ + int[][2] stackArr; + stackArr[0] = &val1; + stackArr[1] = &val2; + + discard coerce_bad1(stackArr); + + return val1+val2; +} \ No newline at end of file diff --git a/source/tlang/testing/complex_stack_array_coerce_bad2.t b/source/tlang/testing/complex_stack_array_coerce_bad2.t new file mode 100644 index 0000000..1107e18 --- /dev/null +++ b/source/tlang/testing/complex_stack_array_coerce_bad2.t @@ -0,0 +1,17 @@ +module complex_stack_array_coerce_bad2; + +int val1; +int val2; + +void coerce_bad2(int*** in) {} + +int function() +{ + int[][2] stackArr; + stackArr[0] = &val1; + stackArr[1] = &val2; + + discard coerce_bad2(stackArr); + + return val1+val2; +} \ No newline at end of file diff --git a/source/tlang/testing/complex_stack_array_coerce_bad3.t b/source/tlang/testing/complex_stack_array_coerce_bad3.t new file mode 100644 index 0000000..252e542 --- /dev/null +++ b/source/tlang/testing/complex_stack_array_coerce_bad3.t @@ -0,0 +1,17 @@ +module complex_stack_array_coerce_bad3; + +int val1; +int val2; + +void coerce_bad3(int in) {} + +int function() +{ + int[][2] stackArr; + stackArr[0] = &val1; + stackArr[1] = &val2; + + discard coerce_bad3(stackArr); + + return val1+val2; +} \ No newline at end of file diff --git a/source/tlang/testing/complex_stack_array_coerce_permutation_good.t b/source/tlang/testing/complex_stack_array_coerce_permutation_good.t new file mode 100644 index 0000000..77dc2e4 --- /dev/null +++ b/source/tlang/testing/complex_stack_array_coerce_permutation_good.t @@ -0,0 +1,23 @@ +module complex_stack_array_coerce_permutation_good; + +int val1; +int val2; + +void coerce_good1(int** in) {} +void coerce_good2(int[][] in) {} +void coerce_good3(int[]* in) {} +void coerce_good4(int*[] in) {} + +int function() +{ + int[][2] stackArr; + stackArr[0] = &val1; + stackArr[1] = &val2; + + discard coerce_good1(stackArr); + discard coerce_good2(stackArr); + discard coerce_good3(stackArr); + discard coerce_good4(stackArr); + + return val1+val2; +} \ No newline at end of file diff --git a/source/tlang/testing/complex_stack_arrays1.t b/source/tlang/testing/complex_stack_arrays1.t new file mode 100644 index 0000000..063fa42 --- /dev/null +++ b/source/tlang/testing/complex_stack_arrays1.t @@ -0,0 +1,9 @@ +module complex_stack_arrays1; + +void function() +{ + int[][22222] myArray; + + int i = 2; + myArray[2][i] = 1 + myArray[2][i]; +} \ No newline at end of file diff --git a/source/tlang/testing/simple_arrays.t b/source/tlang/testing/simple_arrays.t new file mode 100644 index 0000000..e0d23e0 --- /dev/null +++ b/source/tlang/testing/simple_arrays.t @@ -0,0 +1,6 @@ +module simple_arrays; + +void function() +{ + int[][22222] myArray; +} \ No newline at end of file diff --git a/source/tlang/testing/simple_arrays2.t b/source/tlang/testing/simple_arrays2.t new file mode 100644 index 0000000..c249f94 --- /dev/null +++ b/source/tlang/testing/simple_arrays2.t @@ -0,0 +1,12 @@ +module simple_arrays2; + +void function() +{ + int*[] myArray1; + int[]* myArray2; + + myArray2 = cast(int[]*)myArray2; + myArray2 = cast(int[][])myArray2; + myArray2 = cast(int**)myArray2; + myArray2 = cast(int*[])myArray2; +} \ No newline at end of file diff --git a/source/tlang/testing/simple_arrays4.t b/source/tlang/testing/simple_arrays4.t new file mode 100644 index 0000000..b4e9a24 --- /dev/null +++ b/source/tlang/testing/simple_arrays4.t @@ -0,0 +1,8 @@ +module simple_arrays4; + +void function() +{ + int[] myArray; + int i = 2; + myArray[i] = myArray[1]+2; +} \ No newline at end of file diff --git a/source/tlang/testing/simple_pointer_array_syntax.t b/source/tlang/testing/simple_pointer_array_syntax.t new file mode 100644 index 0000000..a2b1c95 --- /dev/null +++ b/source/tlang/testing/simple_pointer_array_syntax.t @@ -0,0 +1,17 @@ +module simple_pointer_array_syntax; + +int j; + +int function(int[] ptr) +{ + *(ptr+0) = 2+2; + return (*ptr)+1*2; +} + +int thing() +{ + int discardExpr = function(&j); + int** l; + + return discardExpr; +} \ No newline at end of file diff --git a/source/tlang/testing/simple_stack_array_coerce.t b/source/tlang/testing/simple_stack_array_coerce.t new file mode 100644 index 0000000..7b896bf --- /dev/null +++ b/source/tlang/testing/simple_stack_array_coerce.t @@ -0,0 +1,15 @@ +module simple_stack_array_coerce; + +void coerce(int* in) +{ + in[0] = 69; + in[1] = 420; +} + +int function() +{ + int[2] stackArr; + discard coerce(stackArr); + + return stackArr[0]+stackArr[1]; +} \ No newline at end of file diff --git a/source/tlang/testing/simple_stack_array_coerce_ptr_syntax.t b/source/tlang/testing/simple_stack_array_coerce_ptr_syntax.t new file mode 100644 index 0000000..c17c990 --- /dev/null +++ b/source/tlang/testing/simple_stack_array_coerce_ptr_syntax.t @@ -0,0 +1,15 @@ +module simple_stack_array_coerce_ptr_syntax; + +void coerce(int* in) +{ + *(in+0) = 69; + *(in+1) = 420; +} + +int function() +{ + int[2] stackArr; + discard coerce(stackArr); + + return stackArr[0]+stackArr[1]; +} \ No newline at end of file diff --git a/source/tlang/testing/simple_stack_array_coerce_wrong.t b/source/tlang/testing/simple_stack_array_coerce_wrong.t new file mode 100644 index 0000000..554f2ed --- /dev/null +++ b/source/tlang/testing/simple_stack_array_coerce_wrong.t @@ -0,0 +1,15 @@ +module simple_stack_array_coerce_wrong; + +void coerce(int** in) +{ + in[0] = 69; + in[1] = 420; +} + +int function() +{ + int[2] stackArr; + discard coerce(stackArr); + + return stackArr[0]+stackArr[1]; +} \ No newline at end of file diff --git a/source/tlang/testing/simple_stack_arrays2.t b/source/tlang/testing/simple_stack_arrays2.t new file mode 100644 index 0000000..4591f8c --- /dev/null +++ b/source/tlang/testing/simple_stack_arrays2.t @@ -0,0 +1,9 @@ +module simple_stack_arrays2; + +void function() +{ + int[22222] myArray; + + int i = 2; + myArray[i] = 1; +} \ No newline at end of file diff --git a/source/tlang/testing/simple_stack_arrays3.t b/source/tlang/testing/simple_stack_arrays3.t new file mode 100644 index 0000000..aedc221 --- /dev/null +++ b/source/tlang/testing/simple_stack_arrays3.t @@ -0,0 +1,11 @@ +module simple_stack_arrays3; + +void function() +{ + int[][22222] myArray; + + int[2][2] myArray2; + + int i = 2; + myArray[i][i] = 69; +} \ No newline at end of file diff --git a/source/tlang/testing/simple_stack_arrays4.t b/source/tlang/testing/simple_stack_arrays4.t new file mode 100644 index 0000000..d3810d2 --- /dev/null +++ b/source/tlang/testing/simple_stack_arrays4.t @@ -0,0 +1,12 @@ +module simple_stack_arrays4; + +int function() +{ + int[22222] myArray; + + int i = 2; + myArray[i] = 60; + myArray[2] = myArray[i]+1; + + return myArray[2]; +} \ No newline at end of file diff --git a/wip.txt b/wip.txt new file mode 100644 index 0000000..ea211f7 --- /dev/null +++ b/wip.txt @@ -0,0 +1,10 @@ +Arrays support + +1. Todo: Add expression support for int k = `myArray[1+1]`; (for example) +2. COntinue working on indexer support +3. How would we process: + ``` + myArray[i][1] + + We should take the [`i`, `1`] and produce a nested assignment expression + ``` \ No newline at end of file