From 5c8e30f1f5d2c60e94fc17fbe3a35c7633ddfc68 Mon Sep 17 00:00:00 2001 From: "Tristan B. Kildaire" Date: Tue, 23 Mar 2021 21:35:13 +0200 Subject: [PATCH] Run type checker system WIP: Resolution of names Reworked type hierachy for Enity in relation to Function, Variable and Class Updated test case --- source/tlang/compiler/compiler.d | 1 + source/tlang/compiler/parser.d | 2 +- source/tlang/compiler/symbols.d | 52 +++++++++++++++++---- source/tlang/compiler/typecheck.d | 75 +++++++++++++++++++++++++++++++ source/tlang/misc/utils.d | 16 +++++++ source/tlang/testing/basic1.t | 4 +- 6 files changed, 139 insertions(+), 11 deletions(-) create mode 100644 source/tlang/misc/utils.d diff --git a/source/tlang/compiler/compiler.d b/source/tlang/compiler/compiler.d index 9d35a96..5f5dcef 100644 --- a/source/tlang/compiler/compiler.d +++ b/source/tlang/compiler/compiler.d @@ -43,5 +43,6 @@ void beginCompilation(string[] sourceFiles) gprintln("Type checking and symbol resolution..."); TypeChecker typeChecker = new TypeChecker(program); + typeChecker.check(); } } \ No newline at end of file diff --git a/source/tlang/compiler/parser.d b/source/tlang/compiler/parser.d index 7a00d09..85bfbb1 100644 --- a/source/tlang/compiler/parser.d +++ b/source/tlang/compiler/parser.d @@ -625,7 +625,7 @@ public final class Parser gprintln("ParseTypedDec: VariableDeclarationWithAssingment: (Type: " ~ type ~ ", Identifier: " ~ identifier ~ ")", DebugType.WARNING); - Variable variable = new Variable(identifier, type); + Variable variable = new Variable(type, identifier); variable.addAssignment(varAssign); generated = variable; diff --git a/source/tlang/compiler/symbols.d b/source/tlang/compiler/symbols.d index 77f12be..6c5c506 100644 --- a/source/tlang/compiler/symbols.d +++ b/source/tlang/compiler/symbols.d @@ -391,6 +391,14 @@ public class Entity : Statement /* Accesor type */ private AccessorType accessorType = AccessorType.PUBLIC; + /* Name of the entity (class's name, function's name, variable's name) */ + private string name; + + this(string name) + { + this.name = name; + } + public void setAccessorType(AccessorType accessorType) { this.accessorType = accessorType; @@ -400,15 +408,26 @@ public class Entity : Statement { return accessorType; } + + public string getName() + { + return name; + } } /* TODO: DO we need intermediary class, TypedEntity */ -public class TypedEntity : Entity {} +public class TypedEntity : Entity +{ + /* TODO: Return type/variable type in here (do what we did for ENtity with `name/identifier`) */ + this(string name) + { + super(name); + } +} public class Clazz : Entity { - private string name; private string parentClass; private string[] interfaces; @@ -416,7 +435,7 @@ public class Clazz : Entity this(string name) { - this.name = name; + super(name); } public void addStatements(Statement[] statements) @@ -424,6 +443,25 @@ public class Clazz : Entity this.statements ~= statements; } + /** + * Checks all added Statement[]s and makes sure they + * are either of type Variable, Function or Class + */ + public bool isFine() + { + foreach(Statement statement; statements) + { + if(typeid(statement) != typeid(Variable) && + typeid(statement) != typeid(Function) && + typeid(statement) != typeid(Clazz)) + { + return false; + } + } + + return true; + } + public override string toString() { return "Class (Name: "~name~", Parent: "~parentClass~", Interfaces: "~to!(string)(interfaces)~")"; @@ -438,14 +476,13 @@ public class ArgumentList public class Function : TypedEntity { - private string name; private string returnType; private Variable[] params; private Statement[] bodyStatements; this(string name, string returnType, Statement[] bodyStatements, Variable[] args) { - this.name = name; + super(name); this.returnType = returnType; this.bodyStatements = bodyStatements; this.params = args; @@ -495,14 +532,13 @@ public class Function : TypedEntity public class Variable : TypedEntity { private string type; - private string identifier; private VariableAssignment assignment; this(string type, string identifier) { + super(identifier); this.type = type; - this.identifier = identifier; } public void addAssignment(VariableAssignment assignment) @@ -522,7 +558,7 @@ public class Variable : TypedEntity public override string toString() { - return "Variable (Ident: "~identifier~", Type: "~type~")"; + return "Variable (Ident: "~name~", Type: "~type~")"; } /* Code gen */ diff --git a/source/tlang/compiler/typecheck.d b/source/tlang/compiler/typecheck.d index f4bad6f..b9e63ba 100644 --- a/source/tlang/compiler/typecheck.d +++ b/source/tlang/compiler/typecheck.d @@ -10,13 +10,88 @@ import std.conv : to; */ public final class TypeChecker { + private Program program; this(Program program) { + this.program = program; + import std.stdio; writeln("Got globals: "~to!(string)(program.getAllOf(new Variable(null, null)))); writeln("Got functions: "~to!(string)(program.getAllOf(new Function(null, null, null, null)))); writeln("Got classes: "~to!(string)(program.getAllOf(new Clazz(null)))); } + + /** + * This function will walk, recursively, through + * each Statement at the top-level and generate + * names of declared items in a global array + * + * This is top-level, iterative then recursive within + * each iteration + * + * The point of this is to know of all symbols + * that exist so that we can do a second pass + * and see if symbols in use (declaration does + * not count as "use") are infact valid references + */ + public void nameResolution() + { + string[] names; + + foreach(Statement statement; program.getAllOf(new Statement())) + { + /* TODO: Add container name */ + // names ~= + // string[] receivedNameSet = resolveNames(statement); + } + } + + private string[] resolveNames(Statement statement) + { + // string containerName + return null; + } + + + public void check() + { + checkDuplicateTopLevel(); + + /* TODO: Process globals */ + /* TODO: Process classes */ + /* TODO: Process functions */ + } + + + + /** + * Ensures that at the top-level there are no duplicate names + */ + private bool checkDuplicateTopLevel() + { + import misc.utils; + import compiler.parser : Parser; + + /* List of names travsersed so far */ + string[] names; + + /* Add all global variables */ + foreach(Variable variable; program.getAllOf(new Variable(null, null))) + { + string name = variable.getName(); + + if(isPresent(names, name)) + { + Parser.expect("Bruh duplicate var"~name); + } + else + { + names ~= variable.getName(); + } + } + + return true; + } } \ No newline at end of file diff --git a/source/tlang/misc/utils.d b/source/tlang/misc/utils.d new file mode 100644 index 0000000..e2d3cb4 --- /dev/null +++ b/source/tlang/misc/utils.d @@ -0,0 +1,16 @@ +module misc.utils; + +import std.string : cmp; + +public bool isPresent(string[] arr, string t) +{ + foreach(string j; arr) + { + if(cmp(j, t) == 0) + { + return true; + } + } + + return false; +} \ No newline at end of file diff --git a/source/tlang/testing/basic1.t b/source/tlang/testing/basic1.t index b5d1cca..65a8e36 100644 --- a/source/tlang/testing/basic1.t +++ b/source/tlang/testing/basic1.t @@ -5,8 +5,8 @@ int x; ubyte y; public ubyte k = 1; -private ubyte k = 1; -protected ubyte k = 1; +private ubyte k2 = 1; +protected ubyte k3 = -1; public class clazz1