added evalf and reorganized main
This commit is contained in:
@@ -72,6 +72,7 @@ gcc tests/src/test-parse.c -o build/test-parse $FLAGS -Lbuild/ -lnoja-compil
|
|||||||
gcc tests/src/test-objects.c -o build/test-objects $FLAGS -Lbuild/ -lnoja-objects
|
gcc tests/src/test-objects.c -o build/test-objects $FLAGS -Lbuild/ -lnoja-objects
|
||||||
|
|
||||||
gcc src/main.c \
|
gcc src/main.c \
|
||||||
|
src/noja.c \
|
||||||
src/debug.c \
|
src/debug.c \
|
||||||
src/eval.c \
|
src/eval.c \
|
||||||
src/buildvalue.c \
|
src/buildvalue.c \
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
fun Apple(Apple, Apple, Apple)
|
||||||
|
while 13:
|
||||||
|
return 26.7;
|
||||||
|
|
||||||
|
return "Hello, world!";
|
||||||
|
}
|
||||||
|
do
|
||||||
|
while 46.9:
|
||||||
|
do
|
||||||
|
fun Apple()
|
||||||
|
{}
|
||||||
|
while {67.97: "Hello, world!", 50.36: "Hello, world!", 54.91: 9};
|
||||||
|
|
||||||
|
while 26;
|
||||||
|
[{90: "Hello, world!"}, {14: 56.96, 16.24: 23, []: [20.31, 41.3, 33.49]}, 44.62];
|
||||||
|
fun Apple(Apple, Apple, Apple) while {[]: 88.42}: do return 57.21; while [];
|
||||||
|
do if []: if {"Hello, world!": "Hello, world!", 0.65: 13.22, "Hello, world!": 61.3}: fun Apple(Apple, Apple, Apple) {} while 3.15;
|
||||||
|
return 41;
|
||||||
|
["Hello, world!", 34.8];
|
||||||
|
return {34.81: {}};
|
||||||
|
do return "Hello, world!"; while [[[12.36, "Hello, world!"], 98, [48.22, 29.87, "Hello, world!"]], [{10.78: 32.44}], "Hello, world!"];
|
||||||
|
do {return 99.31;fun Apple(Apple, Apple) if "Hello, world!": {}} while "Hello, world!";
|
||||||
|
return 38.57;
|
||||||
|
return {67: {"Hello, world!": 93, 5: 84.14, 9: [83.73, 65.86, 47.73]}, "Hello, world!": 40};
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
'hello' + ' world!';
|
||||||
+18
@@ -5,6 +5,24 @@
|
|||||||
#include "o_builtins.h"
|
#include "o_builtins.h"
|
||||||
#include "eval.h"
|
#include "eval.h"
|
||||||
|
|
||||||
|
Object *evalf(Object *closure, Heap *heap, Error *error, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
char buffer[1024];
|
||||||
|
|
||||||
|
va_list va;
|
||||||
|
va_start(va, fmt);
|
||||||
|
int n = vsnprintf(buffer, sizeof(buffer), fmt, va);
|
||||||
|
va_end(va);
|
||||||
|
|
||||||
|
if(n >= (int) sizeof(buffer))
|
||||||
|
{
|
||||||
|
Error_Report(error, 1, "Static buffer is too small");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return eval(buffer, n, closure, heap, error);
|
||||||
|
}
|
||||||
|
|
||||||
Object *eval(const char *str, int len, Object *closure, Heap *heap, Error *error)
|
Object *eval(const char *str, int len, Object *closure, Heap *heap, Error *error)
|
||||||
{
|
{
|
||||||
if(len < 0)
|
if(len < 0)
|
||||||
|
|||||||
+2
-1
@@ -1,3 +1,4 @@
|
|||||||
#include "utils/error.h"
|
#include "utils/error.h"
|
||||||
#include "objects/objects.h"
|
#include "objects/objects.h"
|
||||||
Object *eval(const char *str, int len, Object *closure, Heap *heap, Error *error);
|
Object *eval(const char *str, int len, Object *closure, Heap *heap, Error *error);
|
||||||
|
Object *evalf(Object *closure, Heap *heap, Error *error, const char *fmt, ...);
|
||||||
|
|||||||
+7
-18
@@ -1,20 +1,5 @@
|
|||||||
#include <assert.h>
|
#include "noja.h"
|
||||||
#include <string.h>
|
/*
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include "debug.h"
|
|
||||||
#include "o_builtins.h"
|
|
||||||
#include "compiler/parse.h"
|
|
||||||
#include "compiler/serialize.h"
|
|
||||||
#include "compiler/compile.h"
|
|
||||||
#include "runtime/runtime.h"
|
|
||||||
#include "runtime/runtime_error.h"
|
|
||||||
|
|
||||||
/* $ noja -f <file>
|
|
||||||
* $ noja -c <text>
|
|
||||||
* $ noja -f <file> -o <file>
|
|
||||||
*/
|
|
||||||
|
|
||||||
typedef enum { RUN, HELP, PARSE, VERSION, DISASSEMBLY } Action;
|
typedef enum { RUN, HELP, PARSE, VERSION, DISASSEMBLY } Action;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -102,9 +87,12 @@ static int parse_args(Options *opts, int argc, char **argv, Error *error)
|
|||||||
|
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
|
return noja(argc, argv) ? 0 : -1;
|
||||||
|
/*
|
||||||
Error error;
|
Error error;
|
||||||
Error_Init(&error);
|
Error_Init(&error);
|
||||||
|
|
||||||
@@ -217,7 +205,7 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
RuntimeError error;
|
RuntimeError error;
|
||||||
RuntimeError_Init(&error, runtime);
|
RuntimeError_Init(&error, runtime);
|
||||||
|
|
||||||
Object *builtins = Object_NewBuiltinsMap(runtime, Runtime_GetHeap(runtime), (Error*) &error);
|
Object *builtins = Object_NewBuiltinsMap(runtime, Runtime_GetHeap(runtime), (Error*) &error);
|
||||||
|
|
||||||
if(builtins == NULL)
|
if(builtins == NULL)
|
||||||
@@ -407,5 +395,6 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+260
@@ -0,0 +1,260 @@
|
|||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "debug.h"
|
||||||
|
#include "o_builtins.h"
|
||||||
|
#include "compiler/parse.h"
|
||||||
|
#include "compiler/serialize.h"
|
||||||
|
#include "compiler/compile.h"
|
||||||
|
#include "runtime/runtime.h"
|
||||||
|
#include "runtime/runtime_error.h"
|
||||||
|
|
||||||
|
static const char usage[] =
|
||||||
|
"Usage:\n"
|
||||||
|
" $ noja [ <file> | -f <file> | -c <code> | -h ]\n"
|
||||||
|
"\n"
|
||||||
|
"For example:\n"
|
||||||
|
" $ noja file.noja\n"
|
||||||
|
" $ noja -f file.noja\n"
|
||||||
|
" $ noja -c \"print('some noja code')\"\n"
|
||||||
|
"\n"
|
||||||
|
"NOTE: When a line starts with $ it means that it's a terminal command.\n";
|
||||||
|
|
||||||
|
static _Bool interpret_file(const char *file);
|
||||||
|
static _Bool interpret_code(const char *code);
|
||||||
|
|
||||||
|
_Bool noja(int argc, char **argv)
|
||||||
|
{
|
||||||
|
assert(argc > 0);
|
||||||
|
|
||||||
|
if(argc == 1)
|
||||||
|
{
|
||||||
|
// $ noja
|
||||||
|
fprintf(stderr, "Error: Incorrect usage.\n\n");
|
||||||
|
fprintf(stderr, usage);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(argc > 1);
|
||||||
|
|
||||||
|
if(!strcmp(argv[1], "-f"))
|
||||||
|
{
|
||||||
|
if(argc < 3)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error: Missing file after -f option.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if(argc > 3)
|
||||||
|
fprintf(stderr, "Warning: Ignoring %d options\n", argc - 3);
|
||||||
|
|
||||||
|
const char *file = argv[2];
|
||||||
|
return interpret_file(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!strcmp(argv[1], "-c"))
|
||||||
|
{
|
||||||
|
if(argc < 3)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error: Missing code after -c option.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(argc > 3)
|
||||||
|
fprintf(stderr, "Warning: Ignoring %d options\n", argc - 3);
|
||||||
|
|
||||||
|
const char *code = argv[2];
|
||||||
|
return interpret_code(code);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!strcmp(argv[1], "-h"))
|
||||||
|
{
|
||||||
|
if(argc > 2)
|
||||||
|
fprintf(stderr, "Warning: Ignoring %d options\n", argc - 2);
|
||||||
|
|
||||||
|
fprintf(stdout, usage);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(argc > 2)
|
||||||
|
fprintf(stderr, "Warning: Ignoring %d options\n", argc - 2);
|
||||||
|
|
||||||
|
const char *file = argv[1];
|
||||||
|
return interpret_file(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_error(const char *type, Error *error)
|
||||||
|
{
|
||||||
|
if(type == NULL)
|
||||||
|
fprintf(stderr, "Error");
|
||||||
|
else if(error->internal)
|
||||||
|
fprintf(stderr, "Internal Error");
|
||||||
|
else
|
||||||
|
fprintf(stderr, "%s Error", type);
|
||||||
|
|
||||||
|
fprintf(stderr, ": %s. ", error->message);
|
||||||
|
|
||||||
|
if(error->file != NULL)
|
||||||
|
{
|
||||||
|
if(error->line > 0 && error->func != NULL)
|
||||||
|
fprintf(stderr, "(Reported in %s:%d in %s)", error->file, error->line, error->func);
|
||||||
|
else if(error->line > 0 && error->func == NULL)
|
||||||
|
fprintf(stderr, "(Reported in %s:%d)", error->file, error->line);
|
||||||
|
else if(error->line < 1 && error->func != NULL)
|
||||||
|
fprintf(stderr, "(Reported in %s in %s)", error->file, error->func);
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static _Bool interpret(Source *src)
|
||||||
|
{
|
||||||
|
// Compile the code. This section transforms
|
||||||
|
// a [Source] into an [Executable].
|
||||||
|
Executable *exe;
|
||||||
|
{
|
||||||
|
// Create a bump-pointer allocator to hold the AST.
|
||||||
|
BPAlloc *alloc = BPAlloc_Init(-1);
|
||||||
|
|
||||||
|
if(alloc == NULL)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Internal Error: Couldn't allocate bump-pointer allocator to hold the AST.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Error error;
|
||||||
|
Error_Init(&error);
|
||||||
|
|
||||||
|
// NOTE: The AST is stored in the BPAlloc. It's
|
||||||
|
// lifetime is the same as the pool.
|
||||||
|
AST *ast = parse(src, alloc, &error);
|
||||||
|
|
||||||
|
if(ast == NULL)
|
||||||
|
{
|
||||||
|
assert(error.occurred);
|
||||||
|
print_error("Parsing", &error);
|
||||||
|
Error_Free(&error);
|
||||||
|
BPAlloc_Free(alloc);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
exe = compile(ast, alloc, &error);
|
||||||
|
|
||||||
|
// We're done with the AST, independently from
|
||||||
|
// the compilation result.
|
||||||
|
BPAlloc_Free(alloc);
|
||||||
|
|
||||||
|
if(exe == NULL)
|
||||||
|
{
|
||||||
|
assert(error.occurred);
|
||||||
|
print_error("Compilation", &error);
|
||||||
|
Error_Free(&error);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now execute it.
|
||||||
|
{
|
||||||
|
Runtime *runt = Runtime_New(-1, -1, NULL, NULL);
|
||||||
|
|
||||||
|
if(runt == NULL)
|
||||||
|
{
|
||||||
|
Error error;
|
||||||
|
Error_Init(&error);
|
||||||
|
Error_Report(&error, 1, "Couldn't initialize runtime");
|
||||||
|
print_error(NULL, &error);
|
||||||
|
Error_Free(&error);
|
||||||
|
Executable_Free(exe);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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, runt); // Here we specify the runtime to snapshot in case of failure.
|
||||||
|
|
||||||
|
Object *bins = Object_NewBuiltinsMap(runt, Runtime_GetHeap(runt), (Error*) &error);
|
||||||
|
|
||||||
|
if(bins == NULL)
|
||||||
|
{
|
||||||
|
assert(error.base.occurred == 1);
|
||||||
|
print_error(NULL, (Error*) &error);
|
||||||
|
RuntimeError_Free(&error);
|
||||||
|
Executable_Free(exe);
|
||||||
|
Runtime_Free(runt);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Runtime_SetBuiltins(runt, bins);
|
||||||
|
|
||||||
|
Object *o = run(runt, (Error*) &error, exe, 0, NULL, NULL, 0);
|
||||||
|
|
||||||
|
// NOTE: The pointer to the builtins object is invalidated
|
||||||
|
// now because it may be moved by the garbage collector.
|
||||||
|
|
||||||
|
if(o == NULL)
|
||||||
|
{
|
||||||
|
print_error("Runtime", (Error*) &error);
|
||||||
|
|
||||||
|
if(error.snapshot == NULL)
|
||||||
|
fprintf(stderr, "No snapshot available.\n");
|
||||||
|
else
|
||||||
|
Snapshot_Print(error.snapshot, stderr);
|
||||||
|
|
||||||
|
RuntimeError_Free(&error);
|
||||||
|
}
|
||||||
|
|
||||||
|
Runtime_Free(runt);
|
||||||
|
Executable_Free(exe);
|
||||||
|
|
||||||
|
return o != NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static _Bool interpret_file(const char *file)
|
||||||
|
{
|
||||||
|
Error error;
|
||||||
|
Error_Init(&error);
|
||||||
|
|
||||||
|
Source *src = Source_FromFile(file, &error);
|
||||||
|
|
||||||
|
if(src == NULL)
|
||||||
|
{
|
||||||
|
assert(error.occurred == 1);
|
||||||
|
print_error(NULL, &error);
|
||||||
|
Error_Free(&error);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
_Bool r = interpret(src);
|
||||||
|
|
||||||
|
Source_Free(src);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static _Bool interpret_code(const char *code)
|
||||||
|
{
|
||||||
|
Error error;
|
||||||
|
Error_Init(&error);
|
||||||
|
|
||||||
|
Source *src = Source_FromString(NULL, code, -1, &error);
|
||||||
|
|
||||||
|
if(src == NULL)
|
||||||
|
{
|
||||||
|
assert(error.occurred);
|
||||||
|
print_error(NULL, &error);
|
||||||
|
Error_Free(&error);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
_Bool r = interpret(src);
|
||||||
|
|
||||||
|
Source_Free(src);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
|
||||||
|
_Bool noja(int argc, char **argv);
|
||||||
Reference in New Issue
Block a user