added buildValue

This commit is contained in:
cozis
2022-01-21 20:26:36 +01:00
parent dc5586e94c
commit 7f29b7c01a
11 changed files with 403 additions and 4 deletions
+2
View File
@@ -73,6 +73,8 @@ gcc tests/src/test-objects.c -o build/test-objects $FLAGS -Lbuild/ -lnoja-object
gcc src/main.c \
src/debug.c \
src/eval.c \
src/buildvalue.c \
src/heap_reconst.c \
temp/o_builtins.o \
temp/o_net_builtins.o \
+294
View File
@@ -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;
}
+6
View File
@@ -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
View File
@@ -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;
}
+3
View File
@@ -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
View File
@@ -3,6 +3,7 @@
#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"
@@ -14,8 +15,6 @@
* $ noja -f <file> -o <file>
*/
Object *Object_NewBuiltinsMap(Runtime *runtime, Heap *heap, Error *err);
typedef enum { RUN, HELP, PARSE, VERSION, DISASSEMBLY } Action;
typedef struct {
+1 -2
View File
@@ -4,8 +4,7 @@
#include <stdlib.h>
#include "runtime/runtime.h"
#include "utils/defs.h"
Object *Object_NewNetworkBuiltinsMap(Runtime *runtime, Heap *heap, Error *err);
#include "o_builtins.h"
static Object *select_(Object *self, Object *key, Heap *heap, Error *err);
+3
View File
@@ -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);
+16
View File
@@ -1,4 +1,5 @@
#include <assert.h>
#include <string.h>
#include "../utils/defs.h"
#include "objects.h"
@@ -57,6 +58,21 @@ Object *Object_NewList(int capacity, Heap *heap, Error *error)
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)
{
ListObject *list = (ListObject*) self;
+1
View File
@@ -105,6 +105,7 @@ void Object_WalkExtensions(Object *parent, void (*callback)(void **referer,
Object* Object_NewMap(int num, 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_NewBuffer(int size, Heap *heap, Error *error);
Object* Object_NewClosure(Object *parent, Object *new_map, Heap *heap, Error *error);
+1
View File
@@ -9,6 +9,7 @@
typedef struct xRuntime Runtime;
typedef void CallStackScanner;
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);
_Bool Runtime_Pop(Runtime *runtime, Error *error, unsigned int n);
_Bool Runtime_Push(Runtime *runtime, Error *error, Object *obj);