authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-12-01 21:19:38-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-12-01 21:19:38-07:00
log08a2311efd8b388cd431feb6000741f4a62da613
tree528ba0056e9a54583c91b0787b9d5ffcdcc11de7
parent1ed926c3216016d73e83377a295869d8579e2fde

support if conditionals


10 files changed, 400 insertions(+), 64 deletions(-)

README.md+19-3
...@@ -44,7 +44,11 @@ make...@@ -44,7 +44,11 @@ make
4444
45 * variable declarations and assignment expressions45 * variable declarations and assignment expressions
46 * Type checking46 * Type checking
47 * loops
48 * labels and goto
47 * inline assembly and syscalls49 * inline assembly and syscalls
50 * conditional compilation and ability to check target platform and architecture
51 * main function with command line arguments
48 * running code at compile time52 * running code at compile time
49 * print! macro that takes var args53 * print! macro that takes var args
50 * panic! macro that prints a stack trace to stderr in debug mode and calls54 * panic! macro that prints a stack trace to stderr in debug mode and calls
...@@ -104,14 +108,26 @@ Type : token(Symbol) | PointerType | token(Unreachable)...@@ -104,14 +108,26 @@ Type : token(Symbol) | PointerType | token(Unreachable)
104108
105PointerType : token(Star) token(Const) Type | token(Star) token(Mut) Type109PointerType : token(Star) token(Const) Type | token(Star) token(Mut) Type
106110
107Block : token(LBrace) list(option(Expression), token(Semicolon)) token(RBrace)111Block : token(LBrace) list(option(Statement), token(Semicolon)) token(RBrace)
108112
109Expression : BoolOrExpression | ReturnExpression113Statement : NonBlockExpression token(Semicolon) | BlockExpression
114
115Expression : BlockExpression | NonBlockExpression
116
117NonBlockExpression : BoolOrExpression | ReturnExpression
118
119BlockExpression : IfExpression | Block
110120
111BoolOrExpression : BoolAndExpression token(BoolOr) BoolAndExpression | BoolAndExpression121BoolOrExpression : BoolAndExpression token(BoolOr) BoolAndExpression | BoolAndExpression
112122
113ReturnExpression : token(Return) option(Expression)123ReturnExpression : token(Return) option(Expression)
114124
125IfExpression : token(If) Expression Block option(Else | ElseIf)
126
127ElseIf : token(Else) IfExpression
128
129Else : token(Else) Block
130
115BoolAndExpression : ComparisonExpression token(BoolAnd) ComparisonExpression | ComparisonExpression131BoolAndExpression : ComparisonExpression token(BoolAnd) ComparisonExpression | ComparisonExpression
116132
117ComparisonExpression : BinaryOrExpression ComparisonOperator BinaryOrExpression | BinaryOrExpression133ComparisonExpression : BinaryOrExpression ComparisonOperator BinaryOrExpression | BinaryOrExpression
...@@ -144,7 +160,7 @@ FnCallExpression : PrimaryExpression token(LParen) list(Expression, token(Comma)...@@ -144,7 +160,7 @@ FnCallExpression : PrimaryExpression token(LParen) list(Expression, token(Comma)
144160
145PrefixOp : token(Not) | token(Dash) | token(Tilde)161PrefixOp : token(Not) | token(Dash) | token(Tilde)
146162
147PrimaryExpression : token(Number) | token(String) | token(Unreachable) | GroupedExpression | Block | token(Symbol)163PrimaryExpression : token(Number) | token(String) | token(Unreachable) | GroupedExpression | token(Symbol)
148164
149GroupedExpression : token(LParen) Expression token(RParen)165GroupedExpression : token(LParen) Expression token(RParen)
150```166```
doc/vim/syntax/zig.vim+2-2
...@@ -7,8 +7,8 @@ if exists("b:current_syntax")...@@ -7,8 +7,8 @@ if exists("b:current_syntax")
7 finish7 finish
8endif8endif
99
10syn keyword zigKeyword fn return mut const extern unreachable export pub as use10syn keyword zigKeyword fn return mut const extern unreachable export pub as use if else let void
11syn keyword zigType bool i8 u8 i16 u16 i32 u32 i64 u64 isize usize f32 f64 f128 void11syn keyword zigType bool i8 u8 i16 u16 i32 u32 i64 u64 isize usize f32 f64 f128
1212
13syn region zigCommentLine start="//" end="$" contains=zigTodo,@Spell13syn region zigCommentLine start="//" end="$" contains=zigTodo,@Spell
14syn region zigCommentLineDoc start="//\%(//\@!\|!\)" end="$" contains=zigTodo,@Spell14syn region zigCommentLineDoc start="//\%(//\@!\|!\)" end="$" contains=zigTodo,@Spell
src/analyze.cpp+105-7
...@@ -274,6 +274,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,...@@ -274,6 +274,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
274 case NodeTypeSymbol:274 case NodeTypeSymbol:
275 case NodeTypeCastExpr:275 case NodeTypeCastExpr:
276 case NodeTypePrefixOpExpr:276 case NodeTypePrefixOpExpr:
277 case NodeTypeIfExpr:
277 zig_unreachable();278 zig_unreachable();
278 }279 }
279}280}
...@@ -302,7 +303,9 @@ static void check_type_compatibility(CodeGen *g, AstNode *node, TypeTableEntry *...@@ -302,7 +303,9 @@ static void check_type_compatibility(CodeGen *g, AstNode *node, TypeTableEntry *
302 add_node_error(g, node, buf_sprintf("type mismatch. expected %s. got %s", buf_ptr(&expected_type->name), buf_ptr(&actual_type->name)));303 add_node_error(g, node, buf_sprintf("type mismatch. expected %s. got %s", buf_ptr(&expected_type->name), buf_ptr(&actual_type->name)));
303}304}
304305
305static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context, TypeTableEntry *expected_type, AstNode *node) {306static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,
307 TypeTableEntry *expected_type, AstNode *node)
308{
306 TypeTableEntry *return_type = nullptr;309 TypeTableEntry *return_type = nullptr;
307 switch (node->type) {310 switch (node->type) {
308 case NodeTypeBlock:311 case NodeTypeBlock:
...@@ -348,10 +351,64 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,...@@ -348,10 +351,64 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
348351
349 case NodeTypeBinOpExpr:352 case NodeTypeBinOpExpr:
350 {353 {
351 // TODO: think about expected types354 switch (node->data.bin_op_expr.bin_op) {
352 analyze_expression(g, import, context, expected_type, node->data.bin_op_expr.op1);355 case BinOpTypeBoolOr:
353 analyze_expression(g, import, context, expected_type, node->data.bin_op_expr.op2);356 case BinOpTypeBoolAnd:
354 return_type = expected_type;357 analyze_expression(g, import, context, g->builtin_types.entry_bool,
358 node->data.bin_op_expr.op1);
359 analyze_expression(g, import, context, g->builtin_types.entry_bool,
360 node->data.bin_op_expr.op2);
361 return_type = g->builtin_types.entry_bool;
362 break;
363 case BinOpTypeCmpEq:
364 case BinOpTypeCmpNotEq:
365 case BinOpTypeCmpLessThan:
366 case BinOpTypeCmpGreaterThan:
367 case BinOpTypeCmpLessOrEq:
368 case BinOpTypeCmpGreaterOrEq:
369 // TODO think how should type checking for these work?
370 analyze_expression(g, import, context, g->builtin_types.entry_i32,
371 node->data.bin_op_expr.op1);
372 analyze_expression(g, import, context, g->builtin_types.entry_i32,
373 node->data.bin_op_expr.op2);
374 return_type = g->builtin_types.entry_bool;
375 break;
376 case BinOpTypeBinOr:
377 zig_panic("TODO bin or type");
378 break;
379 case BinOpTypeBinXor:
380 zig_panic("TODO bin xor type");
381 break;
382 case BinOpTypeBinAnd:
383 zig_panic("TODO bin and type");
384 break;
385 case BinOpTypeBitShiftLeft:
386 zig_panic("TODO bit shift left type");
387 break;
388 case BinOpTypeBitShiftRight:
389 zig_panic("TODO bit shift right type");
390 break;
391 case BinOpTypeAdd:
392 case BinOpTypeSub:
393 // TODO think how should type checking for these work?
394 analyze_expression(g, import, context, g->builtin_types.entry_i32,
395 node->data.bin_op_expr.op1);
396 analyze_expression(g, import, context, g->builtin_types.entry_i32,
397 node->data.bin_op_expr.op2);
398 return_type = g->builtin_types.entry_i32;
399 break;
400 case BinOpTypeMult:
401 zig_panic("TODO mult type");
402 break;
403 case BinOpTypeDiv:
404 zig_panic("TODO div type");
405 break;
406 case BinOpTypeMod:
407 zig_panic("TODO modulus type");
408 break;
409 case BinOpTypeInvalid:
410 zig_unreachable();
411 }
355 break;412 break;
356 }413 }
357414
...@@ -426,11 +483,46 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,...@@ -426,11 +483,46 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
426483
427 case NodeTypeSymbol:484 case NodeTypeSymbol:
428 // look up symbol in symbol table485 // look up symbol in symbol table
429 zig_panic("TODO");486 zig_panic("TODO analyze_expression symbol");
430487
431 case NodeTypeCastExpr:488 case NodeTypeCastExpr:
489 zig_panic("TODO analyze_expression cast expr");
490 break;
491
432 case NodeTypePrefixOpExpr:492 case NodeTypePrefixOpExpr:
433 zig_panic("TODO");493 switch (node->data.prefix_op_expr.prefix_op) {
494 case PrefixOpBoolNot:
495 analyze_expression(g, import, context, g->builtin_types.entry_bool,
496 node->data.prefix_op_expr.primary_expr);
497 return_type = g->builtin_types.entry_bool;
498 break;
499 case PrefixOpBinNot:
500 zig_panic("TODO type check bin not");
501 break;
502 case PrefixOpNegation:
503 zig_panic("TODO type check negation");
504 break;
505 case PrefixOpInvalid:
506 zig_unreachable();
507 }
508 break;
509 case NodeTypeIfExpr:
510 {
511 analyze_expression(g, import, context, g->builtin_types.entry_bool, node->data.if_expr.condition);
512
513 TypeTableEntry *else_type;
514 if (node->data.if_expr.else_node) {
515 else_type = analyze_expression(g, import, context, expected_type, node->data.if_expr.else_node);
516 } else {
517 else_type = g->builtin_types.entry_void;
518 }
519 TypeTableEntry *then_type = analyze_expression(g, import, context, expected_type,
520 node->data.if_expr.then_block);
521
522 check_type_compatibility(g, node, expected_type, else_type);
523 return_type = then_type;
524 break;
525 }
434 case NodeTypeDirective:526 case NodeTypeDirective:
435 case NodeTypeFnDecl:527 case NodeTypeFnDecl:
436 case NodeTypeFnProto:528 case NodeTypeFnProto:
...@@ -445,6 +537,11 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,...@@ -445,6 +537,11 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
445 }537 }
446 assert(return_type);538 assert(return_type);
447 check_type_compatibility(g, node, expected_type, return_type);539 check_type_compatibility(g, node, expected_type, return_type);
540
541 assert(!node->codegen_node);
542 node->codegen_node = allocate<CodeGenNode>(1);
543 node->codegen_node->data.expr_node.type_entry = return_type;
544
448 return return_type;545 return return_type;
449}546}
450547
...@@ -509,6 +606,7 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import,...@@ -509,6 +606,7 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import,
509 case NodeTypeSymbol:606 case NodeTypeSymbol:
510 case NodeTypeCastExpr:607 case NodeTypeCastExpr:
511 case NodeTypePrefixOpExpr:608 case NodeTypePrefixOpExpr:
609 case NodeTypeIfExpr:
512 zig_unreachable();610 zig_unreachable();
513 }611 }
514}612}
src/codegen.cpp+111-32
...@@ -120,6 +120,10 @@ static LLVMValueRef get_variable_value(CodeGen *g, Buf *name) {...@@ -120,6 +120,10 @@ static LLVMValueRef get_variable_value(CodeGen *g, Buf *name) {
120 zig_unreachable();120 zig_unreachable();
121}121}
122122
123static TypeTableEntry *get_expr_type(AstNode *node) {
124 return node->codegen_node->data.expr_node.type_entry;
125}
126
123static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {127static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {
124 assert(node->type == NodeTypeFnCallExpr);128 assert(node->type == NodeTypeFnCallExpr);
125129
...@@ -283,6 +287,7 @@ static LLVMValueRef gen_bool_and_expr(CodeGen *g, AstNode *node) {...@@ -283,6 +287,7 @@ static LLVMValueRef gen_bool_and_expr(CodeGen *g, AstNode *node) {
283287
284 LLVMValueRef val1 = gen_expr(g, node->data.bin_op_expr.op1);288 LLVMValueRef val1 = gen_expr(g, node->data.bin_op_expr.op1);
285289
290 LLVMBasicBlockRef orig_block = LLVMGetInsertBlock(g->builder);
286 // block for when val1 == true291 // block for when val1 == true
287 LLVMBasicBlockRef true_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "BoolAndTrue");292 LLVMBasicBlockRef true_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "BoolAndTrue");
288 // block for when val1 == false (don't even evaluate the second part)293 // block for when val1 == false (don't even evaluate the second part)
...@@ -297,13 +302,14 @@ static LLVMValueRef gen_bool_and_expr(CodeGen *g, AstNode *node) {...@@ -297,13 +302,14 @@ static LLVMValueRef gen_bool_and_expr(CodeGen *g, AstNode *node) {
297 LLVMValueRef val2 = gen_expr(g, node->data.bin_op_expr.op2);302 LLVMValueRef val2 = gen_expr(g, node->data.bin_op_expr.op2);
298 add_debug_source_node(g, node);303 add_debug_source_node(g, node);
299 LLVMValueRef val2_i1 = LLVMBuildICmp(g->builder, LLVMIntEQ, val2, zero, "");304 LLVMValueRef val2_i1 = LLVMBuildICmp(g->builder, LLVMIntEQ, val2, zero, "");
305 LLVMBuildBr(g->builder, false_block);
300306
301 LLVMPositionBuilderAtEnd(g->builder, false_block);307 LLVMPositionBuilderAtEnd(g->builder, false_block);
302 add_debug_source_node(g, node);308 add_debug_source_node(g, node);
303 LLVMValueRef phi = LLVMBuildPhi(g->builder, LLVMInt1Type(), "");309 LLVMValueRef phi = LLVMBuildPhi(g->builder, LLVMInt1Type(), "");
304 LLVMValueRef one_i1 = LLVMConstAllOnes(LLVMInt1Type());310 LLVMValueRef one_i1 = LLVMConstAllOnes(LLVMInt1Type());
305 LLVMValueRef incoming_values[2] = {one_i1, val2_i1};311 LLVMValueRef incoming_values[2] = {one_i1, val2_i1};
306 LLVMBasicBlockRef incoming_blocks[2] = {LLVMGetInsertBlock(g->builder), true_block};312 LLVMBasicBlockRef incoming_blocks[2] = {orig_block, true_block};
307 LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2);313 LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2);
308314
309 return phi;315 return phi;
...@@ -314,6 +320,8 @@ static LLVMValueRef gen_bool_or_expr(CodeGen *g, AstNode *expr_node) {...@@ -314,6 +320,8 @@ static LLVMValueRef gen_bool_or_expr(CodeGen *g, AstNode *expr_node) {
314320
315 LLVMValueRef val1 = gen_expr(g, expr_node->data.bin_op_expr.op1);321 LLVMValueRef val1 = gen_expr(g, expr_node->data.bin_op_expr.op1);
316322
323 LLVMBasicBlockRef orig_block = LLVMGetInsertBlock(g->builder);
324
317 // block for when val1 == false325 // block for when val1 == false
318 LLVMBasicBlockRef false_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "BoolOrFalse");326 LLVMBasicBlockRef false_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "BoolOrFalse");
319 // block for when val1 == true (don't even evaluate the second part)327 // block for when val1 == true (don't even evaluate the second part)
...@@ -328,13 +336,14 @@ static LLVMValueRef gen_bool_or_expr(CodeGen *g, AstNode *expr_node) {...@@ -328,13 +336,14 @@ static LLVMValueRef gen_bool_or_expr(CodeGen *g, AstNode *expr_node) {
328 LLVMValueRef val2 = gen_expr(g, expr_node->data.bin_op_expr.op2);336 LLVMValueRef val2 = gen_expr(g, expr_node->data.bin_op_expr.op2);
329 add_debug_source_node(g, expr_node);337 add_debug_source_node(g, expr_node);
330 LLVMValueRef val2_i1 = LLVMBuildICmp(g->builder, LLVMIntEQ, val2, zero, "");338 LLVMValueRef val2_i1 = LLVMBuildICmp(g->builder, LLVMIntEQ, val2, zero, "");
339 LLVMBuildBr(g->builder, true_block);
331340
332 LLVMPositionBuilderAtEnd(g->builder, true_block);341 LLVMPositionBuilderAtEnd(g->builder, true_block);
333 add_debug_source_node(g, expr_node);342 add_debug_source_node(g, expr_node);
334 LLVMValueRef phi = LLVMBuildPhi(g->builder, LLVMInt1Type(), "");343 LLVMValueRef phi = LLVMBuildPhi(g->builder, LLVMInt1Type(), "");
335 LLVMValueRef one_i1 = LLVMConstAllOnes(LLVMInt1Type());344 LLVMValueRef one_i1 = LLVMConstAllOnes(LLVMInt1Type());
336 LLVMValueRef incoming_values[2] = {one_i1, val2_i1};345 LLVMValueRef incoming_values[2] = {one_i1, val2_i1};
337 LLVMBasicBlockRef incoming_blocks[2] = {LLVMGetInsertBlock(g->builder), false_block};346 LLVMBasicBlockRef incoming_blocks[2] = {orig_block, false_block};
338 LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2);347 LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2);
339348
340 return phi;349 return phi;
...@@ -383,9 +392,91 @@ static LLVMValueRef gen_return_expr(CodeGen *g, AstNode *node) {...@@ -383,9 +392,91 @@ static LLVMValueRef gen_return_expr(CodeGen *g, AstNode *node) {
383 return LLVMBuildRetVoid(g->builder);392 return LLVMBuildRetVoid(g->builder);
384 }393 }
385}394}
386/*395
387Expression : BoolOrExpression | ReturnExpression396static LLVMValueRef gen_if_expr(CodeGen *g, AstNode *node) {
388*/397 assert(node->type == NodeTypeIfExpr);
398 assert(node->data.if_expr.condition);
399 assert(node->data.if_expr.then_block);
400
401 LLVMValueRef cond_value = gen_expr(g, node->data.if_expr.condition);
402
403 TypeTableEntry *then_type = get_expr_type(node->data.if_expr.then_block);
404 bool use_expr_value = (then_type != g->builtin_types.entry_unreachable &&
405 then_type != g->builtin_types.entry_void);
406
407 if (node->data.if_expr.else_node) {
408 LLVMBasicBlockRef then_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "Then");
409 LLVMBasicBlockRef else_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "Else");
410 LLVMBasicBlockRef endif_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "EndIf");
411
412 LLVMBuildCondBr(g->builder, cond_value, then_block, else_block);
413
414 LLVMPositionBuilderAtEnd(g->builder, then_block);
415 LLVMValueRef then_expr_result = gen_expr(g, node->data.if_expr.then_block);
416 LLVMBuildBr(g->builder, endif_block);
417
418 LLVMPositionBuilderAtEnd(g->builder, else_block);
419 LLVMValueRef else_expr_result = gen_expr(g, node->data.if_expr.else_node);
420 LLVMBuildBr(g->builder, endif_block);
421
422 LLVMPositionBuilderAtEnd(g->builder, endif_block);
423 if (use_expr_value) {
424 LLVMValueRef phi = LLVMBuildPhi(g->builder, LLVMTypeOf(then_expr_result), "");
425 LLVMValueRef incoming_values[2] = {then_expr_result, else_expr_result};
426 LLVMBasicBlockRef incoming_blocks[2] = {then_block, else_block};
427 LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2);
428
429 return phi;
430 }
431
432 return nullptr;
433 }
434
435 assert(!use_expr_value);
436
437 LLVMBasicBlockRef then_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "Then");
438 LLVMBasicBlockRef endif_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "EndIf");
439
440 LLVMBuildCondBr(g->builder, cond_value, then_block, endif_block);
441
442 LLVMPositionBuilderAtEnd(g->builder, then_block);
443 gen_expr(g, node->data.if_expr.then_block);
444 LLVMBuildBr(g->builder, endif_block);
445
446 LLVMPositionBuilderAtEnd(g->builder, endif_block);
447 return nullptr;
448}
449
450static LLVMValueRef gen_block(CodeGen *g, AstNode *block_node, TypeTableEntry *implicit_return_type) {
451 assert(block_node->type == NodeTypeBlock);
452
453 ImportTableEntry *import = g->cur_fn->import_entry;
454
455 LLVMZigDILexicalBlock *di_block = LLVMZigCreateLexicalBlock(g->dbuilder, g->block_scopes.last(),
456 import->di_file, block_node->line + 1, block_node->column + 1);
457 g->block_scopes.append(LLVMZigLexicalBlockToScope(di_block));
458
459 add_debug_source_node(g, block_node);
460
461 LLVMValueRef return_value;
462 for (int i = 0; i < block_node->data.block.statements.length; i += 1) {
463 AstNode *statement_node = block_node->data.block.statements.at(i);
464 return_value = gen_expr(g, statement_node);
465 }
466
467 if (implicit_return_type) {
468 if (implicit_return_type == g->builtin_types.entry_void) {
469 LLVMBuildRetVoid(g->builder);
470 } else if (implicit_return_type != g->builtin_types.entry_unreachable) {
471 LLVMBuildRet(g->builder, return_value);
472 }
473 }
474
475 g->block_scopes.pop();
476
477 return return_value;
478}
479
389static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {480static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
390 switch (node->type) {481 switch (node->type) {
391 case NodeTypeBinOpExpr:482 case NodeTypeBinOpExpr:
...@@ -403,6 +494,8 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {...@@ -403,6 +494,8 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
403 return LLVMBuildUnreachable(g->builder);494 return LLVMBuildUnreachable(g->builder);
404 case NodeTypeVoid:495 case NodeTypeVoid:
405 return nullptr;496 return nullptr;
497 case NodeTypeIfExpr:
498 return gen_if_expr(g, node);
406 case NodeTypeNumberLiteral:499 case NodeTypeNumberLiteral:
407 {500 {
408 Buf *number_str = &node->data.number;501 Buf *number_str = &node->data.number;
...@@ -427,6 +520,8 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {...@@ -427,6 +520,8 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
427 Buf *name = &node->data.symbol;520 Buf *name = &node->data.symbol;
428 return get_variable_value(g, name);521 return get_variable_value(g, name);
429 }522 }
523 case NodeTypeBlock:
524 return gen_block(g, node, nullptr);
430 case NodeTypeRoot:525 case NodeTypeRoot:
431 case NodeTypeRootExportDecl:526 case NodeTypeRootExportDecl:
432 case NodeTypeFnProto:527 case NodeTypeFnProto:
...@@ -434,7 +529,6 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {...@@ -434,7 +529,6 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
434 case NodeTypeFnDecl:529 case NodeTypeFnDecl:
435 case NodeTypeParamDecl:530 case NodeTypeParamDecl:
436 case NodeTypeType:531 case NodeTypeType:
437 case NodeTypeBlock:
438 case NodeTypeExternBlock:532 case NodeTypeExternBlock:
439 case NodeTypeDirective:533 case NodeTypeDirective:
440 case NodeTypeUse:534 case NodeTypeUse:
...@@ -443,30 +537,6 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {...@@ -443,30 +537,6 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
443 zig_unreachable();537 zig_unreachable();
444}538}
445539
446static void gen_block(CodeGen *g, ImportTableEntry *import, AstNode *block_node, TypeTableEntry *implicit_return_type) {
447 assert(block_node->type == NodeTypeBlock);
448
449 LLVMZigDILexicalBlock *di_block = LLVMZigCreateLexicalBlock(g->dbuilder, g->block_scopes.last(),
450 import->di_file, block_node->line + 1, block_node->column + 1);
451 g->block_scopes.append(LLVMZigLexicalBlockToScope(di_block));
452
453 add_debug_source_node(g, block_node);
454
455 LLVMValueRef return_value;
456 for (int i = 0; i < block_node->data.block.statements.length; i += 1) {
457 AstNode *statement_node = block_node->data.block.statements.at(i);
458 return_value = gen_expr(g, statement_node);
459 }
460
461 if (implicit_return_type == g->builtin_types.entry_void) {
462 LLVMBuildRetVoid(g->builder);
463 } else if (implicit_return_type != g->builtin_types.entry_unreachable) {
464 LLVMBuildRet(g->builder, return_value);
465 }
466
467 g->block_scopes.pop();
468}
469
470static LLVMZigDISubroutineType *create_di_function_type(CodeGen *g, AstNodeFnProto *fn_proto,540static LLVMZigDISubroutineType *create_di_function_type(CodeGen *g, AstNodeFnProto *fn_proto,
471 LLVMZigDIFile *di_file)541 LLVMZigDIFile *di_file)
472{542{
...@@ -558,7 +628,7 @@ static void do_code_gen(CodeGen *g) {...@@ -558,7 +628,7 @@ static void do_code_gen(CodeGen *g) {
558 LLVMGetParams(fn, codegen_fn_def->params);628 LLVMGetParams(fn, codegen_fn_def->params);
559629
560 TypeTableEntry *implicit_return_type = codegen_fn_def->implicit_return_type;630 TypeTableEntry *implicit_return_type = codegen_fn_def->implicit_return_type;
561 gen_block(g, import, fn_def_node->data.fn_def.body, implicit_return_type);631 gen_block(g, fn_def_node->data.fn_def.body, implicit_return_type);
562632
563 g->block_scopes.pop();633 g->block_scopes.pop();
564 }634 }
...@@ -585,6 +655,15 @@ static void define_primitive_types(CodeGen *g) {...@@ -585,6 +655,15 @@ static void define_primitive_types(CodeGen *g) {
585 buf_init_from_str(&entry->name, "(invalid)");655 buf_init_from_str(&entry->name, "(invalid)");
586 g->builtin_types.entry_invalid = entry;656 g->builtin_types.entry_invalid = entry;
587 }657 }
658 {
659 TypeTableEntry *entry = allocate<TypeTableEntry>(1);
660 entry->type_ref = LLVMInt1Type();
661 buf_init_from_str(&entry->name, "bool");
662 entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), 1, 8,
663 LLVMZigEncoding_DW_ATE_unsigned());
664 g->type_table.put(&entry->name, entry);
665 g->builtin_types.entry_bool = entry;
666 }
588 {667 {
589 TypeTableEntry *entry = allocate<TypeTableEntry>(1);668 TypeTableEntry *entry = allocate<TypeTableEntry>(1);
590 entry->type_ref = LLVMInt8Type();669 entry->type_ref = LLVMInt8Type();
...@@ -803,7 +882,7 @@ static Buf *to_c_type(CodeGen *g, AstNode *type_node) {...@@ -803,7 +882,7 @@ static Buf *to_c_type(CodeGen *g, AstNode *type_node) {
803 g->c_stdint_used = true;882 g->c_stdint_used = true;
804 return buf_create_from_str("int32_t");883 return buf_create_from_str("int32_t");
805 } else {884 } else {
806 zig_panic("TODO");885 zig_panic("TODO to_c_type");
807 }886 }
808}887}
809888
src/parser.cpp+117-20
...@@ -91,6 +91,8 @@ const char *node_type_str(NodeType node_type) {...@@ -91,6 +91,8 @@ const char *node_type_str(NodeType node_type) {
91 return "Use";91 return "Use";
92 case NodeTypeVoid:92 case NodeTypeVoid:
93 return "Void";93 return "Void";
94 case NodeTypeIfExpr:
95 return "IfExpr";
94 }96 }
95 zig_unreachable();97 zig_unreachable();
96}98}
...@@ -236,7 +238,15 @@ void ast_print(AstNode *node, int indent) {...@@ -236,7 +238,15 @@ void ast_print(AstNode *node, int indent) {
236 fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.use.path));238 fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.use.path));
237 break;239 break;
238 case NodeTypeVoid:240 case NodeTypeVoid:
239 fprintf(stderr, "Void\n");241 fprintf(stderr, "%s\n", node_type_str(node->type));
242 break;
243 case NodeTypeIfExpr:
244 fprintf(stderr, "%s\n", node_type_str(node->type));
245 if (node->data.if_expr.condition)
246 ast_print(node->data.if_expr.condition, indent + 2);
247 ast_print(node->data.if_expr.then_block, indent + 2);
248 if (node->data.if_expr.else_node)
249 ast_print(node->data.if_expr.else_node, indent + 2);
240 break;250 break;
241 }251 }
242}252}
...@@ -353,6 +363,7 @@ static void ast_invalid_token_error(ParseContext *pc, Token *token) {...@@ -353,6 +363,7 @@ static void ast_invalid_token_error(ParseContext *pc, Token *token) {
353363
354static AstNode *ast_parse_expression(ParseContext *pc, int *token_index, bool mandatory);364static AstNode *ast_parse_expression(ParseContext *pc, int *token_index, bool mandatory);
355static AstNode *ast_parse_block(ParseContext *pc, int *token_index, bool mandatory);365static AstNode *ast_parse_block(ParseContext *pc, int *token_index, bool mandatory);
366static AstNode *ast_parse_if_expr(ParseContext *pc, int *token_index, bool mandatory);
356367
357368
358static void ast_expect_token(ParseContext *pc, Token *token, TokenId token_id) {369static void ast_expect_token(ParseContext *pc, Token *token, TokenId token_id) {
...@@ -558,7 +569,7 @@ static AstNode *ast_parse_grouped_expr(ParseContext *pc, int *token_index, bool...@@ -558,7 +569,7 @@ static AstNode *ast_parse_grouped_expr(ParseContext *pc, int *token_index, bool
558}569}
559570
560/*571/*
561PrimaryExpression : token(Number) | token(String) | token(Unreachable) | GroupedExpression | Block | token(Symbol)572PrimaryExpression : token(Number) | token(String) | token(Unreachable) | GroupedExpression | token(Symbol)
562*/573*/
563static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool mandatory) {574static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool mandatory) {
564 Token *token = &pc->tokens->at(*token_index);575 Token *token = &pc->tokens->at(*token_index);
...@@ -588,11 +599,6 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool...@@ -588,11 +599,6 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool
588 return node;599 return node;
589 }600 }
590601
591 AstNode *block_node = ast_parse_block(pc, token_index, false);
592 if (block_node) {
593 return block_node;
594 }
595
596 AstNode *grouped_expr_node = ast_parse_grouped_expr(pc, token_index, false);602 AstNode *grouped_expr_node = ast_parse_grouped_expr(pc, token_index, false);
597 if (grouped_expr_node) {603 if (grouped_expr_node) {
598 return grouped_expr_node;604 return grouped_expr_node;
...@@ -975,6 +981,50 @@ static AstNode *ast_parse_bool_and_expr(ParseContext *pc, int *token_index, bool...@@ -975,6 +981,50 @@ static AstNode *ast_parse_bool_and_expr(ParseContext *pc, int *token_index, bool
975 return node;981 return node;
976}982}
977983
984/*
985ElseIf : token(Else) IfExpression
986Else : token(Else) Block
987*/
988static AstNode *ast_parse_else_or_else_if(ParseContext *pc, int *token_index, bool mandatory) {
989 Token *else_token = &pc->tokens->at(*token_index);
990
991 if (else_token->id != TokenIdKeywordElse) {
992 if (mandatory) {
993 ast_invalid_token_error(pc, else_token);
994 } else {
995 return nullptr;
996 }
997 }
998 *token_index += 1;
999
1000 AstNode *if_expr = ast_parse_if_expr(pc, token_index, false);
1001 if (if_expr)
1002 return if_expr;
1003
1004 return ast_parse_block(pc, token_index, true);
1005}
1006
1007/*
1008IfExpression : token(If) Expression Block option(Else | ElseIf)
1009*/
1010static AstNode *ast_parse_if_expr(ParseContext *pc, int *token_index, bool mandatory) {
1011 Token *if_tok = &pc->tokens->at(*token_index);
1012 if (if_tok->id != TokenIdKeywordIf) {
1013 if (mandatory) {
1014 ast_invalid_token_error(pc, if_tok);
1015 } else {
1016 return nullptr;
1017 }
1018 }
1019 *token_index += 1;
1020
1021 AstNode *node = ast_create_node(pc, NodeTypeIfExpr, if_tok);
1022 node->data.if_expr.condition = ast_parse_expression(pc, token_index, true);
1023 node->data.if_expr.then_block = ast_parse_block(pc, token_index, true);
1024 node->data.if_expr.else_node = ast_parse_else_or_else_if(pc, token_index, false);
1025 return node;
1026}
1027
978/*1028/*
979ReturnExpression : token(Return) option(Expression)1029ReturnExpression : token(Return) option(Expression)
980*/1030*/
...@@ -1016,27 +1066,68 @@ static AstNode *ast_parse_bool_or_expr(ParseContext *pc, int *token_index, bool...@@ -1016,27 +1066,68 @@ static AstNode *ast_parse_bool_or_expr(ParseContext *pc, int *token_index, bool
1016}1066}
10171067
1018/*1068/*
1019Expression : BoolOrExpression | ReturnExpression1069BlockExpression : IfExpression | Block
1020*/1070*/
1021static AstNode *ast_parse_expression(ParseContext *pc, int *token_index, bool mandatory) {1071static AstNode *ast_parse_block_expr(ParseContext *pc, int *token_index, bool mandatory) {
1022 Token *token = &pc->tokens->at(*token_index);1072 Token *token = &pc->tokens->at(*token_index);
10231073
1024 AstNode *return_expr = ast_parse_return_expr(pc, token_index, false);1074 AstNode *if_expr = ast_parse_if_expr(pc, token_index, false);
1025 if (return_expr)1075 if (if_expr)
1026 return return_expr;1076 return if_expr;
1077
1078 AstNode *block = ast_parse_block(pc, token_index, false);
1079 if (block)
1080 return block;
1081
1082 if (mandatory)
1083 ast_invalid_token_error(pc, token);
1084
1085 return nullptr;
1086}
1087
1088/*
1089NonBlockExpression : BoolOrExpression | ReturnExpression
1090*/
1091static AstNode *ast_parse_non_block_expr(ParseContext *pc, int *token_index, bool mandatory) {
1092 Token *token = &pc->tokens->at(*token_index);
10271093
1028 AstNode *bool_or_expr = ast_parse_bool_or_expr(pc, token_index, false);1094 AstNode *bool_or_expr = ast_parse_bool_or_expr(pc, token_index, false);
1029 if (bool_or_expr)1095 if (bool_or_expr)
1030 return bool_or_expr;1096 return bool_or_expr;
10311097
1032 if (!mandatory)1098 AstNode *return_expr = ast_parse_return_expr(pc, token_index, false);
1033 return nullptr;1099 if (return_expr)
1100 return return_expr;
10341101
1035 ast_invalid_token_error(pc, token);1102 if (mandatory)
1103 ast_invalid_token_error(pc, token);
1104
1105 return nullptr;
1106}
1107
1108/*
1109Expression : BlockExpression | NonBlockExpression
1110*/
1111static AstNode *ast_parse_expression(ParseContext *pc, int *token_index, bool mandatory) {
1112 Token *token = &pc->tokens->at(*token_index);
1113
1114 AstNode *block_expr = ast_parse_block_expr(pc, token_index, false);
1115 if (block_expr)
1116 return block_expr;
1117
1118 AstNode *non_block_expr = ast_parse_non_block_expr(pc, token_index, false);
1119 if (non_block_expr)
1120 return non_block_expr;
1121
1122 if (mandatory)
1123 ast_invalid_token_error(pc, token);
1124
1125 return nullptr;
1036}1126}
10371127
1038/*1128/*
1039Block : token(LBrace) list(option(Expression), token(Semicolon)) token(RBrace)1129Statement : NonBlockExpression token(Semicolon) | BlockExpression
1130Block : token(LBrace) list(option(Statement), token(Semicolon)) token(RBrace)
1040*/1131*/
1041static AstNode *ast_parse_block(ParseContext *pc, int *token_index, bool mandatory) {1132static AstNode *ast_parse_block(ParseContext *pc, int *token_index, bool mandatory) {
1042 Token *last_token = &pc->tokens->at(*token_index);1133 Token *last_token = &pc->tokens->at(*token_index);
...@@ -1058,16 +1149,22 @@ static AstNode *ast_parse_block(ParseContext *pc, int *token_index, bool mandato...@@ -1058,16 +1149,22 @@ static AstNode *ast_parse_block(ParseContext *pc, int *token_index, bool mandato
1058 // {2;} -> {2;void}1149 // {2;} -> {2;void}
1059 // {;2} -> {void;2}1150 // {;2} -> {void;2}
1060 for (;;) {1151 for (;;) {
1061 AstNode *expression_node = ast_parse_expression(pc, token_index, false);1152 AstNode *statement_node = ast_parse_block_expr(pc, token_index, false);
1062 if (!expression_node) {1153 bool semicolon_expected = !statement_node;
1063 expression_node = ast_create_node(pc, NodeTypeVoid, last_token);1154 if (!statement_node) {
1155 statement_node = ast_parse_non_block_expr(pc, token_index, false);
1156 if (!statement_node) {
1157 statement_node = ast_create_node(pc, NodeTypeVoid, last_token);
1158 }
1064 }1159 }
1065 node->data.block.statements.append(expression_node);1160 node->data.block.statements.append(statement_node);
10661161
1067 last_token = &pc->tokens->at(*token_index);1162 last_token = &pc->tokens->at(*token_index);
1068 if (last_token->id == TokenIdRBrace) {1163 if (last_token->id == TokenIdRBrace) {
1069 *token_index += 1;1164 *token_index += 1;
1070 return node;1165 return node;
1166 } else if (!semicolon_expected) {
1167 continue;
1071 } else if (last_token->id == TokenIdSemicolon) {1168 } else if (last_token->id == TokenIdSemicolon) {
1072 *token_index += 1;1169 *token_index += 1;
1073 } else {1170 } else {
src/parser.hpp+8
...@@ -39,6 +39,7 @@ enum NodeType {...@@ -39,6 +39,7 @@ enum NodeType {
39 NodeTypeFnCallExpr,39 NodeTypeFnCallExpr,
40 NodeTypeUse,40 NodeTypeUse,
41 NodeTypeVoid,41 NodeTypeVoid,
42 NodeTypeIfExpr,
42};43};
4344
44struct AstNodeRoot {45struct AstNodeRoot {
...@@ -167,6 +168,12 @@ struct AstNodeUse {...@@ -167,6 +168,12 @@ struct AstNodeUse {
167 ZigList<AstNode *> *directives;168 ZigList<AstNode *> *directives;
168};169};
169170
171struct AstNodeIfExpr {
172 AstNode *condition;
173 AstNode *then_block;
174 AstNode *else_node; // null, block node, or other if expr node
175};
176
170struct AstNode {177struct AstNode {
171 enum NodeType type;178 enum NodeType type;
172 int line;179 int line;
...@@ -190,6 +197,7 @@ struct AstNode {...@@ -190,6 +197,7 @@ struct AstNode {
190 AstNodePrefixOpExpr prefix_op_expr;197 AstNodePrefixOpExpr prefix_op_expr;
191 AstNodeFnCallExpr fn_call_expr;198 AstNodeFnCallExpr fn_call_expr;
192 AstNodeUse use;199 AstNodeUse use;
200 AstNodeIfExpr if_expr;
193 Buf number;201 Buf number;
194 Buf string;202 Buf string;
195 Buf symbol;203 Buf symbol;
src/semantic_info.hpp+6
...@@ -63,6 +63,7 @@ struct CodeGen {...@@ -63,6 +63,7 @@ struct CodeGen {
63 HashMap<Buf *, ImportTableEntry *, buf_hash, buf_eql_buf> import_table;63 HashMap<Buf *, ImportTableEntry *, buf_hash, buf_eql_buf> import_table;
6464
65 struct {65 struct {
66 TypeTableEntry *entry_bool;
66 TypeTableEntry *entry_u8;67 TypeTableEntry *entry_u8;
67 TypeTableEntry *entry_i32;68 TypeTableEntry *entry_i32;
68 TypeTableEntry *entry_string_literal;69 TypeTableEntry *entry_string_literal;
...@@ -111,10 +112,15 @@ struct FnDefNode {...@@ -111,10 +112,15 @@ struct FnDefNode {
111 LLVMValueRef *params;112 LLVMValueRef *params;
112};113};
113114
115struct ExprNode {
116 TypeTableEntry *type_entry;
117};
118
114struct CodeGenNode {119struct CodeGenNode {
115 union {120 union {
116 TypeNode type_node; // for NodeTypeType121 TypeNode type_node; // for NodeTypeType
117 FnDefNode fn_def_node; // for NodeTypeFnDef122 FnDefNode fn_def_node; // for NodeTypeFnDef
123 ExprNode expr_node; // for all the expression nodes
118 } data;124 } data;
119};125};
120126
src/tokenizer.cpp+6
...@@ -183,6 +183,10 @@ static void end_token(Tokenize *t) {...@@ -183,6 +183,10 @@ static void end_token(Tokenize *t) {
183 t->cur_tok->id = TokenIdKeywordUse;183 t->cur_tok->id = TokenIdKeywordUse;
184 } else if (mem_eql_str(token_mem, token_len, "void")) {184 } else if (mem_eql_str(token_mem, token_len, "void")) {
185 t->cur_tok->id = TokenIdKeywordVoid;185 t->cur_tok->id = TokenIdKeywordVoid;
186 } else if (mem_eql_str(token_mem, token_len, "if")) {
187 t->cur_tok->id = TokenIdKeywordIf;
188 } else if (mem_eql_str(token_mem, token_len, "else")) {
189 t->cur_tok->id = TokenIdKeywordElse;
186 }190 }
187191
188 t->cur_tok = nullptr;192 t->cur_tok = nullptr;
...@@ -577,6 +581,8 @@ static const char * token_name(Token *token) {...@@ -577,6 +581,8 @@ static const char * token_name(Token *token) {
577 case TokenIdKeywordAs: return "As";581 case TokenIdKeywordAs: return "As";
578 case TokenIdKeywordUse: return "Use";582 case TokenIdKeywordUse: return "Use";
579 case TokenIdKeywordVoid: return "Void";583 case TokenIdKeywordVoid: return "Void";
584 case TokenIdKeywordIf: return "If";
585 case TokenIdKeywordElse: return "Else";
580 case TokenIdLParen: return "LParen";586 case TokenIdLParen: return "LParen";
581 case TokenIdRParen: return "RParen";587 case TokenIdRParen: return "RParen";
582 case TokenIdComma: return "Comma";588 case TokenIdComma: return "Comma";
src/tokenizer.hpp+2
...@@ -24,6 +24,8 @@ enum TokenId {...@@ -24,6 +24,8 @@ enum TokenId {
24 TokenIdKeywordAs,24 TokenIdKeywordAs,
25 TokenIdKeywordUse,25 TokenIdKeywordUse,
26 TokenIdKeywordVoid,26 TokenIdKeywordVoid,
27 TokenIdKeywordIf,
28 TokenIdKeywordElse,
27 TokenIdLParen,29 TokenIdLParen,
28 TokenIdRParen,30 TokenIdRParen,
29 TokenIdComma,31 TokenIdComma,
test/run_tests.cpp+24
...@@ -189,6 +189,30 @@ static void add_compiling_test_cases(void) {...@@ -189,6 +189,30 @@ static void add_compiling_test_cases(void) {
189 )SOURCE");189 )SOURCE");
190 }190 }
191191
192 add_simple_case("if statements", R"SOURCE(
193 #link("c")
194 extern {
195 fn puts(s: *const u8) -> i32;
196 fn exit(code: i32) -> unreachable;
197 }
198
199 export fn _start() -> unreachable {
200 if 1 != 0 {
201 puts("1 is true");
202 } else {
203 puts("1 is false");
204 }
205 if 0 != 0 {
206 puts("0 is true");
207 } else if 1 - 1 != 0 {
208 puts("1 - 1 is true");
209 }
210 if !(0 != 0) {
211 puts("!0 is true");
212 }
213 exit(0);
214 }
215 )SOURCE", "1 is true\n!0 is true\n");
192}216}
193217
194static void add_compile_failure_test_cases(void) {218static void add_compile_failure_test_cases(void) {