diff options
Diffstat (limited to 'clox/src/vm.c')
-rw-r--r-- | clox/src/vm.c | 41 |
1 files changed, 32 insertions, 9 deletions
diff --git a/clox/src/vm.c b/clox/src/vm.c index eb79661..381c8c0 100644 --- a/clox/src/vm.c +++ b/clox/src/vm.c @@ -1,3 +1,4 @@ +#include <stdarg.h> #include <stdio.h> #include "common.h" @@ -9,6 +10,19 @@ VM vm; static void resetStack() { vm.stackTop = vm.stack; } +static void runtimeError(const char *format, ...) { + va_list args; + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fputs("\n", stderr); + + size_t instruction = vm.ip - vm.chunk->code - 1; + int line = vm.chunk->lines[instruction]; + fprintf(stderr, "[line %d] in script\n", line); + resetStack(); +} + void initVM() { resetStack(); } void freeVM() {} @@ -23,14 +37,19 @@ Value pop() { return *vm.stackTop; } +static Value peek(int distance) { return vm.stackTop[-1 - distance]; } + static InterpretResult run() { #define READ_BYTE() (*vm.ip++) #define READ_CONSTANT() (vm.chunk->constants.values[READ_BYTE()]) -#define BINARY_OP(op) \ +#define BINARY_OP(valueType, op) \ do { \ - double b = pop(); \ - double a = pop(); \ - push(a op b); \ + if (!IS_NUMBER(peek(0)) || !IS_NUMBER(peek(1))) { \ + runtimeError("Operands must be numbers."); \ + } \ + double b = AS_NUMBER(pop()); \ + double a = AS_NUMBER(pop()); \ + push(valueType(a op b)); \ } while (false) for (;;) { @@ -53,19 +72,23 @@ static InterpretResult run() { break; } case OP_ADD: - BINARY_OP(+); + BINARY_OP(NUMBER_VAL, +); break; case OP_SUBTRACT: - BINARY_OP(-); + BINARY_OP(NUMBER_VAL, -); break; case OP_MULTIPLY: - BINARY_OP(*); + BINARY_OP(NUMBER_VAL, *); break; case OP_DIVIDE: - BINARY_OP(/); + BINARY_OP(NUMBER_VAL, /); break; case OP_NEGATE: - push(-pop()); + if (!IS_NUMBER(peek(0))) { + runtimeError("Operand must be a number."); + return INTERPRET_RUNTIME_ERROR; + } + push(NUMBER_VAL(-AS_NUMBER(pop()))); break; case OP_RETURN: { printValue(pop()); |