parent
6592f2cfe5
commit
32c0bb8352
|
@ -26,6 +26,10 @@ bison_target = custom_target(
|
|||
bison, '-d', '-o', '@OUTPUT@', '@INPUT@'
|
||||
]
|
||||
)
|
||||
|
||||
cc = meson.get_compiler('c')
|
||||
m_dep = cc.find_library('m')
|
||||
|
||||
executable(
|
||||
'wuz',
|
||||
sources: [
|
||||
|
@ -39,8 +43,12 @@ executable(
|
|||
'src/value.c',
|
||||
'src/type.c',
|
||||
'src/compiler.c',
|
||||
'src/cstatic.c',
|
||||
'src/vm.c',
|
||||
],
|
||||
dependencies: [
|
||||
m_dep
|
||||
],
|
||||
install: true
|
||||
)
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef COMMONS_H
|
||||
#define COMMON_H
|
||||
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
|
|
@ -26,11 +26,61 @@ void compile_node(compiler* self, node* root, program* prog)
|
|||
program_add_instr(prog, OP_PUSH, idx);
|
||||
value_free(&val);
|
||||
}
|
||||
else if (root->type == NODE_INTEGER)
|
||||
{
|
||||
value val;
|
||||
value_init_integer(&val,
|
||||
atoi(root->value),
|
||||
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_UADD)
|
||||
{
|
||||
compile_children(self, root, prog);
|
||||
program_add_instr(prog, OP_IUADD, NO_PARAM);
|
||||
}
|
||||
else if (root->type == NODE_USUB)
|
||||
{
|
||||
compile_children(self, root, prog);
|
||||
program_add_instr(prog, OP_IUSUB, NO_PARAM);
|
||||
}
|
||||
else if (root->type == NODE_ADD)
|
||||
{
|
||||
compile_children(self, root, prog);
|
||||
program_add_instr(prog, OP_IADD, NO_PARAM);
|
||||
}
|
||||
else if (root->type == NODE_SUB)
|
||||
{
|
||||
compile_children(self, root, prog);
|
||||
program_add_instr(prog, OP_ISUB, NO_PARAM);
|
||||
}
|
||||
else if (root->type == NODE_MUL)
|
||||
{
|
||||
compile_children(self, root, prog);
|
||||
program_add_instr(prog, OP_IMUL, NO_PARAM);
|
||||
}
|
||||
else if (root->type == NODE_DIV)
|
||||
{
|
||||
compile_children(self, root, prog);
|
||||
program_add_instr(prog, OP_IDIV, NO_PARAM);
|
||||
}
|
||||
else if (root->type == NODE_MOD)
|
||||
{
|
||||
compile_children(self, root, prog);
|
||||
program_add_instr(prog, OP_IMOD, NO_PARAM);
|
||||
}
|
||||
else if (root->type == NODE_POW)
|
||||
{
|
||||
compile_children(self, root, prog);
|
||||
program_add_instr(prog, OP_IPOW, NO_PARAM);
|
||||
}
|
||||
else if (root->type == NODE_EQ)
|
||||
{
|
||||
compile_children(self, root, prog);
|
||||
|
|
|
@ -0,0 +1,210 @@
|
|||
#include "cstatic.h"
|
||||
#include "type.h"
|
||||
|
||||
void cstatic_init(cstatic* self)
|
||||
{
|
||||
assert(self);
|
||||
}
|
||||
|
||||
void cstatic_free(cstatic* self)
|
||||
{
|
||||
assert(self);
|
||||
}
|
||||
|
||||
int cstatic_resolve(cstatic* self, node* ast)
|
||||
{
|
||||
assert(self);
|
||||
assert(ast);
|
||||
|
||||
if (ast->type == NODE_INTEGER)
|
||||
{
|
||||
return TY_INTEGER;
|
||||
}
|
||||
else if (ast->type == NODE_BOOLEAN
|
||||
|| ast->type == NODE_EQ
|
||||
|| ast->type == NODE_NE)
|
||||
{
|
||||
return TY_BOOLEAN;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (size_t i=0; i<ast->children.size; i++)
|
||||
{
|
||||
int ty = cstatic_resolve(self, ast->children.data[i]);
|
||||
|
||||
if (ty != TY_NIL)
|
||||
{
|
||||
return ty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return TY_NIL;
|
||||
}
|
||||
|
||||
int cstatic_check(cstatic* self, node* ast, char* msg, size_t size)
|
||||
{
|
||||
assert(self);
|
||||
assert(ast);
|
||||
|
||||
// Children
|
||||
for (size_t i=0; i<ast->children.size; i++)
|
||||
{
|
||||
int status = cstatic_check(self, ast->children.data[i],
|
||||
msg, size);
|
||||
|
||||
if (!status)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Integer Binops
|
||||
if (ast->type == NODE_EQ
|
||||
|| ast->type == NODE_NE)
|
||||
{
|
||||
int status = cstatic_check_same_type(self,
|
||||
ast->children.data[0],
|
||||
ast->children.data[1],
|
||||
msg,
|
||||
size);
|
||||
|
||||
if (!status)
|
||||
{
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
// Boolean Unops
|
||||
else if (ast->type == NODE_ASSERT
|
||||
|| ast->type == NODE_NOT)
|
||||
{
|
||||
int status = cstatic_check_type(self,
|
||||
ast->children.data[0],
|
||||
TY_BOOLEAN,
|
||||
msg,
|
||||
size);
|
||||
|
||||
if (!status)
|
||||
{
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
// Boolean Binops
|
||||
else if (ast->type == NODE_AND
|
||||
|| ast->type == NODE_OR)
|
||||
{
|
||||
int status = cstatic_check_same_type(self,
|
||||
ast->children.data[0],
|
||||
ast->children.data[1],
|
||||
msg,
|
||||
size);
|
||||
|
||||
if (!status)
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
status = cstatic_check_type(self,
|
||||
ast->children.data[0],
|
||||
TY_BOOLEAN,
|
||||
msg,
|
||||
size);
|
||||
if (!status)
|
||||
{
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
// Integer Unops
|
||||
else if (ast->type == NODE_UADD
|
||||
|| ast->type == NODE_USUB)
|
||||
{
|
||||
int status = cstatic_check_type(self,
|
||||
ast->children.data[0],
|
||||
TY_INTEGER,
|
||||
msg,
|
||||
size);
|
||||
if (!status)
|
||||
{
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
// Integer Binops
|
||||
else if (ast->type == NODE_ADD
|
||||
|| ast->type == NODE_SUB
|
||||
|| ast->type == NODE_MUL
|
||||
|| ast->type == NODE_DIV
|
||||
|| ast->type == NODE_MOD
|
||||
|| ast->type == NODE_POW
|
||||
)
|
||||
{
|
||||
int status = cstatic_check_same_type(self,
|
||||
ast->children.data[0],
|
||||
ast->children.data[1],
|
||||
msg,
|
||||
size);
|
||||
|
||||
if (!status)
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
status = cstatic_check_type(self,
|
||||
ast->children.data[0],
|
||||
TY_INTEGER,
|
||||
msg,
|
||||
size);
|
||||
if (!status)
|
||||
{
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int cstatic_check_type(cstatic* self, node* lhs, int rhs,
|
||||
char* msg, size_t size)
|
||||
{
|
||||
assert(self);
|
||||
assert(lhs);
|
||||
|
||||
int left = cstatic_resolve(self, lhs);
|
||||
|
||||
if (left != rhs)
|
||||
{
|
||||
snprintf(msg, size, "E(%d): expected '%s', got '%s'.",
|
||||
lhs->lineno,
|
||||
TypesStr[left],
|
||||
TypesStr[rhs]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int cstatic_check_same_type(cstatic* self, node* lhs, node* rhs,
|
||||
char* msg, size_t size)
|
||||
{
|
||||
assert(self);
|
||||
assert(lhs);
|
||||
assert(rhs);
|
||||
|
||||
int left = cstatic_resolve(self, lhs);
|
||||
int right = cstatic_resolve(self, rhs);
|
||||
|
||||
if (left != right)
|
||||
{
|
||||
snprintf(msg, size, "E(%d): expected '%s', got '%s'.",
|
||||
lhs->lineno,
|
||||
TypesStr[left],
|
||||
TypesStr[right]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
#ifndef CSTATIC_H
|
||||
#define CSTATIC_H
|
||||
|
||||
#include "commons.h"
|
||||
#include "node.h"
|
||||
|
||||
typedef struct {
|
||||
int _unused;
|
||||
} cstatic;
|
||||
|
||||
void cstatic_init(cstatic* self);
|
||||
void cstatic_free(cstatic* self);
|
||||
|
||||
int cstatic_resolve(cstatic* self, node* ast);
|
||||
int cstatic_check(cstatic* self, node* ast, char* msg, size_t size);
|
||||
|
||||
int cstatic_check_type(cstatic* self, node* lhs, int rhs,
|
||||
char* msg, size_t size);
|
||||
|
||||
int cstatic_check_same_type(cstatic* self, node* lhs, node* rhs,
|
||||
char* msg, size_t size);
|
||||
|
||||
#endif
|
17
src/lex.l
17
src/lex.l
|
@ -10,6 +10,7 @@
|
|||
COMMENT ::[^\n]*
|
||||
WHITESPACES [ \t]+
|
||||
BOOLEAN true|false
|
||||
INTEGER -?[0-9]+
|
||||
|
||||
%%
|
||||
"\n" { line++; }
|
||||
|
@ -17,6 +18,13 @@ BOOLEAN true|false
|
|||
{WHITESPACES} {}
|
||||
|
||||
"assert" { return ASSERT; }
|
||||
"+" { return ADD; }
|
||||
"-" { return SUB; }
|
||||
"*" { return MUL; }
|
||||
"/" { return DIV; }
|
||||
"%" { return MOD; }
|
||||
"^" { return POW; }
|
||||
|
||||
"==" { return EQ; }
|
||||
"!=" { return NE; }
|
||||
"&&" { return AND; }
|
||||
|
@ -26,9 +34,16 @@ BOOLEAN true|false
|
|||
")" { return CPAR; }
|
||||
|
||||
{BOOLEAN} {
|
||||
yylval.boolean = yytext;
|
||||
yylval.str = yytext;
|
||||
return BOOLEAN;
|
||||
}
|
||||
|
||||
{INTEGER} {
|
||||
yylval.str = yytext;
|
||||
return INTEGER;
|
||||
}
|
||||
|
||||
|
||||
. {
|
||||
fprintf(stderr, "E(%d): Lexical error near '%s'.\n", line, yytext);
|
||||
exit(-1);
|
||||
|
|
30
src/main.c
30
src/main.c
|
@ -3,6 +3,7 @@
|
|||
#include "parser.h"
|
||||
#include "compiler.h"
|
||||
#include "vm.h"
|
||||
#include "cstatic.h"
|
||||
|
||||
extern FILE* yyin;
|
||||
extern node* ast;
|
||||
|
@ -15,6 +16,11 @@ int main(int argc, char** argv)
|
|||
if (argc > 1)
|
||||
{
|
||||
yyin = fopen(argv[1], "r");
|
||||
}
|
||||
else
|
||||
{
|
||||
yyin = stdin;
|
||||
}
|
||||
|
||||
node* n = malloc(sizeof(node));
|
||||
node_init(n, NODE_PROG, "", 1);
|
||||
|
@ -25,6 +31,21 @@ int main(int argc, char** argv)
|
|||
ast = stack_pop();
|
||||
stack_free();
|
||||
|
||||
// Static checking
|
||||
cstatic cs;
|
||||
cstatic_init(&cs);
|
||||
size_t const SZ = 512;
|
||||
char msg[SZ];
|
||||
|
||||
int status = cstatic_check(&cs, ast, msg, SZ);
|
||||
|
||||
if (!status)
|
||||
{
|
||||
fprintf(stderr, "%s\n", msg);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
// Compilation
|
||||
compiler comp;
|
||||
compiler_init(&comp);
|
||||
|
||||
|
@ -33,6 +54,7 @@ int main(int argc, char** argv)
|
|||
|
||||
compile_node(&comp, ast, &prog);
|
||||
|
||||
// Execution
|
||||
vm v;
|
||||
vm_init(&v);
|
||||
|
||||
|
@ -57,14 +79,14 @@ int main(int argc, char** argv)
|
|||
|
||||
program_free(&prog);
|
||||
compiler_free(&comp);
|
||||
cstatic_free(&cs);
|
||||
node_free(ast);
|
||||
|
||||
if (argc > 1)
|
||||
{
|
||||
fclose(yyin);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
fprintf(stderr, "Usage: wuz <filename>\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
|
@ -3,10 +3,13 @@
|
|||
|
||||
#define NODE_TYPE(G) \
|
||||
G(NODE_PROG), \
|
||||
G(NODE_BOOLEAN), \
|
||||
G(NODE_BOOLEAN), G(NODE_INTEGER), \
|
||||
G(NODE_AND), G(NODE_OR), G(NODE_NOT), \
|
||||
G(NODE_EQ), G(NODE_NE), \
|
||||
G(NODE_ASSERT)
|
||||
G(NODE_ASSERT), \
|
||||
G(NODE_UADD), G(NODE_USUB), G(NODE_ADD), G(NODE_SUB), \
|
||||
G(NODE_MUL), G(NODE_DIV), G(NODE_MOD), G(NODE_POW)
|
||||
|
||||
|
||||
#include "mutils.h"
|
||||
#include "commons.h"
|
||||
|
|
|
@ -5,8 +5,19 @@
|
|||
|
||||
#define OPCODES(G) \
|
||||
G(OP_PUSH), \
|
||||
G(OP_AND), G(OP_OR), G(OP_NOT), \
|
||||
G(OP_EQ), G(OP_ASSERT)
|
||||
G(OP_AND), \
|
||||
G(OP_OR), \
|
||||
G(OP_NOT), \
|
||||
G(OP_EQ), \
|
||||
G(OP_ASSERT), \
|
||||
G(OP_IADD), \
|
||||
G(OP_ISUB), \
|
||||
G(OP_IMUL), \
|
||||
G(OP_IDIV), \
|
||||
G(OP_IMOD), \
|
||||
G(OP_IPOW), \
|
||||
G(OP_IUADD), \
|
||||
G(OP_IUSUB),
|
||||
|
||||
enum Opcodes {
|
||||
OPCODES(GEN_ENUM)
|
||||
|
|
79
src/parser.y
79
src/parser.y
|
@ -17,23 +17,27 @@
|
|||
%}
|
||||
|
||||
%union {
|
||||
char* boolean;
|
||||
char* str;
|
||||
void* node_val;
|
||||
};
|
||||
|
||||
%left ASSERT
|
||||
%token <boolean> BOOLEAN
|
||||
%token <str> BOOLEAN
|
||||
%token <str> INTEGER
|
||||
%left EQ NE
|
||||
%left AND
|
||||
%left OR
|
||||
%left ADD SUB
|
||||
%left MUL DIV MOD
|
||||
%left POW
|
||||
%left NOT
|
||||
%type <node_val> expr;
|
||||
%token OPAR CPAR
|
||||
|
||||
%%
|
||||
|
||||
prog: exprs {
|
||||
|
||||
prog:
|
||||
| exprs {
|
||||
}
|
||||
;
|
||||
|
||||
|
@ -58,6 +62,67 @@ expr:
|
|||
$$ = n;
|
||||
}
|
||||
|
||||
| ADD expr {
|
||||
node *n = malloc(sizeof(node));
|
||||
node_init(n, NODE_UADD, "", line);
|
||||
node_add_child(n, $2);
|
||||
$$ = n;
|
||||
}
|
||||
|
||||
| SUB expr {
|
||||
node *n = malloc(sizeof(node));
|
||||
node_init(n, NODE_USUB, "", line);
|
||||
node_add_child(n, $2);
|
||||
$$ = n;
|
||||
}
|
||||
|
||||
| expr ADD expr {
|
||||
node *n = malloc(sizeof(node));
|
||||
node_init(n, NODE_ADD, "", line);
|
||||
node_add_child(n, $1);
|
||||
node_add_child(n, $3);
|
||||
$$ = n;
|
||||
}
|
||||
|
||||
| expr SUB expr {
|
||||
node *n = malloc(sizeof(node));
|
||||
node_init(n, NODE_SUB, "", line);
|
||||
node_add_child(n, $1);
|
||||
node_add_child(n, $3);
|
||||
$$ = n;
|
||||
}
|
||||
|
||||
| expr MUL expr {
|
||||
node *n = malloc(sizeof(node));
|
||||
node_init(n, NODE_MUL, "", line);
|
||||
node_add_child(n, $1);
|
||||
node_add_child(n, $3);
|
||||
$$ = n;
|
||||
}
|
||||
|
||||
| expr DIV expr {
|
||||
node *n = malloc(sizeof(node));
|
||||
node_init(n, NODE_DIV, "", line);
|
||||
node_add_child(n, $1);
|
||||
node_add_child(n, $3);
|
||||
$$ = n;
|
||||
}
|
||||
|
||||
| expr MOD expr {
|
||||
node *n = malloc(sizeof(node));
|
||||
node_init(n, NODE_MOD, "", line);
|
||||
node_add_child(n, $1);
|
||||
node_add_child(n, $3);
|
||||
$$ = n;
|
||||
}
|
||||
|
||||
| expr POW expr {
|
||||
node *n = malloc(sizeof(node));
|
||||
node_init(n, NODE_POW, "", line);
|
||||
node_add_child(n, $1);
|
||||
node_add_child(n, $3);
|
||||
$$ = n;
|
||||
}
|
||||
|
||||
| expr EQ expr {
|
||||
node *n = malloc(sizeof(node));
|
||||
|
@ -108,6 +173,12 @@ expr:
|
|||
node_init(n, NODE_BOOLEAN, $1, line);
|
||||
$$ = n;
|
||||
}
|
||||
|
||||
| INTEGER {
|
||||
node* n = malloc(sizeof(node));
|
||||
node_init(n, NODE_INTEGER, $1, line);
|
||||
$$ = n;
|
||||
}
|
||||
;
|
||||
|
||||
%%
|
||||
|
|
|
@ -4,7 +4,9 @@
|
|||
#include "commons.h"
|
||||
|
||||
#define TYPES(G) \
|
||||
G(TY_BOOLEAN)
|
||||
G(TY_NIL), \
|
||||
G(TY_BOOLEAN), \
|
||||
G(TY_INTEGER),
|
||||
|
||||
enum Types {
|
||||
TYPES(GEN_ENUM)
|
||||
|
|
18
src/value.c
18
src/value.c
|
@ -10,6 +10,16 @@ void value_init_boolean(value* self, int boolean, int lineno)
|
|||
type_init(self->type, TY_BOOLEAN);
|
||||
}
|
||||
|
||||
void value_init_integer(value* self, int integer, int lineno)
|
||||
{
|
||||
assert(self);
|
||||
self->val.integer = integer;
|
||||
self->lineno = lineno;
|
||||
|
||||
self->type = malloc(sizeof(type));
|
||||
type_init(self->type, TY_INTEGER);
|
||||
}
|
||||
|
||||
void value_free(value* self)
|
||||
{
|
||||
assert(self);
|
||||
|
@ -45,6 +55,11 @@ int value_equals(value* self, value* rhs)
|
|||
return self->val.boolean == rhs->val.boolean;
|
||||
}
|
||||
|
||||
if (self->type->base_type == TY_INTEGER)
|
||||
{
|
||||
return self->val.integer == rhs->val.integer;
|
||||
}
|
||||
|
||||
size_t const SZ = 512;
|
||||
char ty_str[SZ];
|
||||
|
||||
|
@ -65,6 +80,9 @@ size_t value_str(value* self, char* buffer, size_t size)
|
|||
return snprintf(buffer, size, "%s",
|
||||
self->val.boolean == 0
|
||||
? "false" : "true");
|
||||
case TY_INTEGER:
|
||||
return snprintf(buffer, size, "%d",
|
||||
self->val.integer);
|
||||
default: {
|
||||
fprintf(stderr, "E: unknown value");
|
||||
exit(-1);
|
||||
|
|
|
@ -9,10 +9,12 @@ typedef struct {
|
|||
int lineno;
|
||||
union {
|
||||
int boolean;
|
||||
int integer;
|
||||
} val;
|
||||
} value;
|
||||
|
||||
void value_init_boolean(value* self, int boolean, int lineno);
|
||||
void value_init_integer(value* self, int integer, int lineno);
|
||||
void value_free(value* self);
|
||||
|
||||
value* value_new_clone(value* self);
|
||||
|
|
138
src/vm.c
138
src/vm.c
|
@ -46,6 +46,14 @@ void vm_exec(vm* self, program* prog)
|
|||
case OP_OR: vm_or(self); break;
|
||||
case OP_NOT: vm_not(self); break;
|
||||
case OP_EQ: vm_eq(self); break;
|
||||
case OP_IADD: vm_iadd(self); break;
|
||||
case OP_IUADD: vm_iuadd(self); break;
|
||||
case OP_ISUB: vm_isub(self); break;
|
||||
case OP_IUSUB: vm_iusub(self); break;
|
||||
case OP_IMUL: vm_imul(self); break;
|
||||
case OP_IDIV: vm_idiv(self); break;
|
||||
case OP_IMOD: vm_imod(self); break;
|
||||
case OP_IPOW: vm_ipow(self); break;
|
||||
case OP_ASSERT: vm_assert(self); break;
|
||||
default: {
|
||||
fprintf(stderr, "unknown opcode %s\n",
|
||||
|
@ -165,6 +173,136 @@ void vm_not(vm* self)
|
|||
self->pc++;
|
||||
}
|
||||
|
||||
void vm_iadd(vm* self)
|
||||
{
|
||||
value* rhs = vm_pop_value(self);
|
||||
value* lhs = vm_pop_value(self);
|
||||
|
||||
value* val = malloc(sizeof(value));
|
||||
value_init_integer(val, lhs->val.integer + rhs->val.integer, lhs->lineno);
|
||||
vm_push_value(self, val);
|
||||
|
||||
value_free(rhs);
|
||||
free(rhs);
|
||||
value_free(lhs);
|
||||
free(lhs);
|
||||
|
||||
self->pc++;
|
||||
}
|
||||
|
||||
void vm_iuadd(vm* self)
|
||||
{
|
||||
value* lhs = vm_pop_value(self);
|
||||
|
||||
value* val = malloc(sizeof(value));
|
||||
value_init_integer(val, lhs->val.integer, lhs->lineno);
|
||||
vm_push_value(self, val);
|
||||
|
||||
value_free(lhs);
|
||||
free(lhs);
|
||||
|
||||
self->pc++;
|
||||
}
|
||||
|
||||
void vm_isub(vm* self)
|
||||
{
|
||||
value* rhs = vm_pop_value(self);
|
||||
value* lhs = vm_pop_value(self);
|
||||
|
||||
value* val = malloc(sizeof(value));
|
||||
value_init_integer(val, lhs->val.integer - rhs->val.integer, lhs->lineno);
|
||||
vm_push_value(self, val);
|
||||
|
||||
value_free(rhs);
|
||||
free(rhs);
|
||||
value_free(lhs);
|
||||
free(lhs);
|
||||
|
||||
self->pc++;
|
||||
}
|
||||
|
||||
void vm_iusub(vm* self)
|
||||
{
|
||||
value* lhs = vm_pop_value(self);
|
||||
|
||||
value* val = malloc(sizeof(value));
|
||||
value_init_integer(val, -lhs->val.integer, lhs->lineno);
|
||||
vm_push_value(self, val);
|
||||
|
||||
value_free(lhs);
|
||||
free(lhs);
|
||||
|
||||
self->pc++;
|
||||
}
|
||||
|
||||
void vm_imul(vm* self)
|
||||
{
|
||||
value* rhs = vm_pop_value(self);
|
||||
value* lhs = vm_pop_value(self);
|
||||
|
||||
value* val = malloc(sizeof(value));
|
||||
value_init_integer(val, lhs->val.integer * rhs->val.integer, lhs->lineno);
|
||||
vm_push_value(self, val);
|
||||
|
||||
value_free(rhs);
|
||||
free(rhs);
|
||||
value_free(lhs);
|
||||
free(lhs);
|
||||
|
||||
self->pc++;
|
||||
}
|
||||
|
||||
void vm_idiv(vm* self)
|
||||
{
|
||||
value* rhs = vm_pop_value(self);
|
||||
value* lhs = vm_pop_value(self);
|
||||
|
||||
value* val = malloc(sizeof(value));
|
||||
value_init_integer(val, lhs->val.integer / rhs->val.integer, lhs->lineno);
|
||||
vm_push_value(self, val);
|
||||
|
||||
value_free(rhs);
|
||||
free(rhs);
|
||||
value_free(lhs);
|
||||
free(lhs);
|
||||
|
||||
self->pc++;
|
||||
}
|
||||
|
||||
void vm_imod(vm* self)
|
||||
{
|
||||
value* rhs = vm_pop_value(self);
|
||||
value* lhs = vm_pop_value(self);
|
||||
|
||||
value* val = malloc(sizeof(value));
|
||||
value_init_integer(val, lhs->val.integer % rhs->val.integer, lhs->lineno);
|
||||
vm_push_value(self, val);
|
||||
|
||||
value_free(rhs);
|
||||
free(rhs);
|
||||
value_free(lhs);
|
||||
free(lhs);
|
||||
|
||||
self->pc++;
|
||||
}
|
||||
|
||||
void vm_ipow(vm* self)
|
||||
{
|
||||
value* rhs = vm_pop_value(self);
|
||||
value* lhs = vm_pop_value(self);
|
||||
|
||||
value* val = malloc(sizeof(value));
|
||||
value_init_integer(val, pow(lhs->val.integer, rhs->val.integer), lhs->lineno);
|
||||
vm_push_value(self, val);
|
||||
|
||||
value_free(rhs);
|
||||
free(rhs);
|
||||
value_free(lhs);
|
||||
free(lhs);
|
||||
|
||||
self->pc++;
|
||||
}
|
||||
|
||||
void vm_eq(vm* self)
|
||||
{
|
||||
assert(self);
|
||||
|
|
10
src/vm.h
10
src/vm.h
|
@ -29,6 +29,16 @@ void vm_and(vm* self);
|
|||
void vm_or(vm* self);
|
||||
void vm_not(vm* self);
|
||||
|
||||
void vm_iadd(vm* self);
|
||||
void vm_iuadd(vm* self);
|
||||
void vm_isub(vm* self);
|
||||
void vm_iusub(vm* self);
|
||||
void vm_imul(vm* self);
|
||||
void vm_idiv(vm* self);
|
||||
void vm_imod(vm* self);
|
||||
void vm_ipow(vm* self);
|
||||
|
||||
|
||||
void vm_eq(vm* self);
|
||||
void vm_assert(vm* self);
|
||||
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
+ true
|
||||
- true
|
||||
1 + true
|
||||
1 - true
|
||||
1 * true
|
||||
1 / true
|
||||
1 % true
|
||||
1 ^ true
|
||||
|
||||
true + 1
|
||||
true - 1
|
||||
true * 1
|
||||
true / 1
|
||||
true % 1
|
||||
true ^ 1
|
||||
|
||||
true + false
|
||||
true - false
|
||||
true * false
|
||||
true / false
|
||||
true % false
|
||||
true ^ false
|
||||
|
||||
1 && true
|
||||
2 || false
|
||||
!5
|
||||
|
||||
true && 1
|
||||
false || -2
|
||||
!!5
|
|
@ -0,0 +1,37 @@
|
|||
#!/usr/bin/sh
|
||||
OK=0
|
||||
KO=0
|
||||
COUNTER=0
|
||||
LINE=1
|
||||
|
||||
echo -e "\e[34m=== Error Testing ===\e[0m"
|
||||
|
||||
for file in $(find . -name "err_*.wuz")
|
||||
do
|
||||
LINE=1
|
||||
|
||||
while read line;
|
||||
do
|
||||
echo $line | wuz &> /dev/null
|
||||
RET="$?"
|
||||
if [ $RET -ne 0 ] || [ "$line" == "" ]
|
||||
then
|
||||
OK=$(($OK+1))
|
||||
else
|
||||
KO=$(($KO+1))
|
||||
echo -e "\e[33m\tE($file:$LINE) assertion failed\e[0m"
|
||||
fi
|
||||
|
||||
COUNTER=$(($COUNTER + 1))
|
||||
LINE=$(($LINE + 1))
|
||||
done < $file
|
||||
|
||||
if [ "$KO" == "0" ]
|
||||
then
|
||||
echo -e "$file ... \e[32mok\e[0m"
|
||||
else
|
||||
echo -e "$file ... \e[31mko\e[0m"
|
||||
fi
|
||||
|
||||
done
|
||||
|
|
@ -3,7 +3,9 @@
|
|||
OK=0
|
||||
KO=0
|
||||
|
||||
for file in $(find . -name "*.wuz")
|
||||
echo -e "\e[34m=== Unit Testing ===\e[0m"
|
||||
|
||||
for file in $(find . -name "test_*.wuz")
|
||||
do
|
||||
wuz $file
|
||||
RES="$?"
|
||||
|
@ -29,3 +31,6 @@ else
|
|||
echo -e "\e[31m$KO tests failed [$TOTAL]\e[0m"
|
||||
fi
|
||||
|
||||
echo
|
||||
|
||||
./errors.sh
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
assert 1 == 1
|
||||
assert 2 != 3
|
||||
|
||||
assert -1 == 2 + -3
|
||||
assert -8 == -(3 + 1) * 2
|
||||
|
||||
assert 7 == 1 + 2 * 3
|
||||
assert 9 == (1 + 2) * 3
|
||||
|
||||
assert 8 == 2^3
|
||||
|
||||
assert -8 == -2^3
|
||||
|
||||
assert 1 == 5 % 2
|
||||
assert 2 == 5 / 2
|
||||
assert 3 == 6 / 2
|
||||
|
||||
assert 64 == 2^(3+3)
|
||||
|
||||
assert 1 == -2 - -3
|
||||
|
||||
assert 5 + 7 == 12
|
Loading…
Reference in New Issue