Execute input in the REPL.
Guesses whether the input is an expression or statement and handles it appropriately. Finally, after over a year, the Wren REPL automatically prints "3" if you type in "1 + 2". \o/
This commit is contained in:
+24
-13
@@ -3345,6 +3345,7 @@ static void variableDefinition(Compiler* compiler)
|
||||
// Compile the initializer.
|
||||
if (match(compiler, TOKEN_EQ))
|
||||
{
|
||||
ignoreNewlines(compiler);
|
||||
expression(compiler);
|
||||
}
|
||||
else
|
||||
@@ -3387,7 +3388,7 @@ void definition(Compiler* compiler)
|
||||
}
|
||||
|
||||
ObjFn* wrenCompile(WrenVM* vm, ObjModule* module, const char* source,
|
||||
bool printErrors)
|
||||
bool isExpression, bool printErrors)
|
||||
{
|
||||
Parser parser;
|
||||
parser.vm = vm;
|
||||
@@ -3415,29 +3416,39 @@ ObjFn* wrenCompile(WrenVM* vm, ObjModule* module, const char* source,
|
||||
// Read the first token.
|
||||
nextToken(&parser);
|
||||
|
||||
int numExistingVariables = module->variables.count;
|
||||
|
||||
Compiler compiler;
|
||||
initCompiler(&compiler, &parser, NULL, true);
|
||||
ignoreNewlines(&compiler);
|
||||
|
||||
while (!match(&compiler, TOKEN_EOF))
|
||||
if (isExpression)
|
||||
{
|
||||
definition(&compiler);
|
||||
|
||||
// If there is no newline, it must be the end of the block on the same line.
|
||||
if (!matchLine(&compiler))
|
||||
{
|
||||
consume(&compiler, TOKEN_EOF, "Expect end of file.");
|
||||
break;
|
||||
}
|
||||
expression(&compiler);
|
||||
}
|
||||
|
||||
emitOp(&compiler, CODE_NULL);
|
||||
else
|
||||
{
|
||||
while (!match(&compiler, TOKEN_EOF))
|
||||
{
|
||||
definition(&compiler);
|
||||
|
||||
// If there is no newline, it must be the end of the block on the same line.
|
||||
if (!matchLine(&compiler))
|
||||
{
|
||||
consume(&compiler, TOKEN_EOF, "Expect end of file.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
emitOp(&compiler, CODE_NULL);
|
||||
}
|
||||
|
||||
emitOp(&compiler, CODE_RETURN);
|
||||
|
||||
// See if there are any implicitly declared module-level variables that never
|
||||
// got an explicit definition. They will have values that are numbers
|
||||
// indicating the line where the variable was first used.
|
||||
for (int i = 0; i < parser.module->variables.count; i++)
|
||||
for (int i = numExistingVariables; i < parser.module->variables.count; i++)
|
||||
{
|
||||
if (IS_NUM(parser.module->variables.data[i]))
|
||||
{
|
||||
|
||||
@@ -26,10 +26,14 @@ typedef struct sCompiler Compiler;
|
||||
// [ObjFn] that will execute that code when invoked. Returns `NULL` if the
|
||||
// source contains any syntax errors.
|
||||
//
|
||||
// If [isExpression] is `true`, [source] should be a single expression, and
|
||||
// this compiles it to a function that evaluates and returns that expression.
|
||||
// Otherwise, [source] should be a series of top level statements.
|
||||
//
|
||||
// If [printErrors] is `true`, any compile errors are output to stderr.
|
||||
// Otherwise, they are silently discarded.
|
||||
ObjFn* wrenCompile(WrenVM* vm, ObjModule* module, const char* source,
|
||||
bool printErrors);
|
||||
bool isExpression, bool printErrors);
|
||||
|
||||
// When a class is defined, its superclass is not known until runtime since
|
||||
// class definitions are just imperative statements. Most of the bytecode for a
|
||||
|
||||
+1
-1
@@ -484,7 +484,7 @@ static ObjFiber* loadModule(WrenVM* vm, Value name, const char* source)
|
||||
}
|
||||
}
|
||||
|
||||
ObjFn* fn = wrenCompile(vm, module, source, true);
|
||||
ObjFn* fn = wrenCompile(vm, module, source, false, true);
|
||||
if (fn == NULL)
|
||||
{
|
||||
// TODO: Should we still store the module even if it didn't compile?
|
||||
|
||||
Reference in New Issue
Block a user