Skip to content

Commit a6732ab

Browse files
committed
Add new source file typechecker.h/typechecker.c, also add typechecker pass to compiler.c, modify CMakesList.txt.
1 parent 0ec50e0 commit a6732ab

File tree

6 files changed

+154
-2
lines changed

6 files changed

+154
-2
lines changed

CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,8 @@ set(Source_Files__compiler
123123
"src/compiler/token.h"
124124
"src/compiler/type.c"
125125
"src/compiler/type.h"
126+
"src/compiler/typechecker.c"
127+
"src/compiler/typechecker.h"
126128
)
127129
source_group("Source Files\\compiler" FILES ${Source_Files__compiler})
128130

src/compiler/compiler.c

+6
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "compiler.h"
77
#include "parser.h"
88
#include "resolver.h"
9+
#include "typechecker.h"
910
#include "../vm/debug.h"
1011

1112
typedef enum {
@@ -1367,6 +1368,11 @@ ObjFunction* compile(VM* vm, const char* source) {
13671368
resolve(&resolver, ast);
13681369
if (resolver.hadError) return NULL;
13691370

1371+
TypeChecker typeChecker;
1372+
initTypeChecker(vm, &typeChecker, vm->config.debugTypetab);
1373+
typeCheck(&typeChecker, ast);
1374+
if (typeChecker.hadError) return NULL;
1375+
13701376
Compiler compiler;
13711377
initCompiler(vm, &compiler, NULL, COMPILE_TYPE_SCRIPT, NULL, false, vm->config.debugCode);
13721378
compileAst(&compiler, ast);

src/compiler/type.c

+1-2
Original file line numberDiff line numberDiff line change
@@ -153,12 +153,11 @@ static void typeTableAdjustCapacity(TypeTable* typetab, int capacity) {
153153
entries[i].key = NULL;
154154
entries[i].value = NULL;
155155
}
156-
157156
typetab->count = 0;
157+
158158
for (int i = 0; i < typetab->capacity; i++) {
159159
TypeEntry* entry = &typetab->entries[i];
160160
if (entry->key == NULL) continue;
161-
162161
TypeEntry* dest = findTypeEntry(entries, capacity, entry->key);
163162
dest->key = entry->key;
164163
dest->value = entry->value;

src/compiler/type.h

+1
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ static inline CallableTypeModifier callableTypeInitModifier() {
7272
CallableTypeModifier modifier = {
7373
.isAsync = false,
7474
.isClassMethod = false,
75+
.isGenerator = false,
7576
.isInitializer = false,
7677
.isInstanceMethod = false,
7778
.isLambda = false,

src/compiler/typechecker.c

+118
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
#include <stdio.h>
2+
#include <stdlib.h>
3+
#include <string.h>
4+
5+
#include "typechecker.h"
6+
#include "../vm/vm.h"
7+
8+
struct ClassTypeChecker {
9+
ClassTypeChecker* enclosing;
10+
Token name;
11+
BehaviorTypeInfo* type;
12+
bool isAnonymous;
13+
};
14+
15+
struct FunctionTypeChecker {
16+
FunctionTypeChecker* enclosing;
17+
Token name;
18+
SymbolTable* symtab;
19+
CallableTypeInfo* type;
20+
bool isAsync;
21+
};
22+
23+
static void typeError(TypeChecker* typeChecker, const char* format, ...) {
24+
va_list args;
25+
va_start(args, format);
26+
fprintf(stderr, "[line %d] Type Error: ", typeChecker->currentToken.line);
27+
vfprintf(stderr, format, args);
28+
va_end(args);
29+
fputs("\n", stderr);
30+
typeChecker->hadError = true;
31+
}
32+
33+
static void initClassTypeChecker(TypeChecker* typeChecker, ClassTypeChecker* klass, Token name, BehaviorTypeInfo* type, bool isAnonymous) {
34+
klass->enclosing = typeChecker->currentClass;
35+
klass->name = name;
36+
klass->type = type;
37+
klass->isAnonymous = isAnonymous;
38+
typeChecker->currentClass = klass;
39+
}
40+
41+
static void endClassTypeChecker(TypeChecker* typeChecker) {
42+
typeChecker->currentClass = typeChecker->currentClass->enclosing;
43+
}
44+
45+
static void initFunctionTypeChecker(TypeChecker* typeChecker, FunctionTypeChecker* function, Token name, CallableTypeInfo* type, bool isAsync) {
46+
function->enclosing = typeChecker->currentFunction;
47+
function->name = name;
48+
function->type = type;
49+
function->isAsync = isAsync;
50+
typeChecker->currentFunction = function;
51+
}
52+
53+
static void endFunctionTypeChecker(TypeChecker* typeChecker) {
54+
typeChecker->currentFunction = typeChecker->currentFunction->enclosing;
55+
}
56+
57+
void initTypeChecker(VM* vm, TypeChecker* typeChecker, bool debugTypetab) {
58+
typeChecker->vm = vm;
59+
typeChecker->currentNamespace = emptyString(vm);
60+
typeChecker->currentClass = NULL;
61+
typeChecker->currentFunction = NULL;
62+
typeChecker->scopeDepth = 0;
63+
typeChecker->debugTypetab = debugTypetab;
64+
typeChecker->hadError = false;
65+
}
66+
67+
static void typeCheckExpression(TypeChecker* typeChecker, Ast* ast) {
68+
// To be implemented.
69+
}
70+
71+
static void typeCheckStatement(TypeChecker* typeChecker, Ast* ast) {
72+
// To be implemented.
73+
}
74+
75+
static void typeCheckDeclaration(TypeChecker* typeChecker, Ast* ast) {
76+
// To be implemented.
77+
}
78+
79+
void typeCheckAst(TypeChecker* typeChecker, Ast* ast) {
80+
for (int i = 0; i < ast->children->count; i++) {
81+
typeCheckChild(typeChecker, ast, i);
82+
}
83+
}
84+
85+
void typeCheckChild(TypeChecker* typeChecker, Ast* ast, int index) {
86+
Ast* child = astGetChild(ast, index);
87+
child->symtab = ast->symtab;
88+
typeChecker->currentToken = child->token;
89+
90+
switch (child->category) {
91+
case AST_CATEGORY_SCRIPT:
92+
case AST_CATEGORY_OTHER:
93+
typeCheckAst(typeChecker, child);
94+
break;
95+
case AST_CATEGORY_EXPR:
96+
typeCheckExpression(typeChecker, child);
97+
break;
98+
case AST_CATEGORY_STMT:
99+
typeCheckStatement(typeChecker, child);
100+
break;
101+
case AST_CATEGORY_DECL:
102+
typeCheckDeclaration(typeChecker, child);
103+
break;
104+
default:
105+
typeError(typeChecker, "Invalid AST category.");
106+
}
107+
}
108+
109+
void typeCheck(TypeChecker* typeChecker, Ast* ast) {
110+
FunctionTypeChecker functionTypeChecker;
111+
initFunctionTypeChecker(typeChecker, &functionTypeChecker, syntheticToken("script"), NULL, ast->modifier.isAsync);
112+
typeCheckAst(typeChecker, ast);
113+
114+
endFunctionTypeChecker(typeChecker);
115+
if (typeChecker->debugTypetab) {
116+
typeTableOutput(typeChecker->vm->typetab);
117+
}
118+
}

src/compiler/typechecker.h

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#pragma once
2+
#ifndef clox_typechecker_h
3+
#define clox_typechecker_h
4+
5+
#include "ast.h"
6+
7+
typedef struct ClassTypeChecker ClassTypeChecker;
8+
typedef struct FunctionTypeChecker FunctionTypeChecker;
9+
10+
typedef struct {
11+
VM* vm;
12+
Token currentToken;
13+
ObjString* currentNamespace;
14+
ClassTypeChecker* currentClass;
15+
FunctionTypeChecker* currentFunction;
16+
int scopeDepth;
17+
bool debugTypetab;
18+
bool hadError;
19+
} TypeChecker;
20+
21+
void initTypeChecker(VM* vm, TypeChecker* typeChecker, bool debugTypetab);
22+
void typeCheckAst(TypeChecker* typeChecker, Ast* ast);
23+
void typeCheckChild(TypeChecker* typeChecker, Ast* ast, int index);
24+
void typeCheck(TypeChecker* typeChecker, Ast* ast);
25+
26+
#endif // !clox_typechecker_h

0 commit comments

Comments
 (0)