ADD: booleans.

main
bog 2023-08-23 14:40:43 +02:00
parent 768adc4826
commit 6592f2cfe5
30 changed files with 1301 additions and 0 deletions

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
*~*
*\#*
build
doc/build

8
Makefile Normal file
View File

@ -0,0 +1,8 @@
.PHONY: build install tests
build:
meson setup build
meson compile -C build
install: build
meson install -C build

2
doc/Makefile Normal file
View File

@ -0,0 +1,2 @@
all:
sphinx-build . build

2
doc/conf.py Normal file
View File

@ -0,0 +1,2 @@
project = 'WuZ'
html_theme = 'press'

9
doc/index.rst Normal file
View File

@ -0,0 +1,9 @@
WuZ Programming Language
========================
Table of Contents
-----------------
.. toctree::
installation

33
doc/installation.rst Normal file
View File

@ -0,0 +1,33 @@
How to install WuZ
==================
Let's install WuZ !
For now, the only way is to compile it by yourself.
Compiling WuZ using Makefile (aka the easy way)
-----------------------------------------------
You can compile the project using the Makefile
at the repository root.
Then you can install WuZ using the ``make install`` command.
You may need to be root, if so, just do ``sudo make install`` instead.
.. code-block:: bash
make
make install
Et voila ! You are ready to use WuZ.
Compiling WuZ using Meson
---------------------------
If you prefere not to use the provided Makefile,
you can use meson directly.
.. code-block:: bash
meson setup build
meson compile -C build
meson install -C build

46
meson.build Normal file
View File

@ -0,0 +1,46 @@
project(
'WuZ',
'c',
version: '0.0.0',
default_options: [
'warning_level=3'
]
)
flex = find_program('flex')
flex_target = custom_target(
'flex',
input: ['src/lex.l'],
output: ['lex.yy.c'],
command: [
flex, '@INPUT@'
]
)
bison = find_program('bison')
bison_target = custom_target(
'bison',
input: ['src/parser.y'],
output: ['parser.c'],
command: [
bison, '-d', '-o', '@OUTPUT@', '@INPUT@'
]
)
executable(
'wuz',
sources: [
flex_target,
bison_target,
'src/main.c',
'src/node.c',
'src/utils.c',
'src/opcodes.c',
'src/program.c',
'src/value.c',
'src/type.c',
'src/compiler.c',
'src/vm.c',
],
install: true
)

11
src/commons.h Normal file
View File

@ -0,0 +1,11 @@
#ifndef COMMONS_H
#define COMMON_H
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "utils.h"
#include "mutils.h"
#endif

76
src/compiler.c Normal file
View File

@ -0,0 +1,76 @@
#include "compiler.h"
void compiler_init(compiler* self)
{
assert(self);
}
void compiler_free(compiler* self)
{
assert(self);
}
void compile_node(compiler* self, node* root, program* prog)
{
assert(self);
assert(root);
assert(prog);
if (root->type == NODE_BOOLEAN)
{
value val;
value_init_boolean(&val,
strcmp(root->value, "true") == 0,
root->lineno);
size_t idx = program_add_pool(prog, &val);
program_add_instr(prog, OP_PUSH, idx);
value_free(&val);
}
else if (root->type == NODE_ASSERT)
{
compile_children(self, root, prog);
program_add_instr(prog, OP_ASSERT, NO_PARAM);
}
else if (root->type == NODE_EQ)
{
compile_children(self, root, prog);
program_add_instr(prog, OP_EQ, NO_PARAM);
}
else if (root->type == NODE_NE)
{
compile_children(self, root, prog);
program_add_instr(prog, OP_EQ, NO_PARAM);
program_add_instr(prog, OP_NOT, NO_PARAM);
}
else if (root->type == NODE_AND)
{
compile_children(self, root, prog);
program_add_instr(prog, OP_AND, NO_PARAM);
}
else if (root->type == NODE_OR)
{
compile_children(self, root, prog);
program_add_instr(prog, OP_OR, NO_PARAM);
}
else if (root->type == NODE_NOT)
{
compile_children(self, root, prog);
program_add_instr(prog, OP_NOT, NO_PARAM);
}
else
{
compile_children(self, root, prog);
}
}
void compile_children(compiler* self, node* root, program* prog)
{
assert(self);
assert(root);
assert(prog);
for (size_t i=0; i<root->children.size; i++)
{
compile_node(self, root->children.data[i], prog);
}
}

18
src/compiler.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef COMPILER_H
#define COMPILER_H
#include "commons.h"
#include "program.h"
#include "node.h"
typedef struct {
int _unused;
} compiler;
void compiler_init(compiler* self);
void compiler_free(compiler* self);
void compile_node(compiler* self, node* root, program* prog);
void compile_children(compiler* self, node* root, program* prog);
#endif

38
src/lex.l Normal file
View File

@ -0,0 +1,38 @@
%{
#include "parser.h"
#include "src/utils.h"
int line = 1;
%}
%option noyywrap
%option nounput
%option noinput
COMMENT ::[^\n]*
WHITESPACES [ \t]+
BOOLEAN true|false
%%
"\n" { line++; }
{COMMENT} {}
{WHITESPACES} {}
"assert" { return ASSERT; }
"==" { return EQ; }
"!=" { return NE; }
"&&" { return AND; }
"||" { return OR; }
"!" { return NOT; }
"(" { return OPAR; }
")" { return CPAR; }
{BOOLEAN} {
yylval.boolean = yytext;
return BOOLEAN;
}
. {
fprintf(stderr, "E(%d): Lexical error near '%s'.\n", line, yytext);
exit(-1);
}
%%

70
src/main.c Normal file
View File

@ -0,0 +1,70 @@
#include <stdio.h>
#include "node.h"
#include "parser.h"
#include "compiler.h"
#include "vm.h"
extern FILE* yyin;
extern node* ast;
extern void stack_push(node*);
extern node* stack_pop();
extern void stack_free();
int main(int argc, char** argv)
{
if (argc > 1)
{
yyin = fopen(argv[1], "r");
node* n = malloc(sizeof(node));
node_init(n, NODE_PROG, "", 1);
stack_push(n);
yyparse();
ast = stack_pop();
stack_free();
compiler comp;
compiler_init(&comp);
program prog;
program_init(&prog);
compile_node(&comp, ast, &prog);
vm v;
vm_init(&v);
vm_exec(&v, &prog);
if (0) // DEBUG
{
size_t const BUF = 1024;
char buffer[BUF];
node_str(ast, buffer, BUF);
printf("-- ast ---\n%s\n\n", buffer);
program_str(&prog, buffer, BUF);
printf("--- program ---\n%s\n", buffer);
vm_str(&v, buffer, BUF);
printf("--- stack ---\n%s\n", buffer);
}
vm_free(&v);
program_free(&prog);
compiler_free(&comp);
node_free(ast);
fclose(yyin);
return 0;
}
fprintf(stderr, "Usage: wuz <filename>\n");
return -1;
}

7
src/mutils.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef MUTILS_H
#define MUTILS_H
#define GEN_ENUM(X) X
#define GEN_STRING(X) #X
#endif

96
src/node.c Normal file
View File

@ -0,0 +1,96 @@
#include "node.h"
char const* NodeTypeStr[] = {
NODE_TYPE(GEN_STRING)
};
void node_init(node* self, int type, char const* value, int lineno)
{
assert(self);
self->type = type;
self->lineno = lineno;
self->value = str_new(value);
self->children.data = NULL;
self->children.size = 0;
self->children.capacity = 0;
}
void node_free(node* self)
{
assert(self);
assert(self->value);
free(self->value);
self->value = NULL;
for (size_t i=0; i<self->children.size; i++)
{
node_free(self->children.data[i]);
free(self->children.data[i]);
}
free(self->children.data);
self->children.data = NULL;
self->children.size = 0;
self->children.capacity = 0;
}
void node_add_child(node* self, node* child)
{
assert(self);
assert(child);
if (self->children.capacity == 0)
{
self->children.capacity = 1;
self->children.data = malloc(sizeof(node*)
* self->children.capacity);
}
else if (self->children.size >= self->children.capacity)
{
self->children.capacity *= 2;
self->children.data = realloc(self->children.data,
sizeof(node*)
* self->children.capacity);
}
self->children.data[self->children.size] = child;
self->children.size++;
}
size_t node_str(node* self, char* buffer, size_t size)
{
assert(self);
size_t sz = 0;
char const* ty = NodeTypeStr[self->type] + strlen("NODE_");
sz += snprintf(buffer + sz, size - sz, "%s", ty);
if (strcmp(self->value, "") != 0)
{
sz += snprintf(buffer + sz, size - sz, "[%s]", self->value);
}
if (self->children.size > 0)
{
sz += snprintf(buffer + sz, size - sz, "(");
for (size_t i=0; i<self->children.size; i++)
{
if (i > 0)
{
sz += snprintf(buffer + sz, size - sz, ",");
}
sz += node_str(self->children.data[i],
buffer + sz,
size - sz);
}
sz += snprintf(buffer + sz, size - sz, ")");
}
return sz;
}

39
src/node.h Normal file
View File

@ -0,0 +1,39 @@
#ifndef NODE_H
#define NODE_H
#define NODE_TYPE(G) \
G(NODE_PROG), \
G(NODE_BOOLEAN), \
G(NODE_AND), G(NODE_OR), G(NODE_NOT), \
G(NODE_EQ), G(NODE_NE), \
G(NODE_ASSERT)
#include "mutils.h"
#include "commons.h"
enum NodeType {
NODE_TYPE(GEN_ENUM)
};
extern char const* NodeTypeStr[];
typedef struct node {
int type;
char* value;
struct {
size_t capacity;
size_t size;
struct node** data;
} children;
int lineno;
} node;
void node_init(node* self, int type, char const* value, int lineno);
void node_free(node* self);
void node_add_child(node* self, node* child);
size_t node_str(node* self, char* buffer, size_t size);
#endif

5
src/opcodes.c Normal file
View File

@ -0,0 +1,5 @@
#include "opcodes.h"
char const* OpcodesStr[] = {
OPCODES(GEN_STRING)
};

17
src/opcodes.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef OPCODES_H
#define OPCODES_H
#include "mutils.h"
#define OPCODES(G) \
G(OP_PUSH), \
G(OP_AND), G(OP_OR), G(OP_NOT), \
G(OP_EQ), G(OP_ASSERT)
enum Opcodes {
OPCODES(GEN_ENUM)
};
extern char const* OpcodesStr[];
#endif

163
src/parser.y Normal file
View File

@ -0,0 +1,163 @@
%{
#include <stdio.h>
#include <stdlib.h>
#include "src/node.h"
extern int line;
void yyerror(char const*);
node* ast = NULL;
node** stack = NULL;
size_t stack_sz = 0;
size_t stack_cap = 0;
void stack_push(node* n);
node* stack_pop();
node* stack_top();
void stack_free();
%}
%union {
char* boolean;
void* node_val;
};
%left ASSERT
%token <boolean> BOOLEAN
%left EQ NE
%left AND
%left OR
%left NOT
%type <node_val> expr;
%token OPAR CPAR
%%
prog: exprs {
}
;
exprs:
exprs expr {
node* parent = stack_top();
node_add_child(parent, $2);
}
| expr {
node* parent = stack_top();
node_add_child(parent, $1);
}
;
expr:
ASSERT expr {
node *n = malloc(sizeof(node));
node_init(n, NODE_ASSERT, "", line);
node_add_child(n, $2);
$$ = n;
}
| expr EQ expr {
node *n = malloc(sizeof(node));
node_init(n, NODE_EQ, "", line);
node_add_child(n, $1);
node_add_child(n, $3);
$$ = n;
}
| expr NE expr {
node *n = malloc(sizeof(node));
node_init(n, NODE_NE, "", line);
node_add_child(n, $1);
node_add_child(n, $3);
$$ = n;
}
| expr AND expr {
node *n = malloc(sizeof(node));
node_init(n, NODE_AND, "", line);
node_add_child(n, $1);
node_add_child(n, $3);
$$ = n;
}
| expr OR expr {
node *n = malloc(sizeof(node));
node_init(n, NODE_OR, "", line);
node_add_child(n, $1);
node_add_child(n, $3);
$$ = n;
}
| NOT expr {
node *n = malloc(sizeof(node));
node_init(n, NODE_NOT, "", line);
node_add_child(n, $2);
$$ = n;
}
| OPAR expr CPAR {
$$ = $2;
}
| BOOLEAN {
node* n = malloc(sizeof(node));
node_init(n, NODE_BOOLEAN, $1, line);
$$ = n;
}
;
%%
void yyerror(char const* msg)
{
fprintf(stderr, "E(%d): %s\n", line, msg);
exit(-1);
}
void stack_push(node* n)
{
if (stack_cap == 0)
{
stack = malloc(sizeof(node*));
stack_cap = 1;
}
else if (stack_sz >= stack_cap)
{
stack_cap *= 2;
stack = realloc(stack, sizeof(node*) * stack_cap);
}
stack[stack_sz] = n;
stack_sz++;
}
node* stack_pop()
{
assert(stack_sz > 0);
node* n = stack[stack_sz - 1];
stack_sz--;
return n;
}
node* stack_top()
{
assert(stack_sz > 0);
node* n = stack[stack_sz - 1];
return n;
}
void stack_free()
{
for (size_t i=0; i<stack_sz; i++)
{
node_free(stack[i]);
free(stack[i]);
}
free(stack);
stack = NULL;
}

133
src/program.c Normal file
View File

@ -0,0 +1,133 @@
#include "program.h"
void program_init(program* self)
{
assert(self);
self->instrs.size = 0;
self->instrs.capacity = 0;
self->instrs.data = NULL;
self->pool.size = 0;
self->pool.capacity = 0;
self->pool.data = NULL;
}
void program_free(program* self)
{
assert(self);
for (size_t i=0; i<self->instrs.size; i++)
{
free(self->instrs.data[i]);
}
free(self->instrs.data);
self->instrs.data = NULL;
self->instrs.size = 0;
self->instrs.capacity = 0;
for (size_t i=0; i<self->pool.size; i++)
{
value_free(self->pool.data[i]);
free(self->pool.data[i]);
}
free(self->pool.data);
self->pool.data = NULL;
self->pool.size = 0;
self->pool.capacity = 0;
}
void program_add_instr(program* self, int opcode, int param)
{
assert(self);
if (self->instrs.capacity == 0)
{
self->instrs.capacity = 1;
self->instrs.data = malloc(sizeof(instr*)
* self->instrs.capacity);
}
else if (self->instrs.size >= self->instrs.capacity)
{
self->instrs.capacity *= 2;
self->instrs.data = realloc(
self->instrs.data,
sizeof(instr) * self->instrs.capacity
);
}
size_t idx = self->instrs.size;
self->instrs.data[idx] = malloc(sizeof(instr));
self->instrs.data[idx]->opcode = opcode;
self->instrs.data[idx]->param = param;
self->instrs.size++;
}
size_t program_add_pool(program* self, value* val)
{
assert(self);
assert(val);
if (self->pool.capacity == 0)
{
self->pool.capacity = 1;
self->pool.data = malloc(sizeof(value*)
* self->pool.capacity);
}
else if (self->pool.size >= self->pool.capacity)
{
self->pool.capacity *= 2;
self->pool.data = realloc(
self->pool.data,
sizeof(value) * self->pool.capacity
);
}
size_t idx = self->pool.size;
self->pool.data[idx] = value_new_clone(val);
self->pool.size++;
return idx;
}
size_t program_str(program* self, char* buffer, size_t size)
{
assert(self);
size_t sz = 0;
for (size_t i=0; i<self->instrs.size; i++)
{
int opcode = self->instrs.data[i]->opcode;
int param = self->instrs.data[i]->param;
if (param != NO_PARAM)
{
sz += snprintf(buffer + sz, size - sz, "%ld\t%s\t%d",
i,
OpcodesStr[opcode]
+ strlen("OP_"),
param);
}
else
{
sz += snprintf(buffer + sz, size - sz, "%ld\t%s\t",
i,
OpcodesStr[opcode]
+ strlen("OP_"));
}
if (opcode == OP_PUSH && param != -1)
{
sz += snprintf(buffer + sz, size - sz, "\t (");
sz += value_str(self->pool.data[param],
buffer + sz, size - sz);
sz += snprintf(buffer + sz, size - sz, ")");
}
sz += snprintf(buffer + sz, size - sz, "\n");
}
return sz;
}

37
src/program.h Normal file
View File

@ -0,0 +1,37 @@
#ifndef PROGRAM_H
#define PROGRAM_H
#include "commons.h"
#include "opcodes.h"
#include "value.h"
#define NO_PARAM (-1)
typedef struct {
int opcode;
int param;
} instr;
typedef struct {
struct {
size_t capacity;
size_t size;
instr** data;
} instrs;
struct {
size_t capacity;
size_t size;
value** data;
} pool;
} program;
void program_init(program* self);
void program_free(program* self);
void program_add_instr(program* self, int opcode, int param);
size_t program_add_pool(program* self, value* val);
size_t program_str(program* self, char* buffer, size_t size);
#endif

39
src/type.c Normal file
View File

@ -0,0 +1,39 @@
#include "type.h"
char const* TypesStr[] = { TYPES(GEN_STRING) };
void type_init(type* self, int base_type)
{
assert(self);
self->base_type = base_type;
}
void type_free(type* self)
{
assert(self);
}
type* type_new_clone(type* self)
{
assert(self);
type* clone = malloc(sizeof(type));
type_init(clone, self->base_type);
return clone;
}
int type_equals(type* self, type* rhs)
{
assert(self);
assert(rhs);
return self->base_type == rhs->base_type;
}
size_t type_str(type* self, char* buffer, size_t size)
{
assert(self);
return snprintf(buffer, size, "%s", TypesStr[self->base_type]);
}

26
src/type.h Normal file
View File

@ -0,0 +1,26 @@
#ifndef TYPE_H
#define TYPE
#include "commons.h"
#define TYPES(G) \
G(TY_BOOLEAN)
enum Types {
TYPES(GEN_ENUM)
};
extern char const* TypesStr[];
typedef struct type {
int base_type;
} type;
void type_init(type* self, int base_type);
void type_free(type* self);
type* type_new_clone(type* self);
int type_equals(type* self, type* rhs);
size_t type_str(type* self, char* buffer, size_t size);
#endif

12
src/utils.c Normal file
View File

@ -0,0 +1,12 @@
#include "utils.h"
char const* str_new(char const* str)
{
size_t len = strlen(str) + 1;
char* result = malloc(len);
memcpy(result, str, len);
return result;
}

7
src/utils.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef UTILS_H
#define UTILS_H
#include <string.h>
char const* str_new(char const* str);
#endif

73
src/value.c Normal file
View File

@ -0,0 +1,73 @@
#include "value.h"
void value_init_boolean(value* self, int boolean, int lineno)
{
assert(self);
self->val.boolean = boolean;
self->lineno = lineno;
self->type = malloc(sizeof(type));
type_init(self->type, TY_BOOLEAN);
}
void value_free(value* self)
{
assert(self);
type_free(self->type);
free(self->type);
self->type = NULL;
}
value* value_new_clone(value* self)
{
assert(self);
value* clone = malloc(sizeof(value));
clone->type = type_new_clone(self->type);
clone->val = self->val;
clone->lineno = self->lineno;
return clone;
}
int value_equals(value* self, value* rhs)
{
assert(self);
assert(rhs);
if (!type_equals(self->type, rhs->type))
{
return 0;
}
if (self->type->base_type == TY_BOOLEAN)
{
return self->val.boolean == rhs->val.boolean;
}
size_t const SZ = 512;
char ty_str[SZ];
type_str(self->type, ty_str, SZ);
fprintf(stderr, "E: cannot test value equality: unknown type '%s'\n",
ty_str);
exit(-1);
}
size_t value_str(value* self, char* buffer, size_t size)
{
assert(self);
switch (self->type->base_type)
{
case TY_BOOLEAN:
return snprintf(buffer, size, "%s",
self->val.boolean == 0
? "false" : "true");
default: {
fprintf(stderr, "E: unknown value");
exit(-1);
}
}
}

23
src/value.h Normal file
View File

@ -0,0 +1,23 @@
#ifndef VALUE_H
#define VALUE_H
#include "commons.h"
#include "type.h"
typedef struct {
type* type;
int lineno;
union {
int boolean;
} val;
} value;
void value_init_boolean(value* self, int boolean, int lineno);
void value_free(value* self);
value* value_new_clone(value* self);
int value_equals(value* self, value* rhs);
size_t value_str(value* self, char* buffer, size_t size);
#endif

200
src/vm.c Normal file
View File

@ -0,0 +1,200 @@
#include "vm.h"
void vm_init(vm* self)
{
assert(self);
self->stack.size = 0;
self->stack.capacity = 1;
self->stack.data = malloc(sizeof(value*) * self->stack.capacity);
self->prog = NULL;
self->pc = 0;
}
void vm_free(vm* self)
{
assert(self);
for (size_t i=0; i<self->stack.size; i++)
{
value_free(self->stack.data[i]);
free(self->stack.data[i]);
}
free(self->stack.data);
self->stack.size = 0;
self->stack.capacity = 0;
self->stack.data = NULL;
}
void vm_exec(vm* self, program* prog)
{
assert(self);
assert(prog);
self->prog = prog;
while (self->pc < prog->instrs.size)
{
int opcode = prog->instrs.data[self->pc]->opcode;
int param = prog->instrs.data[self->pc]->param;
switch (opcode)
{
case OP_PUSH: vm_push(self, param); break;
case OP_AND: vm_and(self); break;
case OP_OR: vm_or(self); break;
case OP_NOT: vm_not(self); break;
case OP_EQ: vm_eq(self); break;
case OP_ASSERT: vm_assert(self); break;
default: {
fprintf(stderr, "unknown opcode %s\n",
OpcodesStr[opcode]);
exit(-1);
}
}
}
}
void vm_push_value(vm* self, value* val)
{
assert(self);
if (self->stack.size >= self->stack.capacity)
{
self->stack.capacity *= 2;
self->stack.data = realloc(
self->stack.data,
sizeof(value*) * self->stack.capacity
);
}
self->stack.data[self->stack.size] = val;
self->stack.size++;
}
value* vm_pop_value(vm* self)
{
assert(self);
assert(self->stack.size > 0);
value* val = self->stack.data[self->stack.size - 1];
self->stack.size--;
return val;
}
size_t vm_str(vm* self, char* buffer, size_t size)
{
assert(self);
size_t sz = 0;
for (size_t i=0; i<self->stack.size; i++)
{
sz += snprintf(buffer + sz, size - sz,
"%ld\t", i);
sz += value_str(self->stack.data[i], buffer + sz, size - sz);
sz += snprintf(buffer + sz, size - sz,
"\n");
}
return sz;
}
void vm_push(vm* self, int param)
{
assert(self);
assert(param >= 0);
value* val = self->prog->pool.data[param];
vm_push_value(self, value_new_clone(val));
self->pc++;
}
void vm_and(vm* self)
{
value* rhs = vm_pop_value(self);
value* lhs = vm_pop_value(self);
value* val = malloc(sizeof(value));
value_init_boolean(val, lhs->val.boolean && rhs->val.boolean, lhs->lineno);
vm_push_value(self, val);
value_free(rhs);
free(rhs);
value_free(lhs);
free(lhs);
self->pc++;
}
void vm_or(vm* self)
{
value* rhs = vm_pop_value(self);
value* lhs = vm_pop_value(self);
value* val = malloc(sizeof(value));
value_init_boolean(val, lhs->val.boolean || rhs->val.boolean, lhs->lineno);
vm_push_value(self, val);
value_free(rhs);
free(rhs);
value_free(lhs);
free(lhs);
self->pc++;
}
void vm_not(vm* self)
{
value* lhs = vm_pop_value(self);
value* val = malloc(sizeof(value));
value_init_boolean(val, !lhs->val.boolean, lhs->lineno);
vm_push_value(self, val);
value_free(lhs);
free(lhs);
self->pc++;
}
void vm_eq(vm* self)
{
assert(self);
value* rhs = vm_pop_value(self);
value* lhs = vm_pop_value(self);
value* val = malloc(sizeof(value));
value_init_boolean(val, value_equals(lhs, rhs), lhs->lineno);
vm_push_value(self, val);
value_free(lhs); free(lhs);
value_free(rhs); free(rhs);
self->pc++;
}
void vm_assert(vm* self)
{
assert(self);
value* lhs = vm_pop_value(self);
if (!lhs->val.boolean)
{
fprintf(stderr, "E(%d): assertion failed\n", lhs->lineno);
exit(-1);
}
value_free(lhs); free(lhs);
self->pc++;
}

37
src/vm.h Normal file
View File

@ -0,0 +1,37 @@
#ifndef VM_H
#define VM_H
#include "commons.h"
#include "value.h"
#include "program.h"
typedef struct {
struct {
size_t capacity;
size_t size;
value** data;
} stack;
size_t pc;
program* prog;
} vm;
void vm_init(vm* self);
void vm_free(vm* self);
void vm_exec(vm* self, program* prog);
void vm_push_value(vm* self, value* val);
value* vm_pop_value(vm* self);
size_t vm_str(vm* self, char* buffer, size_t size);
void vm_push(vm* self, int param);
void vm_and(vm* self);
void vm_or(vm* self);
void vm_not(vm* self);
void vm_eq(vm* self);
void vm_assert(vm* self);
#endif

39
tests/booleans.wuz Normal file
View File

@ -0,0 +1,39 @@
:: not operator
assert true
assert !false
assert !!true
:: equal operator
:: ==============
:: and operator
assert true == true && true
assert false == true && false
assert false == false && true
assert false == false && false
:: or operator
assert true == true || true
assert true == true || false
assert true == false || true
assert false == false || false
:: not equal operator
:: ==================
:: and operator
assert false != true && true
assert true != true && false
assert true != false && true
assert true != false && false
:: or operator
assert false != true || true
assert false != true || false
assert false != false || true
assert true != false || false
:: groups
assert !(true && false) == false || true
assert !(true || false) == false && true

31
tests/run.sh Executable file
View File

@ -0,0 +1,31 @@
#!/bin/sh
OK=0
KO=0
for file in $(find . -name "*.wuz")
do
wuz $file
RES="$?"
echo -n "$file ... "
if [ "$RES" == "0" ]
then
echo -e "\e[32mok\e[0m"
OK=$(($OK + 1))
else
echo -e "\e[31mko\e[0m"
KO=$(($KO+1))
fi
done
TOTAL=$(($OK+$KO))
if [ $KO -eq 0 ]
then
echo -e "\e[32mAll tests passed [$TOTAL]\e[0m"
else
echo -e "\e[31m$KO tests failed [$TOTAL]\e[0m"
fi