mirror of https://gitlab.com/nakst/essence
add ExternalPassREPLResult
This commit is contained in:
parent
d3653d2958
commit
73a6457025
|
@ -1,6 +1,8 @@
|
||||||
#define ES_INSTANCE_TYPE Instance
|
#define ES_INSTANCE_TYPE Instance
|
||||||
#include <essence.h>
|
#include <essence.h>
|
||||||
|
|
||||||
|
// TODO Resizing the window after calling DirectoryEnumerateChildrenRecursively() is slow.
|
||||||
|
|
||||||
struct Instance : EsInstance {
|
struct Instance : EsInstance {
|
||||||
EsThreadInformation scriptThread;
|
EsThreadInformation scriptThread;
|
||||||
char *inputText;
|
char *inputText;
|
||||||
|
@ -15,6 +17,8 @@ struct Instance : EsInstance {
|
||||||
char *outputLineBuffer;
|
char *outputLineBuffer;
|
||||||
size_t outputLineBufferBytes;
|
size_t outputLineBufferBytes;
|
||||||
size_t outputLineBufferAllocated;
|
size_t outputLineBufferAllocated;
|
||||||
|
bool anyOutput;
|
||||||
|
bool gotREPLResult;
|
||||||
};
|
};
|
||||||
|
|
||||||
void AddPrompt(Instance *instance);
|
void AddPrompt(Instance *instance);
|
||||||
|
@ -166,6 +170,14 @@ int ExternalPrintStdErrHighlight(ExecutionContext *context, Value *returnValue)
|
||||||
return ExternalPrintStdErr(context, returnValue);
|
return ExternalPrintStdErr(context, returnValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ExternalSystemSleepMs(ExecutionContext *context, Value *returnValue) {
|
||||||
|
(void) returnValue;
|
||||||
|
if (context->c->stackPointer < 1) return -1;
|
||||||
|
int64_t ms = context->c->stack[--context->c->stackPointer].i;
|
||||||
|
if (ms > 0) EsSleep(ms);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
int ExternalSystemGetHostName(ExecutionContext *context, Value *returnValue) {
|
int ExternalSystemGetHostName(ExecutionContext *context, Value *returnValue) {
|
||||||
(void) context;
|
(void) context;
|
||||||
RETURN_STRING_COPY("Essence", 7);
|
RETURN_STRING_COPY("Essence", 7);
|
||||||
|
@ -335,6 +347,10 @@ EXTERNAL_STUB(ExternalSystemSetEnvironmentVariable);
|
||||||
// --------------------------------- User interface.
|
// --------------------------------- User interface.
|
||||||
|
|
||||||
#define COLOR_BACKGROUND (0xFFFDFDFD)
|
#define COLOR_BACKGROUND (0xFFFDFDFD)
|
||||||
|
#define COLOR_ROW_ODD (0xFFF4F4F4)
|
||||||
|
#define COLOR_OUTPUT_DECORATION_IN_PROGRESS (0xFFFF7F00)
|
||||||
|
#define COLOR_OUTPUT_DECORATION_SUCCESS (0xFF3070FF)
|
||||||
|
#define COLOR_OUTPUT_DECORATION_FAILURE (0xFFFF3040)
|
||||||
#define COLOR_TEXT_MAIN (0xFF010102)
|
#define COLOR_TEXT_MAIN (0xFF010102)
|
||||||
#define COLOR_TEXT_LIGHT (0xFF606062)
|
#define COLOR_TEXT_LIGHT (0xFF606062)
|
||||||
#define TEXT_SIZE_DEFAULT (14)
|
#define TEXT_SIZE_DEFAULT (14)
|
||||||
|
@ -386,6 +402,31 @@ const EsStyle styleOutputParagraph = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const EsStyle styleOutputParagraphStrong = {
|
||||||
|
.metrics = {
|
||||||
|
.mask = ES_THEME_METRICS_FONT_FAMILY | ES_THEME_METRICS_FONT_WEIGHT
|
||||||
|
| ES_THEME_METRICS_TEXT_SIZE | ES_THEME_METRICS_TEXT_ALIGN | ES_THEME_METRICS_TEXT_COLOR,
|
||||||
|
.textColor = COLOR_TEXT_MAIN,
|
||||||
|
.textAlign = ES_TEXT_H_LEFT | ES_TEXT_WRAP | ES_TEXT_V_TOP,
|
||||||
|
.textSize = TEXT_SIZE_OUTPUT,
|
||||||
|
.fontFamily = ES_FONT_SANS,
|
||||||
|
.fontWeight = 6,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const EsStyle styleOutputParagraphItalic = {
|
||||||
|
.metrics = {
|
||||||
|
.mask = ES_THEME_METRICS_FONT_FAMILY | ES_THEME_METRICS_FONT_WEIGHT | ES_THEME_METRICS_IS_ITALIC
|
||||||
|
| ES_THEME_METRICS_TEXT_SIZE | ES_THEME_METRICS_TEXT_ALIGN | ES_THEME_METRICS_TEXT_COLOR,
|
||||||
|
.textColor = COLOR_TEXT_MAIN,
|
||||||
|
.textAlign = ES_TEXT_H_LEFT | ES_TEXT_WRAP | ES_TEXT_V_TOP,
|
||||||
|
.textSize = TEXT_SIZE_OUTPUT,
|
||||||
|
.fontFamily = ES_FONT_SANS,
|
||||||
|
.fontWeight = 4,
|
||||||
|
.isItalic = true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
const EsStyle stylePromptText = {
|
const EsStyle stylePromptText = {
|
||||||
.metrics = {
|
.metrics = {
|
||||||
.mask = ES_THEME_METRICS_FONT_FAMILY | ES_THEME_METRICS_FONT_WEIGHT
|
.mask = ES_THEME_METRICS_FONT_FAMILY | ES_THEME_METRICS_FONT_WEIGHT
|
||||||
|
@ -454,7 +495,7 @@ const EsStyle styleOutputDecorationInProgress = {
|
||||||
|
|
||||||
.appearance = {
|
.appearance = {
|
||||||
.enabled = true,
|
.enabled = true,
|
||||||
.backgroundColor = 0xFFFF7F00,
|
.backgroundColor = COLOR_OUTPUT_DECORATION_IN_PROGRESS,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -466,7 +507,7 @@ const EsStyle styleOutputDecorationSuccess = {
|
||||||
|
|
||||||
.appearance = {
|
.appearance = {
|
||||||
.enabled = true,
|
.enabled = true,
|
||||||
.backgroundColor = 0xFF3070FF,
|
.backgroundColor = COLOR_OUTPUT_DECORATION_SUCCESS,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -478,14 +519,120 @@ const EsStyle styleOutputDecorationFailure = {
|
||||||
|
|
||||||
.appearance = {
|
.appearance = {
|
||||||
.enabled = true,
|
.enabled = true,
|
||||||
.backgroundColor = 0xFFFF3040,
|
.backgroundColor = COLOR_OUTPUT_DECORATION_FAILURE,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const EsStyle styleListRowEven = {
|
||||||
|
.metrics = {
|
||||||
|
.mask = ES_THEME_METRICS_INSETS,
|
||||||
|
.insets = ES_RECT_1(3),
|
||||||
|
},
|
||||||
|
|
||||||
|
.appearance = {
|
||||||
|
.enabled = true,
|
||||||
|
.backgroundColor = COLOR_BACKGROUND,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const EsStyle styleListRowOdd = {
|
||||||
|
.metrics = {
|
||||||
|
.mask = ES_THEME_METRICS_INSETS,
|
||||||
|
.insets = ES_RECT_1(3),
|
||||||
|
},
|
||||||
|
|
||||||
|
.appearance = {
|
||||||
|
.enabled = true,
|
||||||
|
.backgroundColor = COLOR_ROW_ODD,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
void AddREPLResult(ExecutionContext *context, EsElement *parent, Node *type, Value value) {
|
||||||
|
// TODO Truncating/scrolling/collapsing/saving/copying output.
|
||||||
|
// TODO Letting scripts register custom views for structs.
|
||||||
|
|
||||||
|
size_t bytes;
|
||||||
|
|
||||||
|
if (type->type == T_INT) {
|
||||||
|
char *buffer = EsStringAllocateAndFormat(&bytes, "(int) %d", value.i);
|
||||||
|
EsTextDisplayCreate(parent, ES_CELL_H_FILL, &styleOutputParagraphStrong, buffer, bytes);
|
||||||
|
} else if (type->type == T_BOOL) {
|
||||||
|
char *buffer = EsStringAllocateAndFormat(&bytes, "%z", value.i ? "true" : "false");
|
||||||
|
EsTextDisplayCreate(parent, ES_CELL_H_FILL, &styleOutputParagraphStrong, buffer, bytes);
|
||||||
|
} else if (type->type == T_FLOAT) {
|
||||||
|
char *buffer = EsStringAllocateAndFormat(&bytes, "(float) %F", value.f);
|
||||||
|
EsTextDisplayCreate(parent, ES_CELL_H_FILL, &styleOutputParagraphStrong, buffer, bytes);
|
||||||
|
} else if (type->type == T_STR) {
|
||||||
|
EsAssert(context->heapEntriesAllocated > (uint64_t) value.i);
|
||||||
|
HeapEntry *entry = &context->heap[value.i];
|
||||||
|
const char *valueText;
|
||||||
|
size_t valueBytes;
|
||||||
|
ScriptHeapEntryToString(context, entry, &valueText, &valueBytes);
|
||||||
|
char *buffer = EsStringAllocateAndFormat(&bytes, "\"%s\"", valueBytes, valueText);
|
||||||
|
EsTextDisplayCreate(parent, ES_CELL_H_FILL, &styleOutputParagraphStrong, buffer, bytes);
|
||||||
|
} else if (type->type == T_LIST) {
|
||||||
|
EsPanel *panel = EsPanelCreate(parent, ES_CELL_H_FILL | ES_PANEL_VERTICAL | ES_PANEL_STACK);
|
||||||
|
EsAssert(context->heapEntriesAllocated > (uint64_t) value.i);
|
||||||
|
HeapEntry *entry = &context->heap[value.i];
|
||||||
|
EsAssert(entry->type == T_LIST);
|
||||||
|
|
||||||
|
if (!entry->length) {
|
||||||
|
EsTextDisplayCreate(parent, ES_CELL_H_FILL, &styleOutputParagraphItalic,
|
||||||
|
EsLiteral("Empty list.\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uintptr_t i = 0; i < entry->length; i++) {
|
||||||
|
EsPanel *item = EsPanelCreate(panel, ES_CELL_H_FILL, (i % 2) ? &styleListRowOdd : &styleListRowEven);
|
||||||
|
AddREPLResult(context, item, type->firstChild, entry->list[i]);
|
||||||
|
}
|
||||||
|
} else if (type->type == T_FUNCPTR) {
|
||||||
|
EsTextDisplayCreate(parent, ES_CELL_H_FILL, &styleOutputParagraphItalic,
|
||||||
|
EsLiteral("Function pointer.\n"));
|
||||||
|
} else if (type->type == T_STRUCT) {
|
||||||
|
EsPanel *panel = EsPanelCreate(parent, ES_CELL_H_FILL | ES_PANEL_VERTICAL | ES_PANEL_STACK);
|
||||||
|
char *buffer = EsStringAllocateAndFormat(&bytes, "%s:", type->token.textBytes, type->token.text);
|
||||||
|
EsTextDisplayCreate(panel, ES_CELL_H_FILL, &styleOutputParagraph, buffer, bytes);
|
||||||
|
EsAssert(context->heapEntriesAllocated > (uint64_t) value.i);
|
||||||
|
HeapEntry *entry = &context->heap[value.i];
|
||||||
|
EsAssert(entry->type == T_STRUCT);
|
||||||
|
uintptr_t i = 0;
|
||||||
|
|
||||||
|
Node *field = type->firstChild;
|
||||||
|
|
||||||
|
while (field) {
|
||||||
|
EsAssert(i != entry->fieldCount);
|
||||||
|
EsPanel *item = EsPanelCreate(panel, ES_CELL_H_FILL, (i % 2) ? &styleListRowEven : &styleListRowOdd);
|
||||||
|
AddREPLResult(context, item, field->firstChild, entry->fields[i]);
|
||||||
|
field = field->sibling;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
} else if (type->type == T_NULL) {
|
||||||
|
char *buffer = EsStringAllocateAndFormat(&bytes, "%z", "null");
|
||||||
|
EsTextDisplayCreate(parent, ES_CELL_H_FILL, &styleOutputParagraphStrong, buffer, bytes);
|
||||||
|
} else {
|
||||||
|
EsTextDisplayCreate(parent, ES_CELL_H_FILL, &styleOutputParagraphItalic,
|
||||||
|
EsLiteral("The type of the result was not recognized.\n"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExternalPassREPLResult(ExecutionContext *context, Value value) {
|
||||||
|
Instance *instance = scriptInstance;
|
||||||
|
|
||||||
|
if (instance->gotREPLResult) return;
|
||||||
|
if (instance->outputLineBufferBytes) AddOutput(instance, EsLiteral("\n"));
|
||||||
|
|
||||||
|
instance->anyOutput = true;
|
||||||
|
instance->gotREPLResult = true;
|
||||||
|
|
||||||
|
EsMessageMutexAcquire();
|
||||||
|
AddREPLResult(context, instance->outputPanel, context->functionData->replResultType, value);
|
||||||
|
EsMessageMutexRelease();
|
||||||
|
}
|
||||||
|
|
||||||
void ScriptThread(EsGeneric _instance) {
|
void ScriptThread(EsGeneric _instance) {
|
||||||
Instance *instance = (Instance *) _instance.p;
|
Instance *instance = (Instance *) _instance.p;
|
||||||
scriptInstance = instance;
|
scriptInstance = instance;
|
||||||
int result = ScriptExecuteFromFile(EsLiteral("in"), instance->inputText, instance->inputBytes);
|
int result = ScriptExecuteFromFile(EsLiteral("in"), instance->inputText, instance->inputBytes, true);
|
||||||
instance->inputText = nullptr;
|
instance->inputText = nullptr;
|
||||||
|
|
||||||
if (instance->outputLineBufferBytes) {
|
if (instance->outputLineBufferBytes) {
|
||||||
|
@ -494,6 +641,14 @@ void ScriptThread(EsGeneric _instance) {
|
||||||
|
|
||||||
EsMessageMutexAcquire();
|
EsMessageMutexAcquire();
|
||||||
|
|
||||||
|
if (!instance->anyOutput) {
|
||||||
|
EsElementDestroy(EsElementGetLayoutParent(instance->outputPanel));
|
||||||
|
} else {
|
||||||
|
instance->anyOutput = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
instance->gotREPLResult = false;
|
||||||
|
|
||||||
if (result == 0) {
|
if (result == 0) {
|
||||||
EsSpacerChangeStyle(instance->outputDecoration, &styleOutputDecorationSuccess);
|
EsSpacerChangeStyle(instance->outputDecoration, &styleOutputDecorationSuccess);
|
||||||
} else {
|
} else {
|
||||||
|
@ -525,16 +680,8 @@ void EnterCommand(Instance *instance) {
|
||||||
instance->outputDecoration = EsSpacerCreate(outputPanelWrapper, ES_CELL_V_FILL, &styleOutputDecorationInProgress);
|
instance->outputDecoration = EsSpacerCreate(outputPanelWrapper, ES_CELL_V_FILL, &styleOutputDecorationInProgress);
|
||||||
instance->outputPanel = EsPanelCreate(outputPanelWrapper, ES_CELL_H_FILL | ES_PANEL_STACK | ES_PANEL_VERTICAL, &styleOutputPanel);
|
instance->outputPanel = EsPanelCreate(outputPanelWrapper, ES_CELL_H_FILL | ES_PANEL_STACK | ES_PANEL_VERTICAL, &styleOutputPanel);
|
||||||
|
|
||||||
const char *inputPrefix = "void Start() {\n";
|
instance->inputText = data;
|
||||||
const char *inputSuffix = "\n}";
|
instance->inputBytes = dataBytes;
|
||||||
char *script = (char *) EsHeapAllocate(dataBytes + EsCStringLength(inputPrefix) + EsCStringLength(inputSuffix), false);
|
|
||||||
EsMemoryCopy(script, inputPrefix, EsCStringLength(inputPrefix));
|
|
||||||
EsMemoryCopy(script + EsCStringLength(inputPrefix), data, dataBytes);
|
|
||||||
EsMemoryCopy(script + EsCStringLength(inputPrefix) + dataBytes, inputSuffix, EsCStringLength(inputSuffix));
|
|
||||||
EsHeapFree(data);
|
|
||||||
|
|
||||||
instance->inputText = script;
|
|
||||||
instance->inputBytes = dataBytes + EsCStringLength(inputPrefix) + EsCStringLength(inputSuffix);
|
|
||||||
EsAssert(ES_SUCCESS == EsThreadCreate(ScriptThread, &instance->scriptThread, instance));
|
EsAssert(ES_SUCCESS == EsThreadCreate(ScriptThread, &instance->scriptThread, instance));
|
||||||
EsHandleClose(instance->scriptThread.handle);
|
EsHandleClose(instance->scriptThread.handle);
|
||||||
}
|
}
|
||||||
|
@ -551,6 +698,8 @@ int InputTextboxMessage(EsElement *element, EsMessage *message) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddOutput(Instance *instance, const char *text, size_t textBytes) {
|
void AddOutput(Instance *instance, const char *text, size_t textBytes) {
|
||||||
|
instance->anyOutput = true;
|
||||||
|
|
||||||
for (uintptr_t i = 0; i < textBytes; i++) {
|
for (uintptr_t i = 0; i < textBytes; i++) {
|
||||||
if (text[i] == '\n') {
|
if (text[i] == '\n') {
|
||||||
EsMessageMutexAcquire();
|
EsMessageMutexAcquire();
|
||||||
|
|
188
util/script.c
188
util/script.c
|
@ -85,6 +85,7 @@
|
||||||
#define T_LIST (92)
|
#define T_LIST (92)
|
||||||
#define T_IMPORT_PATH (93)
|
#define T_IMPORT_PATH (93)
|
||||||
#define T_LIST_LITERAL (94)
|
#define T_LIST_LITERAL (94)
|
||||||
|
#define T_REPL_RESULT (95)
|
||||||
|
|
||||||
#define T_EXIT_SCOPE (100)
|
#define T_EXIT_SCOPE (100)
|
||||||
#define T_END_FUNCTION (101)
|
#define T_END_FUNCTION (101)
|
||||||
|
@ -250,6 +251,7 @@ typedef struct FunctionBuilder {
|
||||||
bool isPersistentVariable, isDotAssignment, isListAssignment;
|
bool isPersistentVariable, isDotAssignment, isListAssignment;
|
||||||
uintptr_t globalVariableOffset;
|
uintptr_t globalVariableOffset;
|
||||||
struct ImportData *importData; // Only valid during script loading.
|
struct ImportData *importData; // Only valid during script loading.
|
||||||
|
Node *replResultType;
|
||||||
} FunctionBuilder;
|
} FunctionBuilder;
|
||||||
|
|
||||||
typedef struct BackTraceItem {
|
typedef struct BackTraceItem {
|
||||||
|
@ -381,10 +383,10 @@ ImportData *importedModules;
|
||||||
ImportData **importedModulesLink = &importedModules;
|
ImportData **importedModulesLink = &importedModules;
|
||||||
|
|
||||||
// Forward declarations:
|
// Forward declarations:
|
||||||
Node *ParseBlock(Tokenizer *tokenizer);
|
Node *ParseBlock(Tokenizer *tokenizer, bool replMode);
|
||||||
Node *ParseExpression(Tokenizer *tokenizer, bool allowAssignment, uint8_t precedence);
|
Node *ParseExpression(Tokenizer *tokenizer, bool allowAssignment, uint8_t precedence);
|
||||||
void ScriptPrintNode(Node *node, int indent);
|
void ScriptPrintNode(Node *node, int indent);
|
||||||
bool ScriptLoad(Tokenizer tokenizer, ExecutionContext *context, ImportData *importData);
|
bool ScriptLoad(Tokenizer tokenizer, ExecutionContext *context, ImportData *importData, bool replMode);
|
||||||
void ScriptFreeCoroutine(CoroutineState *c);
|
void ScriptFreeCoroutine(CoroutineState *c);
|
||||||
uintptr_t HeapAllocate(ExecutionContext *context);
|
uintptr_t HeapAllocate(ExecutionContext *context);
|
||||||
|
|
||||||
|
@ -409,6 +411,7 @@ void PrintError4(ExecutionContext *context, uint32_t instructionPointer, const c
|
||||||
void PrintBackTrace(ExecutionContext *context, uint32_t instructionPointer, CoroutineState *c, const char *prefix);
|
void PrintBackTrace(ExecutionContext *context, uint32_t instructionPointer, CoroutineState *c, const char *prefix);
|
||||||
void *FileLoad(const char *path, size_t *length);
|
void *FileLoad(const char *path, size_t *length);
|
||||||
CoroutineState *ExternalCoroutineWaitAny(ExecutionContext *context);
|
CoroutineState *ExternalCoroutineWaitAny(ExecutionContext *context);
|
||||||
|
void ExternalPassREPLResult(ExecutionContext *context, Value value);
|
||||||
|
|
||||||
// --------------------------------- Base module.
|
// --------------------------------- Base module.
|
||||||
|
|
||||||
|
@ -469,6 +472,7 @@ char baseModuleSource[] = {
|
||||||
"int SystemGetProcessorCount() #extcall;"
|
"int SystemGetProcessorCount() #extcall;"
|
||||||
"bool SystemRunningAsAdministrator() #extcall;"
|
"bool SystemRunningAsAdministrator() #extcall;"
|
||||||
"str SystemGetHostName() #extcall;"
|
"str SystemGetHostName() #extcall;"
|
||||||
|
"void SystemSleepMs(int ms) #extcall;"
|
||||||
"int RandomInt(int min, int max) #extcall;"
|
"int RandomInt(int min, int max) #extcall;"
|
||||||
|
|
||||||
"str UUIDGenerate() {"
|
"str UUIDGenerate() {"
|
||||||
|
@ -682,6 +686,7 @@ int ExternalSystemGetEnvironmentVariable(ExecutionContext *context, Value *retur
|
||||||
int ExternalSystemSetEnvironmentVariable(ExecutionContext *context, Value *returnValue);
|
int ExternalSystemSetEnvironmentVariable(ExecutionContext *context, Value *returnValue);
|
||||||
int ExternalSystemRunningAsAdministrator(ExecutionContext *context, Value *returnValue);
|
int ExternalSystemRunningAsAdministrator(ExecutionContext *context, Value *returnValue);
|
||||||
int ExternalSystemGetHostName(ExecutionContext *context, Value *returnValue);
|
int ExternalSystemGetHostName(ExecutionContext *context, Value *returnValue);
|
||||||
|
int ExternalSystemSleepMs(ExecutionContext *context, Value *returnValue);
|
||||||
int ExternalPathCreateDirectory(ExecutionContext *context, Value *returnValue);
|
int ExternalPathCreateDirectory(ExecutionContext *context, Value *returnValue);
|
||||||
int ExternalPathDelete(ExecutionContext *context, Value *returnValue);
|
int ExternalPathDelete(ExecutionContext *context, Value *returnValue);
|
||||||
int ExternalPathExists(ExecutionContext *context, Value *returnValue);
|
int ExternalPathExists(ExecutionContext *context, Value *returnValue);
|
||||||
|
@ -718,6 +723,7 @@ ExternalFunction externalFunctions[] = {
|
||||||
{ .cName = "SystemSetEnvironmentVariable", .callback = ExternalSystemSetEnvironmentVariable },
|
{ .cName = "SystemSetEnvironmentVariable", .callback = ExternalSystemSetEnvironmentVariable },
|
||||||
{ .cName = "SystemRunningAsAdministrator", .callback = ExternalSystemRunningAsAdministrator },
|
{ .cName = "SystemRunningAsAdministrator", .callback = ExternalSystemRunningAsAdministrator },
|
||||||
{ .cName = "SystemGetHostName", .callback = ExternalSystemGetHostName },
|
{ .cName = "SystemGetHostName", .callback = ExternalSystemGetHostName },
|
||||||
|
{ .cName = "SystemSleepMs", .callback = ExternalSystemSleepMs },
|
||||||
{ .cName = "PathExists", .callback = ExternalPathExists },
|
{ .cName = "PathExists", .callback = ExternalPathExists },
|
||||||
{ .cName = "PathIsFile", .callback = ExternalPathIsFile },
|
{ .cName = "PathIsFile", .callback = ExternalPathIsFile },
|
||||||
{ .cName = "PathIsDirectory", .callback = ExternalPathIsDirectory },
|
{ .cName = "PathIsDirectory", .callback = ExternalPathIsDirectory },
|
||||||
|
@ -976,7 +982,10 @@ Node *ParseType(Tokenizer *tokenizer, bool maybe, bool allowVoid) {
|
||||||
node->type = node->token.type;
|
node->type = node->token.type;
|
||||||
|
|
||||||
if (!allowVoid && node->type == T_VOID) {
|
if (!allowVoid && node->type == T_VOID) {
|
||||||
PrintError2(tokenizer, node, "The 'void' type is not allowed here.\n");
|
if (!maybe) {
|
||||||
|
PrintError2(tokenizer, node, "The 'void' type is not allowed here.\n");
|
||||||
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1049,6 +1058,8 @@ Node *ParseCall(Tokenizer *tokenizer, Node *function) {
|
||||||
if (token.type == T_RIGHT_ROUND) {
|
if (token.type == T_RIGHT_ROUND) {
|
||||||
TokenNext(tokenizer);
|
TokenNext(tokenizer);
|
||||||
break;
|
break;
|
||||||
|
} else if (token.type == T_ERROR) {
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (arguments->firstChild) {
|
if (arguments->firstChild) {
|
||||||
|
@ -1291,7 +1302,7 @@ Node *ParseIf(Tokenizer *tokenizer) {
|
||||||
|
|
||||||
if (token.type == T_LEFT_FANCY) {
|
if (token.type == T_LEFT_FANCY) {
|
||||||
TokenNext(tokenizer);
|
TokenNext(tokenizer);
|
||||||
node->firstChild->sibling = ParseBlock(tokenizer);
|
node->firstChild->sibling = ParseBlock(tokenizer, false);
|
||||||
if (!node->firstChild->sibling) return NULL;
|
if (!node->firstChild->sibling) return NULL;
|
||||||
} else {
|
} else {
|
||||||
Node *wrapper = (Node *) AllocateFixed(sizeof(Node));
|
Node *wrapper = (Node *) AllocateFixed(sizeof(Node));
|
||||||
|
@ -1319,7 +1330,7 @@ Node *ParseIf(Tokenizer *tokenizer) {
|
||||||
if (!node->firstChild->sibling->sibling) return NULL;
|
if (!node->firstChild->sibling->sibling) return NULL;
|
||||||
} else if (token.type == T_LEFT_FANCY) {
|
} else if (token.type == T_LEFT_FANCY) {
|
||||||
TokenNext(tokenizer);
|
TokenNext(tokenizer);
|
||||||
node->firstChild->sibling->sibling = ParseBlock(tokenizer);
|
node->firstChild->sibling->sibling = ParseBlock(tokenizer, false);
|
||||||
if (!node->firstChild->sibling->sibling) return NULL;
|
if (!node->firstChild->sibling->sibling) return NULL;
|
||||||
} else {
|
} else {
|
||||||
node->firstChild->sibling->sibling = ParseExpression(tokenizer, true, 0);
|
node->firstChild->sibling->sibling = ParseExpression(tokenizer, true, 0);
|
||||||
|
@ -1337,7 +1348,7 @@ Node *ParseIf(Tokenizer *tokenizer) {
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
Node *ParseVariableDeclarationOrExpression(Tokenizer *tokenizer) {
|
Node *ParseVariableDeclarationOrExpression(Tokenizer *tokenizer, bool replMode) {
|
||||||
Tokenizer copy = *tokenizer;
|
Tokenizer copy = *tokenizer;
|
||||||
bool isVariableDeclaration = false;
|
bool isVariableDeclaration = false;
|
||||||
|
|
||||||
|
@ -1356,6 +1367,12 @@ Node *ParseVariableDeclarationOrExpression(Tokenizer *tokenizer) {
|
||||||
*tokenizer = copy;
|
*tokenizer = copy;
|
||||||
|
|
||||||
if (isVariableDeclaration) {
|
if (isVariableDeclaration) {
|
||||||
|
// TODO Variable support in replMode.
|
||||||
|
if (replMode) {
|
||||||
|
PrintError(tokenizer, "Variables are not yet supported in the console.\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
Node *declaration = (Node *) AllocateFixed(sizeof(Node));
|
Node *declaration = (Node *) AllocateFixed(sizeof(Node));
|
||||||
declaration->type = T_DECLARE;
|
declaration->type = T_DECLARE;
|
||||||
declaration->firstChild = ParseType(tokenizer, false, false);
|
declaration->firstChild = ParseType(tokenizer, false, false);
|
||||||
|
@ -1381,6 +1398,19 @@ Node *ParseVariableDeclarationOrExpression(Tokenizer *tokenizer) {
|
||||||
Node *expression = ParseExpression(tokenizer, true, 0);
|
Node *expression = ParseExpression(tokenizer, true, 0);
|
||||||
if (!expression) return NULL;
|
if (!expression) return NULL;
|
||||||
|
|
||||||
|
if (replMode) {
|
||||||
|
Token end = TokenPeek(tokenizer);
|
||||||
|
|
||||||
|
if (end.type == T_ERROR) {
|
||||||
|
return NULL;
|
||||||
|
} else if (end.type == T_EOF) {
|
||||||
|
Node *replResult = (Node *) AllocateFixed(sizeof(Node));
|
||||||
|
replResult->type = T_REPL_RESULT;
|
||||||
|
replResult->firstChild = expression;
|
||||||
|
return replResult;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Token semicolon = TokenNext(tokenizer);
|
Token semicolon = TokenNext(tokenizer);
|
||||||
|
|
||||||
if (semicolon.type != T_SEMICOLON) {
|
if (semicolon.type != T_SEMICOLON) {
|
||||||
|
@ -1392,7 +1422,7 @@ Node *ParseVariableDeclarationOrExpression(Tokenizer *tokenizer) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Node *ParseBlock(Tokenizer *tokenizer) {
|
Node *ParseBlock(Tokenizer *tokenizer, bool replMode) {
|
||||||
Node *node = (Node *) AllocateFixed(sizeof(Node));
|
Node *node = (Node *) AllocateFixed(sizeof(Node));
|
||||||
Node **link = &node->firstChild;
|
Node **link = &node->firstChild;
|
||||||
node->type = T_BLOCK;
|
node->type = T_BLOCK;
|
||||||
|
@ -1404,7 +1434,7 @@ Node *ParseBlock(Tokenizer *tokenizer) {
|
||||||
|
|
||||||
if (token.type == T_ERROR) {
|
if (token.type == T_ERROR) {
|
||||||
return NULL;
|
return NULL;
|
||||||
} else if (token.type == T_RIGHT_FANCY) {
|
} else if (token.type == (replMode ? T_EOF : T_RIGHT_FANCY)) {
|
||||||
TokenNext(tokenizer);
|
TokenNext(tokenizer);
|
||||||
return node;
|
return node;
|
||||||
} else if (token.type == T_IF) {
|
} else if (token.type == T_IF) {
|
||||||
|
@ -1426,7 +1456,7 @@ Node *ParseBlock(Tokenizer *tokenizer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (token.type == T_LEFT_FANCY) {
|
if (token.type == T_LEFT_FANCY) {
|
||||||
node->firstChild->sibling = ParseBlock(tokenizer);
|
node->firstChild->sibling = ParseBlock(tokenizer, false);
|
||||||
if (!node->firstChild->sibling) return NULL;
|
if (!node->firstChild->sibling) return NULL;
|
||||||
} else {
|
} else {
|
||||||
node->firstChild->sibling = (Node *) AllocateFixed(sizeof(Node));
|
node->firstChild->sibling = (Node *) AllocateFixed(sizeof(Node));
|
||||||
|
@ -1441,7 +1471,7 @@ Node *ParseBlock(Tokenizer *tokenizer) {
|
||||||
Node *node = (Node *) AllocateFixed(sizeof(Node));
|
Node *node = (Node *) AllocateFixed(sizeof(Node));
|
||||||
node->type = T_FOR;
|
node->type = T_FOR;
|
||||||
node->token = TokenNext(tokenizer);
|
node->token = TokenNext(tokenizer);
|
||||||
node->firstChild = ParseVariableDeclarationOrExpression(tokenizer);
|
node->firstChild = ParseVariableDeclarationOrExpression(tokenizer, false);
|
||||||
if (!node->firstChild) return NULL;
|
if (!node->firstChild) return NULL;
|
||||||
node->firstChild->sibling = ParseExpression(tokenizer, false, 0);
|
node->firstChild->sibling = ParseExpression(tokenizer, false, 0);
|
||||||
if (!node->firstChild->sibling) return NULL;
|
if (!node->firstChild->sibling) return NULL;
|
||||||
|
@ -1464,7 +1494,7 @@ Node *ParseBlock(Tokenizer *tokenizer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (token.type == T_LEFT_FANCY) {
|
if (token.type == T_LEFT_FANCY) {
|
||||||
node->firstChild->sibling->sibling->sibling = ParseBlock(tokenizer);
|
node->firstChild->sibling->sibling->sibling = ParseBlock(tokenizer, false);
|
||||||
if (!node->firstChild->sibling->sibling->sibling) return NULL;
|
if (!node->firstChild->sibling->sibling->sibling) return NULL;
|
||||||
} else {
|
} else {
|
||||||
node->firstChild->sibling->sibling->sibling = (Node *) AllocateFixed(sizeof(Node));
|
node->firstChild->sibling->sibling->sibling = (Node *) AllocateFixed(sizeof(Node));
|
||||||
|
@ -1480,6 +1510,12 @@ Node *ParseBlock(Tokenizer *tokenizer) {
|
||||||
*link = wrapper;
|
*link = wrapper;
|
||||||
link = &wrapper->sibling;
|
link = &wrapper->sibling;
|
||||||
} else if (token.type == T_RETURN || token.type == T_ASSERT) {
|
} else if (token.type == T_RETURN || token.type == T_ASSERT) {
|
||||||
|
if (replMode) {
|
||||||
|
PrintError2(tokenizer, node, "%s statements cannot be used in the console.\n",
|
||||||
|
token.type == T_RETURN ? "Return" : "Assert");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
Node *node = (Node *) AllocateFixed(sizeof(Node));
|
Node *node = (Node *) AllocateFixed(sizeof(Node));
|
||||||
node->type = token.type;
|
node->type = token.type;
|
||||||
node->token = TokenNext(tokenizer);
|
node->token = TokenNext(tokenizer);
|
||||||
|
@ -1499,12 +1535,12 @@ Node *ParseBlock(Tokenizer *tokenizer) {
|
||||||
}
|
}
|
||||||
} else if (token.type == T_LEFT_FANCY) {
|
} else if (token.type == T_LEFT_FANCY) {
|
||||||
TokenNext(tokenizer);
|
TokenNext(tokenizer);
|
||||||
Node *block = ParseBlock(tokenizer);
|
Node *block = ParseBlock(tokenizer, false);
|
||||||
if (!block) return NULL;
|
if (!block) return NULL;
|
||||||
*link = block;
|
*link = block;
|
||||||
link = &block->sibling;
|
link = &block->sibling;
|
||||||
} else {
|
} else {
|
||||||
Node *node = ParseVariableDeclarationOrExpression(tokenizer);
|
Node *node = ParseVariableDeclarationOrExpression(tokenizer, replMode);
|
||||||
if (!node) return NULL;
|
if (!node) return NULL;
|
||||||
*link = node;
|
*link = node;
|
||||||
link = &node->sibling;
|
link = &node->sibling;
|
||||||
|
@ -1595,7 +1631,7 @@ Node *ParseGlobalVariableOrFunctionDefinition(Tokenizer *tokenizer, bool allowGl
|
||||||
Node *body = (Node *) AllocateFixed(sizeof(Node));
|
Node *body = (Node *) AllocateFixed(sizeof(Node));
|
||||||
body->type = T_FUNCBODY;
|
body->type = T_FUNCBODY;
|
||||||
functionPointerType->sibling = body;
|
functionPointerType->sibling = body;
|
||||||
body->firstChild = ParseBlock(tokenizer);
|
body->firstChild = ParseBlock(tokenizer, false);
|
||||||
|
|
||||||
if (!body->firstChild) {
|
if (!body->firstChild) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -1643,6 +1679,51 @@ Node *ParseGlobalVariableOrFunctionDefinition(Tokenizer *tokenizer, bool allowGl
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Node *ParseRootREPL(Tokenizer *tokenizer) {
|
||||||
|
Node *root = (Node *) AllocateFixed(sizeof(Node));
|
||||||
|
root->type = T_ROOT;
|
||||||
|
Node **link = &root->firstChild;
|
||||||
|
|
||||||
|
Node *node = (Node *) AllocateFixed(sizeof(Node));
|
||||||
|
node->type = T_IMPORT;
|
||||||
|
node->token.type = T_INLINE;
|
||||||
|
node->token.text = "#inline";
|
||||||
|
node->token.textBytes = 7;
|
||||||
|
node->firstChild = (Node *) AllocateFixed(sizeof(Node));
|
||||||
|
node->firstChild->type = T_IMPORT_PATH;
|
||||||
|
node->firstChild->token.type = T_STRING_LITERAL;
|
||||||
|
node->firstChild->token.text = "__base_module__";
|
||||||
|
node->firstChild->token.textBytes = 15;
|
||||||
|
*link = node;
|
||||||
|
link = &node->sibling;
|
||||||
|
|
||||||
|
Node *function = (Node *) AllocateFixed(sizeof(Node));
|
||||||
|
*link = function;
|
||||||
|
link = &function->sibling;
|
||||||
|
function->type = T_FUNCTION;
|
||||||
|
function->token.text = startFunction;
|
||||||
|
function->token.textBytes = startFunctionBytes;
|
||||||
|
Node *functionPointerType = (Node *) AllocateFixed(sizeof(Node));
|
||||||
|
function->firstChild = functionPointerType;
|
||||||
|
functionPointerType->type = T_FUNCPTR;
|
||||||
|
Node *functionArguments = (Node *) AllocateFixed(sizeof(Node));
|
||||||
|
functionPointerType->firstChild = functionArguments;
|
||||||
|
functionArguments->type = T_ARGUMENTS;
|
||||||
|
Node *functionReturnType = (Node *) AllocateFixed(sizeof(Node));
|
||||||
|
functionArguments->sibling = functionReturnType;
|
||||||
|
functionReturnType->type = T_VOID;
|
||||||
|
Node *functionBody = (Node *) AllocateFixed(sizeof(Node));
|
||||||
|
functionPointerType->sibling = functionBody;
|
||||||
|
functionBody->type = T_FUNCBODY;
|
||||||
|
functionBody->firstChild = ParseBlock(tokenizer, true);
|
||||||
|
|
||||||
|
if (!functionBody->firstChild) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
Node *ParseRoot(Tokenizer *tokenizer) {
|
Node *ParseRoot(Tokenizer *tokenizer) {
|
||||||
Node *root = (Node *) AllocateFixed(sizeof(Node));
|
Node *root = (Node *) AllocateFixed(sizeof(Node));
|
||||||
root->type = T_ROOT;
|
root->type = T_ROOT;
|
||||||
|
@ -2037,7 +2118,7 @@ bool ASTSetScopes(Tokenizer *tokenizer, ExecutionContext *context, Node *node, S
|
||||||
t.input = (const char *) fileData;
|
t.input = (const char *) fileData;
|
||||||
t.line = 1;
|
t.line = 1;
|
||||||
|
|
||||||
if (!ScriptLoad(t, context, node->importData)) {
|
if (!ScriptLoad(t, context, node->importData, false)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2121,6 +2202,19 @@ bool ASTLookupTypeIdentifiers(Tokenizer *tokenizer, Node *node) {
|
||||||
child = child->sibling;
|
child = child->sibling;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (node->type == T_FUNCPTR) {
|
||||||
|
Node *type = node->firstChild->sibling;
|
||||||
|
|
||||||
|
if (type->type == T_IDENTIFIER) {
|
||||||
|
Node *lookup = ScopeLookup(tokenizer, type, false);
|
||||||
|
if (!lookup) return false;
|
||||||
|
Node *copy = (Node *) AllocateFixed(sizeof(Node));
|
||||||
|
*copy = *lookup;
|
||||||
|
copy->sibling = NULL;
|
||||||
|
node->firstChild->sibling = copy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (node->type == T_DECLARE || node->type == T_ARGUMENT || node->type == T_NEW || node->type == T_LIST) {
|
if (node->type == T_DECLARE || node->type == T_ARGUMENT || node->type == T_NEW || node->type == T_LIST) {
|
||||||
Node *type = node->firstChild;
|
Node *type = node->firstChild;
|
||||||
|
|
||||||
|
@ -2169,7 +2263,8 @@ bool ASTSetTypes(Tokenizer *tokenizer, Node *node) {
|
||||||
|| node->type == T_BOOL || node->type == T_VOID || node->type == T_IDENTIFIER
|
|| node->type == T_BOOL || node->type == T_VOID || node->type == T_IDENTIFIER
|
||||||
|| node->type == T_ARGUMENTS || node->type == T_ARGUMENT
|
|| node->type == T_ARGUMENTS || node->type == T_ARGUMENT
|
||||||
|| node->type == T_STRUCT || node->type == T_FUNCTYPE || node->type == T_IMPORT || node->type == T_IMPORT_PATH
|
|| node->type == T_STRUCT || node->type == T_FUNCTYPE || node->type == T_IMPORT || node->type == T_IMPORT_PATH
|
||||||
|| node->type == T_FUNCPTR || node->type == T_FUNCBODY || node->type == T_FUNCTION) {
|
|| node->type == T_FUNCPTR || node->type == T_FUNCBODY || node->type == T_FUNCTION
|
||||||
|
|| node->type == T_REPL_RESULT) {
|
||||||
} else if (node->type == T_NUMERIC_LITERAL) {
|
} else if (node->type == T_NUMERIC_LITERAL) {
|
||||||
size_t dotCount = 0;
|
size_t dotCount = 0;
|
||||||
|
|
||||||
|
@ -3148,6 +3243,17 @@ bool FunctionBuilderRecurse(Tokenizer *tokenizer, Node *node, FunctionBuilder *b
|
||||||
Value v;
|
Value v;
|
||||||
v.i = node->type == T_TRUE ? 1 : 0;
|
v.i = node->type == T_TRUE ? 1 : 0;
|
||||||
FunctionBuilderAppend(builder, &v, sizeof(v));
|
FunctionBuilderAppend(builder, &v, sizeof(v));
|
||||||
|
} else if (node->type == T_REPL_RESULT) {
|
||||||
|
if (!ASTMatching(node->firstChild->expressionType, &globalExpressionTypeVoid)) {
|
||||||
|
FunctionBuilderAppend(builder, &node->type, sizeof(node->type));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (builder->replResultType) {
|
||||||
|
PrintError2(tokenizer, node, "Multiple REPL results are not allowed.\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
builder->replResultType = node->firstChild->expressionType;
|
||||||
} else {
|
} else {
|
||||||
PrintDebug("FunctionBuilderRecurse %d\n", node->type);
|
PrintDebug("FunctionBuilderRecurse %d\n", node->type);
|
||||||
Assert(false);
|
Assert(false);
|
||||||
|
@ -4442,6 +4548,9 @@ int ScriptExecuteFunction(uintptr_t instructionPointer, ExecutionContext *contex
|
||||||
instructionPointer = 1; // There is a T_AWAIT command at address 1.
|
instructionPointer = 1; // There is a T_AWAIT command at address 1.
|
||||||
goto callCommand;
|
goto callCommand;
|
||||||
}
|
}
|
||||||
|
} else if (command == T_REPL_RESULT) {
|
||||||
|
if (context->c->stackPointer < 1) return -1;
|
||||||
|
ExternalPassREPLResult(context, context->c->stack[--context->c->stackPointer]);
|
||||||
} else if (command == T_END_FUNCTION || command == T_EXTCALL) {
|
} else if (command == T_END_FUNCTION || command == T_EXTCALL) {
|
||||||
if (command == T_EXTCALL) {
|
if (command == T_EXTCALL) {
|
||||||
uint16_t index = functionData[instructionPointer + 0] + (functionData[instructionPointer + 1] << 8);
|
uint16_t index = functionData[instructionPointer + 0] + (functionData[instructionPointer + 1] << 8);
|
||||||
|
@ -4620,11 +4729,11 @@ bool ScriptParseOptions(ExecutionContext *context) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ScriptLoad(Tokenizer tokenizer, ExecutionContext *context, ImportData *importData) {
|
bool ScriptLoad(Tokenizer tokenizer, ExecutionContext *context, ImportData *importData, bool replMode) {
|
||||||
Node *previousRootNode = context->rootNode;
|
Node *previousRootNode = context->rootNode;
|
||||||
ImportData *previousImportData = context->functionData->importData;
|
ImportData *previousImportData = context->functionData->importData;
|
||||||
|
|
||||||
context->rootNode = ParseRoot(&tokenizer);
|
context->rootNode = replMode ? ParseRootREPL(&tokenizer) : ParseRoot(&tokenizer);
|
||||||
context->functionData->importData = tokenizer.module;
|
context->functionData->importData = tokenizer.module;
|
||||||
|
|
||||||
uint8_t b = 0; // Make sure no function can start at 0.
|
uint8_t b = 0; // Make sure no function can start at 0.
|
||||||
|
@ -4834,7 +4943,7 @@ void PrintLine(ImportData *importData, uintptr_t line) {
|
||||||
PrintDebug(">> %.*s\n", (int) length, &((char *) importData->fileData)[position]);
|
PrintDebug(">> %.*s\n", (int) length, &((char *) importData->fileData)[position]);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ScriptExecuteFromFile(char *scriptPath, size_t scriptPathBytes, char *fileData, size_t fileDataBytes) {
|
int ScriptExecuteFromFile(char *scriptPath, size_t scriptPathBytes, char *fileData, size_t fileDataBytes, bool replMode) {
|
||||||
Tokenizer tokenizer = { 0 };
|
Tokenizer tokenizer = { 0 };
|
||||||
ImportData importData = { 0 };
|
ImportData importData = { 0 };
|
||||||
importData.path = scriptPath;
|
importData.path = scriptPath;
|
||||||
|
@ -4864,7 +4973,7 @@ int ScriptExecuteFromFile(char *scriptPath, size_t scriptPathBytes, char *fileDa
|
||||||
context.c->previousCoroutineLink = &context.allCoroutines;
|
context.c->previousCoroutineLink = &context.allCoroutines;
|
||||||
context.allCoroutines = context.c;
|
context.allCoroutines = context.c;
|
||||||
|
|
||||||
int result = ScriptLoad(tokenizer, &context, &importData) ? ScriptExecute(&context, &importData) : 1;
|
int result = ScriptLoad(tokenizer, &context, &importData, replMode) ? ScriptExecute(&context, &importData) : 1;
|
||||||
ScriptFree(&context);
|
ScriptFree(&context);
|
||||||
|
|
||||||
importedModules = NULL;
|
importedModules = NULL;
|
||||||
|
@ -5606,6 +5715,37 @@ int ExternalRandomInt(ExecutionContext *context, Value *returnValue) {
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void *SystemSleepThread(void *_coroutine) {
|
||||||
|
CoroutineState *coroutine = (CoroutineState *) _coroutine;
|
||||||
|
struct timespec sleepTime;
|
||||||
|
uint64_t x = 1000000 * coroutine->externalCoroutineData.i;
|
||||||
|
sleepTime.tv_sec = x / 1000000000;
|
||||||
|
sleepTime.tv_nsec = x % 1000000000;
|
||||||
|
nanosleep(&sleepTime, NULL);
|
||||||
|
ExternalCoroutineDone(coroutine);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ExternalSystemSleepMs(ExecutionContext *context, Value *returnValue) {
|
||||||
|
(void) returnValue;
|
||||||
|
if (context->c->externalCoroutine) return 1;
|
||||||
|
if (context->c->stackPointer < 1) return -1;
|
||||||
|
context->c->externalCoroutineData = context->c->stack[--context->c->stackPointer];
|
||||||
|
#ifdef __linux__
|
||||||
|
pthread_t thread;
|
||||||
|
pthread_create(&thread, NULL, SystemSleepThread, context->c);
|
||||||
|
pthread_detach(thread);
|
||||||
|
return 4;
|
||||||
|
#else
|
||||||
|
struct timespec sleepTime;
|
||||||
|
uint64_t x = 1000000 * coroutine->externalCoroutineData.i;
|
||||||
|
sleepTime.tv_sec = x / 1000000000;
|
||||||
|
sleepTime.tv_nsec = x % 1000000000;
|
||||||
|
nanosleep(&sleepTime, NULL);
|
||||||
|
return 1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
CoroutineState *ExternalCoroutineWaitAny(ExecutionContext *context) {
|
CoroutineState *ExternalCoroutineWaitAny(ExecutionContext *context) {
|
||||||
(void) context;
|
(void) context;
|
||||||
while (sem_wait(&externalCoroutineSemaphore) == -1);
|
while (sem_wait(&externalCoroutineSemaphore) == -1);
|
||||||
|
@ -5618,6 +5758,12 @@ CoroutineState *ExternalCoroutineWaitAny(ExecutionContext *context) {
|
||||||
return unblocked;
|
return unblocked;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ExternalPassREPLResult(ExecutionContext *context, Value value) {
|
||||||
|
(void) context;
|
||||||
|
(void) value;
|
||||||
|
Assert(false);
|
||||||
|
}
|
||||||
|
|
||||||
void *AllocateFixed(size_t bytes) {
|
void *AllocateFixed(size_t bytes) {
|
||||||
if (!bytes) {
|
if (!bytes) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -5785,7 +5931,7 @@ int main(int argc, char **argv) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int result = ScriptExecuteFromFile(scriptPath, strlen(scriptPath), data, dataBytes);
|
int result = ScriptExecuteFromFile(scriptPath, strlen(scriptPath), data, dataBytes, false);
|
||||||
|
|
||||||
while (fixedAllocationBlocks) {
|
while (fixedAllocationBlocks) {
|
||||||
void *block = fixedAllocationBlocks;
|
void *block = fixedAllocationBlocks;
|
||||||
|
|
Loading…
Reference in New Issue