diff --git a/clox/src/object.h b/clox/src/object.h index 2a87a51..a26077f 100644 --- a/clox/src/object.h +++ b/clox/src/object.h @@ -25,7 +25,9 @@ struct ObjString { char *chars; }; +ObjString *takeString(char *chars, int length); ObjString *copyString(const char *chars, int length); +void printObject(Value value); static inline bool isObjType(Value value, ObjType type) { return IS_OBJ(value) && AS_OBJ(value)->type == type; diff --git a/clox/src/value.c b/clox/src/value.c index 34e55b8..a5f8540 100644 --- a/clox/src/value.c +++ b/clox/src/value.c @@ -1,6 +1,8 @@ #include +#include #include "memory.h" +#include "object.h" #include "value.h" void initValueArray(ValueArray *array) { @@ -37,6 +39,9 @@ void printValue(Value value) { case VAL_NUMBER: printf("%g", AS_NUMBER(value)); break; + case VAL_OBJ: + printObject(value); + break; } } @@ -50,6 +55,12 @@ bool valuesEqual(Value a, Value b) { return true; case VAL_NUMBER: return AS_NUMBER(a) == AS_NUMBER(b); + case VAL_OBJ: { + ObjString *aString = AS_STRING(a); + ObjString *bString = AS_STRING(b); + return aString->length == bString->length && + memcmp(aString->chars, bString->chars, aString->length) == 0; + } default: return false; /* Unreachable */ } diff --git a/clox/src/vm.c b/clox/src/vm.c index df9f490..fae0092 100644 --- a/clox/src/vm.c +++ b/clox/src/vm.c @@ -1,9 +1,12 @@ #include #include +#include #include "common.h" #include "compiler.h" #include "debug.h" +#include "memory.h" +#include "object.h" #include "vm.h" VM vm; @@ -43,6 +46,20 @@ static bool isFalsey(Value value) { return IS_NIL(value) || (IS_BOOL(value) && !AS_BOOL(value)); } +static void concatenate() { + ObjString *b = AS_STRING(pop()); + ObjString *a = AS_STRING(pop()); + + int length = a->length + b->length; + char *chars = ALLOCATE(char, length + 1); + memcpy(chars, a->chars, a->length); + memcpy(chars + a->length, b->chars, b->length); + chars[length] = '\0'; + + ObjString *result = takeString(chars, length); + push(OBJ_VAL(result)); +} + static InterpretResult run() { #define READ_BYTE() (*vm.ip++) #define READ_CONSTANT() (vm.chunk->constants.values[READ_BYTE()]) @@ -96,9 +113,19 @@ static InterpretResult run() { case OP_LESS: BINARY_OP(BOOL_VAL, <); break; - case OP_ADD: - BINARY_OP(NUMBER_VAL, +); + case OP_ADD: { + if (IS_STRING(peek(0)) && IS_STRING(peek(1))) { + concatenate(); + } else if (IS_NUMBER(peek(0)) && IS_NUMBER(peek(1))) { + double b = AS_NUMBER(pop()); + double a = AS_NUMBER(pop()); + push(NUMBER_VAL(a + b)); + } else { + runtimeError("Operands must be two numbers or two strings."); + return INTERPRET_RUNTIME_ERROR; + } break; + } case OP_SUBTRACT: BINARY_OP(NUMBER_VAL, -); break;