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
|
var a = Foo.new
|
||||||
a.bar
|
a.bar
|
||||||
|
"a string"
|
||||||
|
|||||||
@ -105,6 +105,7 @@ static void expression(Compiler* compiler);
|
|||||||
static void call(Compiler* compiler);
|
static void call(Compiler* compiler);
|
||||||
static void primary(Compiler* compiler);
|
static void primary(Compiler* compiler);
|
||||||
static void number(Compiler* compiler);
|
static void number(Compiler* compiler);
|
||||||
|
static void string(Compiler* compiler);
|
||||||
static TokenType peek(Compiler* compiler);
|
static TokenType peek(Compiler* compiler);
|
||||||
static int match(Compiler* compiler, TokenType expected);
|
static int match(Compiler* compiler, TokenType expected);
|
||||||
static void consume(Compiler* compiler, TokenType expected);
|
static void consume(Compiler* compiler, TokenType expected);
|
||||||
@ -339,6 +340,13 @@ void primary(Compiler* compiler)
|
|||||||
number(compiler);
|
number(compiler);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// String.
|
||||||
|
if (match(compiler, TOKEN_STRING))
|
||||||
|
{
|
||||||
|
string(compiler);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void number(Compiler* compiler)
|
void number(Compiler* compiler)
|
||||||
@ -362,6 +370,27 @@ void number(Compiler* compiler)
|
|||||||
emit(compiler, constant);
|
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)
|
TokenType peek(Compiler* compiler)
|
||||||
{
|
{
|
||||||
return compiler->parser->current.type;
|
return compiler->parser->current.type;
|
||||||
|
|||||||
17
src/vm.c
17
src/vm.c
@ -113,6 +113,15 @@ ObjNum* makeNum(double number)
|
|||||||
return num;
|
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* makeInstance(ObjClass* classObj)
|
||||||
{
|
{
|
||||||
ObjInstance* instance = malloc(sizeof(ObjInstance));
|
ObjInstance* instance = malloc(sizeof(ObjInstance));
|
||||||
@ -304,6 +313,10 @@ Value interpret(VM* vm, ObjBlock* block)
|
|||||||
classObj = vm->numClass;
|
classObj = vm->numClass;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case OBJ_STRING:
|
||||||
|
classObj = vm->stringClass;
|
||||||
|
break;
|
||||||
|
|
||||||
case OBJ_INSTANCE:
|
case OBJ_INSTANCE:
|
||||||
classObj = ((ObjInstance*)receiver)->classObj;
|
classObj = ((ObjInstance*)receiver)->classObj;
|
||||||
break;
|
break;
|
||||||
@ -376,6 +389,10 @@ void printValue(Value value)
|
|||||||
printf("%f", ((ObjNum*)value)->value);
|
printf("%f", ((ObjNum*)value)->value);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case OBJ_STRING:
|
||||||
|
printf("%s", ((ObjString*)value)->value);
|
||||||
|
break;
|
||||||
|
|
||||||
case OBJ_BLOCK:
|
case OBJ_BLOCK:
|
||||||
printf("[block]");
|
printf("[block]");
|
||||||
break;
|
break;
|
||||||
|
|||||||
11
src/vm.h
11
src/vm.h
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
OBJ_NUM,
|
OBJ_NUM,
|
||||||
|
OBJ_STRING,
|
||||||
OBJ_BLOCK,
|
OBJ_BLOCK,
|
||||||
OBJ_CLASS,
|
OBJ_CLASS,
|
||||||
OBJ_INSTANCE
|
OBJ_INSTANCE
|
||||||
@ -33,6 +34,12 @@ typedef struct
|
|||||||
double value;
|
double value;
|
||||||
} ObjNum;
|
} ObjNum;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
Obj obj;
|
||||||
|
const char* value;
|
||||||
|
} ObjString;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
Obj obj;
|
Obj obj;
|
||||||
@ -129,6 +136,7 @@ typedef struct
|
|||||||
ObjClass* blockClass;
|
ObjClass* blockClass;
|
||||||
ObjClass* classClass;
|
ObjClass* classClass;
|
||||||
ObjClass* numClass;
|
ObjClass* numClass;
|
||||||
|
ObjClass* stringClass;
|
||||||
|
|
||||||
SymbolTable globalSymbols;
|
SymbolTable globalSymbols;
|
||||||
// TODO(bob): Using a fixed array is gross here.
|
// TODO(bob): Using a fixed array is gross here.
|
||||||
@ -142,6 +150,9 @@ void freeVM(VM* vm);
|
|||||||
ObjClass* makeClass();
|
ObjClass* makeClass();
|
||||||
ObjBlock* makeBlock();
|
ObjBlock* makeBlock();
|
||||||
ObjNum* makeNum(double number);
|
ObjNum* makeNum(double number);
|
||||||
|
|
||||||
|
// Creates a new string object. Does not copy text.
|
||||||
|
ObjString* makeString(const char* text);
|
||||||
ObjInstance* makeInstance(ObjClass* classObj);
|
ObjInstance* makeInstance(ObjClass* classObj);
|
||||||
|
|
||||||
// Initializes the symbol table.
|
// Initializes the symbol table.
|
||||||
|
|||||||
Reference in New Issue
Block a user