added buildValue
This commit is contained in:
@@ -73,6 +73,8 @@ gcc tests/src/test-objects.c -o build/test-objects $FLAGS -Lbuild/ -lnoja-object
|
|||||||
|
|
||||||
gcc src/main.c \
|
gcc src/main.c \
|
||||||
src/debug.c \
|
src/debug.c \
|
||||||
|
src/eval.c \
|
||||||
|
src/buildvalue.c \
|
||||||
src/heap_reconst.c \
|
src/heap_reconst.c \
|
||||||
temp/o_builtins.o \
|
temp/o_builtins.o \
|
||||||
temp/o_net_builtins.o \
|
temp/o_net_builtins.o \
|
||||||
|
|||||||
@@ -0,0 +1,294 @@
|
|||||||
|
#include <ctype.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "buildvalue.h"
|
||||||
|
#include "eval.h"
|
||||||
|
|
||||||
|
static Object *walkValue(const char *fmt, int *i, va_list va, Heap *heap, Error *error);
|
||||||
|
|
||||||
|
static Object *walkMapValue(const char *fmt, int *i, va_list va, Heap *heap, Error *error)
|
||||||
|
{
|
||||||
|
assert(fmt[*i] == '{');
|
||||||
|
|
||||||
|
*i += 1; // Skip the '{'.
|
||||||
|
|
||||||
|
while(isspace(fmt[*i]))
|
||||||
|
*i += 1;
|
||||||
|
|
||||||
|
Object *map = Object_NewMap(-1, heap, error);
|
||||||
|
|
||||||
|
if(map == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if(fmt[*i] != '}')
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
|
Object *key = walkValue(fmt, i, va, heap, error);
|
||||||
|
|
||||||
|
if(key == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
while(isspace(fmt[*i]))
|
||||||
|
*i += 1;
|
||||||
|
|
||||||
|
if(fmt[*i] == '\0')
|
||||||
|
{
|
||||||
|
Error_Report(error, 0, "Format ended inside a map expression");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(fmt[*i] != ':')
|
||||||
|
{
|
||||||
|
Error_Report(error, 0, "Got unexpected '%c' in format where ':' was expected", fmt[*i]);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
*i += 1; // Skip the ':'.
|
||||||
|
|
||||||
|
Object *val = walkValue(fmt, i, va, heap, error);
|
||||||
|
|
||||||
|
if(val == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if(!Object_Insert(map, key, val, heap, error))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
while(isspace(fmt[*i]))
|
||||||
|
*i += 1;
|
||||||
|
|
||||||
|
if(fmt[*i] == '\0')
|
||||||
|
{
|
||||||
|
Error_Report(error, 0, "Format ended inside a map expression");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(fmt[*i] == '}')
|
||||||
|
break;
|
||||||
|
|
||||||
|
if(fmt[*i] != ',')
|
||||||
|
{
|
||||||
|
Error_Report(error, 0, "Got unexpected '%c' in format where either ',' or '}' were expected", fmt[*i]);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
*i += 1; // Skip the ','.
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(fmt[*i] == '}');
|
||||||
|
|
||||||
|
*i += 1; // Skip the '}'.
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
static Object *walkListValue(const char *fmt, int *i, va_list va, Heap *heap, Error *error)
|
||||||
|
{
|
||||||
|
assert(fmt[*i] == '[');
|
||||||
|
|
||||||
|
*i += 1; // Skip the '['.
|
||||||
|
|
||||||
|
while(isspace(fmt[*i]))
|
||||||
|
*i += 1;
|
||||||
|
|
||||||
|
Object *maybe[8], **ptrs = maybe;
|
||||||
|
int ptrs_cap = sizeof(maybe) / sizeof(maybe[0]),
|
||||||
|
ptrs_num = 0;
|
||||||
|
|
||||||
|
if(fmt[*i] != ']')
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
|
Object *item = walkValue(fmt, i, va, heap, error);
|
||||||
|
|
||||||
|
if(item == NULL)
|
||||||
|
{
|
||||||
|
if(ptrs != maybe) free(ptrs);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ptrs_cap == ptrs_num)
|
||||||
|
{
|
||||||
|
int new_capacity = ptrs_cap * 2;
|
||||||
|
|
||||||
|
Object **temp;
|
||||||
|
|
||||||
|
if(ptrs == maybe)
|
||||||
|
{
|
||||||
|
temp = malloc(sizeof(Object*) * new_capacity);
|
||||||
|
|
||||||
|
if(temp != NULL)
|
||||||
|
memcpy(temp, ptrs, ptrs_num * sizeof(Object*));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
temp = realloc(ptrs, sizeof(Object*) * new_capacity);
|
||||||
|
|
||||||
|
if(temp == NULL)
|
||||||
|
{
|
||||||
|
Error_Report(error, 1, "Insufficient memory");
|
||||||
|
if(ptrs != maybe) free(ptrs);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptrs = temp;
|
||||||
|
ptrs_cap = new_capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptrs[ptrs_num++] = item;
|
||||||
|
|
||||||
|
while(isspace(fmt[*i]))
|
||||||
|
*i += 1;
|
||||||
|
|
||||||
|
if(fmt[*i] == '\0')
|
||||||
|
{
|
||||||
|
Error_Report(error, 0, "Format ended inside a list expression");
|
||||||
|
if(ptrs != maybe) free(ptrs);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(fmt[*i] == ']')
|
||||||
|
break;
|
||||||
|
|
||||||
|
if(fmt[*i] != ',')
|
||||||
|
{
|
||||||
|
Error_Report(error, 0, "Got unexpected '%c' in format where either ',' or ']' were expected", fmt[*i]);
|
||||||
|
if(ptrs != maybe) free(ptrs);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
*i += 1; // Skip the ','.
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(fmt[*i] == ']');
|
||||||
|
|
||||||
|
*i += 1; // Skip the ']'.
|
||||||
|
|
||||||
|
Object *list = Object_NewList2(ptrs_num, ptrs, heap, error);
|
||||||
|
|
||||||
|
if(ptrs != maybe)
|
||||||
|
free(ptrs);
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Object *walkValue(const char *fmt, int *i, va_list va, Heap *heap, Error *error)
|
||||||
|
{
|
||||||
|
int i_;
|
||||||
|
if(i == NULL)
|
||||||
|
i = &i_;
|
||||||
|
|
||||||
|
while(isspace(fmt[*i]))
|
||||||
|
*i += 1;
|
||||||
|
|
||||||
|
if(fmt[*i] == '\0')
|
||||||
|
{
|
||||||
|
Error_Report(error, 0, "Empty format");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(fmt[*i] == '{')
|
||||||
|
return walkMapValue(fmt, i, va, heap, error);
|
||||||
|
|
||||||
|
if(fmt[*i] == '[')
|
||||||
|
return walkListValue(fmt, i, va, heap, error);
|
||||||
|
|
||||||
|
if(fmt[*i] != '$')
|
||||||
|
{
|
||||||
|
Error_Report(error, 0, "Unexpected character '%c' in format", fmt[*i]);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(fmt[*i] == '$');
|
||||||
|
|
||||||
|
*i += 1;
|
||||||
|
|
||||||
|
Object *o;
|
||||||
|
|
||||||
|
switch(fmt[*i])
|
||||||
|
{
|
||||||
|
case '\0':
|
||||||
|
Error_Report(error, 0, "Format ended after '$'");
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
case '{':
|
||||||
|
{
|
||||||
|
// Noja expression until the closing '}'.
|
||||||
|
|
||||||
|
*i += 1; // Skip the '{'.
|
||||||
|
|
||||||
|
int start = *i;
|
||||||
|
|
||||||
|
while(fmt[*i] != '\0' && fmt[*i] != '}') // TODO: Escape '}'.
|
||||||
|
*i += 1;
|
||||||
|
|
||||||
|
if(fmt[*i] == '\0')
|
||||||
|
{
|
||||||
|
// ERROR: Format ended inside of ${..}.
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int end = fmt[*i];
|
||||||
|
|
||||||
|
// NOTE: The last '}' is skipped after the switch.
|
||||||
|
|
||||||
|
const char *src = fmt + start;
|
||||||
|
int len = end - start;
|
||||||
|
|
||||||
|
o = eval(src, len, NULL, heap, error);
|
||||||
|
|
||||||
|
if(o == NULL)
|
||||||
|
return NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'i':
|
||||||
|
o = Object_FromInt(va_arg(va, long long int), heap, error);
|
||||||
|
if(o == NULL) return NULL;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'f':
|
||||||
|
o = Object_FromFloat(va_arg(va, double), heap, error);
|
||||||
|
if(o == NULL) return NULL;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'b':
|
||||||
|
// NOTE: Actually we want a _Bool, not an int.
|
||||||
|
// But gcc says:
|
||||||
|
// > warning: ‘_Bool’ is promoted to ‘int’ when passed through ‘...’
|
||||||
|
// > [...]
|
||||||
|
// > (so you should pass ‘int’ not ‘_Bool’ to ‘va_arg’)
|
||||||
|
//
|
||||||
|
o = Object_FromBool(va_arg(va, int), heap, error);
|
||||||
|
if(o == NULL) return NULL;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 's':
|
||||||
|
o = Object_FromString(va_arg(va, char*), -1, heap, error);
|
||||||
|
if(o == NULL) return NULL;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'o':
|
||||||
|
o = va_arg(va, Object*);
|
||||||
|
assert(o != NULL);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Error_Report(error, 0, "Invalid format specifier '%c'", fmt[*i]);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
*i += 1;
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object *buildValue2(Heap *heap, Error *error, const char *fmt, va_list va)
|
||||||
|
{
|
||||||
|
return walkValue(fmt, NULL, va, heap, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
Object *buildValue(Heap *heap, Error *error, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list va;
|
||||||
|
va_start(va, fmt);
|
||||||
|
Object *o = buildValue2(heap, error, fmt, va);
|
||||||
|
va_end(va);
|
||||||
|
return o;
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
#include <stdarg.h>
|
||||||
|
#include "utils/error.h"
|
||||||
|
#include "objects/objects.h"
|
||||||
|
|
||||||
|
Object *buildValue2(Heap *heap, Error *error, const char *fmt, va_list va);
|
||||||
|
Object *buildValue(Heap *heap, Error *error, const char *fmt, ...);
|
||||||
+75
@@ -0,0 +1,75 @@
|
|||||||
|
#include "compiler/parse.h"
|
||||||
|
#include "compiler/compile.h"
|
||||||
|
#include "runtime/runtime.h"
|
||||||
|
#include "o_builtins.h"
|
||||||
|
#include "eval.h"
|
||||||
|
|
||||||
|
Object *eval(const char *str, int len, Object *closure, Heap *heap, Error *error)
|
||||||
|
{
|
||||||
|
Source *s = Source_FromString(NULL, str, len, error);
|
||||||
|
|
||||||
|
if(s == NULL)
|
||||||
|
return NULL; // Propagate.
|
||||||
|
|
||||||
|
BPAlloc *alloc = BPAlloc_Init(-1);
|
||||||
|
|
||||||
|
if(alloc == NULL)
|
||||||
|
{
|
||||||
|
Error_Report(error, 1, "Insufficient memory");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
AST *ast = parse(s, alloc, error);
|
||||||
|
|
||||||
|
if(ast == NULL)
|
||||||
|
{
|
||||||
|
BPAlloc_Free(alloc);
|
||||||
|
Source_Free(s);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Executable *exe = compile(ast, alloc, error);
|
||||||
|
|
||||||
|
if(exe == NULL)
|
||||||
|
{
|
||||||
|
BPAlloc_Free(alloc);
|
||||||
|
Source_Free(s);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
BPAlloc_Free(alloc);
|
||||||
|
Source_Free(s);
|
||||||
|
|
||||||
|
Runtime *runt = Runtime_New2(-1, heap, 0, NULL, NULL);
|
||||||
|
|
||||||
|
if(runt == NULL)
|
||||||
|
{
|
||||||
|
Error_Report(error, 1, "Insufficient memory");
|
||||||
|
Executable_Free(exe);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object *bins = Object_NewBuiltinsMap(runt, heap, error);
|
||||||
|
|
||||||
|
if(bins == NULL)
|
||||||
|
{
|
||||||
|
Runtime_Free(runt);
|
||||||
|
Executable_Free(exe);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Runtime_SetBuiltins(runt, bins);
|
||||||
|
|
||||||
|
Object *o = run(runt, error, exe, 0, closure, NULL, 0);
|
||||||
|
|
||||||
|
if(o == NULL)
|
||||||
|
{
|
||||||
|
Runtime_Free(runt);
|
||||||
|
Executable_Free(exe);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Runtime_Free(runt);
|
||||||
|
Executable_Free(exe);
|
||||||
|
return o;
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
#include "utils/error.h"
|
||||||
|
#include "objects/objects.h"
|
||||||
|
Object *eval(const char *str, int len, Object *closure, Heap *heap, Error *error);
|
||||||
+1
-2
@@ -3,6 +3,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
#include "o_builtins.h"
|
||||||
#include "compiler/parse.h"
|
#include "compiler/parse.h"
|
||||||
#include "compiler/serialize.h"
|
#include "compiler/serialize.h"
|
||||||
#include "compiler/compile.h"
|
#include "compiler/compile.h"
|
||||||
@@ -14,8 +15,6 @@
|
|||||||
* $ noja -f <file> -o <file>
|
* $ noja -f <file> -o <file>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Object *Object_NewBuiltinsMap(Runtime *runtime, Heap *heap, Error *err);
|
|
||||||
|
|
||||||
typedef enum { RUN, HELP, PARSE, VERSION, DISASSEMBLY } Action;
|
typedef enum { RUN, HELP, PARSE, VERSION, DISASSEMBLY } Action;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|||||||
+1
-2
@@ -4,8 +4,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "runtime/runtime.h"
|
#include "runtime/runtime.h"
|
||||||
#include "utils/defs.h"
|
#include "utils/defs.h"
|
||||||
|
#include "o_builtins.h"
|
||||||
Object *Object_NewNetworkBuiltinsMap(Runtime *runtime, Heap *heap, Error *err);
|
|
||||||
|
|
||||||
static Object *select_(Object *self, Object *key, Heap *heap, Error *err);
|
static Object *select_(Object *self, Object *key, Heap *heap, Error *err);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
#include "runtime/runtime.h"
|
||||||
|
Object *Object_NewBuiltinsMap(Runtime *runtime, Heap *heap, Error *err);
|
||||||
|
Object *Object_NewNetworkBuiltinsMap(Runtime *runtime, Heap *heap, Error *err);
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
#include "../utils/defs.h"
|
#include "../utils/defs.h"
|
||||||
#include "objects.h"
|
#include "objects.h"
|
||||||
|
|
||||||
@@ -57,6 +58,21 @@ Object *Object_NewList(int capacity, Heap *heap, Error *error)
|
|||||||
return (Object*) obj;
|
return (Object*) obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Object *Object_NewList2(int num, Object **items, Heap *heap, Error *error)
|
||||||
|
{
|
||||||
|
assert(num > -1);
|
||||||
|
|
||||||
|
ListObject *list = (ListObject*) Object_NewList(num, heap, error);
|
||||||
|
|
||||||
|
if(list == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
memcpy(list->vals, items, num * sizeof(Object*));
|
||||||
|
list->count = num;
|
||||||
|
|
||||||
|
return (Object*) list;
|
||||||
|
}
|
||||||
|
|
||||||
static void walk(Object *self, void (*callback)(Object **referer, void *userp), void *userp)
|
static void walk(Object *self, void (*callback)(Object **referer, void *userp), void *userp)
|
||||||
{
|
{
|
||||||
ListObject *list = (ListObject*) self;
|
ListObject *list = (ListObject*) self;
|
||||||
|
|||||||
@@ -105,6 +105,7 @@ void Object_WalkExtensions(Object *parent, void (*callback)(void **referer,
|
|||||||
|
|
||||||
Object* Object_NewMap(int num, Heap *heap, Error *error);
|
Object* Object_NewMap(int num, Heap *heap, Error *error);
|
||||||
Object* Object_NewList(int capacity, Heap *heap, Error *error);
|
Object* Object_NewList(int capacity, Heap *heap, Error *error);
|
||||||
|
Object* Object_NewList2(int num, Object **items, Heap *heap, Error *error);
|
||||||
Object* Object_NewNone(Heap *heap, Error *error);
|
Object* Object_NewNone(Heap *heap, Error *error);
|
||||||
Object* Object_NewBuffer(int size, Heap *heap, Error *error);
|
Object* Object_NewBuffer(int size, Heap *heap, Error *error);
|
||||||
Object* Object_NewClosure(Object *parent, Object *new_map, Heap *heap, Error *error);
|
Object* Object_NewClosure(Object *parent, Object *new_map, Heap *heap, Error *error);
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
typedef struct xRuntime Runtime;
|
typedef struct xRuntime Runtime;
|
||||||
typedef void CallStackScanner;
|
typedef void CallStackScanner;
|
||||||
Runtime* Runtime_New(int stack_size, int heap_size, void *callback_userp, _Bool (*callback_addr)(Runtime*, void*));
|
Runtime* Runtime_New(int stack_size, int heap_size, void *callback_userp, _Bool (*callback_addr)(Runtime*, void*));
|
||||||
|
Runtime* Runtime_New2(int stack_size, Heap *heap, _Bool free_heap, void *callback_userp, _Bool (*callback_addr)(Runtime*, void*));
|
||||||
void Runtime_Free(Runtime *runtime);
|
void Runtime_Free(Runtime *runtime);
|
||||||
_Bool Runtime_Pop(Runtime *runtime, Error *error, unsigned int n);
|
_Bool Runtime_Pop(Runtime *runtime, Error *error, unsigned int n);
|
||||||
_Bool Runtime_Push(Runtime *runtime, Error *error, Object *obj);
|
_Bool Runtime_Push(Runtime *runtime, Error *error, Object *obj);
|
||||||
|
|||||||
Reference in New Issue
Block a user