major restructuring
This commit is contained in:
+72
-28
@@ -31,8 +31,12 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <signal.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include "../lib/noja.h"
|
#include "../lib/runtime/run.h"
|
||||||
|
#include "../lib/runtime/runtime.h"
|
||||||
|
#include "../lib/runtime/builtins_api.h"
|
||||||
|
#include "../lib/runtime/serialize_profiling.h"
|
||||||
|
|
||||||
static void usage(FILE *stream, const char *name)
|
static void usage(FILE *stream, const char *name)
|
||||||
{
|
{
|
||||||
@@ -57,12 +61,21 @@ static void help(FILE *stream, const char *name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
Mode_DISASSEMBLy,
|
Mode_DISASSEMBLY,
|
||||||
Mode_ASSEMBLY,
|
Mode_ASSEMBLY,
|
||||||
Mode_DEFAULT,
|
Mode_DEFAULT,
|
||||||
Mode_HELP,
|
Mode_HELP,
|
||||||
} Mode;
|
} Mode;
|
||||||
|
|
||||||
|
Runtime *runtime = NULL;
|
||||||
|
|
||||||
|
static void signalHandler(int signo)
|
||||||
|
{
|
||||||
|
(void) signo;
|
||||||
|
if (runtime != NULL)
|
||||||
|
Runtime_Interrupt(runtime);
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
Mode mode = Mode_DEFAULT;
|
Mode mode = Mode_DEFAULT;
|
||||||
@@ -80,7 +93,7 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
} else if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--disassembly")) {
|
} else if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--disassembly")) {
|
||||||
|
|
||||||
mode = Mode_DISASSEMBLy;
|
mode = Mode_DISASSEMBLY;
|
||||||
|
|
||||||
} else if (!strcmp(argv[i], "-i") || !strcmp(argv[i], "--inline")) {
|
} else if (!strcmp(argv[i], "-i") || !strcmp(argv[i], "--inline")) {
|
||||||
|
|
||||||
@@ -132,46 +145,77 @@ int main(int argc, char **argv)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case Mode_DEFAULT:
|
case Mode_DEFAULT:
|
||||||
|
case Mode_ASSEMBLY:
|
||||||
|
{
|
||||||
if (input == NULL) {
|
if (input == NULL) {
|
||||||
fprintf(stderr, "No input file");
|
fprintf(stderr, "No input file");
|
||||||
code = -1;
|
code = -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (profile) {
|
|
||||||
if (no_file) code = NOJA_profileString(input, heap) ? 0 : -1;
|
|
||||||
else code = NOJA_profileFile(input, heap) ? 0 : -1;
|
|
||||||
} else {
|
|
||||||
if (output != NULL)
|
|
||||||
fprintf(stderr, "Ignoring option -o\n");
|
|
||||||
if (no_file) code = NOJA_runString(input, heap) ? 0 : -1;
|
|
||||||
else code = NOJA_runFile(input, heap) ? 0 : -1;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Mode_ASSEMBLY:
|
RuntimeConfig config = Runtime_GetDefaultConfigs();
|
||||||
if (input == NULL) {
|
config.time = profile;
|
||||||
fprintf(stderr, "No assembly input file");
|
config.heap = heap;
|
||||||
|
|
||||||
|
runtime = Runtime_New(config);
|
||||||
|
if (runtime == NULL) {
|
||||||
|
fprintf(stderr, "Failed to initialize runtime");
|
||||||
code = -1;
|
code = -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (profile) {
|
signal(SIGINT, signalHandler);
|
||||||
if (no_file) code = NOJA_profileAssemblyString(input, heap) ? 0 : -1;
|
signal(SIGTERM, signalHandler);
|
||||||
else code = NOJA_profileAssemblyFile(input, heap) ? 0 : -1;
|
|
||||||
} else {
|
Error error;
|
||||||
if (output != NULL)
|
Error_Init(&error);
|
||||||
fprintf(stderr, "Ignoring option -o\n");
|
|
||||||
if (no_file) code = NOJA_runAssemblyString(input, heap) ? 0 : -1;
|
if (!Runtime_plugDefaultBuiltins(runtime, (Error*) &error)) {
|
||||||
else code = NOJA_runAssemblyFile(input, heap) ? 0 : -1;
|
Error_Print(&error, ErrorType_RUNTIME, stderr);
|
||||||
}
|
Error_Free(&error);
|
||||||
|
Runtime_PrintStackTrace(runtime, stderr);
|
||||||
|
Runtime_Free(runtime);
|
||||||
|
code = -1;
|
||||||
break;
|
break;
|
||||||
case Mode_DISASSEMBLy:
|
}
|
||||||
|
|
||||||
|
bool ok;
|
||||||
|
if (mode == Mode_ASSEMBLY) {
|
||||||
|
if (no_file)
|
||||||
|
ok = runBytecodeString(runtime, input, (Error*) &error);
|
||||||
|
else
|
||||||
|
ok = runBytecodeFile(runtime, input, (Error*) &error);
|
||||||
|
} else {
|
||||||
|
if (no_file)
|
||||||
|
ok = runString(runtime, input, (Error*) &error);
|
||||||
|
else
|
||||||
|
ok = runFile(runtime, input, (Error*) &error);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ok == false) {
|
||||||
|
Error_Print(&error, ErrorType_RUNTIME, stderr);
|
||||||
|
Error_Free(&error);
|
||||||
|
Runtime_PrintStackTrace(runtime, stderr);
|
||||||
|
Runtime_Free(runtime);
|
||||||
|
code = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
code = 0;
|
||||||
|
if (output == NULL)
|
||||||
|
Runtime_SerializeProfilingResultsToStream(runtime, stdout);
|
||||||
|
else
|
||||||
|
Runtime_SerializeProfilingResultsToFile(runtime, output);
|
||||||
|
Runtime_Free(runtime);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Mode_DISASSEMBLY:
|
||||||
if (input == NULL) {
|
if (input == NULL) {
|
||||||
fprintf(stderr, "No disassembly input file");
|
fprintf(stderr, "No disassembly input file");
|
||||||
code = -1;
|
code = -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (no_file) code = NOJA_dumpStringBytecode(input) ? 0 : -1;
|
/* .. */
|
||||||
else code = NOJA_dumpFileBytecode(input) ? 0 : -1;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ typedef struct {
|
|||||||
const char *str;
|
const char *str;
|
||||||
size_t len;
|
size_t len;
|
||||||
size_t cur;
|
size_t cur;
|
||||||
|
int *error_offset;
|
||||||
} Context;
|
} Context;
|
||||||
|
|
||||||
static void skipIdentifier(Context *ctx)
|
static void skipIdentifier(Context *ctx)
|
||||||
@@ -56,6 +57,7 @@ static bool parseLabelAndOpcode(Context *ctx, bool *no_label,
|
|||||||
char c = ctx->str[ctx->cur];
|
char c = ctx->str[ctx->cur];
|
||||||
if(!isalpha(c) && c != '_') {
|
if(!isalpha(c) && c != '_') {
|
||||||
// ERROR: Missing opcode
|
// ERROR: Missing opcode
|
||||||
|
*ctx->error_offset = ctx->cur;
|
||||||
Error_Report(error, ErrorType_SYNTAX, "Missing opcode");
|
Error_Report(error, ErrorType_SYNTAX, "Missing opcode");
|
||||||
#warning "should there be a return here?"
|
#warning "should there be a return here?"
|
||||||
}
|
}
|
||||||
@@ -78,6 +80,7 @@ static bool parseLabelAndOpcode(Context *ctx, bool *no_label,
|
|||||||
skipSpaces(ctx);
|
skipSpaces(ctx);
|
||||||
|
|
||||||
if(ctx->cur == ctx->len || (!isalpha(ctx->str[ctx->cur]) && ctx->str[ctx->cur] != '_')) {
|
if(ctx->cur == ctx->len || (!isalpha(ctx->str[ctx->cur]) && ctx->str[ctx->cur] != '_')) {
|
||||||
|
*ctx->error_offset = ctx->cur;
|
||||||
Error_Report(error, ErrorType_SYNTAX, "Missing opcode after label");
|
Error_Report(error, ErrorType_SYNTAX, "Missing opcode after label");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -112,6 +115,7 @@ static bool parseStringOperand(Context *ctx, Error *error, BPAlloc *alloc, Opera
|
|||||||
ctx->cur += 1;
|
ctx->cur += 1;
|
||||||
|
|
||||||
if(ctx->cur == ctx->len) {
|
if(ctx->cur == ctx->len) {
|
||||||
|
*ctx->error_offset = ctx->cur;
|
||||||
Error_Report(error, ErrorType_SYNTAX, "End of source inside a string literal");
|
Error_Report(error, ErrorType_SYNTAX, "End of source inside a string literal");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -124,6 +128,7 @@ static bool parseStringOperand(Context *ctx, Error *error, BPAlloc *alloc, Opera
|
|||||||
|
|
||||||
char *copy = BPAlloc_Malloc(alloc, literal_length+1);
|
char *copy = BPAlloc_Malloc(alloc, literal_length+1);
|
||||||
if(copy == NULL) {
|
if(copy == NULL) {
|
||||||
|
*ctx->error_offset = ctx->cur;
|
||||||
Error_Report(error, ErrorType_INTERNAL, "No memory");
|
Error_Report(error, ErrorType_INTERNAL, "No memory");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -152,6 +157,7 @@ static bool parseIntegerOperand(Context *ctx, Error *error, Operand *op)
|
|||||||
|
|
||||||
// Will this overflow?
|
// Will this overflow?
|
||||||
if(buffer > (LLONG_MAX - d) / 10) {
|
if(buffer > (LLONG_MAX - d) / 10) {
|
||||||
|
*ctx->error_offset = ctx->cur;
|
||||||
Error_Report(error, ErrorType_SEMANTIC, "Integer literal is too big to be represented in %d bits", 8*sizeof(buffer));
|
Error_Report(error, ErrorType_SEMANTIC, "Integer literal is too big to be represented in %d bits", 8*sizeof(buffer));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -255,6 +261,7 @@ static bool parseOperands(Context *ctx, BPAlloc *alloc, Error *error,
|
|||||||
|
|
||||||
Promise *promise = LabelList_GetLabel(list, ctx->str + offset, length);
|
Promise *promise = LabelList_GetLabel(list, ctx->str + offset, length);
|
||||||
if(promise == NULL) {
|
if(promise == NULL) {
|
||||||
|
*ctx->error_offset = ctx->cur;
|
||||||
Error_Report(error, ErrorType_INTERNAL, "No memory");
|
Error_Report(error, ErrorType_INTERNAL, "No memory");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -264,11 +271,13 @@ static bool parseOperands(Context *ctx, BPAlloc *alloc, Error *error,
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
// ERROR: Unexpected character
|
// ERROR: Unexpected character
|
||||||
|
*ctx->error_offset = ctx->cur;
|
||||||
Error_Report(error, ErrorType_SYNTAX, "Unexpected character '%c'", c);
|
Error_Report(error, ErrorType_SYNTAX, "Unexpected character '%c'", c);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(*opc == opc_max) {
|
if(*opc == opc_max) {
|
||||||
|
*ctx->error_offset = ctx->cur;
|
||||||
Error_Report(error, ErrorType_SEMANTIC, "Too many operands");
|
Error_Report(error, ErrorType_SEMANTIC, "Too many operands");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -282,6 +291,7 @@ static bool parseOperands(Context *ctx, BPAlloc *alloc, Error *error,
|
|||||||
|
|
||||||
c = ctx->str[ctx->cur];
|
c = ctx->str[ctx->cur];
|
||||||
if(c != ',') {
|
if(c != ',') {
|
||||||
|
*ctx->error_offset = ctx->cur;
|
||||||
Error_Report(error, ErrorType_SYNTAX, "Unexpected character '%c' (',' or ';' were expected)", c);
|
Error_Report(error, ErrorType_SYNTAX, "Unexpected character '%c' (',' or ';' were expected)", c);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -296,18 +306,20 @@ static bool parseOperands(Context *ctx, BPAlloc *alloc, Error *error,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Executable *assemble(Source *src, Error *error)
|
Executable *assemble(Source *src, Error *error, int *error_offset)
|
||||||
{
|
{
|
||||||
Executable *exe = NULL;
|
Executable *exe = NULL;
|
||||||
|
|
||||||
BPAlloc *alloc = BPAlloc_Init(-1);
|
BPAlloc *alloc = BPAlloc_Init(-1);
|
||||||
if(alloc == NULL) {
|
if(alloc == NULL) {
|
||||||
|
*error_offset = -1;
|
||||||
Error_Report(error, ErrorType_INTERNAL, "No memory");
|
Error_Report(error, ErrorType_INTERNAL, "No memory");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
LabelList *list = LabelList_New(alloc);
|
LabelList *list = LabelList_New(alloc);
|
||||||
if(list == NULL) {
|
if(list == NULL) {
|
||||||
|
*error_offset = -1;
|
||||||
Error_Report(error, ErrorType_INTERNAL, "No memory");
|
Error_Report(error, ErrorType_INTERNAL, "No memory");
|
||||||
BPAlloc_Free(alloc);
|
BPAlloc_Free(alloc);
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -315,6 +327,7 @@ Executable *assemble(Source *src, Error *error)
|
|||||||
|
|
||||||
ExeBuilder *builder = ExeBuilder_New(alloc);
|
ExeBuilder *builder = ExeBuilder_New(alloc);
|
||||||
if(builder == NULL) {
|
if(builder == NULL) {
|
||||||
|
*error_offset = -1;
|
||||||
Error_Report(error, ErrorType_INTERNAL, "No memory");
|
Error_Report(error, ErrorType_INTERNAL, "No memory");
|
||||||
LabelList_Free(list);
|
LabelList_Free(list);
|
||||||
BPAlloc_Free(alloc);
|
BPAlloc_Free(alloc);
|
||||||
@@ -325,6 +338,7 @@ Executable *assemble(Source *src, Error *error)
|
|||||||
.str = Source_GetBody(src),
|
.str = Source_GetBody(src),
|
||||||
.len = Source_GetSize(src),
|
.len = Source_GetSize(src),
|
||||||
.cur = 0,
|
.cur = 0,
|
||||||
|
.error_offset = error_offset,
|
||||||
};
|
};
|
||||||
while(1) {
|
while(1) {
|
||||||
|
|
||||||
@@ -343,6 +357,7 @@ Executable *assemble(Source *src, Error *error)
|
|||||||
if(no_label == false) {
|
if(no_label == false) {
|
||||||
long long int value = ExeBuilder_InstrCount(builder);
|
long long int value = ExeBuilder_InstrCount(builder);
|
||||||
if(!LabelList_SetLabel(list, ctx.str + label.offset, label.length, value)) {
|
if(!LabelList_SetLabel(list, ctx.str + label.offset, label.length, value)) {
|
||||||
|
*error_offset = ctx.cur;
|
||||||
Error_Report(error, ErrorType_INTERNAL, "Out of memory");
|
Error_Report(error, ErrorType_INTERNAL, "Out of memory");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
@@ -353,6 +368,7 @@ Executable *assemble(Source *src, Error *error)
|
|||||||
Opcode opcode;
|
Opcode opcode;
|
||||||
const char *name = ctx.str + opcode_name.offset;
|
const char *name = ctx.str + opcode_name.offset;
|
||||||
if(!Executable_GetOpcodeBinaryFromName(name, opcode_name.length, &opcode)) {
|
if(!Executable_GetOpcodeBinaryFromName(name, opcode_name.length, &opcode)) {
|
||||||
|
*error_offset = ctx.cur;
|
||||||
Error_Report(error, ErrorType_SEMANTIC, "Opcode %.*s doesn't exist", (int) opcode_name.length, name);
|
Error_Report(error, ErrorType_SEMANTIC, "Opcode %.*s doesn't exist", (int) opcode_name.length, name);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
@@ -378,6 +394,7 @@ Executable *assemble(Source *src, Error *error)
|
|||||||
|
|
||||||
size_t unresolved_count = LabelList_GetUnresolvedCount(list);
|
size_t unresolved_count = LabelList_GetUnresolvedCount(list);
|
||||||
if(unresolved_count > 0) {
|
if(unresolved_count > 0) {
|
||||||
|
*error_offset = -1;
|
||||||
Error_Report(error, ErrorType_SEMANTIC, "%d unresolved labels", unresolved_count);
|
Error_Report(error, ErrorType_SEMANTIC, "%d unresolved labels", unresolved_count);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,5 +3,5 @@
|
|||||||
#include "../utils/error.h"
|
#include "../utils/error.h"
|
||||||
#include "../utils/source.h"
|
#include "../utils/source.h"
|
||||||
#include "../common/executable.h"
|
#include "../common/executable.h"
|
||||||
Executable *assemble(Source *src, Error *error);
|
Executable *assemble(Source *src, Error *error, int *error_offset);
|
||||||
#endif /* ASSEMBLE_H */
|
#endif /* ASSEMBLE_H */
|
||||||
@@ -44,7 +44,7 @@
|
|||||||
#include "../common/defs.h"
|
#include "../common/defs.h"
|
||||||
#include "../objects/objects.h"
|
#include "../objects/objects.h"
|
||||||
#include "../runtime/runtime.h"
|
#include "../runtime/runtime.h"
|
||||||
#include "../compiler/compile.h"
|
#include "../runtime/run.h"
|
||||||
|
|
||||||
static int bin_getCurrentWorkingDirectory(Runtime *runtime, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Error *error)
|
static int bin_getCurrentWorkingDirectory(Runtime *runtime, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Error *error)
|
||||||
{
|
{
|
||||||
@@ -133,56 +133,7 @@ static int bin_import(Runtime *runtime,
|
|||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
const char *path = pargs[0].as_string.data;
|
const char *path = pargs[0].as_string.data;
|
||||||
size_t path_len = pargs[0].as_string.size;
|
return runFileRelativeToScript(runtime, path, rets, error);
|
||||||
|
|
||||||
char full_path[1024];
|
|
||||||
|
|
||||||
if(path[0] == '/') {
|
|
||||||
if(path_len >= sizeof(full_path)) {
|
|
||||||
Error_Report(error, ErrorType_INTERNAL, "Internal buffer is too small");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
strcpy(full_path, path);
|
|
||||||
} else {
|
|
||||||
size_t written = Runtime_GetCurrentScriptFolder(runtime, full_path, sizeof(full_path));
|
|
||||||
if(written == 0) {
|
|
||||||
Error_Report(error, ErrorType_INTERNAL, "Internal buffer is too small");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(written + path_len >= sizeof(full_path)) {
|
|
||||||
Error_Report(error, ErrorType_INTERNAL, "Internal buffer is too small");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(full_path + written, path, path_len);
|
|
||||||
full_path[written + path_len] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
Source *src = Source_FromFile(full_path, error);
|
|
||||||
if(src == NULL)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
Executable *exe = compile(src, error);
|
|
||||||
if(exe == NULL) {
|
|
||||||
Source_Free(src);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
Object *sub_rets[8];
|
|
||||||
int retc = run(runtime, error, exe, 0, NULL, NULL, 0, sub_rets);
|
|
||||||
if(retc < 0)
|
|
||||||
{
|
|
||||||
Source_Free(src);
|
|
||||||
Executable_Free(exe);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
ASSERT(retc == 1);
|
|
||||||
|
|
||||||
Source_Free(src);
|
|
||||||
Executable_Free(exe);
|
|
||||||
rets[0] = sub_rets[0];
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bin_type(Runtime *runtime, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Error *error)
|
static int bin_type(Runtime *runtime, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Error *error)
|
||||||
|
|||||||
@@ -320,7 +320,7 @@ static void flattenTupleTree(CodegenContext *ctx, ExprNode *root, ExprNode *tupl
|
|||||||
|
|
||||||
if(max == *count)
|
if(max == *count)
|
||||||
{
|
{
|
||||||
CodegenContext_ReportErrorAndJump(ctx, ErrorType_INTERNAL, "Static buffer is too small");
|
CodegenContext_ReportErrorAndJump(ctx, root->base.offset, ErrorType_INTERNAL, "Static buffer is too small");
|
||||||
UNREACHABLE;
|
UNREACHABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -348,7 +348,7 @@ static void emitInstrForAssignmentNode(CodegenContext *ctx, OperExprNode *asgn,
|
|||||||
if(((ExprNode*) rop)->kind == EXPR_CALL)
|
if(((ExprNode*) rop)->kind == EXPR_CALL)
|
||||||
emitInstrForFuncCallNode(ctx, (CallExprNode*) rop, label_break, count);
|
emitInstrForFuncCallNode(ctx, (CallExprNode*) rop, label_break, count);
|
||||||
else {
|
else {
|
||||||
CodegenContext_ReportErrorAndJump(ctx, ErrorType_SEMANTIC, "Assigning to %d variables only 1 value", count);
|
CodegenContext_ReportErrorAndJump(ctx, rop->offset, ErrorType_SEMANTIC, "Assigning to %d variables only 1 value", count);
|
||||||
UNREACHABLE;
|
UNREACHABLE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -376,7 +376,7 @@ static void emitInstrForAssignmentNode(CodegenContext *ctx, OperExprNode *asgn,
|
|||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
CodegenContext_ReportErrorAndJump(ctx, ErrorType_SEMANTIC, "Assigning to something that it can't be assigned to");
|
CodegenContext_ReportErrorAndJump(ctx, tuple_item->base.offset, ErrorType_SEMANTIC, "Assigning to something that it can't be assigned to");
|
||||||
UNREACHABLE;
|
UNREACHABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -392,8 +392,8 @@ static void emitInstrForExprNode(CodegenContext *ctx, ExprNode *expr,
|
|||||||
{
|
{
|
||||||
case EXPR_PAIR:
|
case EXPR_PAIR:
|
||||||
CodegenContext_ReportErrorAndJump(
|
CodegenContext_ReportErrorAndJump(
|
||||||
ctx, 0, "Tuple outside of "
|
ctx, expr->base.offset, 0,
|
||||||
"assignment or return statement");
|
"Tuple outside of assignment or return statement");
|
||||||
UNREACHABLE;
|
UNREACHABLE;
|
||||||
return; // For the compiler warning.
|
return; // For the compiler warning.
|
||||||
|
|
||||||
@@ -415,7 +415,7 @@ static void emitInstrForExprNode(CodegenContext *ctx, ExprNode *expr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
case EXPR_ARW:
|
case EXPR_ARW:
|
||||||
CodegenContext_ReportErrorAndJump(ctx, ErrorType_SEMANTIC, "Operator -> out of a function call");
|
CodegenContext_ReportErrorAndJump(ctx, expr->base.offset, ErrorType_SEMANTIC, "Operator -> out of a function call");
|
||||||
UNREACHABLE;
|
UNREACHABLE;
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -683,7 +683,7 @@ static void emitInstrForNode(CodegenContext *ctx, Node *node, Label *label_break
|
|||||||
|
|
||||||
case NODE_BREAK:
|
case NODE_BREAK:
|
||||||
if(label_break == NULL)
|
if(label_break == NULL)
|
||||||
CodegenContext_ReportErrorAndJump(ctx, ErrorType_SEMANTIC, "Break not inside a loop");
|
CodegenContext_ReportErrorAndJump(ctx, node->offset, ErrorType_SEMANTIC, "Break not inside a loop");
|
||||||
emitInstr_JUMP(ctx, label_break, node->offset, node->length);
|
emitInstr_JUMP(ctx, label_break, node->offset, node->length);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -761,7 +761,7 @@ static void emitInstrForNode(CodegenContext *ctx, Node *node, Label *label_break
|
|||||||
* returned and the `error` structure is filled out.
|
* returned and the `error` structure is filled out.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
Executable *codegen(AST *ast, BPAlloc *alloc, Error *error)
|
Executable *codegen(AST *ast, BPAlloc *alloc, Error *error, int *error_offset)
|
||||||
{
|
{
|
||||||
assert(ast != NULL);
|
assert(ast != NULL);
|
||||||
assert(error != NULL);
|
assert(error != NULL);
|
||||||
@@ -770,6 +770,7 @@ Executable *codegen(AST *ast, BPAlloc *alloc, Error *error)
|
|||||||
|
|
||||||
CodegenContext *ctx = CodegenContext_New(error, alloc);
|
CodegenContext *ctx = CodegenContext_New(error, alloc);
|
||||||
if(ctx == NULL) {
|
if(ctx == NULL) {
|
||||||
|
*error_offset = 0;
|
||||||
Error_Report(error, ErrorType_INTERNAL, "No memory");
|
Error_Report(error, ErrorType_INTERNAL, "No memory");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,5 +34,5 @@
|
|||||||
#include "../utils/bpalloc.h"
|
#include "../utils/bpalloc.h"
|
||||||
#include "../common/executable.h"
|
#include "../common/executable.h"
|
||||||
#include "AST.h"
|
#include "AST.h"
|
||||||
Executable *codegen(AST *ast, BPAlloc *alloc, Error *error);
|
Executable *codegen(AST *ast, BPAlloc *alloc, Error *error, int *error_offset);
|
||||||
#endif /* CODEGEN_H */
|
#endif /* CODEGEN_H */
|
||||||
@@ -9,6 +9,7 @@ struct CodegenContext {
|
|||||||
bool own_alloc;
|
bool own_alloc;
|
||||||
bool env_set;
|
bool env_set;
|
||||||
jmp_buf *env;
|
jmp_buf *env;
|
||||||
|
int *error_offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
Label *Label_New(CodegenContext *ctx)
|
Label *Label_New(CodegenContext *ctx)
|
||||||
@@ -17,7 +18,7 @@ Label *Label_New(CodegenContext *ctx)
|
|||||||
if(promise != NULL)
|
if(promise != NULL)
|
||||||
return (Label*) promise;
|
return (Label*) promise;
|
||||||
|
|
||||||
CodegenContext_ReportErrorAndJump(ctx, ErrorType_INTERNAL, "No memory");
|
CodegenContext_ReportErrorAndJump(ctx, -1, ErrorType_INTERNAL, "No memory");
|
||||||
UNREACHABLE;
|
UNREACHABLE;
|
||||||
return NULL; // For the compiler warning.
|
return NULL; // For the compiler warning.
|
||||||
}
|
}
|
||||||
@@ -54,14 +55,14 @@ static void okNowJump(CodegenContext *ctx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CodegenContext_ReportErrorAndJump_(CodegenContext *ctx, const char *file,
|
void CodegenContext_ReportErrorAndJump_(CodegenContext *ctx, const char *file,
|
||||||
const char *func, int line, ErrorType type,
|
const char *func, int line, int error_offset,
|
||||||
const char *format, ...)
|
ErrorType type, const char *format, ...)
|
||||||
{
|
{
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, format);
|
va_start(args, format);
|
||||||
_Error_Report2(ctx->error, type, file, func, line, format, args);
|
_Error_Report2(ctx->error, type, file, func, line, format, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
*ctx->error_offset = error_offset;
|
||||||
okNowJump(ctx);
|
okNowJump(ctx);
|
||||||
UNREACHABLE;
|
UNREACHABLE;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ void CodegenContext_EmitInstr(CodegenContext *ctx, Opcode opcode, Ope
|
|||||||
void CodegenContext_SetJumpDest(CodegenContext *ctx, jmp_buf *env);
|
void CodegenContext_SetJumpDest(CodegenContext *ctx, jmp_buf *env);
|
||||||
void CodegenContext_Free(CodegenContext *ctx);
|
void CodegenContext_Free(CodegenContext *ctx);
|
||||||
Executable *CodegenContext_MakeExecutableAndFree(CodegenContext *ctx, Source *src);
|
Executable *CodegenContext_MakeExecutableAndFree(CodegenContext *ctx, Source *src);
|
||||||
void CodegenContext_ReportErrorAndJump_(CodegenContext *ctx, const char *file, const char *func, int line, ErrorType type, const char *format, ...);
|
void CodegenContext_ReportErrorAndJump_(CodegenContext *ctx, const char *file, const char *func, int line, int error_offset, ErrorType type, const char *format, ...);
|
||||||
#define CodegenContext_ReportErrorAndJump(ctx, int, fmt, ...) CodegenContext_ReportErrorAndJump_(ctx, __FILE__, __func__, __LINE__, int, fmt, ## __VA_ARGS__)
|
#define CodegenContext_ReportErrorAndJump(ctx, error_offset, typ, fmt, ...) CodegenContext_ReportErrorAndJump_(ctx, __FILE__, __func__, __LINE__, error_offset, typ, fmt, ## __VA_ARGS__)
|
||||||
int CodegenContext_InstrCount(CodegenContext *ctx);
|
int CodegenContext_InstrCount(CodegenContext *ctx);
|
||||||
|
|
||||||
typedef struct Label Label;
|
typedef struct Label Label;
|
||||||
|
|||||||
@@ -5,20 +5,21 @@
|
|||||||
#include "codegen.h"
|
#include "codegen.h"
|
||||||
#include "compile.h"
|
#include "compile.h"
|
||||||
|
|
||||||
Executable *compile(Source *src, Error *error)
|
Executable *compile(Source *src, Error *error, int *error_offset)
|
||||||
{
|
{
|
||||||
// Create a bump-pointer allocator to hold the AST.
|
// Create a bump-pointer allocator to hold the AST.
|
||||||
BPAlloc *alloc = BPAlloc_Init(-1);
|
BPAlloc *alloc = BPAlloc_Init(-1);
|
||||||
|
|
||||||
if(alloc == NULL)
|
if(alloc == NULL)
|
||||||
{
|
{
|
||||||
|
*error_offset = -1;
|
||||||
Error_Report(error, ErrorType_INTERNAL, "No memory");
|
Error_Report(error, ErrorType_INTERNAL, "No memory");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: The AST is stored in the BPAlloc. Its
|
// NOTE: The AST is stored in the BPAlloc. Its
|
||||||
// lifetime is the same as the pool.
|
// lifetime is the same as the pool.
|
||||||
AST *ast = parse(src, alloc, error);
|
AST *ast = parse(src, alloc, error, error_offset);
|
||||||
|
|
||||||
if(ast == NULL)
|
if(ast == NULL)
|
||||||
{
|
{
|
||||||
@@ -28,7 +29,7 @@ Executable *compile(Source *src, Error *error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Transform the AST into bytecode.
|
// Transform the AST into bytecode.
|
||||||
Executable *exe = codegen(ast, alloc, error);
|
Executable *exe = codegen(ast, alloc, error, error_offset);
|
||||||
|
|
||||||
// We're done with the AST.
|
// We're done with the AST.
|
||||||
BPAlloc_Free(alloc);
|
BPAlloc_Free(alloc);
|
||||||
|
|||||||
@@ -3,5 +3,5 @@
|
|||||||
#include "../utils/error.h"
|
#include "../utils/error.h"
|
||||||
#include "../utils/source.h"
|
#include "../utils/source.h"
|
||||||
#include "../common/executable.h"
|
#include "../common/executable.h"
|
||||||
Executable *compile(Source *src, Error *error);
|
Executable *compile(Source *src, Error *error, int *error_offset);
|
||||||
#endif /* COMPILE_H */
|
#endif /* COMPILE_H */
|
||||||
+93
-11
@@ -129,6 +129,7 @@ typedef struct {
|
|||||||
Token *token;
|
Token *token;
|
||||||
BPAlloc *alloc;
|
BPAlloc *alloc;
|
||||||
Error *error;
|
Error *error;
|
||||||
|
int *error_offset;
|
||||||
} Context;
|
} Context;
|
||||||
|
|
||||||
static Node *parse_statement(Context *ctx);
|
static Node *parse_statement(Context *ctx);
|
||||||
@@ -152,6 +153,7 @@ static inline _Bool isoper(char c)
|
|||||||
c == '%';
|
c == '%';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#warning "update doc arguments"
|
||||||
/* Symbol: tokenize
|
/* Symbol: tokenize
|
||||||
*
|
*
|
||||||
* Build a list of tokens that represents the
|
* Build a list of tokens that represents the
|
||||||
@@ -175,7 +177,7 @@ static inline _Bool isoper(char c)
|
|||||||
* structure is filled out.
|
* structure is filled out.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static Token *tokenize(Source *src, BPAlloc *alloc, Error *error)
|
static Token *tokenize(Source *src, BPAlloc *alloc, Error *error, int *error_offset)
|
||||||
{
|
{
|
||||||
const char *str = Source_GetBody(src);
|
const char *str = Source_GetBody(src);
|
||||||
int len = Source_GetSize(src);
|
int len = Source_GetSize(src);
|
||||||
@@ -209,6 +211,7 @@ static Token *tokenize(Source *src, BPAlloc *alloc, Error *error)
|
|||||||
if(tok == NULL)
|
if(tok == NULL)
|
||||||
{
|
{
|
||||||
// Error: No memory.
|
// Error: No memory.
|
||||||
|
*error_offset = i;
|
||||||
Error_Report(error, ErrorType_INTERNAL, "No memory");
|
Error_Report(error, ErrorType_INTERNAL, "No memory");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -295,6 +298,7 @@ static Token *tokenize(Source *src, BPAlloc *alloc, Error *error)
|
|||||||
|
|
||||||
if(i == len)
|
if(i == len)
|
||||||
{
|
{
|
||||||
|
*error_offset = i;
|
||||||
Error_Report(error, 0, "Source ended inside string literal");
|
Error_Report(error, 0, "Source ended inside string literal");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -377,6 +381,7 @@ static Token *tokenize(Source *src, BPAlloc *alloc, Error *error)
|
|||||||
if(tok == NULL)
|
if(tok == NULL)
|
||||||
{
|
{
|
||||||
// Error: No memory.
|
// Error: No memory.
|
||||||
|
*error_offset = i;
|
||||||
Error_Report(error, ErrorType_INTERNAL, "No memory");
|
Error_Report(error, ErrorType_INTERNAL, "No memory");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -427,7 +432,7 @@ static Token *tokenize(Source *src, BPAlloc *alloc, Error *error)
|
|||||||
* is freed before the AST.
|
* is freed before the AST.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
AST *parse(Source *src, BPAlloc *alloc, Error *error)
|
AST *parse(Source *src, BPAlloc *alloc, Error *error, int *error_offset)
|
||||||
{
|
{
|
||||||
assert(src != NULL);
|
assert(src != NULL);
|
||||||
assert(alloc != NULL);
|
assert(alloc != NULL);
|
||||||
@@ -436,9 +441,10 @@ AST *parse(Source *src, BPAlloc *alloc, Error *error)
|
|||||||
AST *ast = BPAlloc_Malloc(alloc, sizeof(AST));
|
AST *ast = BPAlloc_Malloc(alloc, sizeof(AST));
|
||||||
|
|
||||||
if(ast == NULL)
|
if(ast == NULL)
|
||||||
|
#warning "should an error be reported here?"
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
Token *tokens = tokenize(src, alloc, error);
|
Token *tokens = tokenize(src, alloc, error, error_offset);
|
||||||
|
|
||||||
if(tokens == NULL)
|
if(tokens == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -448,7 +454,7 @@ AST *parse(Source *src, BPAlloc *alloc, Error *error)
|
|||||||
ctx.token = tokens;
|
ctx.token = tokens;
|
||||||
ctx.alloc = alloc;
|
ctx.alloc = alloc;
|
||||||
ctx.error = error;
|
ctx.error = error;
|
||||||
|
ctx.error_offset = error_offset;
|
||||||
Node *root = parse_compound_statement(&ctx, TDONE);
|
Node *root = parse_compound_statement(&ctx, TDONE);
|
||||||
|
|
||||||
if(root == NULL)
|
if(root == NULL)
|
||||||
@@ -599,6 +605,7 @@ static Node *parse_statement(Context *ctx)
|
|||||||
|
|
||||||
if(current(ctx) != ';')
|
if(current(ctx) != ';')
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_SYNTAX, "Got token \"%.*s\" where \";\" was expected", ctx->token->length, ctx->src + ctx->token->offset);
|
Error_Report(ctx->error, ErrorType_SYNTAX, "Got token \"%.*s\" where \";\" was expected", ctx->token->length, ctx->src + ctx->token->offset);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -609,6 +616,7 @@ static Node *parse_statement(Context *ctx)
|
|||||||
|
|
||||||
if(node == NULL)
|
if(node == NULL)
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_INTERNAL, "No memory");
|
Error_Report(ctx->error, ErrorType_INTERNAL, "No memory");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -633,6 +641,7 @@ static Node *parse_statement(Context *ctx)
|
|||||||
|
|
||||||
if(current(ctx) != ';')
|
if(current(ctx) != ';')
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = current_token(ctx)->offset;
|
||||||
Error_Report(ctx->error, ErrorType_SYNTAX,
|
Error_Report(ctx->error, ErrorType_SYNTAX,
|
||||||
"Got token \"%.*s\" where \";\" was expected",
|
"Got token \"%.*s\" where \";\" was expected",
|
||||||
ctx->token->length, ctx->src + ctx->token->offset);
|
ctx->token->length, ctx->src + ctx->token->offset);
|
||||||
@@ -645,6 +654,7 @@ static Node *parse_statement(Context *ctx)
|
|||||||
|
|
||||||
if(node == NULL)
|
if(node == NULL)
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = current_token(ctx)->offset;
|
||||||
Error_Report(ctx->error, ErrorType_INTERNAL, "No memory");
|
Error_Report(ctx->error, ErrorType_INTERNAL, "No memory");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -667,6 +677,7 @@ static Node *parse_statement(Context *ctx)
|
|||||||
return parse_dowhile_statement(ctx);
|
return parse_dowhile_statement(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*ctx->error_offset = current_token(ctx)->offset;
|
||||||
Error_Report(ctx->error, ErrorType_SYNTAX, "Got token \"%.*s\" where the start of a statement was expected",
|
Error_Report(ctx->error, ErrorType_SYNTAX, "Got token \"%.*s\" where the start of a statement was expected",
|
||||||
ctx->token->length, ctx->src + ctx->token->offset);
|
ctx->token->length, ctx->src + ctx->token->offset);
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -683,15 +694,14 @@ static Node *parse_expression_statement(Context *ctx)
|
|||||||
|
|
||||||
if(done(ctx))
|
if(done(ctx))
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_SYNTAX, "Source ended right after an expression, where a ';' was expected");
|
Error_Report(ctx->error, ErrorType_SYNTAX, "Source ended right after an expression, where a ';' was expected");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(current(ctx) != ';')
|
if(current(ctx) != ';')
|
||||||
{
|
{
|
||||||
// ERROR: Got something other than a semicolon at the end
|
*ctx->error_offset = ctx->token->offset;
|
||||||
// of statement.
|
|
||||||
|
|
||||||
Error_Report(ctx->error, ErrorType_SYNTAX, "Got token \"%.*s\" where \";\" was expected", ctx->token->length, ctx->src + ctx->token->offset);
|
Error_Report(ctx->error, ErrorType_SYNTAX, "Got token \"%.*s\" where \";\" was expected", ctx->token->length, ctx->src + ctx->token->offset);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -715,6 +725,7 @@ static Node *makeStringExprNode(Context *ctx, const char *str, int len)
|
|||||||
|
|
||||||
if(copy == NULL)
|
if(copy == NULL)
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_INTERNAL, "No memory");
|
Error_Report(ctx->error, ErrorType_INTERNAL, "No memory");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -730,6 +741,7 @@ static Node *makeStringExprNode(Context *ctx, const char *str, int len)
|
|||||||
|
|
||||||
if(node == NULL)
|
if(node == NULL)
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_INTERNAL, "No memory");
|
Error_Report(ctx->error, ErrorType_INTERNAL, "No memory");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -752,12 +764,14 @@ static Node *parse_string_primary_expression(Context *ctx)
|
|||||||
|
|
||||||
if(done(ctx))
|
if(done(ctx))
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_SYNTAX, "Source ended where a string literal was expected");
|
Error_Report(ctx->error, ErrorType_SYNTAX, "Source ended where a string literal was expected");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(current(ctx) != TSTRING)
|
if(current(ctx) != TSTRING)
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_SYNTAX, "Got token \"%.*s\" where a string literal was expected", ctx->token->length, ctx->src + ctx->token->offset);
|
Error_Report(ctx->error, ErrorType_SYNTAX, "Got token \"%.*s\" where a string literal was expected", ctx->token->length, ctx->src + ctx->token->offset);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -784,6 +798,7 @@ static Node *parse_string_primary_expression(Context *ctx)
|
|||||||
|
|
||||||
if(temp_used + segm_len >= (int) sizeof(temp))
|
if(temp_used + segm_len >= (int) sizeof(temp))
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_INTERNAL, "String is too big to be rendered inside the fixed size buffer");
|
Error_Report(ctx->error, ErrorType_INTERNAL, "String is too big to be rendered inside the fixed size buffer");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -797,6 +812,7 @@ static Node *parse_string_primary_expression(Context *ctx)
|
|||||||
|
|
||||||
if(temp_used + 1 >= (int) sizeof(temp))
|
if(temp_used + 1 >= (int) sizeof(temp))
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_INTERNAL, "String is too big to be rendered inside the fixed size buffer");
|
Error_Report(ctx->error, ErrorType_INTERNAL, "String is too big to be rendered inside the fixed size buffer");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -818,6 +834,7 @@ static Node *parse_string_primary_expression(Context *ctx)
|
|||||||
case '\'': temp[temp_used++] = '\''; break;
|
case '\'': temp[temp_used++] = '\''; break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_SYNTAX, "Invalid escape sequence \\%c", src[i]);
|
Error_Report(ctx->error, ErrorType_SYNTAX, "Invalid escape sequence \\%c", src[i]);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -843,12 +860,14 @@ static Node *parse_list_primary_expression(Context *ctx)
|
|||||||
|
|
||||||
if(done(ctx))
|
if(done(ctx))
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_SYNTAX, "Source ended where a list literal was expected");
|
Error_Report(ctx->error, ErrorType_SYNTAX, "Source ended where a list literal was expected");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(current(ctx) != '[')
|
if(current(ctx) != '[')
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_SYNTAX, "Got token \"%.*s\" where a list literal was expected", ctx->token->length, ctx->src + ctx->token->offset);
|
Error_Report(ctx->error, ErrorType_SYNTAX, "Got token \"%.*s\" where a list literal was expected", ctx->token->length, ctx->src + ctx->token->offset);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -887,6 +906,7 @@ static Node *parse_list_primary_expression(Context *ctx)
|
|||||||
|
|
||||||
if(current(ctx) != ',')
|
if(current(ctx) != ',')
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
if(current(ctx) == TDONE)
|
if(current(ctx) == TDONE)
|
||||||
Error_Report(ctx->error, ErrorType_SYNTAX, "Source ended inside a list literal");
|
Error_Report(ctx->error, ErrorType_SYNTAX, "Source ended inside a list literal");
|
||||||
else
|
else
|
||||||
@@ -910,6 +930,7 @@ static Node *parse_list_primary_expression(Context *ctx)
|
|||||||
|
|
||||||
if(list == NULL)
|
if(list == NULL)
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_INTERNAL, "No memory");
|
Error_Report(ctx->error, ErrorType_INTERNAL, "No memory");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -933,6 +954,7 @@ static Node *parse_map_primary_expression(Context *ctx)
|
|||||||
|
|
||||||
if(done(ctx))
|
if(done(ctx))
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_SYNTAX,
|
Error_Report(ctx->error, ErrorType_SYNTAX,
|
||||||
"Source ended where a map literal was expected");
|
"Source ended where a map literal was expected");
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -940,6 +962,7 @@ static Node *parse_map_primary_expression(Context *ctx)
|
|||||||
|
|
||||||
if(current(ctx) != '{')
|
if(current(ctx) != '{')
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_SYNTAX,
|
Error_Report(ctx->error, ErrorType_SYNTAX,
|
||||||
"Got token \"%.*s\" where a map literal was expected",
|
"Got token \"%.*s\" where a map literal was expected",
|
||||||
ctx->token->length, ctx->src + ctx->token->offset);
|
ctx->token->length, ctx->src + ctx->token->offset);
|
||||||
@@ -956,6 +979,7 @@ static Node *parse_map_primary_expression(Context *ctx)
|
|||||||
|
|
||||||
if(done(ctx))
|
if(done(ctx))
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_SYNTAX, "Source ended where a map child item's key was expected");
|
Error_Report(ctx->error, ErrorType_SYNTAX, "Source ended where a map child item's key was expected");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -1007,6 +1031,7 @@ static Node *parse_map_primary_expression(Context *ctx)
|
|||||||
|
|
||||||
if(done(ctx))
|
if(done(ctx))
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_SYNTAX,
|
Error_Report(ctx->error, ErrorType_SYNTAX,
|
||||||
"Source ended where a map key-value "
|
"Source ended where a map key-value "
|
||||||
"separator ':' was expected");
|
"separator ':' was expected");
|
||||||
@@ -1015,6 +1040,7 @@ static Node *parse_map_primary_expression(Context *ctx)
|
|||||||
|
|
||||||
if(current(ctx) != ':')
|
if(current(ctx) != ':')
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_SYNTAX,
|
Error_Report(ctx->error, ErrorType_SYNTAX,
|
||||||
"Got token \"%.*s\" where a map key-value "
|
"Got token \"%.*s\" where a map key-value "
|
||||||
"separator ':' was expected",
|
"separator ':' was expected",
|
||||||
@@ -1054,6 +1080,7 @@ static Node *parse_map_primary_expression(Context *ctx)
|
|||||||
if (!item_is_func_decl) {
|
if (!item_is_func_decl) {
|
||||||
if(current(ctx) != ',')
|
if(current(ctx) != ',')
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
if(current(ctx) == TDONE)
|
if(current(ctx) == TDONE)
|
||||||
Error_Report(ctx->error, ErrorType_SYNTAX, "Source ended inside a map literal");
|
Error_Report(ctx->error, ErrorType_SYNTAX, "Source ended inside a map literal");
|
||||||
else
|
else
|
||||||
@@ -1080,6 +1107,7 @@ static Node *parse_map_primary_expression(Context *ctx)
|
|||||||
|
|
||||||
if(map == NULL)
|
if(map == NULL)
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_INTERNAL, "No memory");
|
Error_Report(ctx->error, ErrorType_INTERNAL, "No memory");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -1119,6 +1147,7 @@ static Node *makeIdentExprNode(Context *ctx)
|
|||||||
|
|
||||||
if(copy == NULL)
|
if(copy == NULL)
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_INTERNAL, "No memory");
|
Error_Report(ctx->error, ErrorType_INTERNAL, "No memory");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -1129,6 +1158,7 @@ static Node *makeIdentExprNode(Context *ctx)
|
|||||||
|
|
||||||
if(node == NULL)
|
if(node == NULL)
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_INTERNAL, "No memory");
|
Error_Report(ctx->error, ErrorType_INTERNAL, "No memory");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -1151,6 +1181,7 @@ static Node *parse_primary_expresion(Context *ctx)
|
|||||||
|
|
||||||
if(done(ctx))
|
if(done(ctx))
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_SYNTAX, "Source ended where a primary expression was expected");
|
Error_Report(ctx->error, ErrorType_SYNTAX, "Source ended where a primary expression was expected");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -1175,12 +1206,14 @@ static Node *parse_primary_expresion(Context *ctx)
|
|||||||
|
|
||||||
if(done(ctx))
|
if(done(ctx))
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_SYNTAX, "Source ended before \")\", after sub-expression");
|
Error_Report(ctx->error, ErrorType_SYNTAX, "Source ended before \")\", after sub-expression");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(current(ctx) != ')')
|
if(current(ctx) != ')')
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_SYNTAX, "Missing \")\", after sub-expression");
|
Error_Report(ctx->error, ErrorType_SYNTAX, "Missing \")\", after sub-expression");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -1194,6 +1227,7 @@ static Node *parse_primary_expresion(Context *ctx)
|
|||||||
|
|
||||||
if(ctx->token->length >= (int) sizeof(buffer))
|
if(ctx->token->length >= (int) sizeof(buffer))
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_INTERNAL, "Integer is too big");
|
Error_Report(ctx->error, ErrorType_INTERNAL, "Integer is too big");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -1207,6 +1241,7 @@ static Node *parse_primary_expresion(Context *ctx)
|
|||||||
|
|
||||||
if(errno == ERANGE)
|
if(errno == ERANGE)
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_INTERNAL, "Integer is too big");
|
Error_Report(ctx->error, ErrorType_INTERNAL, "Integer is too big");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -1218,6 +1253,7 @@ static Node *parse_primary_expresion(Context *ctx)
|
|||||||
|
|
||||||
if(node == NULL)
|
if(node == NULL)
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_INTERNAL, "No memory");
|
Error_Report(ctx->error, ErrorType_INTERNAL, "No memory");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -1241,6 +1277,7 @@ static Node *parse_primary_expresion(Context *ctx)
|
|||||||
|
|
||||||
if(ctx->token->length >= (int) sizeof(buffer))
|
if(ctx->token->length >= (int) sizeof(buffer))
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_INTERNAL, "Floating is too big");
|
Error_Report(ctx->error, ErrorType_INTERNAL, "Floating is too big");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -1254,6 +1291,7 @@ static Node *parse_primary_expresion(Context *ctx)
|
|||||||
|
|
||||||
if(errno == ERANGE)
|
if(errno == ERANGE)
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_INTERNAL, "Floating is too big");
|
Error_Report(ctx->error, ErrorType_INTERNAL, "Floating is too big");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -1265,6 +1303,7 @@ static Node *parse_primary_expresion(Context *ctx)
|
|||||||
|
|
||||||
if(node == NULL)
|
if(node == NULL)
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_INTERNAL, "No memory");
|
Error_Report(ctx->error, ErrorType_INTERNAL, "No memory");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -1295,6 +1334,7 @@ static Node *parse_primary_expresion(Context *ctx)
|
|||||||
|
|
||||||
if(node == NULL)
|
if(node == NULL)
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_INTERNAL, "No memory");
|
Error_Report(ctx->error, ErrorType_INTERNAL, "No memory");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -1319,6 +1359,7 @@ static Node *parse_primary_expresion(Context *ctx)
|
|||||||
|
|
||||||
if(node == NULL)
|
if(node == NULL)
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_INTERNAL, "No memory");
|
Error_Report(ctx->error, ErrorType_INTERNAL, "No memory");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -1343,6 +1384,7 @@ static Node *parse_primary_expresion(Context *ctx)
|
|||||||
|
|
||||||
if(node == NULL)
|
if(node == NULL)
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_INTERNAL, "No memory");
|
Error_Report(ctx->error, ErrorType_INTERNAL, "No memory");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -1369,10 +1411,12 @@ static Node *parse_primary_expresion(Context *ctx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
case TDONE:
|
case TDONE:
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_INTERNAL, "Unexpected end of source where a primary expression was expected");
|
Error_Report(ctx->error, ErrorType_INTERNAL, "Unexpected end of source where a primary expression was expected");
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_INTERNAL, "Unexpected token \"%.*s\" where a primary expression was expected", ctx->token->length, ctx->src + ctx->token->offset);
|
Error_Report(ctx->error, ErrorType_INTERNAL, "Unexpected token \"%.*s\" where a primary expression was expected", ctx->token->length, ctx->src + ctx->token->offset);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -1387,6 +1431,7 @@ static Node *makeIndexOrArrowSelectionExprNode(Context *ctx, bool arrow, Node *s
|
|||||||
|
|
||||||
if(sel == NULL)
|
if(sel == NULL)
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_INTERNAL, "No memory");
|
Error_Report(ctx->error, ErrorType_INTERNAL, "No memory");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -1425,12 +1470,14 @@ static Node *parse_postfix_expression(Context *ctx)
|
|||||||
|
|
||||||
if(done(ctx))
|
if(done(ctx))
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_SYNTAX, "Source ended after dot or arrow");
|
Error_Report(ctx->error, ErrorType_SYNTAX, "Source ended after dot or arrow");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(current(ctx) != TIDENT)
|
if(current(ctx) != TIDENT)
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_SYNTAX, "Got unexpected token \"%.*s\" after dot or arrow, where an identifier was expected", ctx->token->length, ctx->src + ctx->token->offset);
|
Error_Report(ctx->error, ErrorType_SYNTAX, "Got unexpected token \"%.*s\" after dot or arrow, where an identifier was expected", ctx->token->length, ctx->src + ctx->token->offset);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -1462,6 +1509,7 @@ static Node *parse_postfix_expression(Context *ctx)
|
|||||||
|
|
||||||
if(ls->itemc == 0)
|
if(ls->itemc == 0)
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_SYNTAX, "Missing index in index selection expression");
|
Error_Report(ctx->error, ErrorType_SYNTAX, "Missing index in index selection expression");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -1507,6 +1555,7 @@ static Node *parse_postfix_expression(Context *ctx)
|
|||||||
|
|
||||||
if(current(ctx) != ',')
|
if(current(ctx) != ',')
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
if(current(ctx) == TDONE)
|
if(current(ctx) == TDONE)
|
||||||
Error_Report(ctx->error, ErrorType_SYNTAX, "Source ended inside a function argument list");
|
Error_Report(ctx->error, ErrorType_SYNTAX, "Source ended inside a function argument list");
|
||||||
else
|
else
|
||||||
@@ -1529,6 +1578,7 @@ static Node *parse_postfix_expression(Context *ctx)
|
|||||||
|
|
||||||
if(call == NULL)
|
if(call == NULL)
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_INTERNAL, "No memory");
|
Error_Report(ctx->error, ErrorType_INTERNAL, "No memory");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -1559,6 +1609,7 @@ static Node *parse_prefix_expression(Context *ctx)
|
|||||||
{
|
{
|
||||||
if(done(ctx))
|
if(done(ctx))
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_SYNTAX, "Source ended where a prefix expression was expected");
|
Error_Report(ctx->error, ErrorType_SYNTAX, "Source ended where a prefix expression was expected");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -1566,6 +1617,7 @@ static Node *parse_prefix_expression(Context *ctx)
|
|||||||
switch(current(ctx))
|
switch(current(ctx))
|
||||||
{
|
{
|
||||||
case TDONE:
|
case TDONE:
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_INTERNAL, "Unexpected end of source where a prefix expression was expected");
|
Error_Report(ctx->error, ErrorType_INTERNAL, "Unexpected end of source where a prefix expression was expected");
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
@@ -1779,12 +1831,14 @@ static Node *parse_ifelse_statement(Context *ctx)
|
|||||||
|
|
||||||
if(done(ctx))
|
if(done(ctx))
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_SYNTAX, "Source ended where an if-else statement was expected");
|
Error_Report(ctx->error, ErrorType_SYNTAX, "Source ended where an if-else statement was expected");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(current(ctx) != TKWIF)
|
if(current(ctx) != TKWIF)
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_SYNTAX, "Got unexpected token \"%.*s\" where an if-else statement was expected", ctx->token->length, ctx->src + ctx->token->offset);
|
Error_Report(ctx->error, ErrorType_SYNTAX, "Got unexpected token \"%.*s\" where an if-else statement was expected", ctx->token->length, ctx->src + ctx->token->offset);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -1801,12 +1855,14 @@ static Node *parse_ifelse_statement(Context *ctx)
|
|||||||
|
|
||||||
if(done(ctx))
|
if(done(ctx))
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_SYNTAX, "Source ended right after an if-else condition, where a ':' was expected");
|
Error_Report(ctx->error, ErrorType_SYNTAX, "Source ended right after an if-else condition, where a ':' was expected");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(current(ctx) != ':')
|
if(current(ctx) != ':')
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_SYNTAX, "Got unexpected token \"%.*s\" after an if-else condition, where a ':' was expected", ctx->token->length, ctx->src + ctx->token->offset);
|
Error_Report(ctx->error, ErrorType_SYNTAX, "Got unexpected token \"%.*s\" after an if-else condition, where a ':' was expected", ctx->token->length, ctx->src + ctx->token->offset);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -1836,7 +1892,7 @@ static Node *parse_ifelse_statement(Context *ctx)
|
|||||||
|
|
||||||
if(ifelse == NULL)
|
if(ifelse == NULL)
|
||||||
{
|
{
|
||||||
// ERROR: No memory.
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_INTERNAL, "No memory");
|
Error_Report(ctx->error, ErrorType_INTERNAL, "No memory");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -1876,6 +1932,7 @@ static Node *parse_compound_statement(Context *ctx, TokenKind end)
|
|||||||
|
|
||||||
if(current(ctx) != end)
|
if(current(ctx) != end)
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_SYNTAX, "Source ended inside compound statement");
|
Error_Report(ctx->error, ErrorType_SYNTAX, "Source ended inside compound statement");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -1886,7 +1943,7 @@ static Node *parse_compound_statement(Context *ctx, TokenKind end)
|
|||||||
|
|
||||||
if(node == NULL)
|
if(node == NULL)
|
||||||
{
|
{
|
||||||
// ERROR: No memory.
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_INTERNAL, "No memory");
|
Error_Report(ctx->error, ErrorType_INTERNAL, "No memory");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -1907,6 +1964,7 @@ static _Bool parse_function_arguments(Context *ctx, int *argc_, Node **argv_)
|
|||||||
|
|
||||||
if(next(ctx) != '(')
|
if(next(ctx) != '(')
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
if(done(ctx))
|
if(done(ctx))
|
||||||
Error_Report(ctx->error, ErrorType_SYNTAX, "Source ended where a function argument list was expected");
|
Error_Report(ctx->error, ErrorType_SYNTAX, "Source ended where a function argument list was expected");
|
||||||
else
|
else
|
||||||
@@ -1925,12 +1983,14 @@ static _Bool parse_function_arguments(Context *ctx, int *argc_, Node **argv_)
|
|||||||
{
|
{
|
||||||
if(done(ctx))
|
if(done(ctx))
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_SYNTAX, "Source ended inside a function argument list");
|
Error_Report(ctx->error, ErrorType_SYNTAX, "Source ended inside a function argument list");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(current(ctx) != TIDENT)
|
if(current(ctx) != TIDENT)
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_SYNTAX, "Got unexpected token \"%.*s\" where a function argument name was expected", ctx->token->length, ctx->src + ctx->token->offset);
|
Error_Report(ctx->error, ErrorType_SYNTAX, "Got unexpected token \"%.*s\" where a function argument name was expected", ctx->token->length, ctx->src + ctx->token->offset);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1939,6 +1999,7 @@ static _Bool parse_function_arguments(Context *ctx, int *argc_, Node **argv_)
|
|||||||
|
|
||||||
if(arg_name == NULL)
|
if(arg_name == NULL)
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_INTERNAL, "No memory");
|
Error_Report(ctx->error, ErrorType_INTERNAL, "No memory");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1968,6 +2029,7 @@ static _Bool parse_function_arguments(Context *ctx, int *argc_, Node **argv_)
|
|||||||
|
|
||||||
if(arg == NULL)
|
if(arg == NULL)
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_INTERNAL, "No memory");
|
Error_Report(ctx->error, ErrorType_INTERNAL, "No memory");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1990,6 +2052,7 @@ static _Bool parse_function_arguments(Context *ctx, int *argc_, Node **argv_)
|
|||||||
|
|
||||||
if(done(ctx))
|
if(done(ctx))
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_SYNTAX, "Source ended inside a function argument list");
|
Error_Report(ctx->error, ErrorType_SYNTAX, "Source ended inside a function argument list");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1999,6 +2062,7 @@ static _Bool parse_function_arguments(Context *ctx, int *argc_, Node **argv_)
|
|||||||
|
|
||||||
if(current(ctx) != ',')
|
if(current(ctx) != ',')
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_SYNTAX, "Got unexpected token \"%.*s\" inside function argument list, where either ',' or ')' were expected", ctx->token->length, ctx->src + ctx->token->offset);
|
Error_Report(ctx->error, ErrorType_SYNTAX, "Got unexpected token \"%.*s\" inside function argument list, where either ',' or ')' were expected", ctx->token->length, ctx->src + ctx->token->offset);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -2021,12 +2085,14 @@ static FuncDeclNode *parse_function_definition(Context *ctx)
|
|||||||
|
|
||||||
if(done(ctx))
|
if(done(ctx))
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_SYNTAX, "Source ended where a function definition was expected");
|
Error_Report(ctx->error, ErrorType_SYNTAX, "Source ended where a function definition was expected");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(current(ctx) != TKWFUN)
|
if(current(ctx) != TKWFUN)
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_SYNTAX, "Got unexpected token \"%.*s\" where a function definition was expected", ctx->token->length, ctx->src + ctx->token->offset);
|
Error_Report(ctx->error, ErrorType_SYNTAX, "Got unexpected token \"%.*s\" where a function definition was expected", ctx->token->length, ctx->src + ctx->token->offset);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -2035,6 +2101,7 @@ static FuncDeclNode *parse_function_definition(Context *ctx)
|
|||||||
|
|
||||||
if(next(ctx) != TIDENT)
|
if(next(ctx) != TIDENT)
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
if(done(ctx))
|
if(done(ctx))
|
||||||
Error_Report(ctx->error, ErrorType_SYNTAX, "Source ended where an identifier was expected as function name");
|
Error_Report(ctx->error, ErrorType_SYNTAX, "Source ended where an identifier was expected as function name");
|
||||||
else
|
else
|
||||||
@@ -2045,6 +2112,7 @@ static FuncDeclNode *parse_function_definition(Context *ctx)
|
|||||||
char *name_val = copy_token_text(ctx);
|
char *name_val = copy_token_text(ctx);
|
||||||
if(name_val == NULL)
|
if(name_val == NULL)
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_INTERNAL, "No memory");
|
Error_Report(ctx->error, ErrorType_INTERNAL, "No memory");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -2059,6 +2127,7 @@ static FuncDeclNode *parse_function_definition(Context *ctx)
|
|||||||
|
|
||||||
if(done(ctx))
|
if(done(ctx))
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_SYNTAX, "Source ended before function body");
|
Error_Report(ctx->error, ErrorType_SYNTAX, "Source ended before function body");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -2077,6 +2146,7 @@ static FuncDeclNode *parse_function_definition(Context *ctx)
|
|||||||
FuncExprNode *expr = BPAlloc_Malloc(ctx->alloc, sizeof(FuncExprNode));
|
FuncExprNode *expr = BPAlloc_Malloc(ctx->alloc, sizeof(FuncExprNode));
|
||||||
if (expr == NULL)
|
if (expr == NULL)
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_INTERNAL, "No memory");
|
Error_Report(ctx->error, ErrorType_INTERNAL, "No memory");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -2092,6 +2162,7 @@ static FuncDeclNode *parse_function_definition(Context *ctx)
|
|||||||
StringExprNode *name = BPAlloc_Malloc(ctx->alloc, sizeof(StringExprNode));
|
StringExprNode *name = BPAlloc_Malloc(ctx->alloc, sizeof(StringExprNode));
|
||||||
if (name == NULL)
|
if (name == NULL)
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_INTERNAL, "No memory");
|
Error_Report(ctx->error, ErrorType_INTERNAL, "No memory");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -2106,6 +2177,7 @@ static FuncDeclNode *parse_function_definition(Context *ctx)
|
|||||||
func = BPAlloc_Malloc(ctx->alloc, sizeof(FuncDeclNode));
|
func = BPAlloc_Malloc(ctx->alloc, sizeof(FuncDeclNode));
|
||||||
if(func == NULL)
|
if(func == NULL)
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_INTERNAL, "No memory");
|
Error_Report(ctx->error, ErrorType_INTERNAL, "No memory");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -2126,12 +2198,14 @@ static Node *parse_while_statement(Context *ctx)
|
|||||||
|
|
||||||
if(done(ctx))
|
if(done(ctx))
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_SYNTAX, "Source ended where a while statement was expected");
|
Error_Report(ctx->error, ErrorType_SYNTAX, "Source ended where a while statement was expected");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(current(ctx) != TKWWHILE)
|
if(current(ctx) != TKWWHILE)
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_SYNTAX, "Got unexpected token \"%.*s\" where a while statement was expected", ctx->token->length, ctx->src + ctx->token->offset);
|
Error_Report(ctx->error, ErrorType_SYNTAX, "Got unexpected token \"%.*s\" where a while statement was expected", ctx->token->length, ctx->src + ctx->token->offset);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -2148,12 +2222,14 @@ static Node *parse_while_statement(Context *ctx)
|
|||||||
|
|
||||||
if(done(ctx))
|
if(done(ctx))
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_SYNTAX, "Source ended right after a while loop condition, where a ':' was expected");
|
Error_Report(ctx->error, ErrorType_SYNTAX, "Source ended right after a while loop condition, where a ':' was expected");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(current(ctx) != ':')
|
if(current(ctx) != ':')
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_SYNTAX, "Got unexpected token \"%.*s\" after a while loop condition, where a ':' was expected", ctx->token->length, ctx->src + ctx->token->offset);
|
Error_Report(ctx->error, ErrorType_SYNTAX, "Got unexpected token \"%.*s\" after a while loop condition, where a ':' was expected", ctx->token->length, ctx->src + ctx->token->offset);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -2171,7 +2247,7 @@ static Node *parse_while_statement(Context *ctx)
|
|||||||
|
|
||||||
if(whl == NULL)
|
if(whl == NULL)
|
||||||
{
|
{
|
||||||
// ERROR: No memory.
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_INTERNAL, "No memory");
|
Error_Report(ctx->error, ErrorType_INTERNAL, "No memory");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -2193,12 +2269,14 @@ static Node *parse_dowhile_statement(Context *ctx)
|
|||||||
|
|
||||||
if(done(ctx))
|
if(done(ctx))
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_SYNTAX, "Source ended where a do-while statement was expected");
|
Error_Report(ctx->error, ErrorType_SYNTAX, "Source ended where a do-while statement was expected");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(current(ctx) != TKWDO)
|
if(current(ctx) != TKWDO)
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_SYNTAX, "Got unexpected token \"%.*s\" where a do-while statement was expected", ctx->token->length, ctx->src + ctx->token->offset);
|
Error_Report(ctx->error, ErrorType_SYNTAX, "Got unexpected token \"%.*s\" where a do-while statement was expected", ctx->token->length, ctx->src + ctx->token->offset);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -2215,12 +2293,14 @@ static Node *parse_dowhile_statement(Context *ctx)
|
|||||||
|
|
||||||
if(done(ctx))
|
if(done(ctx))
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_SYNTAX, "Source ended right after a do-while body, where the \"while\" keyword was expected");
|
Error_Report(ctx->error, ErrorType_SYNTAX, "Source ended right after a do-while body, where the \"while\" keyword was expected");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(current(ctx) != TKWWHILE)
|
if(current(ctx) != TKWWHILE)
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_SYNTAX, "Got unexpected token \"%.*s\" after a do-while body, where the \"while\" keyword was expected", ctx->token->length, ctx->src + ctx->token->offset);
|
Error_Report(ctx->error, ErrorType_SYNTAX, "Got unexpected token \"%.*s\" after a do-while body, where the \"while\" keyword was expected", ctx->token->length, ctx->src + ctx->token->offset);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -2234,12 +2314,14 @@ static Node *parse_dowhile_statement(Context *ctx)
|
|||||||
|
|
||||||
if(done(ctx))
|
if(done(ctx))
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_SYNTAX, "Source ended right after a do-while condition, where a ';' was expected");
|
Error_Report(ctx->error, ErrorType_SYNTAX, "Source ended right after a do-while condition, where a ';' was expected");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(current(ctx) != ';')
|
if(current(ctx) != ';')
|
||||||
{
|
{
|
||||||
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_SYNTAX, "Got unexpected token \"%.*s\" after a do-while conditnion, where a ';' was expected", ctx->token->length, ctx->src + ctx->token->offset);
|
Error_Report(ctx->error, ErrorType_SYNTAX, "Got unexpected token \"%.*s\" after a do-while conditnion, where a ';' was expected", ctx->token->length, ctx->src + ctx->token->offset);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -2252,7 +2334,7 @@ static Node *parse_dowhile_statement(Context *ctx)
|
|||||||
|
|
||||||
if(dowhl == NULL)
|
if(dowhl == NULL)
|
||||||
{
|
{
|
||||||
// ERROR: No memory.
|
*ctx->error_offset = ctx->token->offset;
|
||||||
Error_Report(ctx->error, ErrorType_INTERNAL, "No memory");
|
Error_Report(ctx->error, ErrorType_INTERNAL, "No memory");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,5 +34,5 @@
|
|||||||
#include "../utils/source.h"
|
#include "../utils/source.h"
|
||||||
#include "../utils/error.h"
|
#include "../utils/error.h"
|
||||||
#include "AST.h"
|
#include "AST.h"
|
||||||
AST *parse(Source *src, BPAlloc *alloc, Error *error);
|
AST *parse(Source *src, BPAlloc *alloc, Error *error, int *error_offset);
|
||||||
#endif
|
#endif
|
||||||
-412
@@ -1,412 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <assert.h>
|
|
||||||
#include "utils/error.h"
|
|
||||||
#include "utils/source.h"
|
|
||||||
#include "compiler/compile.h"
|
|
||||||
#include "assembler/assemble.h"
|
|
||||||
#include "builtins/basic.h"
|
|
||||||
#include "runtime/timing.h"
|
|
||||||
#include "noja.h"
|
|
||||||
|
|
||||||
static void serializeProfilingResults(Runtime *runtime, const char *file)
|
|
||||||
{
|
|
||||||
TimingTable *table = Runtime_GetTimingTable(runtime);
|
|
||||||
if (table == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
FILE *stream = fopen(file, "wb");
|
|
||||||
if (stream == NULL) {
|
|
||||||
fprintf(stderr, "Failed to serialize profiling results\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const FunctionExecutionSummary *summary;
|
|
||||||
size_t count;
|
|
||||||
|
|
||||||
summary = TimingTable_getSummary(table, &count);
|
|
||||||
assert(summary != NULL);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < count; i++) {
|
|
||||||
if (summary[i].calls > 0) {
|
|
||||||
fprintf(stream, "%20s - %s - %ld calls - %.2lfus\n",
|
|
||||||
summary[i].name,
|
|
||||||
Source_GetName(summary[i].src),
|
|
||||||
summary[i].calls,
|
|
||||||
summary[i].time * 1000000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(stream);
|
|
||||||
fprintf(stderr, "Wrote profiling result to %s\n", file);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#include <signal.h>
|
|
||||||
|
|
||||||
Runtime *runtime = NULL;
|
|
||||||
|
|
||||||
static void signalHandler(int signo)
|
|
||||||
{
|
|
||||||
(void) signo;
|
|
||||||
if (runtime != NULL)
|
|
||||||
Runtime_Interrupt(runtime);
|
|
||||||
}
|
|
||||||
|
|
||||||
static _Bool interpret(Executable *exe, bool time, size_t heap)
|
|
||||||
{
|
|
||||||
RuntimeConfig config = Runtime_GetDefaultConfigs();
|
|
||||||
config.time = time;
|
|
||||||
|
|
||||||
runtime = Runtime_New(heap, config);
|
|
||||||
if(runtime == NULL)
|
|
||||||
{
|
|
||||||
Error error;
|
|
||||||
Error_Init(&error);
|
|
||||||
Error_Report(&error, ErrorType_INTERNAL, "Couldn't initialize runtime");
|
|
||||||
Error_Print(&error, ErrorType_UNSPECIFIED);
|
|
||||||
Error_Free(&error);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
signal(SIGINT, signalHandler);
|
|
||||||
signal(SIGTERM, signalHandler);
|
|
||||||
|
|
||||||
// We use a [RuntimeError] instead of a simple [Error]
|
|
||||||
// because the [RuntimeError] makes a snapshot of the
|
|
||||||
// runtime state when an error is reported. Other than
|
|
||||||
// this fact they are interchangable. Any function that
|
|
||||||
// expects a pointer to [Error] can receive a [RuntimeError]
|
|
||||||
// upcasted to [Error].
|
|
||||||
RuntimeError error;
|
|
||||||
RuntimeError_Init(&error, runtime); // Here we specify the runtime to snapshot in case of failure.
|
|
||||||
|
|
||||||
{
|
|
||||||
Object *native_bins = Object_NewStaticMap(bins_basic, bins_basic_init, runtime, (Error*) &error);
|
|
||||||
if(native_bins == NULL)
|
|
||||||
{
|
|
||||||
assert(error.base.occurred == 1);
|
|
||||||
Error_Print((Error*) &error, ErrorType_RUNTIME);
|
|
||||||
RuntimeError_Free(&error);
|
|
||||||
Runtime_Free(runtime);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Just to execute the prelude
|
|
||||||
Runtime_SetBuiltins(runtime, native_bins);
|
|
||||||
|
|
||||||
extern char start_noja[];
|
|
||||||
Source *prelude = Source_FromString("<prelude>", start_noja, -1, (Error*) &error);
|
|
||||||
if (prelude == NULL) {
|
|
||||||
assert(error.base.occurred == 1);
|
|
||||||
Error_Print((Error*) &error, ErrorType_RUNTIME);
|
|
||||||
RuntimeError_Free(&error);
|
|
||||||
Runtime_Free(runtime);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Executable *prelude_exe = compile(prelude, (Error*) &error);
|
|
||||||
if(prelude_exe == NULL) {
|
|
||||||
Error_Print((Error*) &error, ErrorType_RUNTIME);
|
|
||||||
RuntimeError_Free(&error);
|
|
||||||
Runtime_Free(runtime);
|
|
||||||
Source_Free(prelude);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Object *rets[8];
|
|
||||||
int retc = run(runtime, (Error*) &error, prelude_exe, 0, NULL, NULL, 0, rets);
|
|
||||||
if(retc < 0) {
|
|
||||||
Error_Print((Error*) &error, ErrorType_RUNTIME);
|
|
||||||
RuntimeError_Free(&error);
|
|
||||||
Runtime_Free(runtime);
|
|
||||||
Source_Free(prelude);
|
|
||||||
Executable_Free(prelude_exe);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
Object *noja_bins = rets[0];
|
|
||||||
|
|
||||||
// Need to remake the native built-ins because
|
|
||||||
// running the script invalidated the previous
|
|
||||||
// pointer.
|
|
||||||
native_bins = Object_NewStaticMap(bins_basic, bins_basic_init, runtime, (Error*) &error);
|
|
||||||
if(native_bins == NULL)
|
|
||||||
{
|
|
||||||
assert(error.base.occurred == 1);
|
|
||||||
Error_Print((Error*) &error, ErrorType_RUNTIME);
|
|
||||||
RuntimeError_Free(&error);
|
|
||||||
Runtime_Free(runtime);
|
|
||||||
Source_Free(prelude);
|
|
||||||
Executable_Free(prelude_exe);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Object *all_bins = Object_NewClosure(native_bins, noja_bins, Runtime_GetHeap(runtime), (Error*) &error);
|
|
||||||
if (all_bins == NULL) {
|
|
||||||
Error_Print((Error*) &error, ErrorType_RUNTIME);
|
|
||||||
RuntimeError_Free(&error);
|
|
||||||
Runtime_Free(runtime);
|
|
||||||
Source_Free(prelude);
|
|
||||||
Executable_Free(prelude_exe);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Runtime_SetBuiltins(runtime, all_bins);
|
|
||||||
|
|
||||||
Source_Free(prelude);
|
|
||||||
Executable_Free(prelude_exe);
|
|
||||||
}
|
|
||||||
|
|
||||||
Object *rets[8];
|
|
||||||
int retc = run(runtime, (Error*) &error, exe, 0, NULL, NULL, 0, rets);
|
|
||||||
|
|
||||||
// NOTE: The pointer to the builtins object is invalidated
|
|
||||||
// now because it may be moved by the garbage collector.
|
|
||||||
|
|
||||||
if(retc < 0)
|
|
||||||
{
|
|
||||||
Error_Print((Error*) &error, ErrorType_RUNTIME);
|
|
||||||
|
|
||||||
if(error.snapshot == NULL)
|
|
||||||
fprintf(stderr, "No snapshot available.\n");
|
|
||||||
else
|
|
||||||
Snapshot_Print(error.snapshot, stderr);
|
|
||||||
|
|
||||||
RuntimeError_Free(&error);
|
|
||||||
}
|
|
||||||
|
|
||||||
serializeProfilingResults(runtime, "profiling-results.txt");
|
|
||||||
|
|
||||||
Runtime_Free(runtime);
|
|
||||||
return retc > -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Executable *compile_source_and_print_error_on_failure(Source *src)
|
|
||||||
{
|
|
||||||
Error error;
|
|
||||||
Error_Init(&error);
|
|
||||||
Executable *exe = compile(src, &error);
|
|
||||||
if(exe == NULL) {
|
|
||||||
Error_Print(&error, ErrorType_UNSPECIFIED);
|
|
||||||
Error_Free(&error);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
Error_Free(&error);
|
|
||||||
return exe;
|
|
||||||
}
|
|
||||||
|
|
||||||
static _Bool disassemble(Source *src)
|
|
||||||
{
|
|
||||||
Executable *exe = compile_source_and_print_error_on_failure(src);
|
|
||||||
if(exe == NULL) return 0;
|
|
||||||
Executable_Dump(exe, stdout);
|
|
||||||
Executable_Free(exe);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static _Bool interpret_file(const char *file, bool time, size_t heap)
|
|
||||||
{
|
|
||||||
Error error;
|
|
||||||
Error_Init(&error);
|
|
||||||
|
|
||||||
Source *src = Source_FromFile(file, &error);
|
|
||||||
if(src == NULL)
|
|
||||||
{
|
|
||||||
assert(error.occurred == 1);
|
|
||||||
Error_Print(&error, ErrorType_UNSPECIFIED);
|
|
||||||
Error_Free(&error);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Executable *exe = compile_source_and_print_error_on_failure(src);
|
|
||||||
if(exe == NULL) {
|
|
||||||
Source_Free(src);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
_Bool r = interpret(exe, time, heap);
|
|
||||||
|
|
||||||
Executable_Free(exe);
|
|
||||||
Source_Free(src);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
static _Bool interpret_code(const char *code, bool time, size_t heap)
|
|
||||||
{
|
|
||||||
Error error;
|
|
||||||
Error_Init(&error);
|
|
||||||
|
|
||||||
Source *src = Source_FromString(NULL, code, -1, &error);
|
|
||||||
|
|
||||||
if(src == NULL)
|
|
||||||
{
|
|
||||||
assert(error.occurred);
|
|
||||||
Error_Print(&error, ErrorType_UNSPECIFIED);
|
|
||||||
Error_Free(&error);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Executable *exe = compile_source_and_print_error_on_failure(src);
|
|
||||||
if(exe == NULL) {
|
|
||||||
Source_Free(src);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
_Bool r = interpret(exe, time, heap);
|
|
||||||
|
|
||||||
Executable_Free(exe);
|
|
||||||
Source_Free(src);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
static _Bool interpret_asm_file(const char *file, bool time, size_t heap)
|
|
||||||
{
|
|
||||||
Error error;
|
|
||||||
Error_Init(&error);
|
|
||||||
|
|
||||||
Source *src = Source_FromFile(file, &error);
|
|
||||||
|
|
||||||
if(src == NULL)
|
|
||||||
{
|
|
||||||
assert(error.occurred == 1);
|
|
||||||
Error_Print(&error, ErrorType_UNSPECIFIED);
|
|
||||||
Error_Free(&error);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Executable *exe = assemble(src, &error);
|
|
||||||
if(exe == NULL) {
|
|
||||||
Error_Print(&error, ErrorType_UNSPECIFIED);
|
|
||||||
Source_Free(src);
|
|
||||||
Error_Free(&error);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
_Bool r = interpret(exe, time, heap);
|
|
||||||
|
|
||||||
Executable_Free(exe);
|
|
||||||
Source_Free(src);
|
|
||||||
Error_Free(&error);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
static _Bool interpret_asm_code(const char *code, bool time, size_t heap)
|
|
||||||
{
|
|
||||||
Error error;
|
|
||||||
Error_Init(&error);
|
|
||||||
|
|
||||||
Source *src = Source_FromString(NULL, code, -1, &error);
|
|
||||||
|
|
||||||
if(src == NULL)
|
|
||||||
{
|
|
||||||
assert(error.occurred);
|
|
||||||
Error_Print(&error, ErrorType_UNSPECIFIED);
|
|
||||||
Error_Free(&error);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Executable *exe = assemble(src, &error);
|
|
||||||
if(exe == NULL) {
|
|
||||||
Error_Print(&error, ErrorType_UNSPECIFIED);
|
|
||||||
Source_Free(src);
|
|
||||||
Error_Free(&error);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
_Bool r = interpret(exe, time, heap);
|
|
||||||
|
|
||||||
Executable_Free(exe);
|
|
||||||
Source_Free(src);
|
|
||||||
Error_Free(&error);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
static _Bool disassemble_file(const char *file)
|
|
||||||
{
|
|
||||||
Error error;
|
|
||||||
Error_Init(&error);
|
|
||||||
|
|
||||||
Source *src = Source_FromFile(file, &error);
|
|
||||||
|
|
||||||
if(src == NULL)
|
|
||||||
{
|
|
||||||
assert(error.occurred == 1);
|
|
||||||
Error_Print(&error, ErrorType_UNSPECIFIED);
|
|
||||||
Error_Free(&error);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
_Bool r = disassemble(src);
|
|
||||||
|
|
||||||
Source_Free(src);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
static _Bool disassemble_code(const char *code)
|
|
||||||
{
|
|
||||||
Error error;
|
|
||||||
Error_Init(&error);
|
|
||||||
|
|
||||||
Source *src = Source_FromString(NULL, code, -1, &error);
|
|
||||||
|
|
||||||
if(src == NULL)
|
|
||||||
{
|
|
||||||
assert(error.occurred);
|
|
||||||
Error_Print(&error, ErrorType_UNSPECIFIED);
|
|
||||||
Error_Free(&error);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
_Bool r = disassemble(src);
|
|
||||||
|
|
||||||
Source_Free(src);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
_Bool NOJA_runString(const char *str, size_t heap)
|
|
||||||
{
|
|
||||||
return interpret_code(str, false, heap);
|
|
||||||
}
|
|
||||||
|
|
||||||
_Bool NOJA_runFile(const char *file, size_t heap)
|
|
||||||
{
|
|
||||||
return interpret_file(file, false, heap);
|
|
||||||
}
|
|
||||||
|
|
||||||
_Bool NOJA_dumpFileBytecode(const char *file)
|
|
||||||
{
|
|
||||||
return disassemble_file(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
_Bool NOJA_dumpStringBytecode(const char *str)
|
|
||||||
{
|
|
||||||
return disassemble_code(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
_Bool NOJA_runAssemblyFile(const char *file, size_t heap)
|
|
||||||
{
|
|
||||||
return interpret_asm_file(file, false, heap);
|
|
||||||
}
|
|
||||||
|
|
||||||
_Bool NOJA_runAssemblyString(const char *str, size_t heap)
|
|
||||||
{
|
|
||||||
return interpret_asm_code(str, false, heap);
|
|
||||||
}
|
|
||||||
|
|
||||||
_Bool NOJA_profileString(const char *str, size_t heap)
|
|
||||||
{
|
|
||||||
return interpret_code(str, true, heap);
|
|
||||||
}
|
|
||||||
|
|
||||||
_Bool NOJA_profileFile(const char *file, size_t heap)
|
|
||||||
{
|
|
||||||
return interpret_file(file, true, heap);
|
|
||||||
}
|
|
||||||
|
|
||||||
_Bool NOJA_profileAssemblyFile(const char *file, size_t heap)
|
|
||||||
{
|
|
||||||
return interpret_asm_file(file, true, heap);
|
|
||||||
}
|
|
||||||
|
|
||||||
_Bool NOJA_profileAssemblyString(const char *str, size_t heap)
|
|
||||||
{
|
|
||||||
return interpret_asm_code(str, true, heap);
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
#ifndef NOJA_H
|
|
||||||
#define NOJA_H
|
|
||||||
_Bool NOJA_runFile (const char *file, size_t heap);
|
|
||||||
_Bool NOJA_runString(const char *str, size_t heap);
|
|
||||||
_Bool NOJA_runAssemblyFile(const char *file, size_t heap);
|
|
||||||
_Bool NOJA_runAssemblyString(const char *str, size_t heap);
|
|
||||||
_Bool NOJA_dumpFileBytecode(const char *file);
|
|
||||||
_Bool NOJA_dumpStringBytecode(const char *str);
|
|
||||||
_Bool NOJA_profileFile(const char *file, size_t heap);
|
|
||||||
_Bool NOJA_profileString(const char *str, size_t heap);
|
|
||||||
_Bool NOJA_profileAssemblyFile(const char *file, size_t heap);
|
|
||||||
_Bool NOJA_profileAssemblyString(const char *str, size_t heap);
|
|
||||||
#endif /* NOJA_H */
|
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
#include "run.h"
|
||||||
|
#include "builtins_api.h"
|
||||||
|
#include "../builtins/basic.h"
|
||||||
|
|
||||||
|
bool Runtime_plugBuiltinsFromStaticMap(Runtime *runtime, StaticMapSlot *bin_table, void (*bin_table_constructor)(StaticMapSlot*), Error *error)
|
||||||
|
{
|
||||||
|
Object *object = Object_NewStaticMap(bin_table, bin_table_constructor, runtime, error);
|
||||||
|
if (object == NULL)
|
||||||
|
return false;
|
||||||
|
return Runtime_plugBuiltins(runtime, object, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Runtime_plugBuiltinsFromSource(Runtime *runtime, Source *source, Error *error)
|
||||||
|
{
|
||||||
|
Object *rets[8];
|
||||||
|
int retc = runSource(runtime, source, rets, error);
|
||||||
|
if(retc < 0)
|
||||||
|
return false;
|
||||||
|
if (retc == 0)
|
||||||
|
return true;
|
||||||
|
return Runtime_plugBuiltins(runtime, rets[0], error);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Runtime_plugBuiltinsFromFile(Runtime *runtime, const char *file, Error *error)
|
||||||
|
{
|
||||||
|
Source *source = Source_FromFile(file, error);
|
||||||
|
if (source == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bool result = Runtime_plugBuiltinsFromSource(runtime, source, error);
|
||||||
|
|
||||||
|
Source_Free(source);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Runtime_plugBuiltinsFromString(Runtime *runtime, const char *string, Error *error)
|
||||||
|
{
|
||||||
|
Source *source = Source_FromString("<prelude>", string, -1, error);
|
||||||
|
if (source == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bool result = Runtime_plugBuiltinsFromSource(runtime, source, error);
|
||||||
|
|
||||||
|
Source_Free(source);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Runtime_plugDefaultBuiltins(Runtime *runtime, Error *error)
|
||||||
|
{
|
||||||
|
extern char start_noja[];
|
||||||
|
return Runtime_plugBuiltinsFromStaticMap(runtime, bins_basic, bins_basic_init, error)
|
||||||
|
&& Runtime_plugBuiltinsFromString(runtime, start_noja, error)
|
||||||
|
&& Runtime_plugBuiltinsFromString(runtime, "XXX=999;", error);
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
#include "runtime.h"
|
||||||
|
bool Runtime_plugDefaultBuiltins(Runtime *runtime, Error *error);
|
||||||
|
bool Runtime_plugBuiltinsFromString(Runtime *runtime, const char *string, Error *error);
|
||||||
|
bool Runtime_plugBuiltinsFromFile(Runtime *runtime, const char *file, Error *error);
|
||||||
|
bool Runtime_plugBuiltinsFromStaticMap(Runtime *runtime, StaticMapSlot *bin_table, void (*bin_table_constructor)(StaticMapSlot*), Error *error);
|
||||||
|
bool Runtime_plugBuiltinsFromSource(Runtime *runtime, Source *source, Error *error);
|
||||||
@@ -1,220 +0,0 @@
|
|||||||
|
|
||||||
/* +--------------------------------------------------------------------------+
|
|
||||||
** | _ _ _ |
|
|
||||||
** | | \ | | (_) |
|
|
||||||
** | | \| | ___ _ __ _ |
|
|
||||||
** | | . ` |/ _ \| |/ _` | |
|
|
||||||
** | | |\ | (_) | | (_| | |
|
|
||||||
** | |_| \_|\___/| |\__,_| |
|
|
||||||
** | _/ | |
|
|
||||||
** | |__/ |
|
|
||||||
** +--------------------------------------------------------------------------+
|
|
||||||
** | Copyright (c) 2022 Francesco Cozzuto <francesco.cozzuto@gmail.com> |
|
|
||||||
** +--------------------------------------------------------------------------+
|
|
||||||
** | This file is part of The Noja Interpreter. |
|
|
||||||
** | |
|
|
||||||
** | The Noja Interpreter is free software: you can redistribute it and/or |
|
|
||||||
** | modify it under the terms of the GNU General Public License as published |
|
|
||||||
** | by the Free Software Foundation, either version 3 of the License, or (at |
|
|
||||||
** | your option) any later version. |
|
|
||||||
** | |
|
|
||||||
** | The Noja Interpreter is distributed in the hope that it will be useful, |
|
|
||||||
** | but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
|
||||||
** | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General |
|
|
||||||
** | Public License for more details. |
|
|
||||||
** | |
|
|
||||||
** | You should have received a copy of the GNU General Public License along |
|
|
||||||
** | with The Noja Interpreter. If not, see <http://www.gnu.org/licenses/>. |
|
|
||||||
** +--------------------------------------------------------------------------+
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <time.h>
|
|
||||||
#include <assert.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include "../utils/defs.h"
|
|
||||||
#include "../objects/objects.h"
|
|
||||||
#include "timing.h"
|
|
||||||
#include "runtime.h"
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
Object base;
|
|
||||||
const char *name;
|
|
||||||
Runtime *runtime;
|
|
||||||
Executable *exe;
|
|
||||||
int index, argc;
|
|
||||||
Object *closure;
|
|
||||||
TimingID timing_id;
|
|
||||||
} FunctionObject;
|
|
||||||
|
|
||||||
static _Bool free_(Object *self, Error *error)
|
|
||||||
{
|
|
||||||
(void) error;
|
|
||||||
|
|
||||||
FunctionObject *func = (FunctionObject*) self;
|
|
||||||
Executable_Free(func->exe);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void walk(Object *self, void (*callback)(Object **referer, void *userp), void *userp)
|
|
||||||
{
|
|
||||||
FunctionObject *func = (FunctionObject*) self;
|
|
||||||
callback(&func->closure, userp);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int call(Object *self, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Heap *heap, Error *error)
|
|
||||||
{
|
|
||||||
assert(self != NULL && heap != NULL && error != NULL);
|
|
||||||
|
|
||||||
FunctionObject *func = (FunctionObject*) self;
|
|
||||||
|
|
||||||
assert(func->exe != NULL);
|
|
||||||
assert(func->argc >= 0);
|
|
||||||
assert(func->index >= 0);
|
|
||||||
|
|
||||||
// Make sure the right amount of arguments is provided.
|
|
||||||
|
|
||||||
Object **argv2;
|
|
||||||
|
|
||||||
int expected_argc = func->argc;
|
|
||||||
|
|
||||||
if(expected_argc < (int) argc)
|
|
||||||
{
|
|
||||||
// Nothing to be done. By using
|
|
||||||
// the right argc the additional
|
|
||||||
// arguments are ignored implicitly.
|
|
||||||
argv2 = argv;
|
|
||||||
}
|
|
||||||
else if(expected_argc > (int) argc)
|
|
||||||
{
|
|
||||||
// Some arguments are missing.
|
|
||||||
argv2 = malloc(sizeof(Object*) * expected_argc);
|
|
||||||
|
|
||||||
if(argv2 == NULL)
|
|
||||||
{
|
|
||||||
Error_Report(error, ErrorType_INTERNAL, "No memory");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy the provided arguments.
|
|
||||||
for(int i = 0; i < (int) argc; i += 1)
|
|
||||||
argv2[i] = argv[i];
|
|
||||||
|
|
||||||
// Set the unspecified arguments to none.
|
|
||||||
for(int i = argc; i < expected_argc; i += 1)
|
|
||||||
{
|
|
||||||
argv2[i] = Object_NewNone(heap, error);
|
|
||||||
|
|
||||||
if(argv2[i] == NULL)
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
// The right amount of arguments was provided.
|
|
||||||
argv2 = argv;
|
|
||||||
|
|
||||||
clock_t begin;
|
|
||||||
TimingID timing_id;
|
|
||||||
TimingTable *timing_table = Runtime_GetTimingTable(func->runtime);
|
|
||||||
if (timing_table != NULL) {
|
|
||||||
begin = clock();
|
|
||||||
|
|
||||||
// Need to save the object's member
|
|
||||||
// before the run function since it
|
|
||||||
// may trigger a GC cycle invalidating
|
|
||||||
// the object pointer.
|
|
||||||
timing_id = func->timing_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
int retc = run(func->runtime, error, func->exe, func->index, func->closure, argv2, expected_argc, rets);
|
|
||||||
|
|
||||||
if (timing_table != NULL) {
|
|
||||||
double time = (double) (clock() - begin) / CLOCKS_PER_SEC;
|
|
||||||
TimingTable_sumCallTime(timing_table, timing_id, time);
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: Every object reference is invalidated from here.
|
|
||||||
|
|
||||||
if(argv2 != argv)
|
|
||||||
free(argv2);
|
|
||||||
|
|
||||||
return retc;
|
|
||||||
}
|
|
||||||
|
|
||||||
static TypeObject t_func = {
|
|
||||||
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
|
|
||||||
.name = "function",
|
|
||||||
.size = sizeof (FunctionObject),
|
|
||||||
.call = call,
|
|
||||||
.walk = walk,
|
|
||||||
.free = free_,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Symbol: Object_FromNojaFunction
|
|
||||||
*
|
|
||||||
* Creates an object from a noja executable structure.
|
|
||||||
*
|
|
||||||
* Args:
|
|
||||||
* - runtime: The reference to an instanciated Runtime.
|
|
||||||
*
|
|
||||||
* - exe: A noja executable.
|
|
||||||
*
|
|
||||||
* - index: The index of the first bytecode instruction
|
|
||||||
* of the noja function within the executable.
|
|
||||||
*
|
|
||||||
* - argc: The number of arguments the function expects.
|
|
||||||
* It must be positive (unlike [Object_FromNativeFunction],
|
|
||||||
* where -1 means variadic).
|
|
||||||
*
|
|
||||||
* - closure: An object containing variables that will be
|
|
||||||
* accessible from the noja function other than
|
|
||||||
* the ones that will be defined inside it.
|
|
||||||
*
|
|
||||||
* - heap: The heap that will be used to allocate the object.
|
|
||||||
* It can't be NULL.
|
|
||||||
*
|
|
||||||
* - error: Output parameter where error information is stored.
|
|
||||||
* It can't be NULL.
|
|
||||||
*
|
|
||||||
* Returns:
|
|
||||||
* The newly created object. If an error occurred, NULL is returned
|
|
||||||
* and information about the error is stored in the [error] argument.
|
|
||||||
*/
|
|
||||||
Object *Object_FromNojaFunction(Runtime *runtime, const char *name, Executable *exe, int index, int argc, Object *closure, Heap *heap, Error *error)
|
|
||||||
{
|
|
||||||
assert(runtime != NULL);
|
|
||||||
assert(exe != NULL);
|
|
||||||
assert(index >= 0);
|
|
||||||
assert(argc >= 0);
|
|
||||||
assert(heap != NULL);
|
|
||||||
assert(error != NULL);
|
|
||||||
|
|
||||||
FunctionObject *func = (FunctionObject*) Heap_Malloc(heap, &t_func, error);
|
|
||||||
|
|
||||||
if(func == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
Executable *exe_copy = Executable_Copy(exe);
|
|
||||||
|
|
||||||
if(exe_copy == NULL)
|
|
||||||
{
|
|
||||||
Error_Report(error, ErrorType_INTERNAL, "Failed to copy executable");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
func->runtime = runtime;
|
|
||||||
func->name = name; // Should this be copied?
|
|
||||||
func->exe = exe_copy;
|
|
||||||
func->index = index;
|
|
||||||
func->argc = argc;
|
|
||||||
func->closure = closure;
|
|
||||||
|
|
||||||
TimingTable *table = Runtime_GetTimingTable(runtime);
|
|
||||||
if (table != NULL) {
|
|
||||||
#warning "TODO: Calculate line number"
|
|
||||||
size_t line = 0;
|
|
||||||
Source *src = Executable_GetSource(exe);
|
|
||||||
func->timing_id = TimingTable_newEntry(table, src, line, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (Object*) func;
|
|
||||||
}
|
|
||||||
@@ -1,173 +0,0 @@
|
|||||||
|
|
||||||
/* +--------------------------------------------------------------------------+
|
|
||||||
** | _ _ _ |
|
|
||||||
** | | \ | | (_) |
|
|
||||||
** | | \| | ___ _ __ _ |
|
|
||||||
** | | . ` |/ _ \| |/ _` | |
|
|
||||||
** | | |\ | (_) | | (_| | |
|
|
||||||
** | |_| \_|\___/| |\__,_| |
|
|
||||||
** | _/ | |
|
|
||||||
** | |__/ |
|
|
||||||
** +--------------------------------------------------------------------------+
|
|
||||||
** | Copyright (c) 2022 Francesco Cozzuto <francesco.cozzuto@gmail.com> |
|
|
||||||
** +--------------------------------------------------------------------------+
|
|
||||||
** | This file is part of The Noja Interpreter. |
|
|
||||||
** | |
|
|
||||||
** | The Noja Interpreter is free software: you can redistribute it and/or |
|
|
||||||
** | modify it under the terms of the GNU General Public License as published |
|
|
||||||
** | by the Free Software Foundation, either version 3 of the License, or (at |
|
|
||||||
** | your option) any later version. |
|
|
||||||
** | |
|
|
||||||
** | The Noja Interpreter is distributed in the hope that it will be useful, |
|
|
||||||
** | but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
|
||||||
** | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General |
|
|
||||||
** | Public License for more details. |
|
|
||||||
** | |
|
|
||||||
** | You should have received a copy of the GNU General Public License along |
|
|
||||||
** | with The Noja Interpreter. If not, see <http://www.gnu.org/licenses/>. |
|
|
||||||
** +--------------------------------------------------------------------------+
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* WHAT IS THIS FILE?
|
|
||||||
* This file implements an object that makes it possible
|
|
||||||
* to call native functions from within noja code.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#include <assert.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include "../utils/defs.h"
|
|
||||||
#include "../objects/objects.h"
|
|
||||||
#include "runtime.h"
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
Object base;
|
|
||||||
Runtime *runtime;
|
|
||||||
int (*callback)(Runtime *runtime, Object **argv, unsigned int argc, Object *rets[MAX_RETS], Error *error);
|
|
||||||
int argc;
|
|
||||||
} NativeFunctionObject;
|
|
||||||
|
|
||||||
static int call(Object *self, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Heap *heap, Error *error)
|
|
||||||
{
|
|
||||||
assert(self != NULL);
|
|
||||||
assert(heap != NULL);
|
|
||||||
assert(error != NULL);
|
|
||||||
|
|
||||||
NativeFunctionObject *func = (NativeFunctionObject*) self;
|
|
||||||
|
|
||||||
// If the function isn't variadic, make sure
|
|
||||||
// the right amount of arguments is provided.
|
|
||||||
|
|
||||||
Object **argv2;
|
|
||||||
int argc2;
|
|
||||||
|
|
||||||
int expected_argc = func->argc;
|
|
||||||
|
|
||||||
if(expected_argc < 0 || expected_argc == (int) argc)
|
|
||||||
{
|
|
||||||
// The function is variadic or the right
|
|
||||||
// amount of arguments was provided.
|
|
||||||
argv2 = argv;
|
|
||||||
argc2 = argc;
|
|
||||||
}
|
|
||||||
else if(expected_argc < (int) argc)
|
|
||||||
{
|
|
||||||
// Nothing to be done. By using
|
|
||||||
// the right argc the additional
|
|
||||||
// arguments are ignored implicitly.
|
|
||||||
argv2 = argv;
|
|
||||||
argc2 = expected_argc;
|
|
||||||
}
|
|
||||||
else if(expected_argc > (int) argc)
|
|
||||||
{
|
|
||||||
// Some arguments are missing.
|
|
||||||
argv2 = malloc(sizeof(Object*) * expected_argc);
|
|
||||||
argc2 = expected_argc;
|
|
||||||
|
|
||||||
if(argv2 == NULL)
|
|
||||||
{
|
|
||||||
Error_Report(error, 1, "No memory");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy the provided arguments.
|
|
||||||
for(int i = 0; i < (int) argc; i += 1)
|
|
||||||
argv2[i] = argv[i];
|
|
||||||
|
|
||||||
// Set the unspecified arguments to none.
|
|
||||||
for(int i = argc; i < expected_argc; i += 1)
|
|
||||||
{
|
|
||||||
argv2[i] = Object_NewNone(heap, error);
|
|
||||||
|
|
||||||
if(argv2[i] == NULL)
|
|
||||||
{
|
|
||||||
free(argv2);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
UNREACHABLE;
|
|
||||||
argv2 = NULL;
|
|
||||||
argc2 = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(func->callback != NULL);
|
|
||||||
int retc = func->callback(func->runtime, argv2, argc2, rets, error);
|
|
||||||
|
|
||||||
// NOTE: Since the callback may have executed some bytecode, a GC
|
|
||||||
// cycle may have been triggered, therefore we must assume
|
|
||||||
// every object reference that was locally saved is invalidated
|
|
||||||
// from here (the returned object is good tho).
|
|
||||||
|
|
||||||
if(argv2 != argv)
|
|
||||||
free(argv2);
|
|
||||||
|
|
||||||
return retc;
|
|
||||||
}
|
|
||||||
|
|
||||||
static TypeObject t_nfunc = {
|
|
||||||
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
|
|
||||||
.name = "native function",
|
|
||||||
.size = sizeof (NativeFunctionObject),
|
|
||||||
.call = call,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Symbol: Object_FromNativeFunction
|
|
||||||
*
|
|
||||||
* Creates an object from a function pointer.
|
|
||||||
*
|
|
||||||
* Args:
|
|
||||||
* - runtime: The reference to an instanciated Runtime. This must be
|
|
||||||
* provided so that the callback can also access it.
|
|
||||||
*
|
|
||||||
* - callback: The native function to be executed when this object
|
|
||||||
* is called.
|
|
||||||
*
|
|
||||||
* - argc: The number of arguments the function expects. If -1 is
|
|
||||||
* provided, then the function is considered to be variadic.
|
|
||||||
*
|
|
||||||
* - heap: The heap that will be used to allocate the object.
|
|
||||||
* It can't be NULL.
|
|
||||||
*
|
|
||||||
* - error: Output parameter where error information is stored.
|
|
||||||
* It can't be NULL.
|
|
||||||
*
|
|
||||||
* Returns:
|
|
||||||
* The newly created object. If an error occurred, NULL is returned
|
|
||||||
* and information about the error is stored in the [error] argument.
|
|
||||||
*/
|
|
||||||
Object *Object_FromNativeFunction(Runtime *runtime, int (*callback)(Runtime*, Object**, unsigned int, Object*[static MAX_RETS], Error*), int argc, Heap *heap, Error *error)
|
|
||||||
{
|
|
||||||
assert(callback != NULL);
|
|
||||||
|
|
||||||
NativeFunctionObject *func = (NativeFunctionObject*) Heap_Malloc(heap, &t_nfunc, error);
|
|
||||||
|
|
||||||
if(func == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
func->runtime = runtime;
|
|
||||||
func->callback = callback;
|
|
||||||
func->argc = argc;
|
|
||||||
|
|
||||||
return (Object*) func;
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include "path.h"
|
||||||
|
#include "../utils/defs.h"
|
||||||
|
#include "../utils/path.h"
|
||||||
|
|
||||||
|
// Returns the length written in buff (not considering the zero byte)
|
||||||
|
size_t Runtime_GetCurrentScriptFolder(Runtime *runtime, char *buff, size_t buffsize)
|
||||||
|
{
|
||||||
|
const char *path = Runtime_GetCurrentScriptAbsolutePath(runtime);
|
||||||
|
if(path == NULL) {
|
||||||
|
if(getcwd(buff, buffsize) == NULL)
|
||||||
|
return 0;
|
||||||
|
size_t cwdlen = strlen(buff);
|
||||||
|
if (buff[cwdlen-1] == '/')
|
||||||
|
return cwdlen;
|
||||||
|
else {
|
||||||
|
if (cwdlen+1 >= buffsize)
|
||||||
|
return 0;
|
||||||
|
buff[cwdlen] = '/';
|
||||||
|
return cwdlen+1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This following block is a custom implementation
|
||||||
|
// of [dirname], which doesn't write into the input
|
||||||
|
// string and is way buggier. It will for sure give
|
||||||
|
// problems in the future!!
|
||||||
|
size_t dir_len;
|
||||||
|
{
|
||||||
|
// This is buggy code!!
|
||||||
|
size_t path_len = strlen(path);
|
||||||
|
ASSERT(path_len > 0); // Not empty
|
||||||
|
ASSERT(Path_IsAbsolute(path)); // Is absolute
|
||||||
|
ASSERT(path[path_len-1] != '/'); // Doesn't end with a slash.
|
||||||
|
|
||||||
|
size_t popped = 0;
|
||||||
|
while(path[path_len-1-popped] != '/')
|
||||||
|
popped += 1;
|
||||||
|
|
||||||
|
ASSERT(path_len > popped);
|
||||||
|
|
||||||
|
dir_len = path_len - popped;
|
||||||
|
|
||||||
|
ASSERT(dir_len < path_len);
|
||||||
|
ASSERT(path[dir_len-1] == '/');
|
||||||
|
}
|
||||||
|
|
||||||
|
if(dir_len >= buffsize)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
memcpy(buff, path, dir_len);
|
||||||
|
buff[dir_len] = '\0';
|
||||||
|
return dir_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *Runtime_GetCurrentScriptAbsolutePath(Runtime *runtime)
|
||||||
|
{
|
||||||
|
Executable *exe = Runtime_GetMostRecentExecutable(runtime);
|
||||||
|
if (exe == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
Source *src = Executable_GetSource(exe);
|
||||||
|
if(src == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
const char *path = Source_GetAbsolutePath(src);
|
||||||
|
if(path == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
ASSERT(path[0] != '\0');
|
||||||
|
return path;
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
#include <stddef.h>
|
||||||
|
#include "runtime.h"
|
||||||
|
const char *Runtime_GetCurrentScriptAbsolutePath(Runtime *runtime);
|
||||||
|
size_t Runtime_GetCurrentScriptFolder(Runtime *runtime, char *buff, size_t buffsize);
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,12 @@
|
|||||||
|
#include "runtime.h"
|
||||||
|
int runSource(Runtime *runtime, Source *source, Object *rets[static MAX_RETS], Error *error);
|
||||||
|
int runBytecodeSource(Runtime *runtime, Source *source, Object *rets[static MAX_RETS], Error *error);
|
||||||
|
bool runFile(Runtime *runtime, const char *file, Error *error);
|
||||||
|
bool runString(Runtime *runtime, const char *string, Error *error);
|
||||||
|
bool runBytecodeFile(Runtime *runtime, const char *file, Error *error);
|
||||||
|
bool runBytecodeString(Runtime *runtime, const char *string, Error *error);
|
||||||
|
int runFileEx(Runtime *runtime, const char *file, Object *rets[static MAX_RETS], Error *error);
|
||||||
|
int runStringEx(Runtime *runtime, const char *name, const char *string, Object *rets[static MAX_RETS], Error *error);
|
||||||
|
int runBytecodeFileEx(Runtime *runtime, const char *file, Object *rets[static MAX_RETS], Error *error);
|
||||||
|
int runBytecodeStringEx(Runtime *runtime, const char *name, const char *string, Object *rets[static MAX_RETS], Error *error);
|
||||||
|
int runFileRelativeToScript(Runtime *runtime, const char *file, Object *rets[static MAX_RETS], Error *error);
|
||||||
+387
-1279
File diff suppressed because it is too large
Load Diff
@@ -40,6 +40,7 @@
|
|||||||
|
|
||||||
typedef struct xRuntime Runtime;
|
typedef struct xRuntime Runtime;
|
||||||
typedef struct xSnapshot Snapshot;
|
typedef struct xSnapshot Snapshot;
|
||||||
|
typedef struct StaticMapSlot StaticMapSlot;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
bool (*func)(Runtime*, void*);
|
bool (*func)(Runtime*, void*);
|
||||||
@@ -48,31 +49,49 @@ typedef struct {
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
bool time;
|
bool time;
|
||||||
|
size_t heap;
|
||||||
size_t stack;
|
size_t stack;
|
||||||
RuntimeCallback callback;
|
RuntimeCallback callback;
|
||||||
} RuntimeConfig;
|
} RuntimeConfig;
|
||||||
|
|
||||||
Runtime* Runtime_New(int heap_size, RuntimeConfig config);
|
Runtime* Runtime_New(RuntimeConfig config);
|
||||||
Runtime* Runtime_New2(Heap *heap, bool free_it, RuntimeConfig config);
|
|
||||||
void Runtime_Free(Runtime *runtime);
|
void Runtime_Free(Runtime *runtime);
|
||||||
_Bool Runtime_Pop(Runtime *runtime, Error *error, unsigned int n);
|
|
||||||
_Bool Runtime_Push(Runtime *runtime, Error *error, Object *obj);
|
Object *Runtime_Top(Runtime *runtime, int n);
|
||||||
|
bool Runtime_Pop (Runtime *runtime, Error *error, Object **p, unsigned int n);
|
||||||
|
bool Runtime_Push(Runtime *runtime, Error *error, Object *obj);
|
||||||
|
bool Runtime_PushFrame(Runtime *runtime, Error *error, Object *closure, Executable *exe, int index);
|
||||||
|
bool Runtime_PushNativeFrame(Runtime *runtime, Error *error);
|
||||||
|
bool Runtime_PushFailedFrame(Runtime *runtime, Error *error, Source *source, int offset);
|
||||||
|
bool Runtime_PopFrame(Runtime *runtime);
|
||||||
|
void Runtime_SetInstructionIndex(Runtime *runtime, int index);
|
||||||
|
bool Runtime_SetVariable(Runtime *runtime, Error *error, const char *name, Object *value);
|
||||||
|
bool Runtime_GetVariable(Runtime *runtime, Error *error, const char *name, Object **value);
|
||||||
|
Object *Runtime_GetLocals(Runtime *runtime);
|
||||||
|
Object *Runtime_GetClosure(Runtime *runtime);
|
||||||
|
size_t Runtime_GetFrameStackUsage(Runtime *runtime);
|
||||||
|
bool Runtime_WasInterrupted(Runtime *runtime);
|
||||||
|
RuntimeCallback Runtime_GetCallback(Runtime *runtime);
|
||||||
|
bool Runtime_CollectGarbage(Runtime *runtime, Error *error);
|
||||||
|
void Runtime_PrintStackTrace(Runtime *runtime, FILE *stream);
|
||||||
void Runtime_Interrupt(Runtime *runtime);
|
void Runtime_Interrupt(Runtime *runtime);
|
||||||
Heap* Runtime_GetHeap(Runtime *runtime);
|
Heap* Runtime_GetHeap(Runtime *runtime);
|
||||||
Stack* Runtime_GetStack(Runtime *runtime);
|
Stack* Runtime_GetStack(Runtime *runtime);
|
||||||
Object* Runtime_GetBuiltins(Runtime *runtime);
|
|
||||||
void Runtime_SetBuiltins(Runtime *runtime, Object *builtins);
|
|
||||||
int Runtime_GetCurrentIndex(Runtime *runtime);
|
int Runtime_GetCurrentIndex(Runtime *runtime);
|
||||||
Executable *Runtime_GetCurrentExecutable(Runtime *runtime);
|
Executable *Runtime_GetCurrentExecutable(Runtime *runtime);
|
||||||
|
Executable *Runtime_GetMostRecentExecutable(Runtime *runtime);
|
||||||
size_t Runtime_GetCurrentScriptFolder(Runtime *runtime, char *buff, size_t buffsize);
|
size_t Runtime_GetCurrentScriptFolder(Runtime *runtime, char *buff, size_t buffsize);
|
||||||
const char *Runtime_GetCurrentScriptAbsolutePath(Runtime *runtime);
|
const char *Runtime_GetCurrentScriptAbsolutePath(Runtime *runtime);
|
||||||
TimingTable *Runtime_GetTimingTable(Runtime *runtime);
|
TimingTable *Runtime_GetTimingTable(Runtime *runtime);
|
||||||
RuntimeConfig Runtime_GetDefaultConfigs();
|
RuntimeConfig Runtime_GetDefaultConfigs();
|
||||||
|
|
||||||
|
bool Runtime_plugBuiltins(Runtime *runtime, Object *object, Error *error);
|
||||||
|
int Runtime_runSource(Runtime *runtime, Source *source, Object *rets[static MAX_RETS], Error *error);
|
||||||
|
int Runtime_runBytecodeSource(Runtime *runtime, Source *source, Object *rets[static MAX_RETS], Error *error);
|
||||||
|
|
||||||
Snapshot *Snapshot_New(Runtime *runtime);
|
Snapshot *Snapshot_New(Runtime *runtime);
|
||||||
void Snapshot_Free(Snapshot *snapshot);
|
void Snapshot_Free(Snapshot *snapshot);
|
||||||
void Snapshot_Print(Snapshot *snapshot, FILE *fp);
|
void Snapshot_Print(Snapshot *snapshot, FILE *fp);
|
||||||
int run(Runtime *runtime, Error *error, Executable *exe, int index, Object *closure, Object **argv, int argc, Object *rets[static MAX_RETS]);
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SM_END,
|
SM_END,
|
||||||
@@ -87,8 +106,6 @@ typedef enum {
|
|||||||
SM_OBJECT,
|
SM_OBJECT,
|
||||||
} StaticMapSlotKind;
|
} StaticMapSlotKind;
|
||||||
|
|
||||||
typedef struct StaticMapSlot StaticMapSlot;
|
|
||||||
|
|
||||||
struct StaticMapSlot {
|
struct StaticMapSlot {
|
||||||
const char *name;
|
const char *name;
|
||||||
StaticMapSlotKind kind;
|
StaticMapSlotKind kind;
|
||||||
@@ -117,5 +134,6 @@ typedef struct {
|
|||||||
|
|
||||||
void RuntimeError_Init(RuntimeError *error, Runtime *runtime);
|
void RuntimeError_Init(RuntimeError *error, Runtime *runtime);
|
||||||
void RuntimeError_Free(RuntimeError *error);
|
void RuntimeError_Free(RuntimeError *error);
|
||||||
|
void RuntimeError_Print(RuntimeError *error, ErrorType type_if_unspecified, FILE *stream);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
|
|
||||||
/* +--------------------------------------------------------------------------+
|
|
||||||
** | _ _ _ |
|
|
||||||
** | | \ | | (_) |
|
|
||||||
** | | \| | ___ _ __ _ |
|
|
||||||
** | | . ` |/ _ \| |/ _` | |
|
|
||||||
** | | |\ | (_) | | (_| | |
|
|
||||||
** | |_| \_|\___/| |\__,_| |
|
|
||||||
** | _/ | |
|
|
||||||
** | |__/ |
|
|
||||||
** +--------------------------------------------------------------------------+
|
|
||||||
** | Copyright (c) 2022 Francesco Cozzuto <francesco.cozzuto@gmail.com> |
|
|
||||||
** +--------------------------------------------------------------------------+
|
|
||||||
** | This file is part of The Noja Interpreter. |
|
|
||||||
** | |
|
|
||||||
** | The Noja Interpreter is free software: you can redistribute it and/or |
|
|
||||||
** | modify it under the terms of the GNU General Public License as published |
|
|
||||||
** | by the Free Software Foundation, either version 3 of the License, or (at |
|
|
||||||
** | your option) any later version. |
|
|
||||||
** | |
|
|
||||||
** | The Noja Interpreter is distributed in the hope that it will be useful, |
|
|
||||||
** | but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
|
||||||
** | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General |
|
|
||||||
** | Public License for more details. |
|
|
||||||
** | |
|
|
||||||
** | You should have received a copy of the GNU General Public License along |
|
|
||||||
** | with The Noja Interpreter. If not, see <http://www.gnu.org/licenses/>. |
|
|
||||||
** +--------------------------------------------------------------------------+
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include "runtime.h"
|
|
||||||
|
|
||||||
static void on_report(Error *error)
|
|
||||||
{
|
|
||||||
assert(error != NULL);
|
|
||||||
|
|
||||||
RuntimeError *error2 = (RuntimeError*) error;
|
|
||||||
|
|
||||||
if(error2->runtime != NULL)
|
|
||||||
error2->snapshot = Snapshot_New(error2->runtime);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RuntimeError_Init(RuntimeError *error, Runtime *runtime)
|
|
||||||
{
|
|
||||||
assert(error != NULL);
|
|
||||||
|
|
||||||
Error_Init2(&error->base, on_report);
|
|
||||||
|
|
||||||
error->runtime = runtime;
|
|
||||||
error->snapshot = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RuntimeError_Free(RuntimeError *error)
|
|
||||||
{
|
|
||||||
if(error->snapshot)
|
|
||||||
Snapshot_Free(error->snapshot);
|
|
||||||
Error_Free(&error->base);
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
#include "serialize_profiling.h"
|
||||||
|
|
||||||
|
void Runtime_SerializeProfilingResultsToStream(Runtime *runtime, FILE *stream)
|
||||||
|
{
|
||||||
|
TimingTable *table = Runtime_GetTimingTable(runtime);
|
||||||
|
if (table == NULL)
|
||||||
|
return; // Runtime wasn't profiling
|
||||||
|
|
||||||
|
size_t count;
|
||||||
|
const FunctionExecutionSummary *summary = TimingTable_getSummary(table, &count);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < count; i++) {
|
||||||
|
if (summary[i].calls > 0) {
|
||||||
|
fprintf(stream, "%20s - %s - %ld calls - %.2lfus\n",
|
||||||
|
summary[i].name,
|
||||||
|
Source_GetName(summary[i].src),
|
||||||
|
summary[i].calls,
|
||||||
|
summary[i].time * 1000000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Runtime_SerializeProfilingResultsToFile(Runtime *runtime, const char *file)
|
||||||
|
{
|
||||||
|
FILE *stream = fopen(file, "wb");
|
||||||
|
if (stream == NULL)
|
||||||
|
return false;
|
||||||
|
Runtime_SerializeProfilingResultsToStream(runtime, stream);
|
||||||
|
fclose(stream);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
#include "runtime.h"
|
||||||
|
|
||||||
|
void Runtime_SerializeProfilingResultsToStream(Runtime *runtime, FILE *stream);
|
||||||
|
bool Runtime_SerializeProfilingResultsToFile(Runtime *runtime, const char *file);
|
||||||
@@ -137,7 +137,7 @@ void Error_Panic_(const char *file, int line,
|
|||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Error_Print(Error *error, ErrorType type_if_unspecified)
|
void Error_Print(Error *error, ErrorType type_if_unspecified, FILE *stream)
|
||||||
{
|
{
|
||||||
ErrorType type = error->type;
|
ErrorType type = error->type;
|
||||||
if (type == ErrorType_UNSPECIFIED)
|
if (type == ErrorType_UNSPECIFIED)
|
||||||
@@ -152,19 +152,19 @@ void Error_Print(Error *error, ErrorType type_if_unspecified)
|
|||||||
default: name = "Error"; break;
|
default: name = "Error"; break;
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(stderr, "%s: %s.", name, error->message);
|
fprintf(stream, "%s: %s.", name, error->message);
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if(error->file != NULL)
|
if(error->file != NULL)
|
||||||
{
|
{
|
||||||
if(error->line > 0 && error->func != NULL)
|
if(error->line > 0 && error->func != NULL)
|
||||||
fprintf(stderr, " (Reported in %s:%d in %s)", error->file, error->line, error->func);
|
fprintf(stream, " (Reported in %s:%d in %s)", error->file, error->line, error->func);
|
||||||
else if(error->line > 0 && error->func == NULL)
|
else if(error->line > 0 && error->func == NULL)
|
||||||
fprintf(stderr, " (Reported in %s:%d)", error->file, error->line);
|
fprintf(stream, " (Reported in %s:%d)", error->file, error->line);
|
||||||
else if(error->line < 1 && error->func != NULL)
|
else if(error->line < 1 && error->func != NULL)
|
||||||
fprintf(stderr, " (Reported in %s in %s)", error->file, error->func);
|
fprintf(stream, " (Reported in %s in %s)", error->file, error->func);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
fprintf(stderr, "\n");
|
fprintf(stream, "\n");
|
||||||
}
|
}
|
||||||
@@ -30,6 +30,8 @@
|
|||||||
|
|
||||||
#ifndef ERROR_H
|
#ifndef ERROR_H
|
||||||
#define ERROR_H
|
#define ERROR_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@@ -63,5 +65,5 @@ void _Error_Report (Error *err, ErrorType typ, const char *file, const char *f
|
|||||||
void _Error_Report2(Error *err, ErrorType typ, const char *file, const char *func, int line, const char *fmt, va_list va);
|
void _Error_Report2(Error *err, ErrorType typ, const char *file, const char *func, int line, const char *fmt, va_list va);
|
||||||
void Error_Panic_(const char *file, int line, const char *fmt, ...);
|
void Error_Panic_(const char *file, int line, const char *fmt, ...);
|
||||||
#define Error_Panic(fmt, ...) Error_Panic_(__FILE__, __LINE__, fmt, ## __VA_ARGS__)
|
#define Error_Panic(fmt, ...) Error_Panic_(__FILE__, __LINE__, fmt, ## __VA_ARGS__)
|
||||||
void Error_Print(Error *error, ErrorType type_if_unspecified);
|
void Error_Print(Error *error, ErrorType type_if_unspecified, FILE *stream);
|
||||||
#endif
|
#endif
|
||||||
+9
-8
@@ -284,14 +284,14 @@ static bool parseTestCaseSource(Source *source, TestCase *testcase)
|
|||||||
|
|
||||||
testcase->source = Source_FromString("<input>", str + source_offset, source_length, &error);
|
testcase->source = Source_FromString("<input>", str + source_offset, source_length, &error);
|
||||||
if(testcase->source == NULL) {
|
if(testcase->source == NULL) {
|
||||||
Error_Print(&error, ErrorType_UNSPECIFIED);
|
Error_Print(&error, ErrorType_UNSPECIFIED, stderr);
|
||||||
Error_Free(&error);
|
Error_Free(&error);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
testcase->bytecode = Source_FromString("<output>", str + bytecode_offset, bytecode_length, &error);
|
testcase->bytecode = Source_FromString("<output>", str + bytecode_offset, bytecode_length, &error);
|
||||||
if(testcase->bytecode == NULL) {
|
if(testcase->bytecode == NULL) {
|
||||||
Error_Print(&error, ErrorType_UNSPECIFIED);
|
Error_Print(&error, ErrorType_UNSPECIFIED, stderr);
|
||||||
Source_Free(testcase->source);
|
Source_Free(testcase->source);
|
||||||
Error_Free(&error);
|
Error_Free(&error);
|
||||||
return false;
|
return false;
|
||||||
@@ -303,11 +303,12 @@ static bool parseTestCaseSource(Source *source, TestCase *testcase)
|
|||||||
|
|
||||||
static Executable *compile_source_and_print_error_on_failure(Source *src)
|
static Executable *compile_source_and_print_error_on_failure(Source *src)
|
||||||
{
|
{
|
||||||
|
int error_offset;
|
||||||
Error error;
|
Error error;
|
||||||
Error_Init(&error);
|
Error_Init(&error);
|
||||||
Executable *exe = compile(src, &error);
|
Executable *exe = compile(src, &error, &error_offset);
|
||||||
if(exe == NULL) {
|
if(exe == NULL) {
|
||||||
Error_Print(&error, ErrorType_UNSPECIFIED);
|
Error_Print(&error, ErrorType_UNSPECIFIED, stderr);
|
||||||
Error_Free(&error);
|
Error_Free(&error);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -330,7 +331,7 @@ static TestResult runTest(const char *file)
|
|||||||
|
|
||||||
source = Source_FromFile(file, &error);
|
source = Source_FromFile(file, &error);
|
||||||
if(source == NULL) {
|
if(source == NULL) {
|
||||||
Error_Print(&error, ErrorType_UNSPECIFIED);
|
Error_Print(&error, ErrorType_UNSPECIFIED, stderr);
|
||||||
Error_Free(&error);
|
Error_Free(&error);
|
||||||
return TestResult_ABORT;
|
return TestResult_ABORT;
|
||||||
}
|
}
|
||||||
@@ -358,10 +359,10 @@ static TestResult runTest(const char *file)
|
|||||||
{
|
{
|
||||||
Error error;
|
Error error;
|
||||||
Error_Init(&error);
|
Error_Init(&error);
|
||||||
|
int error_offset;
|
||||||
exe2 = assemble(testcase.bytecode, &error);
|
exe2 = assemble(testcase.bytecode, &error, &error_offset);
|
||||||
if(exe2 == NULL) {
|
if(exe2 == NULL) {
|
||||||
Error_Print(&error, ErrorType_UNSPECIFIED);
|
Error_Print(&error, ErrorType_UNSPECIFIED, stderr);
|
||||||
Error_Free(&error);
|
Error_Free(&error);
|
||||||
Executable_Free(exe1);
|
Executable_Free(exe1);
|
||||||
Source_Free(testcase.source);
|
Source_Free(testcase.source);
|
||||||
|
|||||||
Reference in New Issue
Block a user