Skip to content

Commit f1ae4b9

Browse files
committed
Modify parser.c to parse void keyword properly, minor update to resolver.c, type.h/type.c and README.md.
1 parent 68b874a commit f1ae4b9

File tree

5 files changed

+32
-12
lines changed

5 files changed

+32
-12
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ https://github.com/munificent/craftinginterpreters
4343
- Promise API with event loop provided by libuv library for non-blocking IO operations.
4444
- Introduction of `async` and `await` keywords, which allows C#/JS style of concurrency.
4545
- Optional static typing support for function/method parameters and return values, types only exist at compile time and are erased at runtime.
46+
- Semicolon inference as well as basic type inference for immutable local/global variables.
4647
- Customized Runtime configuration for CLox using clox.ini.
4748
- Allow loading lox source files in lox script and another lox source file with `require` keyword.
4849
- Cross-platform build with Cmake and package manager with vcpkg.

src/compiler/parser.c

+21-9
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ static void synchronize(Parser* parser) {
277277
static Ast* expression(Parser* parser);
278278
static Ast* statement(Parser* parser);
279279
static Ast* block(Parser* parser);
280-
static Ast* function(Parser* parser, bool isAsync, bool isLambda);
280+
static Ast* function(Parser* parser, bool isAsync, bool isLambda, bool isVoid);
281281
static Ast* declaration(Parser* parser);
282282
static ParseRule* getRule(TokenSymbol type);
283283
static Ast* parsePrecedence(Parser* parser, Precedence precedence);
@@ -517,11 +517,11 @@ static Ast* collection(Parser* parser, Token token, bool canAssign) {
517517
}
518518

519519
static Ast* closure(Parser* parser, Token token, bool canAssign) {
520-
return function(parser, false, false);
520+
return function(parser, false, false, false);
521521
}
522522

523523
static Ast* lambda(Parser* parser, Token token, bool canAssign) {
524-
return function(parser, false, true);
524+
return function(parser, false, true, false);
525525
}
526526

527527
static Ast* variable(Parser* parser, Token token, bool canAssign) {
@@ -588,13 +588,14 @@ static Ast* lambdaParameters(Parser* parser) {
588588
return params;
589589
}
590590

591-
static Ast* function(Parser* parser, bool isAsync, bool isLambda) {
591+
static Ast* function(Parser* parser, bool isAsync, bool isLambda, bool isVoid) {
592592
Token token = parser->previous;
593593
Ast* params = isLambda ? lambdaParameters(parser) : functionParameters(parser);
594594
Ast* body = block(parser);
595595
Ast* func = newAst(AST_EXPR_FUNCTION, token, 2, params, body);
596596
func->modifier.isAsync = isAsync;
597597
func->modifier.isLambda = isLambda;
598+
func->modifier.isVoid = isVoid;
598599
return func;
599600
}
600601

@@ -603,10 +604,11 @@ static Ast* methods(Parser* parser, Token* name) {
603604
Ast* methodList = emptyAst(AST_LIST_METHOD, *name);
604605

605606
while (!check(parser, TOKEN_RIGHT_BRACE) && !check(parser, TOKEN_EOF)) {
606-
bool isAsync = false, isClass = false, isInitializer = false, hasReturnType = false;
607+
bool isAsync = false, isClass = false, isInitializer = false, isVoid = false, hasReturnType = false;
607608
Ast* returnType = NULL;
608609
if (match(parser, TOKEN_ASYNC)) isAsync = true;
609610
if (match(parser, TOKEN_CLASS)) isClass = true;
611+
if (match(parser, TOKEN_VOID)) isVoid = true;
610612
if (check2(parser, TOKEN_IDENTIFIER) || (check(parser, TOKEN_IDENTIFIER) && tokenIsOperator(parser->next))) {
611613
hasReturnType = true;
612614
returnType = type_(parser, "Expect method return type.");
@@ -623,6 +625,7 @@ static Ast* methods(Parser* parser, Token* name) {
623625
method->modifier.isAsync = isAsync;
624626
method->modifier.isClass = isClass;
625627
method->modifier.isInitializer = isInitializer;
628+
method->modifier.isVoid = isVoid;
626629

627630
if (hasReturnType) {
628631
astAppendChild(method, returnType);
@@ -711,10 +714,10 @@ static Ast* yield(Parser* parser, Token token, bool canAssign) {
711714

712715
static Ast* async(Parser* parser, Token token, bool canAssign) {
713716
if (match(parser, TOKEN_FUN)) {
714-
return function(parser, true, false);
717+
return function(parser, true, false, false);
715718
}
716719
else if (match(parser, TOKEN_LEFT_BRACE)) {
717-
return function(parser, true, true);
720+
return function(parser, true, true, false);
718721
}
719722
else {
720723
parseErrorAtPrevious(parser, "Can only use async as expression modifier for anonymous functions or lambda.");
@@ -1115,12 +1118,14 @@ static Ast* classDeclaration(Parser* parser) {
11151118
}
11161119

11171120
static Ast* funDeclaration(Parser* parser, bool isAsync, bool hasReturnType) {
1121+
bool isVoid = match(parser, TOKEN_VOID);
11181122
Ast* returnType = hasReturnType ? type_(parser, "Expect function return type.") : NULL;
11191123
consume(parser, TOKEN_IDENTIFIER, "Expect function name.");
11201124
Token name = parser->previous;
1121-
Ast* body = function(parser, isAsync, false);
1125+
Ast* body = function(parser, isAsync, false, isVoid);
11221126

11231127
Ast* ast = newAst(AST_DECL_FUN, name, 1, body);
1128+
ast->modifier.isVoid = true;
11241129
if (returnType != NULL) astAppendChild(ast, returnType);
11251130
return ast;
11261131
}
@@ -1172,7 +1177,11 @@ static Ast* declaration(Parser* parser) {
11721177
advance(parser);
11731178
return funDeclaration(parser, true, false);
11741179
}
1175-
if (check(parser, TOKEN_ASYNC) && checkNext(parser, TOKEN_IDENTIFIER)) {
1180+
else if (check(parser, TOKEN_ASYNC) && checkNext(parser, TOKEN_VOID)) {
1181+
advance(parser);
1182+
return funDeclaration(parser, true, false);
1183+
}
1184+
else if (check(parser, TOKEN_ASYNC) && checkNext(parser, TOKEN_IDENTIFIER)) {
11761185
advance(parser);
11771186
return funDeclaration(parser, true, true);
11781187
}
@@ -1184,6 +1193,9 @@ static Ast* declaration(Parser* parser) {
11841193
advance(parser);
11851194
return funDeclaration(parser, false, false);
11861195
}
1196+
else if (check(parser, TOKEN_VOID) && checkNext(parser, TOKEN_IDENTIFIER)) {
1197+
return funDeclaration(parser, false, false);
1198+
}
11871199
else if (check2(parser, TOKEN_IDENTIFIER)) {
11881200
return funDeclaration(parser, false, true);
11891201
}

src/compiler/resolver.c

+5
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ static void setFunctionTypeModifier(Ast* ast, CallableTypeInfo* callableType) {
174174
callableType->modifier.isInstanceMethod = !ast->modifier.isClass;
175175
callableType->modifier.isLambda = ast->modifier.isLambda;
176176
callableType->modifier.isVariadic = ast->modifier.isVariadic;
177+
callableType->modifier.isVoid = ast->modifier.isVoid;
177178
}
178179

179180
static bool findSymbol(Resolver* resolver, Token token) {
@@ -473,6 +474,7 @@ static void function(Resolver* resolver, Ast* ast, bool isLambda, bool isAsync)
473474
functionResolver.modifier.isInitializer = ast->modifier.isInitializer;
474475
functionResolver.modifier.isInstanceMethod = !ast->modifier.isClass;
475476
functionResolver.modifier.isLambda = isLambda;
477+
functionResolver.modifier.isVoid = ast->modifier.isVoid;
476478

477479
SymbolScope scope = getFunctionScope(ast);
478480
beginScope(resolver, ast, scope);
@@ -943,6 +945,9 @@ static void resolveReturnStatement(Resolver* resolver, Ast* ast) {
943945
semanticError(resolver, "Cannot use 'return' from an initializer.");
944946
}
945947
else if (astHasChild(ast)) {
948+
if (resolver->currentFunction->modifier.isVoid) {
949+
semanticError(resolver, "Cannot return value from a void function/method.");
950+
}
946951
resolveChild(resolver, ast, 0);
947952
}
948953
}

src/compiler/type.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ static void typeTableOutputMethod(TypeTable* methods) {
254254
printf(" %s", method->modifier.isAsync ? "async " : "");
255255

256256
if (method->returnType == NULL) printf("dynamic ");
257-
else if (memcmp(method->returnType->shortName->chars, "Nil", 3) == 0) printf("void ");
257+
else if (method->modifier.isVoid) printf("void ");
258258
else printf("%s ", method->returnType->shortName->chars);
259259
printf("%s(", entry->key->chars);
260260

@@ -290,7 +290,7 @@ static void typeTableOutputBehavior(BehaviorTypeInfo* behavior) {
290290
static void typeTableOutputFunction(CallableTypeInfo* function) {
291291
printf(" signature: ");
292292
if (function->returnType == NULL) printf("dynamic ");
293-
else if (memcmp(function->returnType->shortName->chars, "Nil", 3) == 0) printf("void ");
293+
else if (function->modifier.isVoid) printf("void ");
294294
else printf("%s ", function->returnType->shortName->chars);
295295
printf("%s(", function->baseType.shortName->chars);
296296

src/compiler/type.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ typedef struct {
4747
bool isInstanceMethod;
4848
bool isLambda;
4949
bool isVariadic;
50+
bool isVoid;
5051
} CallableTypeModifier;
5152

5253
typedef struct {
@@ -76,7 +77,8 @@ static inline CallableTypeModifier callableTypeInitModifier() {
7677
.isInitializer = false,
7778
.isInstanceMethod = false,
7879
.isLambda = false,
79-
.isVariadic = false
80+
.isVariadic = false,
81+
.isVoid = false
8082
};
8183
return modifier;
8284
}

0 commit comments

Comments
 (0)