feat: add io.write primitive and test runner with number literal tests

Implement the io.write() primitive function that prints a value followed by a newline, enabling basic output for testing. Add a Python test runner script (runtests) that discovers and executes .wren test files, comparing output against // expect: comments. Include initial number literal tests covering positive, negative, and zero values. Remove debug print statements from the VM interpreter and refactor primitive registration macros for cleaner code.
This commit is contained in:
Bob Nystrom
2013-10-28 05:45:40 +00:00
parent 0ad65b2a0b
commit 5fb2b6b253
7 changed files with 228 additions and 45 deletions
+2 -2
View File
@@ -268,8 +268,8 @@ int defineName(Compiler* compiler)
}
int symbol = addSymbol(symbols,
compiler->parser->source + compiler->parser->previous.start,
compiler->parser->previous.end - compiler->parser->previous.start);
compiler->parser->source + compiler->parser->previous.start,
compiler->parser->previous.end - compiler->parser->previous.start);
if (symbol == -1)
{
+1 -3
View File
@@ -30,9 +30,7 @@ int main(int argc, const char * argv[])
if (block)
{
Value value = interpret(vm, block);
printValue(value);
printf("\n");
interpret(vm, block);
}
freeVM(vm);
+29 -10
View File
@@ -1,3 +1,4 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -6,14 +7,21 @@
#define PRIMITIVE(cls, name, prim) \
{ \
int symbol = ensureSymbol(&vm->symbols, name, strlen(name)); \
vm->cls##Class->methods[symbol].type = METHOD_PRIMITIVE; \
vm->cls##Class->methods[symbol].primitive = primitive_##cls##_##prim; \
cls->methods[symbol].type = METHOD_PRIMITIVE; \
cls->methods[symbol].primitive = primitive_##prim; \
}
#define DEF_PRIMITIVE(cls, prim) \
static Value primitive_##cls##_##prim(Value* args, int numArgs)
#define DEF_PRIMITIVE(prim) \
static Value primitive_##prim(Value* args, int numArgs)
DEF_PRIMITIVE(num, abs)
#define GLOBAL(cls, name) \
{ \
ObjInstance* obj = makeInstance(cls); \
int symbol = addSymbol(&vm->globalSymbols, name, strlen(name)); \
vm->globals[symbol] = (Value)obj; \
}
DEF_PRIMITIVE(num_abs)
{
double value = ((ObjNum*)args[0])->value;
if (value < 0) value = -value;
@@ -21,7 +29,7 @@ DEF_PRIMITIVE(num, abs)
return (Value)makeNum(value);
}
DEF_PRIMITIVE(string, contains)
DEF_PRIMITIVE(string_contains)
{
const char* string = ((ObjString*)args[0])->value;
// TODO(bob): Check type of arg first!
@@ -31,16 +39,27 @@ DEF_PRIMITIVE(string, contains)
return (Value)makeNum(strstr(string, search) != NULL);
}
DEF_PRIMITIVE(string, count)
DEF_PRIMITIVE(string_count)
{
double count = strlen(((ObjString*)args[0])->value);
return (Value)makeNum(count);
}
DEF_PRIMITIVE(io_write)
{
printValue(args[1]);
printf("\n");
return args[1];
}
void registerPrimitives(VM* vm)
{
PRIMITIVE(num, "abs", abs);
PRIMITIVE(string, "contains ", contains);
PRIMITIVE(string, "count", count);
PRIMITIVE(vm->numClass, "abs", num_abs);
PRIMITIVE(vm->stringClass, "contains ", string_contains);
PRIMITIVE(vm->stringClass, "count", string_count);
ObjClass* ioClass = makeClass();
PRIMITIVE(ioClass, "write ", io_write);
GLOBAL(ioClass, "io");
}
+2 -30
View File
@@ -200,9 +200,6 @@ Value interpret(VM* vm, ObjBlock* block)
int constant = frame->block->bytecode[frame->ip++];
Value value = frame->block->constants[constant];
fiber.stack[fiber.stackSize++] = value;
printf("load constant ");
printValue(value);
printf(" to %d\n", fiber.stackSize - 1);
break;
}
@@ -213,13 +210,11 @@ Value interpret(VM* vm, ObjBlock* block)
// Define a "new" method on the metaclass.
// TODO(bob): Can this be inherited?
int newSymbol = ensureSymbol(&vm->symbols, "new", strlen("new"));
printf("define new %d\n", newSymbol);
classObj->metaclass->methods[newSymbol].type = METHOD_PRIMITIVE;
classObj->metaclass->methods[newSymbol].primitive =
primitive_metaclass_new;
push(&fiber, (Value)classObj);
printf("push class at %d\n", fiber.stackSize - 1);
break;
}
@@ -232,10 +227,6 @@ Value interpret(VM* vm, ObjBlock* block)
ObjBlock* body = (ObjBlock*)frame->block->constants[constant];
classObj->methods[symbol].type = METHOD_BLOCK;
classObj->methods[symbol].block = body;
printf("define method %d using constant %d on ", symbol, constant);
printValue((Value)classObj);
printf("\n");
break;
}
@@ -243,14 +234,12 @@ Value interpret(VM* vm, ObjBlock* block)
{
int local = frame->block->bytecode[frame->ip++];
push(&fiber, fiber.stack[frame->locals + local]);
printf("load local %d to %d\n", local, fiber.stackSize - 1);
break;
}
case CODE_STORE_LOCAL:
{
int local = frame->block->bytecode[frame->ip++];
printf("store local %d from %d\n", local, fiber.stackSize - 1);
fiber.stack[frame->locals + local] = fiber.stack[fiber.stackSize - 1];
break;
}
@@ -259,25 +248,21 @@ Value interpret(VM* vm, ObjBlock* block)
{
int global = frame->block->bytecode[frame->ip++];
push(&fiber, vm->globals[global]);
printf("load global %d to %d\n", global, fiber.stackSize - 1);
break;
}
case CODE_STORE_GLOBAL:
{
int global = frame->block->bytecode[frame->ip++];
printf("store global %d from %d\n", global, fiber.stackSize - 1);
vm->globals[global] = fiber.stack[fiber.stackSize - 1];
break;
}
case CODE_DUP:
push(&fiber, fiber.stack[fiber.stackSize - 1]);
printf("dup %d\n", fiber.stackSize - 1);
break;
case CODE_POP:
printf("pop %d\n", fiber.stackSize - 1);
pop(&fiber);
break;
@@ -323,10 +308,6 @@ Value interpret(VM* vm, ObjBlock* block)
break;
}
printf("call %d on ", symbol);
printValue(receiver);
printf("\n");
Method* method = &classObj->methods[symbol];
switch (method->type)
{
@@ -363,19 +344,10 @@ Value interpret(VM* vm, ObjBlock* block)
fiber.numFrames--;
// If we are returning from the top-level block, just return the value.
if (fiber.numFrames == 0)
{
printf("done with result ");
printValue(result);
printf("\n");
return result;
}
if (fiber.numFrames == 0) return result;
// Store the result of the block in the first slot, which is where the
// caller expects it.
printf("return and store result ");
printValue(result);
printf(" in %d\n", frame->locals);
fiber.stack[frame->locals] = result;
// Discard the stack slots for the locals.
@@ -391,7 +363,7 @@ void printValue(Value value)
switch (value->type)
{
case OBJ_NUM:
printf("%f", ((ObjNum*)value)->value);
printf("%g", ((ObjNum*)value)->value);
break;
case OBJ_STRING: