forked from Mirror/wren
String literals and objects.
This commit is contained in:
@ -5,3 +5,4 @@ class Foo { // line comment
|
||||
}
|
||||
var a = Foo.new
|
||||
a.bar
|
||||
"a string"
|
||||
|
||||
@ -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;
|
||||
|
||||
17
src/vm.c
17
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;
|
||||
|
||||
11
src/vm.h
11
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.
|
||||
|
||||
Reference in New Issue
Block a user