diff --git a/example/hello.wren b/example/hello.wren index 197294c4..76116364 100644 --- a/example/hello.wren +++ b/example/hello.wren @@ -5,3 +5,4 @@ class Foo { // line comment } var a = Foo.new a.bar +"a string" diff --git a/src/compiler.c b/src/compiler.c index 5b0e8969..6a072a42 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -105,6 +105,7 @@ static void expression(Compiler* compiler); static void call(Compiler* compiler); static void primary(Compiler* compiler); static void number(Compiler* compiler); +static void string(Compiler* compiler); static TokenType peek(Compiler* compiler); static int match(Compiler* compiler, TokenType expected); static void consume(Compiler* compiler, TokenType expected); @@ -339,6 +340,13 @@ void primary(Compiler* compiler) number(compiler); return; } + + // String. + if (match(compiler, TOKEN_STRING)) + { + string(compiler); + return; + } } void number(Compiler* compiler) @@ -362,6 +370,27 @@ void number(Compiler* compiler) emit(compiler, constant); } +void string(Compiler* compiler) +{ + Token* token = &compiler->parser->previous; + + // TODO(bob): Handle escaping. + + // Copy the string to the heap. + // Strip the surrounding "" off. + size_t length = token->end - token->start - 2; + char* text = malloc(length + 1); + strncpy(text, compiler->parser->source + token->start + 1, length); + text[length] = '\0'; + + // Define a constant for the literal. + int constant = addConstant(compiler, (Value)makeString(text)); + + // Compile the code to load the constant. + emit(compiler, CODE_CONSTANT); + emit(compiler, constant); +} + TokenType peek(Compiler* compiler) { return compiler->parser->current.type; diff --git a/src/vm.c b/src/vm.c index 606143c9..295a10a4 100644 --- a/src/vm.c +++ b/src/vm.c @@ -113,6 +113,15 @@ ObjNum* makeNum(double number) return num; } +ObjString* makeString(const char* text) +{ + ObjString* string = malloc(sizeof(ObjString)); + string->obj.type = OBJ_STRING; + string->obj.flags = 0; + string->value = text; + return string; +} + ObjInstance* makeInstance(ObjClass* classObj) { ObjInstance* instance = malloc(sizeof(ObjInstance)); @@ -304,6 +313,10 @@ Value interpret(VM* vm, ObjBlock* block) classObj = vm->numClass; break; + case OBJ_STRING: + classObj = vm->stringClass; + break; + case OBJ_INSTANCE: classObj = ((ObjInstance*)receiver)->classObj; break; @@ -376,6 +389,10 @@ void printValue(Value value) printf("%f", ((ObjNum*)value)->value); break; + case OBJ_STRING: + printf("%s", ((ObjString*)value)->value); + break; + case OBJ_BLOCK: printf("[block]"); break; diff --git a/src/vm.h b/src/vm.h index 8ba25d0f..5c9ea56b 100644 --- a/src/vm.h +++ b/src/vm.h @@ -8,6 +8,7 @@ typedef enum { OBJ_NUM, + OBJ_STRING, OBJ_BLOCK, OBJ_CLASS, OBJ_INSTANCE @@ -33,6 +34,12 @@ typedef struct double value; } ObjNum; +typedef struct +{ + Obj obj; + const char* value; +} ObjString; + typedef struct { Obj obj; @@ -129,6 +136,7 @@ typedef struct ObjClass* blockClass; ObjClass* classClass; ObjClass* numClass; + ObjClass* stringClass; SymbolTable globalSymbols; // TODO(bob): Using a fixed array is gross here. @@ -142,6 +150,9 @@ void freeVM(VM* vm); ObjClass* makeClass(); ObjBlock* makeBlock(); ObjNum* makeNum(double number); + +// Creates a new string object. Does not copy text. +ObjString* makeString(const char* text); ObjInstance* makeInstance(ObjClass* classObj); // Initializes the symbol table.