Skip to content

Commit 576bce9

Browse files
committed
feat: add logical operators (and, or) and while statements
1 parent 25f8ecb commit 576bce9

4 files changed

Lines changed: 67 additions & 9 deletions

File tree

src/chunk.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ typedef enum
2828
OP_PRINT,
2929
OP_JUMP,
3030
OP_JUMP_IF_FALSE,
31+
OP_LOOP,
3132
OP_RETURN,
3233
} OpCode;
3334

src/compiler.c

Lines changed: 57 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
1-
#include <assert.h>
21
#include <stdint.h>
32
#include <stdio.h>
43
#include <stdlib.h>
54
#include <string.h>
6-
#include <sys/types.h>
75

86
#include "chunk.h"
97
#include "common.h"
@@ -153,6 +151,18 @@ static void emit_bytes(u8 byte_1, u8 byte_2)
153151
emit_byte(byte_2);
154152
}
155153

154+
static void emit_loop(int loop_start)
155+
{
156+
emit_byte(OP_LOOP);
157+
158+
int offset = current_chunk()->count - loop_start + 2;
159+
if (offset > UINT16_MAX)
160+
error("Loop body too large");
161+
162+
emit_byte((offset >> 8) & 0xff);
163+
emit_byte(offset & 0xff);
164+
}
165+
156166
static int emit_jump(u8 instruction)
157167
{
158168
emit_byte(instruction);
@@ -319,6 +329,16 @@ static void define_variable(u8 global, bool is_immutable)
319329
emit_bytes(OP_DEFINE_GLOBAL, global);
320330
}
321331

332+
static void and_(bool can_assign)
333+
{
334+
int end_jump = emit_jump(OP_JUMP_IF_FALSE);
335+
336+
emit_byte(OP_POP);
337+
parse_precedence(PREC_AND);
338+
339+
patch_jump(end_jump);
340+
}
341+
322342
static void binary(bool can_assign)
323343
{
324344
TokenType operator_type = parser.previous.type;
@@ -393,6 +413,18 @@ static void number(bool can_assign)
393413
emit_constant(NUMBER_VAL(value));
394414
}
395415

416+
static void or_(bool can_assign)
417+
{
418+
int else_jump = emit_jump(OP_JUMP_IF_FALSE);
419+
int end_jump = emit_jump(OP_JUMP);
420+
421+
patch_jump(else_jump);
422+
emit_byte(OP_POP);
423+
424+
parse_precedence(PREC_OR);
425+
patch_jump(end_jump);
426+
}
427+
396428
static void string(bool can_assign)
397429
{
398430
emit_constant(OBJ_VAL(
@@ -489,15 +521,15 @@ ParseRule rules[] = {
489521
[TOKEN_STRING] = { string, NULL, PREC_NONE },
490522
[TOKEN_NUMBER] = { number, NULL, PREC_NONE },
491523
[TOKEN_IDENTIFIER] = { variable, NULL, PREC_NONE },
492-
[TOKEN_AND] = { NULL, NULL, PREC_NONE },
524+
[TOKEN_AND] = { NULL, and_, PREC_AND },
493525
[TOKEN_CLASS] = { NULL, NULL, PREC_NONE },
494526
[TOKEN_ELSE] = { NULL, NULL, PREC_NONE },
495527
[TOKEN_FALSE] = { literal, NULL, PREC_NONE },
496528
[TOKEN_FOR] = { NULL, NULL, PREC_NONE },
497529
[TOKEN_FUN] = { NULL, NULL, PREC_NONE },
498530
[TOKEN_IF] = { NULL, NULL, PREC_NONE },
499531
[TOKEN_NIL] = { literal, NULL, PREC_NONE },
500-
[TOKEN_OR] = { NULL, NULL, PREC_NONE },
532+
[TOKEN_OR] = { NULL, or_, PREC_OR },
501533
[TOKEN_PRINT] = { NULL, NULL, PREC_NONE },
502534
[TOKEN_RETURN] = { NULL, NULL, PREC_NONE },
503535
[TOKEN_SUPER] = { NULL, NULL, PREC_NONE },
@@ -610,6 +642,23 @@ static void print_statement()
610642
emit_byte(OP_PRINT);
611643
}
612644

645+
static void while_statement()
646+
{
647+
int loop_start = current_chunk()->count;
648+
consume(TOKEN_LEFT_PAREN, "Expect '(' after while statement");
649+
expression();
650+
consume(TOKEN_RIGHT_PAREN, "Expect ')' after condition");
651+
652+
int exit_jump = emit_jump(OP_JUMP_IF_FALSE);
653+
654+
emit_byte(OP_POP);
655+
statement();
656+
657+
emit_loop(loop_start);
658+
patch_jump(exit_jump);
659+
emit_byte(OP_POP);
660+
}
661+
613662
static void synchronize()
614663
{
615664
parser.panic_mode = false;
@@ -660,6 +709,10 @@ static void statement()
660709
{
661710
if_statement();
662711
}
712+
else if (match(TOKEN_WHILE))
713+
{
714+
while_statement();
715+
}
663716
else if (match(TOKEN_LEFT_BRACE))
664717
{
665718
begin_scope();

src/debug.c

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ int disassemble_instruction(Chunk* chunk, int offset)
7676
return jump_instruction("OP_JUMP", 1, chunk, offset);
7777
case OP_JUMP_IF_FALSE:
7878
return jump_instruction("OP_JUMP_IF_FALSE", 1, chunk, offset);
79+
case OP_LOOP:
80+
return jump_instruction("OP_JUMP_IF_FALSE", -1, chunk, offset);
7981
case OP_RETURN:
8082
return simple_instruction("OP_RETURN", offset);
8183
default:
@@ -100,7 +102,7 @@ static int byte_instruction(const char* name, Chunk* chunk, int offset)
100102
static int jump_instruction(const char* name, int sign, Chunk* chunk,
101103
int offset)
102104
{
103-
u16 jump = (u16)(chunk->code[offset + 1] << 8);
105+
u16 jump = (u16)(chunk->code[offset + 1] << 8); // n << 8 -> n * 2^8
104106
jump |= chunk->code[offset];
105107
printf("%-16s %4d -> %d\n", name, offset, offset + 3 + sign * jump);
106108
return offset + 3;
@@ -141,7 +143,6 @@ static const char* token_type_to_string(TokenType type)
141143
return "SLASH";
142144
case TOKEN_STAR:
143145
return "STAR";
144-
145146
case TOKEN_BANG:
146147
return "BANG";
147148
case TOKEN_BANG_EQUAL:
@@ -158,14 +159,12 @@ static const char* token_type_to_string(TokenType type)
158159
return "LESS";
159160
case TOKEN_LESS_EQUAL:
160161
return "LESS_EQUAL";
161-
162162
case TOKEN_IDENTIFIER:
163163
return "IDENTIFIER";
164164
case TOKEN_STRING:
165165
return "STRING";
166166
case TOKEN_NUMBER:
167167
return "NUMBER";
168-
169168
case TOKEN_AND:
170169
return "AND";
171170
case TOKEN_CLASS:
@@ -200,7 +199,6 @@ static const char* token_type_to_string(TokenType type)
200199
return "VAL";
201200
case TOKEN_WHILE:
202201
return "WHILE";
203-
204202
case TOKEN_ERROR:
205203
return "ERROR";
206204
case TOKEN_EOF:

src/vm.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,12 @@ static InterpretResult run()
251251
vm.ip += offset;
252252
break;
253253
}
254+
case OP_LOOP:
255+
{
256+
u16 offset = READ_SHORT();
257+
vm.ip -= offset;
258+
break;
259+
}
254260
case OP_RETURN:
255261
return INTERPRET_OK;
256262
}

0 commit comments

Comments
 (0)