Working on the public API
This commit is contained in:
@@ -1,2 +1,5 @@
|
|||||||
all:
|
all: WL.c
|
||||||
gcc src/basic.c src/file.c src/parse.c src/assemble.c src/eval.c src/main.c -o wl -Wall -Wextra -O0 -g3
|
gcc WL.c main.c -o wl -Wall -Wextra -O0 -g3
|
||||||
|
|
||||||
|
WL.c: $(wildcard src/*.c src/*.h)
|
||||||
|
py amalg.py
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
#ifndef WL_AMALGAMATION
|
||||||
|
#define WL_AMALGAMATION
|
||||||
|
|
||||||
|
// This file was generated automatically. Do not modify directly!
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// src/public.h
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#line 1 "src/public.h"
|
||||||
|
#ifndef WL_PUBLIC_INCLUDED
|
||||||
|
#define WL_PUBLIC_INCLUDED
|
||||||
|
|
||||||
|
#ifndef WL_AMALGAMATION
|
||||||
|
#include "includes.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct WL_State WL_State;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char *ptr;
|
||||||
|
int len;
|
||||||
|
} WL_String;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char *ptr;
|
||||||
|
int len;
|
||||||
|
} WL_Program;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
WL_DONE,
|
||||||
|
WL_ERROR,
|
||||||
|
WL_VAR,
|
||||||
|
WL_CALL,
|
||||||
|
WL_OUTPUT,
|
||||||
|
} WL_ResultType;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
WL_ResultType type;
|
||||||
|
WL_String str;
|
||||||
|
} WL_Result;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char *ptr;
|
||||||
|
int len;
|
||||||
|
int cur;
|
||||||
|
} WL_Arena;
|
||||||
|
|
||||||
|
int WL_compile (char *src, int len, WL_Arena arena, WL_Program *program, char *err, int errmax);
|
||||||
|
WL_State *WL_State_init (WL_Arena *a, WL_Program p, char *err, int errmax);
|
||||||
|
void WL_State_free (WL_State *state);
|
||||||
|
WL_Result WL_eval (WL_State *state);
|
||||||
|
int WL_streq (WL_String a, char *b, int blen);
|
||||||
|
int WL_popint (WL_State *state, long long *x);
|
||||||
|
int WL_popfloat (WL_State *state, float *x);
|
||||||
|
int WL_popstr (WL_State *state, char **str, int *len);
|
||||||
|
int WL_popany (WL_State *state);
|
||||||
|
void WL_select (WL_State *state);
|
||||||
|
void WL_pushint (WL_State *state, long long x);
|
||||||
|
void WL_pushfloat (WL_State *state, float x);
|
||||||
|
void WL_pushstr (WL_State *state, char *str, int len);
|
||||||
|
void WL_pusharray (WL_State *state, int cap);
|
||||||
|
void WL_pushmap (WL_State *state, int cap);
|
||||||
|
void WL_insert (WL_State *state);
|
||||||
|
|
||||||
|
#endif // WL_PUBLIC_INCLUDED
|
||||||
|
#endif // WL_AMALGAMATION
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
|
||||||
|
class Amalgamator:
|
||||||
|
def __init__(self):
|
||||||
|
self.out = ""
|
||||||
|
|
||||||
|
def append_text(self, text):
|
||||||
|
self.out += text
|
||||||
|
|
||||||
|
def append_file(self, file):
|
||||||
|
|
||||||
|
self.out += "\n"
|
||||||
|
self.out += "////////////////////////////////////////////////////////////////////////////////////////\n"
|
||||||
|
self.out += "// " + file + "\n"
|
||||||
|
self.out += "////////////////////////////////////////////////////////////////////////////////////////\n"
|
||||||
|
self.out += "\n"
|
||||||
|
self.out += "#line 1 \"" + file + "\"\n"
|
||||||
|
self.out += open(file).read()
|
||||||
|
|
||||||
|
if len(self.out) > 0 and self.out[len(self.out)-1] != '\n':
|
||||||
|
self.out += "\n"
|
||||||
|
|
||||||
|
def save(self, file):
|
||||||
|
open(file, 'w').write(self.out)
|
||||||
|
|
||||||
|
desc = """
|
||||||
|
// This file was generated automatically. Do not modify directly!
|
||||||
|
"""
|
||||||
|
|
||||||
|
header = Amalgamator()
|
||||||
|
header.append_text("#ifndef WL_AMALGAMATION\n")
|
||||||
|
header.append_text("#define WL_AMALGAMATION\n")
|
||||||
|
header.append_text(desc)
|
||||||
|
header.append_file("src/public.h")
|
||||||
|
header.append_text("#endif // WL_AMALGAMATION\n")
|
||||||
|
header.save("WL.h")
|
||||||
|
|
||||||
|
source = Amalgamator()
|
||||||
|
source.append_text("#include \"WL.h\"\n")
|
||||||
|
source.append_file("src/includes.h")
|
||||||
|
source.append_file("src/basic.h")
|
||||||
|
source.append_file("src/basic.c")
|
||||||
|
source.append_file("src/file.h")
|
||||||
|
source.append_file("src/file.c")
|
||||||
|
source.append_file("src/parse.h")
|
||||||
|
source.append_file("src/parse.c")
|
||||||
|
source.append_file("src/assemble.h")
|
||||||
|
source.append_file("src/assemble.c")
|
||||||
|
source.append_file("src/value.h")
|
||||||
|
source.append_file("src/value.c")
|
||||||
|
source.append_file("src/eval.h")
|
||||||
|
source.append_file("src/eval.c")
|
||||||
|
source.append_file("src/public.c")
|
||||||
|
source.save("WL.c")
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "WL.h"
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
FILE *f = fopen("main.wl", "rb");
|
||||||
|
if (f == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
fseek(f, 0, SEEK_END);
|
||||||
|
long file_size = ftell(f);
|
||||||
|
fseek(f, 0, SEEK_SET);
|
||||||
|
|
||||||
|
char *file_data = malloc(file_size);
|
||||||
|
|
||||||
|
fread(file_data, 1, file_size, f);
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
char err[1<<9];
|
||||||
|
char *mem = malloc(1<<20);
|
||||||
|
WL_Arena a = { mem, 1<<20, 0 };
|
||||||
|
|
||||||
|
WL_Program program;
|
||||||
|
int ret = WL_compile(file_data, file_size, a, &program, err, (int) sizeof(err));
|
||||||
|
if (ret < 0) {
|
||||||
|
printf("%s\n", err);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
WL_State *state = WL_State_init(&a, program, err, (int) sizeof(err));
|
||||||
|
|
||||||
|
for (bool done = false; !done; ) {
|
||||||
|
|
||||||
|
WL_Result result = WL_eval(state);
|
||||||
|
switch (result.type) {
|
||||||
|
|
||||||
|
case WL_DONE:
|
||||||
|
done = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WL_ERROR:
|
||||||
|
done = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WL_VAR:
|
||||||
|
if (0) {}
|
||||||
|
else if (WL_streq(result.str, "varA", -1)) WL_pushint(state, 1);
|
||||||
|
else if (WL_streq(result.str, "varB", -1)) WL_pushint(state, 1);
|
||||||
|
else if (WL_streq(result.str, "varC", -1)) WL_pushint(state, 1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WL_CALL:
|
||||||
|
// TODO
|
||||||
|
printf("(called [%.*s])\n", result.str.len, result.str.ptr);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WL_OUTPUT:
|
||||||
|
fwrite(result.str.ptr, 1, result.str.len, stdout);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WL_State_free(state);
|
||||||
|
free(file_data);
|
||||||
|
free(mem);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -1,10 +1,2 @@
|
|||||||
|
|
||||||
fun comment(data)
|
$do_something(1, 2, 3)
|
||||||
<div>
|
|
||||||
<a>\data.author</a>
|
|
||||||
<p>\data.content</p>
|
|
||||||
\for sub_comment in data.sub_comments:
|
|
||||||
comment(sub_comment)
|
|
||||||
</div>
|
|
||||||
|
|
||||||
comment()
|
|
||||||
+95
-35
@@ -1,10 +1,6 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
#ifndef WL_AMALGAMATION
|
#ifndef WL_AMALGAMATION
|
||||||
|
#include "includes.h"
|
||||||
#include "parse.h"
|
#include "parse.h"
|
||||||
#include "assemble.h"
|
#include "assemble.h"
|
||||||
#endif
|
#endif
|
||||||
@@ -53,12 +49,12 @@ typedef struct {
|
|||||||
char *ptr;
|
char *ptr;
|
||||||
int len;
|
int len;
|
||||||
int cap;
|
int cap;
|
||||||
b32 err;
|
bool err;
|
||||||
} OutputBuffer;
|
} OutputBuffer;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
||||||
Arena *a;
|
WL_Arena *a;
|
||||||
|
|
||||||
OutputBuffer out;
|
OutputBuffer out;
|
||||||
|
|
||||||
@@ -232,7 +228,7 @@ Scope *parent_scope(Assembler *a)
|
|||||||
return scope;
|
return scope;
|
||||||
}
|
}
|
||||||
|
|
||||||
b32 global_scope(Assembler *a)
|
bool global_scope(Assembler *a)
|
||||||
{
|
{
|
||||||
return parent_scope(a)->type == SCOPE_GLOBAL;
|
return parent_scope(a)->type == SCOPE_GLOBAL;
|
||||||
}
|
}
|
||||||
@@ -305,7 +301,7 @@ int declare_function(Assembler *a, String name, int off)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
b32 is_expr(Node *node)
|
bool is_expr(Node *node)
|
||||||
{
|
{
|
||||||
switch (node->type) {
|
switch (node->type) {
|
||||||
|
|
||||||
@@ -331,6 +327,7 @@ b32 is_expr(Node *node)
|
|||||||
case NODE_VALUE_FLOAT:
|
case NODE_VALUE_FLOAT:
|
||||||
case NODE_VALUE_STR:
|
case NODE_VALUE_STR:
|
||||||
case NODE_VALUE_VAR:
|
case NODE_VALUE_VAR:
|
||||||
|
case NODE_VALUE_SYSVAR:
|
||||||
case NODE_VALUE_HTML:
|
case NODE_VALUE_HTML:
|
||||||
case NODE_VALUE_ARRAY:
|
case NODE_VALUE_ARRAY:
|
||||||
case NODE_VALUE_MAP:
|
case NODE_VALUE_MAP:
|
||||||
@@ -400,7 +397,7 @@ int pop_scope(Assembler *a)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void assemble_statement(Assembler *a, Node *node, b32 pop_expr);
|
void assemble_statement(Assembler *a, Node *node, bool pop_expr);
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
OutputBuffer tmp;
|
OutputBuffer tmp;
|
||||||
@@ -506,10 +503,35 @@ void assemble_expr(Assembler *a, Node *node, int num_results)
|
|||||||
arg = arg->next;
|
arg = arg->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(func->type == NODE_VALUE_VAR);
|
if (func->type == NODE_VALUE_SYSVAR) {
|
||||||
|
|
||||||
append_u8(&a->out, OPCODE_CALL);
|
String name = func->sval;
|
||||||
int p = append_u32(&a->out, 0);
|
int off = add_string_literal(a, name);
|
||||||
|
|
||||||
|
append_u8(&a->out, OPCODE_SYSCALL);
|
||||||
|
append_u32(&a->out, off);
|
||||||
|
append_u32(&a->out, name.len);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
assert(func->type == NODE_VALUE_VAR);
|
||||||
|
|
||||||
|
append_u8(&a->out, OPCODE_CALL);
|
||||||
|
int p = append_u32(&a->out, 0);
|
||||||
|
|
||||||
|
FunctionCall *call = alloc(a->a, sizeof(FunctionCall), _Alignof(FunctionCall));
|
||||||
|
if (call == NULL) {
|
||||||
|
assembler_report(a, "Out of memory");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
call->name = func->sval;
|
||||||
|
call->off = p;
|
||||||
|
|
||||||
|
Scope *scope = &a->scopes[a->num_scopes-1];
|
||||||
|
|
||||||
|
call->next = scope->calls;
|
||||||
|
scope->calls = call;
|
||||||
|
}
|
||||||
|
|
||||||
if (num_results == 0)
|
if (num_results == 0)
|
||||||
append_u8(&a->out, OPCODE_GPOP);
|
append_u8(&a->out, OPCODE_GPOP);
|
||||||
@@ -519,19 +541,6 @@ void assemble_expr(Assembler *a, Node *node, int num_results)
|
|||||||
}
|
}
|
||||||
|
|
||||||
append_u8(&a->out, OPCODE_GCOALESCE);
|
append_u8(&a->out, OPCODE_GCOALESCE);
|
||||||
|
|
||||||
FunctionCall *call = alloc(a->a, sizeof(FunctionCall), _Alignof(FunctionCall));
|
|
||||||
if (call == NULL) {
|
|
||||||
assembler_report(a, "Out of memory");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
call->name = func->sval;
|
|
||||||
call->off = p;
|
|
||||||
|
|
||||||
Scope *scope = &a->scopes[a->num_scopes-1];
|
|
||||||
|
|
||||||
call->next = scope->calls;
|
|
||||||
scope->calls = call;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -751,7 +760,27 @@ void assemble_expr(Assembler *a, Node *node, int num_results)
|
|||||||
|
|
||||||
if (num_results == 0)
|
if (num_results == 0)
|
||||||
append_u8(&a->out, OPCODE_POP);
|
append_u8(&a->out, OPCODE_POP);
|
||||||
else if (num_results != -1) {
|
else if (num_results != -1 && num_results != 1) {
|
||||||
|
append_u8(&a->out, OPCODE_GROUP);
|
||||||
|
append_u8(&a->out, OPCODE_GTRUNC);
|
||||||
|
append_u32(&a->out, num_results-1);
|
||||||
|
append_u8(&a->out, OPCODE_GCOALESCE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NODE_VALUE_SYSVAR:
|
||||||
|
{
|
||||||
|
String name = node->sval;
|
||||||
|
int off = add_string_literal(a, name);
|
||||||
|
|
||||||
|
append_u8(&a->out, OPCODE_SYSVAR);
|
||||||
|
append_u32(&a->out, off);
|
||||||
|
append_u32(&a->out, name.len);
|
||||||
|
|
||||||
|
if (num_results == 0)
|
||||||
|
append_u8(&a->out, OPCODE_POP);
|
||||||
|
else if (num_results != -1 && num_results != 1) {
|
||||||
append_u8(&a->out, OPCODE_GROUP);
|
append_u8(&a->out, OPCODE_GROUP);
|
||||||
append_u8(&a->out, OPCODE_GTRUNC);
|
append_u8(&a->out, OPCODE_GTRUNC);
|
||||||
append_u32(&a->out, num_results-1);
|
append_u32(&a->out, num_results-1);
|
||||||
@@ -901,7 +930,7 @@ void assemble_expr(Assembler *a, Node *node, int num_results)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void assemble_statement(Assembler *a, Node *node, b32 pop_expr)
|
void assemble_statement(Assembler *a, Node *node, bool pop_expr)
|
||||||
{
|
{
|
||||||
switch (node->type) {
|
switch (node->type) {
|
||||||
|
|
||||||
@@ -1131,13 +1160,16 @@ typedef struct {
|
|||||||
uint32_t data_size;
|
uint32_t data_size;
|
||||||
} Header;
|
} Header;
|
||||||
|
|
||||||
AssembleResult assemble(Node *root, Arena *arena, char *errbuf, int errmax)
|
AssembleResult assemble(Node *root, WL_Arena *arena, char *errbuf, int errmax)
|
||||||
{
|
{
|
||||||
Assembler a = {0, .a=arena, .errbuf=errbuf, .errmax=errmax, .errlen=0};
|
Assembler a = {0};
|
||||||
|
a.errbuf = errbuf;
|
||||||
|
a.errmax = errmax;
|
||||||
|
a.a = arena;
|
||||||
|
|
||||||
int ret = push_scope(&a, SCOPE_GLOBAL);
|
int ret = push_scope(&a, SCOPE_GLOBAL);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return (AssembleResult) { (Program) {0}, a.errlen };
|
return (AssembleResult) { (WL_Program) {0}, a.errlen };
|
||||||
|
|
||||||
append_u8(&a.out, OPCODE_GROUP);
|
append_u8(&a.out, OPCODE_GROUP);
|
||||||
|
|
||||||
@@ -1158,7 +1190,7 @@ AssembleResult assemble(Node *root, Arena *arena, char *errbuf, int errmax)
|
|||||||
|
|
||||||
ret = pop_scope(&a);
|
ret = pop_scope(&a);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return (AssembleResult) { (Program) {0}, a.errlen };
|
return (AssembleResult) { (WL_Program) {0}, a.errlen };
|
||||||
|
|
||||||
OutputBuffer out = {0};
|
OutputBuffer out = {0};
|
||||||
append_u32(&out, 0xFEEDBEEF); // magic
|
append_u32(&out, 0xFEEDBEEF); // magic
|
||||||
@@ -1168,10 +1200,10 @@ AssembleResult assemble(Node *root, Arena *arena, char *errbuf, int errmax)
|
|||||||
append_mem(&out, a.strings, a.strings_len);
|
append_mem(&out, a.strings, a.strings_len);
|
||||||
|
|
||||||
free(a.out.ptr);
|
free(a.out.ptr);
|
||||||
return (AssembleResult) { (Program) { out.ptr, out.len }, a.errlen };
|
return (AssembleResult) { (WL_Program) { out.ptr, out.len }, a.errlen };
|
||||||
}
|
}
|
||||||
|
|
||||||
int parse_program_header(Program p, String *code, String *data, char *errbuf, int errmax)
|
int parse_program_header(WL_Program p, String *code, String *data, char *errbuf, int errmax)
|
||||||
{
|
{
|
||||||
if ((uint32_t) p.len < 3 * sizeof(uint32_t)) {
|
if ((uint32_t) p.len < 3 * sizeof(uint32_t)) {
|
||||||
snprintf(errbuf, errmax, "Invalid program");
|
snprintf(errbuf, errmax, "Invalid program");
|
||||||
@@ -1200,7 +1232,7 @@ int parse_program_header(Program p, String *code, String *data, char *errbuf, in
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_program(Program program)
|
void print_program(WL_Program program)
|
||||||
{
|
{
|
||||||
String code;
|
String code;
|
||||||
String data;
|
String data;
|
||||||
@@ -1460,6 +1492,34 @@ char *print_instruction(char *p, char *data)
|
|||||||
case OPCODE_PRINT:
|
case OPCODE_PRINT:
|
||||||
printf("PRINT");
|
printf("PRINT");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case OPCODE_SYSVAR:
|
||||||
|
{
|
||||||
|
uint32_t off;
|
||||||
|
memcpy(&off, p, sizeof(uint32_t));
|
||||||
|
p += sizeof(uint32_t);
|
||||||
|
|
||||||
|
uint32_t len;
|
||||||
|
memcpy(&len, p, sizeof(uint32_t));
|
||||||
|
p += sizeof(uint32_t);
|
||||||
|
|
||||||
|
printf("SYSVAR \"%.*s\"", (int) len, (char*) data + off);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPCODE_SYSCALL:
|
||||||
|
{
|
||||||
|
uint32_t off;
|
||||||
|
memcpy(&off, p, sizeof(uint32_t));
|
||||||
|
p += sizeof(uint32_t);
|
||||||
|
|
||||||
|
uint32_t len;
|
||||||
|
memcpy(&len, p, sizeof(uint32_t));
|
||||||
|
p += sizeof(uint32_t);
|
||||||
|
|
||||||
|
printf("SYSCALL \"%.*s\"", (int) len, (char*) data + off);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
|
|||||||
+9
-9
@@ -1,7 +1,10 @@
|
|||||||
#ifndef WL_ASSEMBLE_INCLUDED
|
#ifndef WL_ASSEMBLE_INCLUDED
|
||||||
#define WL_ASSEMBLE_INCLUDED
|
#define WL_ASSEMBLE_INCLUDED
|
||||||
|
|
||||||
|
#ifndef WL_AMALGAMATION
|
||||||
|
#include "public.h"
|
||||||
#include "parse.h"
|
#include "parse.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
OPCODE_NOPE = 0x00,
|
OPCODE_NOPE = 0x00,
|
||||||
@@ -41,21 +44,18 @@ enum {
|
|||||||
OPCODE_INSERT2 = 0x19,
|
OPCODE_INSERT2 = 0x19,
|
||||||
OPCODE_SELECT = 0x20,
|
OPCODE_SELECT = 0x20,
|
||||||
OPCODE_PRINT = 0x24,
|
OPCODE_PRINT = 0x24,
|
||||||
|
OPCODE_SYSVAR = 0x2C,
|
||||||
|
OPCODE_SYSCALL = 0x2D,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
void *ptr;
|
WL_Program program;
|
||||||
int len;
|
|
||||||
} Program;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
Program program;
|
|
||||||
int errlen;
|
int errlen;
|
||||||
} AssembleResult;
|
} AssembleResult;
|
||||||
|
|
||||||
int parse_program_header(Program p, String *code, String *data, char *errbuf, int errmax);
|
int parse_program_header(WL_Program p, String *code, String *data, char *errbuf, int errmax);
|
||||||
void print_program(Program program);
|
void print_program(WL_Program program);
|
||||||
char *print_instruction(char *p, char *data);
|
char *print_instruction(char *p, char *data);
|
||||||
AssembleResult assemble(Node *root, Arena *arena, char *errbuf, int errmax);
|
AssembleResult assemble(Node *root, WL_Arena *arena, char *errbuf, int errmax);
|
||||||
|
|
||||||
#endif // WL_ASSEMBLE_INCLUDED
|
#endif // WL_ASSEMBLE_INCLUDED
|
||||||
+11
-11
@@ -1,31 +1,31 @@
|
|||||||
#include <stddef.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#ifndef WL_AMALGAMATION
|
#ifndef WL_AMALGAMATION
|
||||||
|
#include "includes.h"
|
||||||
#include "basic.h"
|
#include "basic.h"
|
||||||
|
#include "public.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
b32 is_space(char c)
|
bool is_space(char c)
|
||||||
{
|
{
|
||||||
return c == ' ' || c == '\t' || c == '\r' || c == '\n';
|
return c == ' ' || c == '\t' || c == '\r' || c == '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
b32 is_digit(char c)
|
bool is_digit(char c)
|
||||||
{
|
{
|
||||||
return c >= '0' && c <= '9';
|
return c >= '0' && c <= '9';
|
||||||
}
|
}
|
||||||
|
|
||||||
b32 is_alpha(char c)
|
bool is_alpha(char c)
|
||||||
{
|
{
|
||||||
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
|
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
|
||||||
}
|
}
|
||||||
|
|
||||||
b32 is_printable(char c)
|
bool is_printable(char c)
|
||||||
{
|
{
|
||||||
return c >= ' ' && c <= '~';
|
return c >= ' ' && c <= '~';
|
||||||
}
|
}
|
||||||
|
|
||||||
b32 is_hex_digit(char c)
|
bool is_hex_digit(char c)
|
||||||
{
|
{
|
||||||
return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
|
return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
|
||||||
}
|
}
|
||||||
@@ -49,7 +49,7 @@ int hex_digit_to_int(char c)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
b32 streq(String a, String b)
|
bool streq(String a, String b)
|
||||||
{
|
{
|
||||||
if (a.len != b.len)
|
if (a.len != b.len)
|
||||||
return false;
|
return false;
|
||||||
@@ -59,7 +59,7 @@ b32 streq(String a, String b)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
b32 streqcase(String a, String b)
|
bool streqcase(String a, String b)
|
||||||
{
|
{
|
||||||
if (a.len != b.len)
|
if (a.len != b.len)
|
||||||
return false;
|
return false;
|
||||||
@@ -69,7 +69,7 @@ b32 streqcase(String a, String b)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *alloc(Arena *a, int len, int align)
|
void *alloc(WL_Arena *a, int len, int align)
|
||||||
{
|
{
|
||||||
int pad = -(intptr_t) (a->ptr + a->cur) & (align-1);
|
int pad = -(intptr_t) (a->ptr + a->cur) & (align-1);
|
||||||
if (a->len - a->cur < len + pad)
|
if (a->len - a->cur < len + pad)
|
||||||
@@ -79,7 +79,7 @@ void *alloc(Arena *a, int len, int align)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
b32 grow_alloc(Arena *a, char *p, int new_len)
|
bool grow_alloc(WL_Arena *a, char *p, int new_len)
|
||||||
{
|
{
|
||||||
int new_cur = (p - a->ptr) + new_len;
|
int new_cur = (p - a->ptr) + new_len;
|
||||||
if (new_cur > a->len)
|
if (new_cur > a->len)
|
||||||
|
|||||||
+12
-18
@@ -1,21 +1,15 @@
|
|||||||
#ifndef WL_BASIC_INCLUDED
|
#ifndef WL_BASIC_INCLUDED
|
||||||
#define WL_BASIC_INCLUDED
|
#define WL_BASIC_INCLUDED
|
||||||
|
|
||||||
typedef unsigned int b32;
|
#ifndef WL_AMALGAMATION
|
||||||
#define true 1
|
#include "public.h"
|
||||||
#define false 0
|
#endif
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char *ptr;
|
char *ptr;
|
||||||
int len;
|
int len;
|
||||||
} String;
|
} String;
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char *ptr;
|
|
||||||
int len;
|
|
||||||
int cur;
|
|
||||||
} Arena;
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#define LLU "llu"
|
#define LLU "llu"
|
||||||
#define LLD "lld"
|
#define LLD "lld"
|
||||||
@@ -31,18 +25,18 @@ typedef struct {
|
|||||||
|
|
||||||
#define COUNT(X) (int) (sizeof(X) / sizeof((X)[0]))
|
#define COUNT(X) (int) (sizeof(X) / sizeof((X)[0]))
|
||||||
|
|
||||||
b32 is_space(char c);
|
bool is_space(char c);
|
||||||
b32 is_digit(char c);
|
bool is_digit(char c);
|
||||||
b32 is_alpha(char c);
|
bool is_alpha(char c);
|
||||||
b32 is_printable(char c);
|
bool is_printable(char c);
|
||||||
char to_lower(char c);
|
char to_lower(char c);
|
||||||
b32 is_hex_digit(char c);
|
bool is_hex_digit(char c);
|
||||||
int hex_digit_to_int(char c);
|
int hex_digit_to_int(char c);
|
||||||
|
|
||||||
b32 streq(String a, String b);
|
bool streq(String a, String b);
|
||||||
b32 streqcase(String a, String b);
|
bool streqcase(String a, String b);
|
||||||
|
|
||||||
void *alloc(Arena *a, int len, int align);
|
void *alloc(WL_Arena *a, int len, int align);
|
||||||
b32 grow_alloc(Arena *a, char *p, int new_len);
|
bool grow_alloc(WL_Arena *a, char *p, int new_len);
|
||||||
|
|
||||||
#endif // WL_BASIC_INCLUDED
|
#endif // WL_BASIC_INCLUDED
|
||||||
+514
-693
File diff suppressed because it is too large
Load Diff
+4
-1
@@ -1,8 +1,11 @@
|
|||||||
#ifndef WL_EVAL_INCLUDED
|
#ifndef WL_EVAL_INCLUDED
|
||||||
#define WL_EVAL_INCLUDED
|
#define WL_EVAL_INCLUDED
|
||||||
|
|
||||||
|
#ifndef WL_AMALGAMATION
|
||||||
#include "assemble.h"
|
#include "assemble.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
int eval(Program p, Arena *a, char *errbuf, int errmax);
|
// TODO: pretty sure this is unused
|
||||||
|
int eval(WL_Program p, WL_Arena *a, char *errbuf, int errmax);
|
||||||
|
|
||||||
#endif // WL_EVAL_INCLUDED
|
#endif // WL_EVAL_INCLUDED
|
||||||
|
|||||||
+1
-11
@@ -1,15 +1,5 @@
|
|||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#ifndef _WIN32
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <limits.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef WL_AMALGAMATION
|
#ifndef WL_AMALGAMATION
|
||||||
|
#include "includes.h"
|
||||||
#include "file.h"
|
#include "file.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
+2
-3
@@ -2,12 +2,11 @@
|
|||||||
#define WL_FILE_INCLUDED
|
#define WL_FILE_INCLUDED
|
||||||
|
|
||||||
#ifndef WL_AMALGAMATION
|
#ifndef WL_AMALGAMATION
|
||||||
|
#include "includes.h"
|
||||||
#include "basic.h"
|
#include "basic.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if _WIN32
|
#ifdef _WIN32
|
||||||
#define WIN32_LEAN_AND_MEAN
|
|
||||||
#include <windows.h>
|
|
||||||
typedef HANDLE File;
|
typedef HANDLE File;
|
||||||
#else
|
#else
|
||||||
typedef int File;
|
typedef int File;
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
#ifndef WL_INCLUDES_INCLUDED
|
||||||
|
#define WL_INCLUDES_INCLUDED
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // WL_INCLUDES_INCLUDED
|
||||||
-48
@@ -1,48 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#include "file.h"
|
|
||||||
#include "eval.h"
|
|
||||||
#include "parse.h"
|
|
||||||
#include "assemble.h"
|
|
||||||
|
|
||||||
int main(void)
|
|
||||||
{
|
|
||||||
String src;
|
|
||||||
int ret = file_read_all(S("main.wl"), &src);
|
|
||||||
if (ret < 0) {
|
|
||||||
printf("Error!\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
char err[1<<9];
|
|
||||||
char *mem = malloc(1<<20);
|
|
||||||
Arena a = { mem, 1<<20, 0 };
|
|
||||||
|
|
||||||
ParseResult parse_result = parse(src, &a, err, COUNT(err));
|
|
||||||
if (parse_result.node == NULL) {
|
|
||||||
printf("%.*s\n", parse_result.errlen, err);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
print_node(parse_result.node);
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
AssembleResult assemble_result = assemble(parse_result.node, &a, err, COUNT(err));
|
|
||||||
if (assemble_result.errlen) {
|
|
||||||
printf("%.*s\n", parse_result.errlen, err);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
print_program(assemble_result.program);
|
|
||||||
|
|
||||||
ret = eval(assemble_result.program, &a, err, COUNT(err));
|
|
||||||
if (ret < 0) {
|
|
||||||
printf("%s\n", err);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
free(src.ptr);
|
|
||||||
free(mem);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
+42
-10
@@ -1,6 +1,3 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#ifndef WL_AMALGAMATION
|
#ifndef WL_AMALGAMATION
|
||||||
#include "parse.h"
|
#include "parse.h"
|
||||||
@@ -46,6 +43,7 @@ typedef enum {
|
|||||||
TOKEN_DOT,
|
TOKEN_DOT,
|
||||||
TOKEN_COMMA,
|
TOKEN_COMMA,
|
||||||
TOKEN_COLON,
|
TOKEN_COLON,
|
||||||
|
TOKEN_DOLLAR,
|
||||||
TOKEN_NEWLINE,
|
TOKEN_NEWLINE,
|
||||||
} TokType;
|
} TokType;
|
||||||
|
|
||||||
@@ -61,13 +59,13 @@ typedef struct {
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Scanner s;
|
Scanner s;
|
||||||
Arena *a;
|
WL_Arena *a;
|
||||||
char *errbuf;
|
char *errbuf;
|
||||||
int errmax;
|
int errmax;
|
||||||
int errlen;
|
int errlen;
|
||||||
} Parser;
|
} Parser;
|
||||||
|
|
||||||
b32 consume_str(Scanner *s, String x)
|
bool consume_str(Scanner *s, String x)
|
||||||
{
|
{
|
||||||
if (x.len == 0)
|
if (x.len == 0)
|
||||||
return false;
|
return false;
|
||||||
@@ -153,6 +151,7 @@ String tok2str(Token token, char *buf, int max)
|
|||||||
case TOKEN_DOT: return S(".");
|
case TOKEN_DOT: return S(".");
|
||||||
case TOKEN_COMMA: return S(",");
|
case TOKEN_COMMA: return S(",");
|
||||||
case TOKEN_COLON: return S(":");
|
case TOKEN_COLON: return S(":");
|
||||||
|
case TOKEN_DOLLAR: return S("$");
|
||||||
|
|
||||||
case TOKEN_NEWLINE: return S("\\n");
|
case TOKEN_NEWLINE: return S("\\n");
|
||||||
}
|
}
|
||||||
@@ -395,6 +394,7 @@ Token next_token(Parser *p)
|
|||||||
if (consume_str(&p->s, S("."))) return (Token) { .type=TOKEN_DOT };
|
if (consume_str(&p->s, S("."))) return (Token) { .type=TOKEN_DOT };
|
||||||
if (consume_str(&p->s, S(","))) return (Token) { .type=TOKEN_COMMA };
|
if (consume_str(&p->s, S(","))) return (Token) { .type=TOKEN_COMMA };
|
||||||
if (consume_str(&p->s, S(":"))) return (Token) { .type=TOKEN_COLON };
|
if (consume_str(&p->s, S(":"))) return (Token) { .type=TOKEN_COLON };
|
||||||
|
if (consume_str(&p->s, S("$"))) return (Token) { .type=TOKEN_DOLLAR };
|
||||||
|
|
||||||
parser_report(p, "Invalid character '%c'", c);
|
parser_report(p, "Invalid character '%c'", c);
|
||||||
return (Token) { .type=TOKEN_ERROR };
|
return (Token) { .type=TOKEN_ERROR };
|
||||||
@@ -441,7 +441,7 @@ Node *parse_html(Parser *p)
|
|||||||
Node *param_head;
|
Node *param_head;
|
||||||
Node **param_tail = ¶m_head;
|
Node **param_tail = ¶m_head;
|
||||||
|
|
||||||
b32 no_body = false;
|
bool no_body = false;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
|
||||||
int param_offset = p->s.cur;
|
int param_offset = p->s.cur;
|
||||||
@@ -768,7 +768,7 @@ int precedence(Token t, int flags)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
b32 right_associative(Token t)
|
bool right_associative(Token t)
|
||||||
{
|
{
|
||||||
return t.type == TOKEN_OPER_ASS;
|
return t.type == TOKEN_OPER_ASS;
|
||||||
}
|
}
|
||||||
@@ -927,6 +927,26 @@ Node *parse_atom(Parser *p)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case TOKEN_DOLLAR:
|
||||||
|
{
|
||||||
|
t = next_token(p);
|
||||||
|
if (t.type != TOKEN_IDENT) {
|
||||||
|
parser_report(p, "Missing identifier after '$'");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Node *node = alloc_node(p);
|
||||||
|
if (node == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
node->type = NODE_VALUE_SYSVAR;
|
||||||
|
node->text = (String) { p->s.src + start, p->s.cur - start };
|
||||||
|
node->sval = t.sval;
|
||||||
|
|
||||||
|
ret = node;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
char buf[1<<8];
|
char buf[1<<8];
|
||||||
@@ -989,7 +1009,7 @@ Node *parse_atom(Parser *p)
|
|||||||
|
|
||||||
ret = parent;
|
ret = parent;
|
||||||
|
|
||||||
} else if (t.type == TOKEN_PAREN_OPEN && ret->type == NODE_VALUE_VAR) {
|
} else if (t.type == TOKEN_PAREN_OPEN && (ret->type == NODE_VALUE_VAR || ret->type == NODE_VALUE_SYSVAR)) {
|
||||||
|
|
||||||
Node *arg_head;
|
Node *arg_head;
|
||||||
Node **arg_tail = &arg_head;
|
Node **arg_tail = &arg_head;
|
||||||
@@ -1280,7 +1300,7 @@ Node *parse_while_stmt(Parser *p, int opflags)
|
|||||||
return parent;
|
return parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
Node *parse_block_stmt(Parser *p, b32 curly)
|
Node *parse_block_stmt(Parser *p, bool curly)
|
||||||
{
|
{
|
||||||
int start = p->s.cur;
|
int start = p->s.cur;
|
||||||
|
|
||||||
@@ -1523,6 +1543,14 @@ void print_node(Node *node)
|
|||||||
{
|
{
|
||||||
switch (node->type) {
|
switch (node->type) {
|
||||||
|
|
||||||
|
case NODE_NESTED:
|
||||||
|
{
|
||||||
|
printf("(");
|
||||||
|
print_node(node->left);
|
||||||
|
printf(")");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case NODE_PRINT:
|
case NODE_PRINT:
|
||||||
{
|
{
|
||||||
printf("print ");
|
printf("print ");
|
||||||
@@ -1653,6 +1681,10 @@ void print_node(Node *node)
|
|||||||
printf("%.*s", node->sval.len, node->sval.ptr);
|
printf("%.*s", node->sval.len, node->sval.ptr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case NODE_VALUE_SYSVAR:
|
||||||
|
printf("$%.*s", node->sval.len, node->sval.ptr);
|
||||||
|
break;
|
||||||
|
|
||||||
case NODE_IFELSE:
|
case NODE_IFELSE:
|
||||||
printf("if ");
|
printf("if ");
|
||||||
print_node(node->cond);
|
print_node(node->cond);
|
||||||
@@ -1823,7 +1855,7 @@ void print_node(Node *node)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseResult parse(String src, Arena *a, char *errbuf, int errmax)
|
ParseResult parse(String src, WL_Arena *a, char *errbuf, int errmax)
|
||||||
{
|
{
|
||||||
Parser p = {
|
Parser p = {
|
||||||
.s={ src.ptr, src.len, 0 },
|
.s={ src.ptr, src.len, 0 },
|
||||||
|
|||||||
+3
-3
@@ -1,9 +1,8 @@
|
|||||||
#ifndef WL_PARSE_INCLUDED
|
#ifndef WL_PARSE_INCLUDED
|
||||||
#define WL_PARSE_INCLUDED
|
#define WL_PARSE_INCLUDED
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#ifndef WL_AMALGAMATION
|
#ifndef WL_AMALGAMATION
|
||||||
|
#include "includes.h"
|
||||||
#include "basic.h"
|
#include "basic.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -35,6 +34,7 @@ typedef enum {
|
|||||||
NODE_VALUE_FLOAT,
|
NODE_VALUE_FLOAT,
|
||||||
NODE_VALUE_STR,
|
NODE_VALUE_STR,
|
||||||
NODE_VALUE_VAR,
|
NODE_VALUE_VAR,
|
||||||
|
NODE_VALUE_SYSVAR,
|
||||||
NODE_VALUE_HTML,
|
NODE_VALUE_HTML,
|
||||||
NODE_VALUE_ARRAY,
|
NODE_VALUE_ARRAY,
|
||||||
NODE_VALUE_MAP,
|
NODE_VALUE_MAP,
|
||||||
@@ -83,6 +83,6 @@ typedef struct {
|
|||||||
} ParseResult;
|
} ParseResult;
|
||||||
|
|
||||||
void print_node(Node *node);
|
void print_node(Node *node);
|
||||||
ParseResult parse(String src, Arena *a, char *errbuf, int errmax);
|
ParseResult parse(String src, WL_Arena *a, char *errbuf, int errmax);
|
||||||
|
|
||||||
#endif // WL_PARSE_INCLUDED
|
#endif // WL_PARSE_INCLUDED
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
|
||||||
|
#ifndef WL_AMALGAMATION
|
||||||
|
#include "eval.h"
|
||||||
|
#include "parse.h"
|
||||||
|
#include "assemble.h"
|
||||||
|
#include "WL.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int WL_streq(WL_String a, char *b, int blen)
|
||||||
|
{
|
||||||
|
if (b == NULL) b = "";
|
||||||
|
if (blen < 0) blen = strlen(b);
|
||||||
|
|
||||||
|
if (a.len != blen)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < a.len; i++)
|
||||||
|
if (a.ptr[i] != b[i])
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int WL_compile(char *src, int len, WL_Arena arena, WL_Program *program, char *err, int errmax)
|
||||||
|
{
|
||||||
|
if (src == NULL) src = "";
|
||||||
|
if (len < 0) len = strlen(src);
|
||||||
|
|
||||||
|
Node *root;
|
||||||
|
ParseResult pres = parse((String) {src, len}, &arena, err, errmax);
|
||||||
|
if (pres.node == NULL)
|
||||||
|
return -1;
|
||||||
|
root = pres.node;
|
||||||
|
|
||||||
|
AssembleResult ares = assemble(root, &arena, err, errmax);
|
||||||
|
if (ares.errlen)
|
||||||
|
return -1;
|
||||||
|
*program = ares.program;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
#ifndef WL_PUBLIC_INCLUDED
|
||||||
|
#define WL_PUBLIC_INCLUDED
|
||||||
|
|
||||||
|
#ifndef WL_AMALGAMATION
|
||||||
|
#include "includes.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct WL_State WL_State;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char *ptr;
|
||||||
|
int len;
|
||||||
|
} WL_String;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char *ptr;
|
||||||
|
int len;
|
||||||
|
} WL_Program;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
WL_DONE,
|
||||||
|
WL_ERROR,
|
||||||
|
WL_VAR,
|
||||||
|
WL_CALL,
|
||||||
|
WL_OUTPUT,
|
||||||
|
} WL_ResultType;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
WL_ResultType type;
|
||||||
|
WL_String str;
|
||||||
|
} WL_Result;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char *ptr;
|
||||||
|
int len;
|
||||||
|
int cur;
|
||||||
|
} WL_Arena;
|
||||||
|
|
||||||
|
int WL_compile (char *src, int len, WL_Arena arena, WL_Program *program, char *err, int errmax);
|
||||||
|
WL_State *WL_State_init (WL_Arena *a, WL_Program p, char *err, int errmax);
|
||||||
|
void WL_State_free (WL_State *state);
|
||||||
|
WL_Result WL_eval (WL_State *state);
|
||||||
|
int WL_streq (WL_String a, char *b, int blen);
|
||||||
|
int WL_popint (WL_State *state, long long *x);
|
||||||
|
int WL_popfloat (WL_State *state, float *x);
|
||||||
|
int WL_popstr (WL_State *state, char **str, int *len);
|
||||||
|
int WL_popany (WL_State *state);
|
||||||
|
void WL_select (WL_State *state);
|
||||||
|
void WL_pushint (WL_State *state, long long x);
|
||||||
|
void WL_pushfloat (WL_State *state, float x);
|
||||||
|
void WL_pushstr (WL_State *state, char *str, int len);
|
||||||
|
void WL_pusharray (WL_State *state, int cap);
|
||||||
|
void WL_pushmap (WL_State *state, int cap);
|
||||||
|
void WL_insert (WL_State *state);
|
||||||
|
|
||||||
|
#endif // WL_PUBLIC_INCLUDED
|
||||||
+458
@@ -0,0 +1,458 @@
|
|||||||
|
|
||||||
|
#ifndef WL_AMALGAMATION
|
||||||
|
#include "value.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ITEMS_PER_MAP_BATCH 8
|
||||||
|
#define ITEMS_PER_ARRAY_BATCH 16
|
||||||
|
|
||||||
|
typedef struct MapItems MapItems;
|
||||||
|
struct MapItems {
|
||||||
|
MapItems *next;
|
||||||
|
Value keys [ITEMS_PER_MAP_BATCH];
|
||||||
|
Value items[ITEMS_PER_MAP_BATCH];
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Type type;
|
||||||
|
int count;
|
||||||
|
int tail_count;
|
||||||
|
MapItems head;
|
||||||
|
MapItems *tail;
|
||||||
|
} MapValue;
|
||||||
|
|
||||||
|
typedef struct ArrayItems ArrayItems;
|
||||||
|
struct ArrayItems {
|
||||||
|
ArrayItems *next;
|
||||||
|
Value items[ITEMS_PER_ARRAY_BATCH];
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Type type;
|
||||||
|
int count;
|
||||||
|
int tail_count;
|
||||||
|
ArrayItems head;
|
||||||
|
ArrayItems *tail;
|
||||||
|
} ArrayValue;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Type type;
|
||||||
|
double raw;
|
||||||
|
} FloatValue;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Type type;
|
||||||
|
int64_t raw;
|
||||||
|
} IntValue;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Type type;
|
||||||
|
int len;
|
||||||
|
char data[];
|
||||||
|
} StringValue;
|
||||||
|
|
||||||
|
Type type_of(Value v)
|
||||||
|
{
|
||||||
|
// 000 none
|
||||||
|
// 001 true
|
||||||
|
// 010 false
|
||||||
|
// 011 int
|
||||||
|
// 100
|
||||||
|
// 101
|
||||||
|
// 110 error
|
||||||
|
// 111 pointer
|
||||||
|
|
||||||
|
switch (v & 7) {
|
||||||
|
case 0: return TYPE_NONE;
|
||||||
|
case 1: return TYPE_BOOL;
|
||||||
|
case 2: return TYPE_BOOL;
|
||||||
|
case 3: return TYPE_INT;
|
||||||
|
case 4: break;
|
||||||
|
case 5: break;
|
||||||
|
case 6: return TYPE_ERROR;
|
||||||
|
case 7: return *(Type*) ((uintptr_t) v & ~(uintptr_t) 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
return TYPE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t get_int(Value v)
|
||||||
|
{
|
||||||
|
if ((v & 7) == 3)
|
||||||
|
return (int64_t) (v >> 3);
|
||||||
|
|
||||||
|
IntValue *p = (IntValue*) v;
|
||||||
|
return p->raw;
|
||||||
|
}
|
||||||
|
|
||||||
|
float get_float(Value v)
|
||||||
|
{
|
||||||
|
FloatValue *p = (FloatValue*) v;
|
||||||
|
return p->raw;
|
||||||
|
}
|
||||||
|
|
||||||
|
String get_str(Value v)
|
||||||
|
{
|
||||||
|
StringValue *p = (StringValue*) (v & ~(uintptr_t) 7);
|
||||||
|
return (String) { p->data, p->len };
|
||||||
|
}
|
||||||
|
|
||||||
|
static MapValue *get_map(Value v)
|
||||||
|
{
|
||||||
|
return (MapValue*) (v & ~(uintptr_t) 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ArrayValue *get_array(Value v)
|
||||||
|
{
|
||||||
|
return (ArrayValue*) (v & ~(uintptr_t) 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
Value make_int(WL_Arena *a, int64_t x)
|
||||||
|
{
|
||||||
|
if (x <= (int64_t) (1ULL << 60)-1 && x >= (int64_t) -(1ULL << 60))
|
||||||
|
return ((Value) x << 3) | 3;
|
||||||
|
|
||||||
|
IntValue *v = alloc(a, (int) sizeof(IntValue), _Alignof(IntValue));
|
||||||
|
if (v == NULL)
|
||||||
|
return VALUE_ERROR;
|
||||||
|
|
||||||
|
v->type = TYPE_INT;
|
||||||
|
v->raw = x;
|
||||||
|
|
||||||
|
assert(((uintptr_t) v & 7) == 0);
|
||||||
|
return ((Value) v) | 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
Value make_float(WL_Arena *a, float x)
|
||||||
|
{
|
||||||
|
FloatValue *v = alloc(a, (int) sizeof(FloatValue), _Alignof(FloatValue));
|
||||||
|
if (v == NULL)
|
||||||
|
return VALUE_ERROR;
|
||||||
|
|
||||||
|
v->type = TYPE_FLOAT;
|
||||||
|
v->raw = x;
|
||||||
|
|
||||||
|
assert(((uintptr_t) v & 7) == 0);
|
||||||
|
return ((Value) v) | 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
Value make_str(WL_Arena *a, String x) // TODO: This should reuse the string contents when possible
|
||||||
|
{
|
||||||
|
StringValue *v = alloc(a, (int) sizeof(StringValue) + x.len, 8);
|
||||||
|
if (v == NULL)
|
||||||
|
return VALUE_ERROR;
|
||||||
|
|
||||||
|
v->type = TYPE_STRING;
|
||||||
|
v->len = x.len;
|
||||||
|
memcpy(v->data, x.ptr, x.len);
|
||||||
|
|
||||||
|
assert(((uintptr_t) v & 7) == 0);
|
||||||
|
return ((Value) v) | 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
Value make_map(WL_Arena *a)
|
||||||
|
{
|
||||||
|
MapValue *m = alloc(a, (int) sizeof(MapValue), _Alignof(MapValue));
|
||||||
|
if (m == NULL)
|
||||||
|
return VALUE_ERROR;
|
||||||
|
|
||||||
|
m->type = TYPE_MAP;
|
||||||
|
m->count = 0;
|
||||||
|
m->tail_count = 0;
|
||||||
|
m->tail = &m->head;
|
||||||
|
|
||||||
|
return (Value) m | 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
Value make_array(WL_Arena *a)
|
||||||
|
{
|
||||||
|
ArrayValue *v = alloc(a, (int) sizeof(ArrayValue), _Alignof(ArrayValue));
|
||||||
|
if (v == NULL)
|
||||||
|
return VALUE_ERROR;
|
||||||
|
|
||||||
|
v->type = TYPE_ARRAY;
|
||||||
|
v->count = 0;
|
||||||
|
v->tail_count = 0;
|
||||||
|
v->tail = &v->head;
|
||||||
|
|
||||||
|
return (Value) v | 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
int map_select(Value map, Value key, Value *val)
|
||||||
|
{
|
||||||
|
MapValue *p = get_map(map);
|
||||||
|
MapItems *batch = &p->head;
|
||||||
|
while (batch) {
|
||||||
|
|
||||||
|
int num = ITEMS_PER_MAP_BATCH;
|
||||||
|
if (batch->next == NULL)
|
||||||
|
num = p->tail_count;
|
||||||
|
|
||||||
|
for (int i = 0; i < num; i++)
|
||||||
|
if (valeq(batch->keys[i], key)) {
|
||||||
|
*val = batch->items[i];
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
batch = batch->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int map_insert(WL_Arena *a, Value map, Value key, Value val)
|
||||||
|
{
|
||||||
|
MapValue *p = get_map(map);
|
||||||
|
if (p->tail_count == ITEMS_PER_MAP_BATCH) {
|
||||||
|
|
||||||
|
MapItems *batch = alloc(a, (int) sizeof(MapItems), _Alignof(MapItems));
|
||||||
|
if (batch == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
batch->next = NULL;
|
||||||
|
p->tail = batch;
|
||||||
|
p->tail_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
p->tail->keys[p->tail_count] = key;
|
||||||
|
p->tail->items[p->tail_count] = val;
|
||||||
|
p->tail_count++;
|
||||||
|
p->count++;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Value *array_select(Value array, int key)
|
||||||
|
{
|
||||||
|
ArrayValue *p = get_array(array);
|
||||||
|
ArrayItems *batch = &p->head;
|
||||||
|
int cursor = 0;
|
||||||
|
while (batch) {
|
||||||
|
|
||||||
|
int num = ITEMS_PER_MAP_BATCH;
|
||||||
|
if (batch->next == NULL)
|
||||||
|
num = p->tail_count;
|
||||||
|
|
||||||
|
if (cursor <= key && key < cursor + num)
|
||||||
|
return &batch->items[key - cursor];
|
||||||
|
|
||||||
|
batch = batch->next;
|
||||||
|
cursor += num;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int array_append(WL_Arena *a, Value array, Value val)
|
||||||
|
{
|
||||||
|
ArrayValue *p = get_array(array);
|
||||||
|
if (p->tail_count == ITEMS_PER_MAP_BATCH) {
|
||||||
|
|
||||||
|
ArrayItems *batch = alloc(a, (int) sizeof(ArrayItems), _Alignof(ArrayItems));
|
||||||
|
if (batch == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
batch->next = NULL;
|
||||||
|
p->tail = batch;
|
||||||
|
p->tail_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
p->tail->items[p->tail_count] = val;
|
||||||
|
p->tail_count++;
|
||||||
|
p->count++;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool valeq(Value a, Value b)
|
||||||
|
{
|
||||||
|
Type t1 = type_of(a);
|
||||||
|
Type t2 = type_of(b);
|
||||||
|
|
||||||
|
if (t1 != t2)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
switch (t1) {
|
||||||
|
|
||||||
|
case TYPE_NONE:
|
||||||
|
return VALUE_TRUE;
|
||||||
|
|
||||||
|
case TYPE_BOOL:
|
||||||
|
return a == b;
|
||||||
|
|
||||||
|
case TYPE_INT:
|
||||||
|
return get_int(a) == get_int(b);
|
||||||
|
|
||||||
|
case TYPE_FLOAT:
|
||||||
|
return get_float(a) == get_float(b);
|
||||||
|
|
||||||
|
case TYPE_MAP:
|
||||||
|
return false; // TODO
|
||||||
|
|
||||||
|
case TYPE_ARRAY:
|
||||||
|
return false; // TODO
|
||||||
|
|
||||||
|
case TYPE_STRING:
|
||||||
|
return streq(get_str(a), get_str(b));
|
||||||
|
|
||||||
|
case TYPE_ERROR:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool valgrt(Value a, Value b)
|
||||||
|
{
|
||||||
|
Type t1 = type_of(a);
|
||||||
|
Type t2 = type_of(b);
|
||||||
|
|
||||||
|
if (t1 != t2)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
switch (t1) {
|
||||||
|
|
||||||
|
case TYPE_NONE:
|
||||||
|
return VALUE_FALSE;
|
||||||
|
|
||||||
|
case TYPE_BOOL:
|
||||||
|
return VALUE_FALSE;
|
||||||
|
|
||||||
|
case TYPE_INT:
|
||||||
|
return get_int(a) > get_int(b);
|
||||||
|
|
||||||
|
case TYPE_FLOAT:
|
||||||
|
return get_float(a) > get_float(b);
|
||||||
|
|
||||||
|
case TYPE_MAP:
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case TYPE_ARRAY:
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case TYPE_STRING:
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case TYPE_ERROR:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char *dst;
|
||||||
|
int max;
|
||||||
|
int len;
|
||||||
|
} ToStringContext;
|
||||||
|
|
||||||
|
static void tostr_appends(ToStringContext *tostr, String x)
|
||||||
|
{
|
||||||
|
if (tostr->max > tostr->len) {
|
||||||
|
int cpy = tostr->max - tostr->len;
|
||||||
|
if (cpy > x.len)
|
||||||
|
cpy = x.len;
|
||||||
|
memcpy(tostr->dst + tostr->len, x.ptr, cpy);
|
||||||
|
}
|
||||||
|
tostr->len += x.len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tostr_appendi(ToStringContext *tostr, int64_t x)
|
||||||
|
{
|
||||||
|
int len;
|
||||||
|
if (tostr->max >= tostr->len)
|
||||||
|
len = snprintf(tostr->dst + tostr->len, tostr->max - tostr->len, "%" LLD, x);
|
||||||
|
else
|
||||||
|
len = snprintf(NULL, 0, "%" LLD, x);
|
||||||
|
tostr->len += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tostr_appendf(ToStringContext *tostr, double x)
|
||||||
|
{
|
||||||
|
int len;
|
||||||
|
if (tostr->max >= tostr->len)
|
||||||
|
len = snprintf(tostr->dst + tostr->len, tostr->max - tostr->len, "%f", x);
|
||||||
|
else
|
||||||
|
len = snprintf(NULL, 0, "%f", x);
|
||||||
|
tostr->len += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void value_to_string_inner(Value v, ToStringContext *tostr)
|
||||||
|
{
|
||||||
|
switch (type_of(v)) {
|
||||||
|
|
||||||
|
case TYPE_NONE:
|
||||||
|
tostr_appends(tostr, S("none"));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TYPE_BOOL:
|
||||||
|
// TODO
|
||||||
|
//tostr_appends(tostr, get_bool(v) ? S("true") : S("false"));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TYPE_INT:
|
||||||
|
tostr_appendi(tostr, get_int(v));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TYPE_FLOAT:
|
||||||
|
tostr_appendf(tostr, get_float(v));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TYPE_MAP:
|
||||||
|
{
|
||||||
|
tostr_appends(tostr, S("{ "));
|
||||||
|
MapValue *m = get_map(v);
|
||||||
|
MapItems *batch = &m->head;
|
||||||
|
while (batch) {
|
||||||
|
|
||||||
|
int num = ITEMS_PER_MAP_BATCH;
|
||||||
|
if (batch->next == NULL)
|
||||||
|
num = m->tail_count;
|
||||||
|
|
||||||
|
for (int i = 0; i < num; i++) {
|
||||||
|
value_to_string_inner(batch->keys[i], tostr);
|
||||||
|
tostr_appends(tostr, S(": "));
|
||||||
|
value_to_string_inner(batch->items[i], tostr);
|
||||||
|
tostr_appends(tostr, S(", "));
|
||||||
|
}
|
||||||
|
|
||||||
|
batch = batch->next;
|
||||||
|
}
|
||||||
|
tostr_appends(tostr, S("}"));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TYPE_ARRAY:
|
||||||
|
{
|
||||||
|
ArrayValue *a = get_array(v);
|
||||||
|
ArrayItems *batch = &a->head;
|
||||||
|
int cursor = 0;
|
||||||
|
while (batch) {
|
||||||
|
|
||||||
|
int num = ITEMS_PER_MAP_BATCH;
|
||||||
|
if (batch->next == NULL)
|
||||||
|
num = a->tail_count;
|
||||||
|
|
||||||
|
for (int i = 0; i < num; i++)
|
||||||
|
value_to_string_inner(batch->items[i], tostr);
|
||||||
|
|
||||||
|
batch = batch->next;
|
||||||
|
cursor += num;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TYPE_STRING:
|
||||||
|
tostr_appends(tostr, get_str(v));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TYPE_ERROR:
|
||||||
|
tostr_appends(tostr, S("error"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int value_to_string(Value v, char *dst, int max)
|
||||||
|
{
|
||||||
|
ToStringContext tostr = { dst, max, 0 };
|
||||||
|
value_to_string_inner(v, &tostr);
|
||||||
|
return tostr.len;
|
||||||
|
}
|
||||||
+44
@@ -0,0 +1,44 @@
|
|||||||
|
#ifndef WL_VALUE_INCLUDED
|
||||||
|
#define WL_VALUE_INCLUDED
|
||||||
|
|
||||||
|
#ifndef WL_AMALGAMATION
|
||||||
|
#include "basic.h"
|
||||||
|
#include "includes.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define VALUE_NONE ((Value) 0)
|
||||||
|
#define VALUE_TRUE ((Value) 1)
|
||||||
|
#define VALUE_FALSE ((Value) 2)
|
||||||
|
#define VALUE_ERROR ((Value) 6)
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
TYPE_NONE,
|
||||||
|
TYPE_BOOL,
|
||||||
|
TYPE_INT,
|
||||||
|
TYPE_FLOAT,
|
||||||
|
TYPE_MAP,
|
||||||
|
TYPE_ARRAY,
|
||||||
|
TYPE_STRING,
|
||||||
|
TYPE_ERROR,
|
||||||
|
} Type;
|
||||||
|
|
||||||
|
typedef uint64_t Value;
|
||||||
|
|
||||||
|
Type type_of (Value v);
|
||||||
|
int64_t get_int (Value v);
|
||||||
|
float get_float (Value v);
|
||||||
|
String get_str (Value v);
|
||||||
|
Value make_int (WL_Arena *a, int64_t x);
|
||||||
|
Value make_float (WL_Arena *a, float x);
|
||||||
|
Value make_str (WL_Arena *a, String x);
|
||||||
|
Value make_map (WL_Arena *a);
|
||||||
|
Value make_array (WL_Arena *a);
|
||||||
|
int map_select (Value map, Value key, Value *val);
|
||||||
|
int map_insert (WL_Arena *a, Value map, Value key, Value val);
|
||||||
|
Value* array_select (Value array, int key);
|
||||||
|
int array_append (WL_Arena *a, Value array, Value val);
|
||||||
|
bool valeq (Value a, Value b);
|
||||||
|
bool valgrt (Value a, Value b);
|
||||||
|
int value_to_string(Value v, char *dst, int max);
|
||||||
|
|
||||||
|
#endif // WL_VALUE_INCLUDED
|
||||||
Reference in New Issue
Block a user