major restructuring

This commit is contained in:
Francesco Cozzuto
2023-01-20 20:52:20 +01:00
parent 0980cc193d
commit 411388755f
30 changed files with 2175 additions and 2362 deletions
+72 -28
View File
@@ -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;
} }
+18 -1
View File
@@ -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;
} }
+1 -1
View File
@@ -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 */
+2 -51
View File
@@ -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)
+9 -8
View File
@@ -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;
} }
+1 -1
View File
@@ -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 */
+5 -4
View File
@@ -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;
} }
+2 -2
View File
@@ -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;
+4 -3
View File
@@ -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);
+1 -1
View File
@@ -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
View File
@@ -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;
} }
+1 -1
View File
@@ -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
View File
@@ -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);
}
-13
View File
@@ -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 */
+54
View File
@@ -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);
}
+6
View File
@@ -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);
-220
View File
@@ -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;
}
-173
View File
@@ -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;
}
+73
View File
@@ -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;
}
+4
View File
@@ -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
+12
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+27 -9
View File
@@ -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
-59
View File
@@ -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);
}
+31
View File
@@ -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;
}
+4
View File
@@ -0,0 +1,4 @@
#include "runtime.h"
void Runtime_SerializeProfilingResultsToStream(Runtime *runtime, FILE *stream);
bool Runtime_SerializeProfilingResultsToFile(Runtime *runtime, const char *file);
+6 -6
View 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");
} }
+3 -1
View File
@@ -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
View File
@@ -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);