fix: switch REPL eval to use fiber execution and add explicit stdout flush
Replace `Meta.eval()` to compile source into a fiber instead of a function, fixing issue #456 where top-level variable declarations failed in the REPL. Add `Stdout` import and flush stdout before reading stdin since `System.print()` no longer auto-flushes. Refactor token detection to use `lexFirst()` instead of full `lex()`, and add new `Meta.compile()` method returning a fiber. Internally rename `wrenNewString` to `wrenNewStringLength` with explicit length parameter, updating all call sites across compiler, core, and meta modules.
This commit is contained in:
@@ -911,8 +911,8 @@ static void readString(Parser* parser)
|
||||
}
|
||||
}
|
||||
|
||||
parser->current.value = wrenNewString(parser->vm,
|
||||
(char*)string.data, string.count);
|
||||
parser->current.value = wrenNewStringLength(parser->vm,
|
||||
(char*)string.data, string.count);
|
||||
|
||||
wrenByteBufferClear(parser->vm, &string);
|
||||
makeToken(parser, type);
|
||||
@@ -3188,8 +3188,8 @@ static bool method(Compiler* compiler, Variable classVariable)
|
||||
if (isForeign)
|
||||
{
|
||||
// Define a constant for the signature.
|
||||
emitConstant(compiler, wrenNewString(compiler->parser->vm,
|
||||
fullSignature, length));
|
||||
emitConstant(compiler, wrenNewStringLength(compiler->parser->vm,
|
||||
fullSignature, length));
|
||||
|
||||
// We don't need the function we started compiling in the parameter list
|
||||
// any more.
|
||||
@@ -3229,8 +3229,8 @@ static void classDefinition(Compiler* compiler, bool isForeign)
|
||||
classVariable.index = declareNamedVariable(compiler);
|
||||
|
||||
// Create shared class name value
|
||||
Value classNameString = wrenNewString(compiler->parser->vm,
|
||||
compiler->parser->previous.start, compiler->parser->previous.length);
|
||||
Value classNameString = wrenNewStringLength(compiler->parser->vm,
|
||||
compiler->parser->previous.start, compiler->parser->previous.length);
|
||||
|
||||
// Create class name string to track method duplicates
|
||||
ObjString* className = AS_STRING(classNameString);
|
||||
@@ -3349,9 +3349,9 @@ static void import(Compiler* compiler)
|
||||
|
||||
// Define a string constant for the variable name.
|
||||
int variableConstant = addConstant(compiler,
|
||||
wrenNewString(compiler->parser->vm,
|
||||
compiler->parser->previous.start,
|
||||
compiler->parser->previous.length));
|
||||
wrenNewStringLength(compiler->parser->vm,
|
||||
compiler->parser->previous.start,
|
||||
compiler->parser->previous.length));
|
||||
|
||||
// Load the variable from the other module.
|
||||
loadCoreVariable(compiler, "System");
|
||||
|
||||
+1
-1
@@ -1110,7 +1110,7 @@ DEF_PRIMITIVE(system_writeString)
|
||||
// Creates either the Object or Class class in the core module with [name].
|
||||
static ObjClass* defineClass(WrenVM* vm, ObjModule* module, const char* name)
|
||||
{
|
||||
ObjString* nameString = AS_STRING(wrenStringFormat(vm, "$", name));
|
||||
ObjString* nameString = AS_STRING(wrenNewString(vm, name));
|
||||
wrenPushRoot(vm, (Obj*)nameString);
|
||||
|
||||
ObjClass* classObj = wrenNewSingleClass(vm, 0, nameString);
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
|
||||
#define RETURN_ERROR(msg) \
|
||||
do { \
|
||||
vm->fiber->error = wrenNewString(vm, msg, sizeof(msg) - 1); \
|
||||
vm->fiber->error = wrenNewStringLength(vm, msg, sizeof(msg) - 1); \
|
||||
return false; \
|
||||
} while (0);
|
||||
|
||||
|
||||
+12
-6
@@ -695,21 +695,27 @@ static void hashString(ObjString* string)
|
||||
string->hash = hash;
|
||||
}
|
||||
|
||||
Value wrenNewString(WrenVM* vm, const char* text, size_t length)
|
||||
Value wrenNewString(WrenVM* vm, const char* text)
|
||||
{
|
||||
return wrenNewStringLength(vm, text, strlen(text));
|
||||
}
|
||||
|
||||
Value wrenNewStringLength(WrenVM* vm, const char* text, size_t length)
|
||||
{
|
||||
// Allow NULL if the string is empty since byte buffers don't allocate any
|
||||
// characters for a zero-length string.
|
||||
ASSERT(length == 0 || text != NULL, "Unexpected NULL string.");
|
||||
|
||||
|
||||
ObjString* string = allocateString(vm, length);
|
||||
|
||||
|
||||
// Copy the string (if given one).
|
||||
if (length > 0 && text != NULL) memcpy(string->value, text, length);
|
||||
|
||||
|
||||
hashString(string);
|
||||
return OBJ_VAL(string);
|
||||
}
|
||||
|
||||
|
||||
Value wrenNewStringFromRange(WrenVM* vm, ObjString* source, int start,
|
||||
uint32_t count, int step)
|
||||
{
|
||||
@@ -775,7 +781,7 @@ Value wrenNumToString(WrenVM* vm, double value)
|
||||
// = 24
|
||||
char buffer[24];
|
||||
int length = sprintf(buffer, "%.14g", value);
|
||||
return wrenNewString(vm, buffer, length);
|
||||
return wrenNewStringLength(vm, buffer, length);
|
||||
}
|
||||
|
||||
Value wrenStringFromCodePoint(WrenVM* vm, int value)
|
||||
@@ -868,7 +874,7 @@ Value wrenStringCodePointAt(WrenVM* vm, ObjString* string, uint32_t index)
|
||||
char bytes[2];
|
||||
bytes[0] = string->value[index];
|
||||
bytes[1] = '\0';
|
||||
return wrenNewString(vm, bytes, 1);
|
||||
return wrenNewStringLength(vm, bytes, 1);
|
||||
}
|
||||
|
||||
return wrenStringFromCodePoint(vm, codePoint);
|
||||
|
||||
+7
-2
@@ -81,7 +81,7 @@
|
||||
// Creates a new string object from [text], which should be a bare C string
|
||||
// literal. This determines the length of the string automatically at compile
|
||||
// time based on the size of the character array (-1 for the terminating '\0').
|
||||
#define CONST_STRING(vm, text) wrenNewString((vm), (text), sizeof(text) - 1)
|
||||
#define CONST_STRING(vm, text) wrenNewStringLength((vm), (text), sizeof(text) - 1)
|
||||
|
||||
// Identifies which specific type a heap-allocated object is.
|
||||
typedef enum {
|
||||
@@ -692,10 +692,15 @@ ObjModule* wrenNewModule(WrenVM* vm, ObjString* name);
|
||||
// Creates a new range from [from] to [to].
|
||||
Value wrenNewRange(WrenVM* vm, double from, double to, bool isInclusive);
|
||||
|
||||
// Creates a new string object and copies [text] into it.
|
||||
//
|
||||
// [text] must be non-NULL.
|
||||
Value wrenNewString(WrenVM* vm, const char* text);
|
||||
|
||||
// Creates a new string object of [length] and copies [text] into it.
|
||||
//
|
||||
// [text] may be NULL if [length] is zero.
|
||||
Value wrenNewString(WrenVM* vm, const char* text, size_t length);
|
||||
Value wrenNewStringLength(WrenVM* vm, const char* text, size_t length);
|
||||
|
||||
// Creates a new string object by taking a range of characters from [source].
|
||||
// The range starts at [start], contains [count] bytes, and increments by
|
||||
|
||||
+26
-15
@@ -474,7 +474,8 @@ static ObjModule* getModule(WrenVM* vm, Value name)
|
||||
return !IS_UNDEFINED(moduleValue) ? AS_MODULE(moduleValue) : NULL;
|
||||
}
|
||||
|
||||
static ObjFiber* loadModule(WrenVM* vm, Value name, const char* source)
|
||||
static ObjFiber* compileInModule(WrenVM* vm, Value name, const char* source,
|
||||
bool isExpression, bool printErrors)
|
||||
{
|
||||
// See if the module has already been loaded.
|
||||
ObjModule* module = getModule(vm, name);
|
||||
@@ -497,7 +498,7 @@ static ObjFiber* loadModule(WrenVM* vm, Value name, const char* source)
|
||||
}
|
||||
}
|
||||
|
||||
ObjFn* fn = wrenCompile(vm, module, source, false, true);
|
||||
ObjFn* fn = wrenCompile(vm, module, source, isExpression, printErrors);
|
||||
if (fn == NULL)
|
||||
{
|
||||
// TODO: Should we still store the module even if it didn't compile?
|
||||
@@ -506,7 +507,7 @@ static ObjFiber* loadModule(WrenVM* vm, Value name, const char* source)
|
||||
|
||||
wrenPushRoot(vm, (Obj*)fn);
|
||||
|
||||
// TODO: Doc.
|
||||
// Functions are always wrapped in closures.
|
||||
ObjClosure* closure = wrenNewClosure(vm, fn);
|
||||
wrenPushRoot(vm, (Obj*)closure);
|
||||
|
||||
@@ -1327,27 +1328,37 @@ WrenInterpretResult wrenInterpret(WrenVM* vm, const char* source)
|
||||
|
||||
WrenInterpretResult wrenInterpretInModule(WrenVM* vm, const char* module,
|
||||
const char* source)
|
||||
{
|
||||
ObjFiber* fiber = wrenCompileSource(vm, module, source, false, true);
|
||||
if (fiber == NULL) return WREN_RESULT_COMPILE_ERROR;
|
||||
|
||||
return runInterpreter(vm, fiber);
|
||||
}
|
||||
|
||||
ObjFiber* wrenCompileSource(WrenVM* vm, const char* module, const char* source,
|
||||
bool isExpression, bool printErrors)
|
||||
{
|
||||
Value nameValue = NULL_VAL;
|
||||
if (module != NULL)
|
||||
{
|
||||
nameValue = wrenStringFormat(vm, "$", module);
|
||||
nameValue = wrenNewString(vm, module);
|
||||
wrenPushRoot(vm, AS_OBJ(nameValue));
|
||||
}
|
||||
|
||||
ObjFiber* fiber = loadModule(vm, nameValue, source);
|
||||
if (fiber == NULL)
|
||||
|
||||
ObjFiber* fiber = compileInModule(vm, nameValue, source,
|
||||
isExpression, printErrors);
|
||||
if (fiber == NULL && module != NULL)
|
||||
{
|
||||
wrenPopRoot(vm);
|
||||
return WREN_RESULT_COMPILE_ERROR;
|
||||
wrenPopRoot(vm); // nameValue.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
if (module != NULL)
|
||||
{
|
||||
wrenPopRoot(vm); // nameValue.
|
||||
}
|
||||
|
||||
return runInterpreter(vm, fiber);
|
||||
|
||||
return fiber;
|
||||
}
|
||||
|
||||
Value wrenImportModule(WrenVM* vm, Value name)
|
||||
@@ -1386,7 +1397,7 @@ Value wrenImportModule(WrenVM* vm, Value name)
|
||||
return NULL_VAL;
|
||||
}
|
||||
|
||||
ObjFiber* moduleFiber = loadModule(vm, name, source);
|
||||
ObjFiber* moduleFiber = compileInModule(vm, name, source, false, true);
|
||||
|
||||
// Modules loaded by the host are expected to be dynamically allocated with
|
||||
// ownership given to the VM, which will free it. The built in optional
|
||||
@@ -1608,7 +1619,7 @@ void wrenSetSlotBool(WrenVM* vm, int slot, bool value)
|
||||
void wrenSetSlotBytes(WrenVM* vm, int slot, const char* bytes, size_t length)
|
||||
{
|
||||
ASSERT(bytes != NULL, "Byte array cannot be NULL.");
|
||||
setSlot(vm, slot, wrenNewString(vm, bytes, length));
|
||||
setSlot(vm, slot, wrenNewStringLength(vm, bytes, length));
|
||||
}
|
||||
|
||||
void wrenSetSlotDouble(WrenVM* vm, int slot, double value)
|
||||
@@ -1645,7 +1656,7 @@ void wrenSetSlotString(WrenVM* vm, int slot, const char* text)
|
||||
{
|
||||
ASSERT(text != NULL, "String cannot be NULL.");
|
||||
|
||||
setSlot(vm, slot, wrenNewString(vm, text, strlen(text)));
|
||||
setSlot(vm, slot, wrenNewString(vm, text));
|
||||
}
|
||||
|
||||
void wrenSetSlotHandle(WrenVM* vm, int slot, WrenHandle* handle)
|
||||
|
||||
@@ -135,6 +135,13 @@ WrenHandle* wrenMakeHandle(WrenVM* vm, Value value);
|
||||
WrenInterpretResult wrenInterpretInModule(WrenVM* vm, const char* module,
|
||||
const char* source);
|
||||
|
||||
// Compile [source] in the context of [module] and wrap in a fiber that can
|
||||
// execute it.
|
||||
//
|
||||
// Returns NULL if a compile error occurred.
|
||||
ObjFiber* wrenCompileSource(WrenVM* vm, const char* module, const char* source,
|
||||
bool isExpression, bool printErrors);
|
||||
|
||||
// Imports the module with [name], a string.
|
||||
//
|
||||
// If the module has already been imported (or is already in the middle of
|
||||
|
||||
Reference in New Issue
Block a user