From d548a066a63add60c2d587a8ad42ef04cd685e5c Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Sat, 28 Jan 2023 18:12:49 +0200 Subject: [PATCH] Check - Corrected import path for `compiler.lexer` -> `compiler.lexer.core` Parser - Corrected import path for `compiler.lexer` -> `compiler.lexer.core` TypeChecker - Corrected import path for `compiler.lexer` -> `compiler.lexer.core` Compiler - Moved configuration code outside of it - Renamed to `compiler.core` DGen - Check for any object files to link in, if so append them to the `cc` call Lexer - Moved from `compiler.lexer` to `compiler.lexer.core` Configuration - Overhauled configuration system Mapper - Added definition to `SymbolMappingTechnique` Command-line - Migrated to new configuration system - Migrated `SymbolMappingTechnique` to Mapper module - Added support for specifying object fils to link in using the `-ll` flag` Tests - Added `file_io.c` for testing `simple_extern.t` with `extern_test.sh` - Added `extern_test.sh` for testing `simple_extern.t` --- extern_test.sh | 13 ++ source/tlang/commandline/commands.d | 26 ++- source/tlang/compiler/codegen/emit/core.d | 2 +- source/tlang/compiler/codegen/emit/dgen.d | 22 +- source/tlang/compiler/codegen/mapper/core.d | 6 + source/tlang/compiler/configuration.d | 202 +++++++++++++++++++ source/tlang/compiler/{compiler.d => core.d} | 65 ++---- source/tlang/compiler/{ => lexer}/lexer.d | 2 +- source/tlang/compiler/parsing/core.d | 18 +- source/tlang/compiler/parsing/exceptions.d | 3 +- source/tlang/compiler/symbols/check.d | 2 +- source/tlang/compiler/typecheck/core.d | 14 +- source/tlang/testing/file_io.c | 8 + source/tlang/testing/simple_extern.t | 10 +- 14 files changed, 299 insertions(+), 94 deletions(-) create mode 100755 extern_test.sh create mode 100644 source/tlang/compiler/configuration.d rename source/tlang/compiler/{compiler.d => core.d} (86%) rename source/tlang/compiler/{ => lexer}/lexer.d (99%) create mode 100644 source/tlang/testing/file_io.c diff --git a/extern_test.sh b/extern_test.sh new file mode 100755 index 0000000..bffee6d --- /dev/null +++ b/extern_test.sh @@ -0,0 +1,13 @@ +#1/bin/sh + +# Compile C to object file as library to link in +gcc source/tlang/testing/file_io.c -c -o file_io.o + +# Compile T to C, then compile C and link with other object file into a final object file +./tlang compile source/tlang/testing/simple_extern.t -sm HASHMAPPER -et true -pg true -ll file_io.o + +# Run the tlang file +./tlang.out + +# Run (with strace) to see it +strace -e trace=write ./tlang.out diff --git a/source/tlang/commandline/commands.d b/source/tlang/commandline/commands.d index 4efcb22..d57ffe0 100644 --- a/source/tlang/commandline/commands.d +++ b/source/tlang/commandline/commands.d @@ -8,22 +8,18 @@ module commandline.commands; import jcli; import std.stdio; -import compiler.compiler : beginCompilation; import misc.exceptions : TError; import std.exception : ErrnoException; -import compiler.lexer : Lexer, Token; +import compiler.lexer.core : Lexer, Token; import compiler.parsing.core : Parser; import compiler.typecheck.core : TypeChecker; import gogga; -import compiler.compiler : Compiler; +import compiler.core : Compiler, beginCompilation; +import compiler.configuration : ConfigEntry; import std.conv : to; -//TODO: Re-order the definitions below so that they appear with compile first, then lex, parse, ..., help +import compiler.codegen.mapper.core : SymbolMappingTechnique; -public enum SymbolMappingTechnique -{ - hashmapper, - lebanese -} +//TODO: Re-order the definitions below so that they appear with compile first, then lex, parse, ..., help public enum VerbosityLevel { @@ -49,7 +45,7 @@ mixin template BaseCommand() void BaseCommandInit(Compiler compiler) { // Set the verbosity level - compiler.getConfig().setConfig("verbosity", debugLevel); + compiler.getConfig().addConfig(ConfigEntry("verbosity", debugLevel)); } } @@ -80,20 +76,22 @@ mixin template EmitBase() @ArgNamed("library-link|ll", "Paths to any object files to ,ink in during the linking phase") @(ArgConfig.optional) @(ArgConfig.aggregate) - string[] bruh; } void EmitBaseInit(Compiler compiler) { // Set the symbol mapper technique - compiler.getConfig().setConfig("emit:mapper", symbolTechnique); + compiler.getConfig().addConfig(ConfigEntry("emit:mapper", symbolTechnique)); // Set whether pretty-printed code should be generated - compiler.getConfig().setConfig("dgen:pretty_code", prettyPrintCodeGen); + compiler.getConfig().addConfig(ConfigEntry("dgen:pretty_code", prettyPrintCodeGen)); // Set whether or not to enable the entry point testing code - compiler.getConfig().setConfig("dgen:emit_entrypoint_test", entrypointTestEmit); + compiler.getConfig().addConfig(ConfigEntry("dgen:emit_entrypoint_test", entrypointTestEmit)); + + // Set the paths to the object files to link in + compiler.getConfig().addConfig(ConfigEntry("linker:link_files", bruh)); } } diff --git a/source/tlang/compiler/codegen/emit/core.d b/source/tlang/compiler/codegen/emit/core.d index a189884..b71e3b1 100644 --- a/source/tlang/compiler/codegen/emit/core.d +++ b/source/tlang/compiler/codegen/emit/core.d @@ -10,7 +10,7 @@ import compiler.codegen.instruction : Instruction; import std.range : walkLength; import gogga; import std.conv : to; -import compiler.compiler : CompilerConfiguration; +import compiler.configuration : CompilerConfiguration; import compiler.codegen.mapper.core : SymbolMapper; /** diff --git a/source/tlang/compiler/codegen/emit/dgen.d b/source/tlang/compiler/codegen/emit/dgen.d index 502530b..48dbc27 100644 --- a/source/tlang/compiler/codegen/emit/dgen.d +++ b/source/tlang/compiler/codegen/emit/dgen.d @@ -18,7 +18,7 @@ import compiler.symbols.data : SymbolType, Variable, Function, VariableParameter import compiler.symbols.check : getCharacter; import misc.utils : Stack; import compiler.symbols.typing.core : Type, Primitive, Integer, Void, Pointer; -import compiler.compiler : CompilerConfiguration; +import compiler.configuration : CompilerConfiguration; public final class DCodeEmitter : CodeEmitter { @@ -41,7 +41,7 @@ public final class DCodeEmitter : CodeEmitter string tabStr; /* Only generate tabs if enabled in compiler config */ - if(config.getConfig!(bool)("dgen:pretty_code")) + if(config.getConfig("dgen:pretty_code").getBoolean()) { for(ulong i = 0; i < count; i++) { @@ -554,7 +554,7 @@ public final class DCodeEmitter : CodeEmitter // If enabled (default: yes) then emit entry point (TODO: change later) - if(config.getConfig!(bool)("dgen:emit_entrypoint_test")) + if(config.getConfig("dgen:emit_entrypoint_test").getBoolean()) { //TODO: Emit main (entry point) emitEntryPoint(); @@ -878,7 +878,21 @@ int main() try { //NOTE: Change to system compiler (maybe, we need to choose a good C compiler) - Pid ccPID = spawnProcess(["clang", "-o", "tlang.out", file.name()]); + 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); int code = wait(ccPID); diff --git a/source/tlang/compiler/codegen/mapper/core.d b/source/tlang/compiler/codegen/mapper/core.d index 4dd7868..b608929 100644 --- a/source/tlang/compiler/codegen/mapper/core.d +++ b/source/tlang/compiler/codegen/mapper/core.d @@ -22,4 +22,10 @@ public class SymbolMapper } public abstract string symbolLookup(Entity entityIn); +} + +public enum SymbolMappingTechnique : string +{ + HASHMAPPER = "hashmapper", + LEBANESE = "lebanese" } \ No newline at end of file diff --git a/source/tlang/compiler/configuration.d b/source/tlang/compiler/configuration.d new file mode 100644 index 0000000..fc6eeb7 --- /dev/null +++ b/source/tlang/compiler/configuration.d @@ -0,0 +1,202 @@ +module compiler.configuration; + +import compiler.core : CompilerException, CompilerError; +import std.string : cmp; + +private union ConfigValue +{ + ulong number; + bool boolean; + string text; + string[] textArray; +} + +public enum ConfigType +{ + NUMBER, + BOOLEAN, + TEXT, + TEXT_ARRAY +} + +public struct ConfigEntry +{ + private string name; + private ConfigValue value; + private ConfigType type; + + private this(string entryName, ConfigType entryType) + { + this.name = entryName; + this.type = entryType; + } + + this(VType)(string entryName, VType valType) + { + this(entryName, ConfigType.TEXT); + value.text = to!(string)(valType); + } + + this(string entryName, ulong entryValue) + { + this(entryName, ConfigType.NUMBER); + value.number = entryValue; + } + + this(string entryName, bool entryValue) + { + this(entryName, ConfigType.BOOLEAN); + value.boolean = entryValue; + } + + this(string entryName, string entryValue) + { + this(entryName, ConfigType.TEXT); + value.text = entryValue; + } + + this(string entryName, string[] entryValue) + { + this(entryName, ConfigType.TEXT_ARRAY); + value.textArray = entryValue; + } + + public ulong getNumber() + { + if(type == ConfigType.NUMBER) + { + return value.number; + } + else + { + throw new CompilerException(CompilerError.CONFIG_TYPE_ERROR, "Type mismatch for key '"~name~"'"); + } + } + + public bool getBoolean() + { + if(type == ConfigType.BOOLEAN) + { + return value.boolean; + } + else + { + throw new CompilerException(CompilerError.CONFIG_TYPE_ERROR, "Type mismatch for key '"~name~"'"); + } + } + + public string getText() + { + if(type == ConfigType.TEXT) + { + return value.text; + } + else + { + throw new CompilerException(CompilerError.CONFIG_TYPE_ERROR, "Type mismatch for key '"~name~"'"); + } + } + + public string[] getArray() + { + if(type == ConfigType.TEXT_ARRAY) + { + return value.textArray; + } + else + { + throw new CompilerException(CompilerError.CONFIG_TYPE_ERROR, "Type mismatch for key '"~name~"'"); + } + } + + public string getName() + { + return name; + } + + public ConfigType getType() + { + return type; + } + +} + +/** + * TODO: Add a union and then also a get funciton that + * interprets per each for us (using templatescan be automated + * maybe) + * Implement this! + */ +/** + * TODO: Implement a union below as the value + * of tye key-value pair + */ +public class CompilerConfiguration +{ + private ConfigEntry[] entries; + + public void addConfig(ConfigEntry entry) + { + // If duplicate then update entry + if(hasConfig(entry.getName())) + { + updateConfig(entry); + } + // Else, add a new entry + else + { + entries ~= entry; + } + } + + private void updateConfig(ConfigEntry newEntry) + { + for(ulong i = 0; i < entries.length; i++) + { + if(cmp(entries[i].getName(), newEntry.getName()) == 0) + { + if(entries[i].getType() == newEntry.getType()) + { + entries[i] = newEntry; + break; + } + else + { + throw new CompilerException(CompilerError.CONFIG_TYPE_ERROR, "Tried updating an entry to a different type"); + } + } + } + } + + public ConfigEntry getConfig(string key) + { + ConfigEntry foundEntry; + if(hasConfig_internal(key, foundEntry)) + { + return foundEntry; + } + else + { + throw new CompilerException(CompilerError.CONFIG_KEY_NOT_FOUND); + } + } + + private bool hasConfig_internal(string key, ref ConfigEntry foundEntry) + { + foreach(ConfigEntry curEntry; entries) + { + if(cmp(curEntry.getName(), key) == 0) + { + foundEntry = curEntry; + return true; + } + } + return false; + } + + public bool hasConfig(string key) + { + ConfigEntry _discard; + return hasConfig_internal(key, _discard); + } +} \ No newline at end of file diff --git a/source/tlang/compiler/compiler.d b/source/tlang/compiler/core.d similarity index 86% rename from source/tlang/compiler/compiler.d rename to source/tlang/compiler/core.d index 0714413..ae3c6a4 100644 --- a/source/tlang/compiler/compiler.d +++ b/source/tlang/compiler/core.d @@ -1,8 +1,8 @@ -module compiler.compiler; +module compiler.core; import gogga; import std.conv : to; -import compiler.lexer; +import compiler.lexer.core; import std.stdio : File; import compiler.parsing.core; import compiler.symbols.check; @@ -17,6 +17,9 @@ import compiler.codegen.mapper.core : SymbolMapper; import compiler.codegen.mapper.hashmapper : HashMapper; import compiler.codegen.mapper.lebanese : LebaneseMapper; import std.string : cmp; +import compiler.configuration : CompilerConfiguration, ConfigEntry; + +// TODO: Add configentry unittests public enum CompilerError { @@ -25,7 +28,9 @@ public enum CompilerError PARSE_NOT_YET_PERFORMED, TYPECHECK_NOT_YET_PERFORMED, CONFIG_ERROR, - CONFIG_KEY_NOT_FOUND + CONFIG_KEY_NOT_FOUND, + CONFIG_TYPE_ERROR, + CONFIG_DUPLICATE_ENTRY } public final class CompilerException : TError @@ -39,47 +44,6 @@ public final class CompilerException : TError } } -public class ConfigObject -{ - -} - -public class ConfigList : ConfigObject -{ - private ConfigObject[] list; -} - -public class CompilerConfiguration -{ - private string[string] config; - - public void setConfig(VType)(string key, VType value) - { - config[key] = to!(string)(value); - } - - public VType getConfig(VType)(string key) - { - import std.algorithm : canFind; - if(hasConfig(key)) - { - return to!(VType)(config[key]); - } - else - { - throw new CompilerException(CompilerError.CONFIG_KEY_NOT_FOUND); - } - } - - public bool hasConfig(string key) - { - string[] keys = config.keys(); - import std.algorithm.searching : canFind; - - return canFind(keys, key); - } -} - public class Compiler { /* The input source code */ @@ -109,16 +73,16 @@ public class Compiler private void defaultConfig() { /* Enable Behaviour-C fixes */ - config.setConfig("behavec:preinline_args", true); + config.addConfig(ConfigEntry("behavec:preinline_args", true)); /* Enable pretty code generation for DGen */ - config.setConfig("dgen:pretty_code", true); + config.addConfig(ConfigEntry("dgen:pretty_code", true)); /* Enable entry point test generation for DGen */ - config.setConfig("dgen:emit_entrypoint_test", true); + config.addConfig(ConfigEntry("dgen:emit_entrypoint_test", true)); /* Set the mapping to hashing of entity names (TODO: This should be changed before release) */ - config.setConfig("emit:mapper", "hashmapper"); + config.addConfig(ConfigEntry("emit:mapper", "hashmapper")); } public CompilerConfiguration getConfig() @@ -217,7 +181,7 @@ public class Compiler } SymbolMapper mapper; - string mapperType = config.getConfig!(string)("emit:mapper"); + string mapperType = config.getConfig("emit:mapper").getText(); if(cmp(mapperType, "hashmapper") == 0) { @@ -311,4 +275,5 @@ unittest // { // beginCompilation([testFile]); // } -} \ No newline at end of file +} + diff --git a/source/tlang/compiler/lexer.d b/source/tlang/compiler/lexer/lexer.d similarity index 99% rename from source/tlang/compiler/lexer.d rename to source/tlang/compiler/lexer/lexer.d index 206037a..649f329 100644 --- a/source/tlang/compiler/lexer.d +++ b/source/tlang/compiler/lexer/lexer.d @@ -1,4 +1,4 @@ -module compiler.lexer; +module compiler.lexer.core; import std.container.slist; import gogga; diff --git a/source/tlang/compiler/parsing/core.d b/source/tlang/compiler/parsing/core.d index b579c97..a59ece2 100644 --- a/source/tlang/compiler/parsing/core.d +++ b/source/tlang/compiler/parsing/core.d @@ -5,7 +5,7 @@ import std.conv : to; import std.string : isNumeric, cmp; import compiler.symbols.check; import compiler.symbols.data; -import compiler.lexer : Token; +import compiler.lexer.core : Token; import core.stdc.stdlib; import misc.exceptions : TError; import compiler.parsing.exceptions; @@ -1990,7 +1990,7 @@ unittest import std.file; import std.stdio; - import compiler.lexer; + import compiler.lexer.core; string sourceCode = ` module myModule; @@ -2029,7 +2029,7 @@ unittest { import std.file; import std.stdio; - import compiler.lexer; + import compiler.lexer.core; import compiler.typecheck.core; string sourceCode = ` @@ -2196,7 +2196,7 @@ class myClass2 unittest { import std.stdio; - import compiler.lexer; + import compiler.lexer.core; import compiler.typecheck.core; @@ -2264,7 +2264,7 @@ void function() unittest { import std.stdio; - import compiler.lexer; + import compiler.lexer.core; import compiler.typecheck.core; @@ -2346,7 +2346,7 @@ int myFunction(int i, int j) unittest { import std.stdio; - import compiler.lexer; + import compiler.lexer.core; import compiler.typecheck.core; @@ -2448,7 +2448,7 @@ void function() unittest { import std.stdio; - import compiler.lexer; + import compiler.lexer.core; import compiler.typecheck.core; string sourceCode = ` @@ -2548,7 +2548,7 @@ int thing() unittest { import std.stdio; - import compiler.lexer; + import compiler.lexer.core; import compiler.typecheck.core; @@ -2671,7 +2671,7 @@ void function() unittest { import std.stdio; - import compiler.lexer; + import compiler.lexer.core; import compiler.typecheck.core; diff --git a/source/tlang/compiler/parsing/exceptions.d b/source/tlang/compiler/parsing/exceptions.d index be2f75f..8259d1b 100644 --- a/source/tlang/compiler/parsing/exceptions.d +++ b/source/tlang/compiler/parsing/exceptions.d @@ -1,11 +1,10 @@ module compiler.parsing.exceptions; import compiler.parsing.core; -import compiler.lexer; import misc.exceptions; import compiler.symbols.check; import compiler.symbols.data; -import compiler.lexer : Token; +import compiler.lexer.core : Token; import std.conv : to; public class ParserException : TError diff --git a/source/tlang/compiler/symbols/check.d b/source/tlang/compiler/symbols/check.d index 1813f54..bc5079b 100644 --- a/source/tlang/compiler/symbols/check.d +++ b/source/tlang/compiler/symbols/check.d @@ -1,6 +1,6 @@ module compiler.symbols.check; -import compiler.lexer : Token; +import compiler.lexer.core : Token; import std.conv : to; import std.string : isNumeric, cmp; import misc.utils; diff --git a/source/tlang/compiler/typecheck/core.d b/source/tlang/compiler/typecheck/core.d index 0046b2f..6335431 100644 --- a/source/tlang/compiler/typecheck/core.d +++ b/source/tlang/compiler/typecheck/core.d @@ -1740,7 +1740,7 @@ unittest { import std.file; import std.stdio; - import compiler.lexer; + import compiler.lexer.core; import compiler.parsing.core; string sourceFile = "source/tlang/testing/collide_container_module1.t"; @@ -1787,7 +1787,7 @@ unittest { import std.file; import std.stdio; - import compiler.lexer; + import compiler.lexer.core; import compiler.parsing.core; string sourceFile = "source/tlang/testing/collide_container_module2.t"; @@ -1832,7 +1832,7 @@ unittest { import std.file; import std.stdio; - import compiler.lexer; + import compiler.lexer.core; import compiler.parsing.core; string sourceFile = "source/tlang/testing/collide_container_non_module.t"; @@ -1877,7 +1877,7 @@ unittest { import std.file; import std.stdio; - import compiler.lexer; + import compiler.lexer.core; import compiler.parsing.core; string sourceFile = "source/tlang/testing/collide_member.t"; @@ -1921,7 +1921,7 @@ unittest { import std.file; import std.stdio; - import compiler.lexer; + import compiler.lexer.core; import compiler.parsing.core; string sourceFile = "source/tlang/testing/precedence_collision_test.t"; @@ -1967,7 +1967,7 @@ unittest { import std.file; import std.stdio; - import compiler.lexer; + import compiler.lexer.core; import compiler.parsing.core; string sourceFile = "source/tlang/testing/collide_container.t"; @@ -2052,7 +2052,7 @@ unittest { import std.file; import std.stdio; - import compiler.lexer; + import compiler.lexer.core; import compiler.parsing.core; string sourceFile = "source/tlang/testing/typecheck/simple_function_call.t"; diff --git a/source/tlang/testing/file_io.c b/source/tlang/testing/file_io.c new file mode 100644 index 0000000..29382cc --- /dev/null +++ b/source/tlang/testing/file_io.c @@ -0,0 +1,8 @@ +#include + +int ctr = 2; + +unsigned int doWrite(unsigned int fd, unsigned char* buffer, unsigned int count) +{ + write(fd, buffer, count+ctr); +} \ No newline at end of file diff --git a/source/tlang/testing/simple_extern.t b/source/tlang/testing/simple_extern.t index 02bf836..3809ef0 100644 --- a/source/tlang/testing/simple_extern.t +++ b/source/tlang/testing/simple_extern.t @@ -1,12 +1,12 @@ module simple_extern; -extern efunc uint write(uint fd, ubyte* buffer, uint count); -extern evar int kak; +extern efunc uint doWrite(uint fd, ubyte* buffer, uint count); +extern evar int ctr; void test() { - ubyte* buff; - discard write(cast(uint)0, buff, cast(uint)1001); + ctr = ctr + 1; - kak = kak + 1; + ubyte* buff; + discard doWrite(cast(uint)0, buff, cast(uint)1001); } \ No newline at end of file