Working on the public API

This commit is contained in:
2025-08-05 14:43:27 +02:00
parent 3d2f6cf429
commit 2ce5835021
22 changed files with 7086 additions and 853 deletions
+5 -2
View File
@@ -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
+5573
View File
File diff suppressed because it is too large Load Diff
+67
View File
@@ -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
+53
View File
@@ -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")
+70
View File
@@ -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 -9
View File
@@ -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()
+88 -28
View File
@@ -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,20 +503,22 @@ void assemble_expr(Assembler *a, Node *node, int num_results)
arg = arg->next; arg = arg->next;
} }
if (func->type == NODE_VALUE_SYSVAR) {
String name = func->sval;
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); assert(func->type == NODE_VALUE_VAR);
append_u8(&a->out, OPCODE_CALL); append_u8(&a->out, OPCODE_CALL);
int p = append_u32(&a->out, 0); int p = append_u32(&a->out, 0);
if (num_results == 0)
append_u8(&a->out, OPCODE_GPOP);
else if (num_results != -1) {
append_u8(&a->out, OPCODE_GTRUNC);
append_u32(&a->out, num_results);
}
append_u8(&a->out, OPCODE_GCOALESCE);
FunctionCall *call = alloc(a->a, sizeof(FunctionCall), _Alignof(FunctionCall)); FunctionCall *call = alloc(a->a, sizeof(FunctionCall), _Alignof(FunctionCall));
if (call == NULL) { if (call == NULL) {
assembler_report(a, "Out of memory"); assembler_report(a, "Out of memory");
@@ -533,6 +532,16 @@ void assemble_expr(Assembler *a, Node *node, int num_results)
call->next = scope->calls; call->next = scope->calls;
scope->calls = call; scope->calls = call;
} }
if (num_results == 0)
append_u8(&a->out, OPCODE_GPOP);
else if (num_results != -1) {
append_u8(&a->out, OPCODE_GTRUNC);
append_u32(&a->out, num_results);
}
append_u8(&a->out, OPCODE_GCOALESCE);
}
break; break;
case NODE_OPER_POS: case NODE_OPER_POS:
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
+513 -692
View File
File diff suppressed because it is too large Load Diff
+4 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+25
View 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
View File
@@ -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
View File
@@ -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 = &param_head; Node **param_tail = &param_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
View File
@@ -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
+41
View File
@@ -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;
}
+56
View File
@@ -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
View File
@@ -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
View File
@@ -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