int, float and strings.

main
bog 2024-02-11 15:45:39 +01:00
parent 5a67acd796
commit dd5c65b448
28 changed files with 1473 additions and 60 deletions

View File

@ -34,6 +34,27 @@ int compiler_compile(struct compiler* self,
program_push_instr(program, OP_PUSH, addr); program_push_instr(program, OP_PUSH, addr);
} break; } break;
case NODE_INT: {
struct value* val = malloc(sizeof(struct value));
value_init_int(val, atoi(node->value), node->line);
size_t addr = program_push_constant(program, val);
program_push_instr(program, OP_PUSH, addr);
} break;
case NODE_FLOAT: {
struct value* val = malloc(sizeof(struct value));
value_init_float(val, atof(node->value), node->line);
size_t addr = program_push_constant(program, val);
program_push_instr(program, OP_PUSH, addr);
} break;
case NODE_STRING: {
struct value* val = malloc(sizeof(struct value));
value_init_string(val, node->value, node->line);
size_t addr = program_push_constant(program, val);
program_push_instr(program, OP_PUSH, addr);
} break;
case NODE_ASSERT: { case NODE_ASSERT: {
compiler_compile(self, node->children.data[0], program); compiler_compile(self, node->children.data[0], program);
size_t brt = program_push_instr(program, OP_BRT, NO_PARAM); size_t brt = program_push_instr(program, OP_BRT, NO_PARAM);
@ -55,6 +76,19 @@ int compiler_compile(struct compiler* self,
} break; } break;
case NODE_EQ: {
compiler_compile(self, node->children.data[0], program);
compiler_compile(self, node->children.data[1], program);
program_push_instr(program, OP_EQ, NO_PARAM);
} break;
case NODE_NE: {
compiler_compile(self, node->children.data[0], program);
compiler_compile(self, node->children.data[1], program);
program_push_instr(program, OP_EQ, NO_PARAM);
program_push_instr(program, OP_NOT, NO_PARAM);
} break;
case NODE_NOT: { case NODE_NOT: {
compiler_compile(self, node->children.data[0], program); compiler_compile(self, node->children.data[0], program);
program_push_instr(program, OP_NOT, NO_PARAM); program_push_instr(program, OP_NOT, NO_PARAM);
@ -158,6 +192,40 @@ int compiler_compile(struct compiler* self,
vec_free(&to_pivot); vec_free(&to_pivot);
} break; } break;
case NODE_ADD:
case NODE_SUB:
case NODE_MUL:
case NODE_DIV:
case NODE_MOD:
case NODE_POW:
case NODE_LT:
case NODE_LE:
case NODE_GT:
case NODE_GE:
{
for (size_t i=0; i<node->children.size; i++)
{
compiler_compile(self, node->children.data[i], program);
}
switch (node->type)
{
case NODE_ADD: program_push_instr(program, OP_ADD, NO_PARAM); break;
case NODE_SUB: program_push_instr(program, OP_SUB, NO_PARAM); break;
case NODE_MUL: program_push_instr(program, OP_MUL, NO_PARAM); break;
case NODE_DIV: program_push_instr(program, OP_DIV, NO_PARAM); break;
case NODE_MOD: program_push_instr(program, OP_MOD, NO_PARAM); break;
case NODE_POW: program_push_instr(program, OP_POW, NO_PARAM); break;
case NODE_LT: program_push_instr(program, OP_LT, NO_PARAM); break;
case NODE_LE: program_push_instr(program, OP_LE, NO_PARAM); break;
case NODE_GT: program_push_instr(program, OP_GT, NO_PARAM); break;
case NODE_GE: program_push_instr(program, OP_GE, NO_PARAM); break;
default: break;
}
} break;
default: { default: {
for (size_t i=0; i<node->children.size; i++) for (size_t i=0; i<node->children.size; i++)
{ {

View File

@ -3,7 +3,9 @@
#define OPCODES(G) \ #define OPCODES(G) \
G(OP_PUSH), G(OP_POP), G(OP_BRF), G(OP_BR), G(OP_HALT), \ G(OP_PUSH), G(OP_POP), G(OP_BRF), G(OP_BR), G(OP_HALT), \
G(OP_BRT), G(OP_NOP), G(OP_NOT) G(OP_BRT), G(OP_NOP), G(OP_NOT), G(OP_EQ), \
G(OP_ADD), G(OP_SUB), G(OP_MUL), G(OP_DIV), G(OP_MOD), G(OP_POW), \
G(OP_LT), G(OP_LE), G(OP_GT),G(OP_GE),
#include <commons.h> #include <commons.h>

View File

@ -8,8 +8,13 @@ EXPR ::=
| ASSERT EXPR | ASSERT EXPR
OR ::= AND (or AND)* OR ::= AND (or AND)*
AND ::= NOT (and NOT)* AND ::= EQNE (and EQNE)*
NOT ::= not* LITERAL EQNE ::= CMP ((eq|ne) CMP)?
CMP ::= TERM ((lt|le|gt|ge) TERM)?
TERM ::= FACTOR ((add|sub) FACTOR)*
FACTOR ::= POW ((mul|div|mod) POW)*
POW ::= NOT (pow NOT)?
NOT ::= not* LITERAL
LITERAL ::= BUILTIN | opar EXPR cpar LITERAL ::= BUILTIN | opar EXPR cpar
BUILTIN ::= bool BUILTIN ::= bool | int | float | string

View File

@ -275,7 +275,7 @@ int main(int argc, char** argv)
if (show_stack) if (show_stack)
{ {
char buffer[GUX_STR_SIZE]; char buffer[GUX_STR_SIZE];
vm_str(&vm, buffer, GUX_STR_SIZE); vm_str(&vm, &program, buffer, GUX_STR_SIZE);
printf("%s\n", buffer); printf("%s\n", buffer);
} }

View File

@ -24,9 +24,10 @@ target_include_directories(gux-lang
) )
target_link_libraries(gux-lang target_link_libraries(gux-lang
PUBLIC gux-lib PUBLIC gux-lib m
) )
# ===== # =====
# TESTS # TESTS
# ===== # =====

View File

@ -1,4 +1,5 @@
#include "lexer.h" #include "lexer.h"
#include "commons.h"
void lexer_init(struct lexer* self, char const* source) void lexer_init(struct lexer* self, char const* source)
{ {
@ -11,7 +12,22 @@ void lexer_init(struct lexer* self, char const* source)
vec_init(&self->toks, 1); vec_init(&self->toks, 1);
lexer_add_tok(self, "<", NODE_LT, 0);
lexer_add_tok(self, "<=", NODE_LE, 0);
lexer_add_tok(self, ">", NODE_GT, 0);
lexer_add_tok(self, ">=", NODE_GE, 0);
lexer_add_tok(self, "+", NODE_ADD, 0);
lexer_add_tok(self, "-", NODE_SUB, 0);
lexer_add_tok(self, "*", NODE_MUL, 0);
lexer_add_tok(self, "/", NODE_DIV, 0);
lexer_add_tok(self, "%", NODE_MOD, 0);
lexer_add_tok(self, "**", NODE_POW, 0);
lexer_add_tok(self, "==", NODE_EQ, 0);
lexer_add_tok(self, "!=", NODE_NE, 0);
lexer_add_tok(self, "&&", NODE_AND, 0); lexer_add_tok(self, "&&", NODE_AND, 0);
lexer_add_tok(self, "||", NODE_OR, 0); lexer_add_tok(self, "||", NODE_OR, 0);
lexer_add_tok(self, "!", NODE_NOT, 0); lexer_add_tok(self, "!", NODE_NOT, 0);
lexer_add_tok(self, "(", NODE_OPAR, 0); lexer_add_tok(self, "(", NODE_OPAR, 0);
@ -71,16 +87,33 @@ struct node* lexer_next_new(struct lexer* self)
struct token_info info; struct token_info info;
if (lexer_scan_float(self, &info))
{
struct node* node = malloc(sizeof(struct node));
node_init(node, info.type, info.value, self->line);
self->cursor = info.position;
return node;
}
if (lexer_scan_int(self, &info))
{
struct node* node = malloc(sizeof(struct node));
node_init(node, info.type, info.value, self->line);
self->cursor = info.position;
return node;
}
struct node* best = NULL; struct node* best = NULL;
size_t pos = 0; size_t pos = 0;
// tokens
for (size_t i=0; i<self->toks.size; i++) for (size_t i=0; i<self->toks.size; i++)
{ {
struct tok* tok = self->toks.data[i]; struct tok* tok = self->toks.data[i];
if (lexer_scan_text(self, tok->sym, &info)) if (lexer_scan_text(self, tok->sym, &info))
{ {
if (best == NULL || pos > info.position) if (best == NULL || info.position > pos)
{ {
struct node* node = malloc(sizeof(struct node)); struct node* node = malloc(sizeof(struct node));
node_init(node, tok->type, "", self->line); node_init(node, tok->type, "", self->line);
@ -88,13 +121,12 @@ struct node* lexer_next_new(struct lexer* self)
if (best) if (best)
{ {
node_free(best); node_free(best);
free(best);
} }
best = node; best = node;
pos = info.position; pos = info.position;
} }
self->cursor = info.position;
} }
} }
@ -121,6 +153,14 @@ struct node* lexer_next_new(struct lexer* self)
return node; return node;
} }
if (lexer_scan_string(self, &info))
{
struct node* node = malloc(sizeof(struct node));
node_init(node, info.type, info.value, self->line);
self->cursor = info.position;
return node;
}
return NULL; return NULL;
} }
@ -191,7 +231,7 @@ int lexer_scan_keyword(struct lexer* self,
} }
info->position = self->cursor + strlen(keyword); info->position = self->cursor + strlen(keyword);
info->value = keyword; memcpy(info->value, keyword, GUX_STR_SIZE * sizeof(char));
return 1; return 1;
} }
@ -218,11 +258,160 @@ int lexer_scan_text(struct lexer* self,
} }
info->position = self->cursor + strlen(text); info->position = self->cursor + strlen(text);
info->value = text; memcpy(info->value, text, GUX_STR_SIZE * sizeof(char));
return 1; return 1;
} }
int lexer_scan_int(struct lexer* self,
struct token_info* info)
{
assert(self);
assert(info);
size_t cursor = self->cursor;
char value[GUX_STR_SIZE];
memset(value, 0, GUX_STR_SIZE);
size_t sz = 0;
if (cursor < strlen(self->source)
&& self->source[cursor] == '-')
{
value[sz++] = '-';
cursor++;
}
while (cursor < strlen(self->source)
&& isdigit(self->source[cursor]))
{
value[sz] = self->source[cursor];
cursor++;
sz++;
}
if (sz == 1 && value[0] == '-')
{
return 0;
}
if (sz > 0)
{
info->position = cursor;
info->type = NODE_INT;
memcpy(info->value, value, GUX_STR_SIZE * sizeof(char));
return 1;
}
return 0;
}
int lexer_scan_float(struct lexer* self,
struct token_info* info)
{
assert(self);
assert(info);
size_t cursor = self->cursor;
char value[GUX_STR_SIZE];
memset(value, 0, GUX_STR_SIZE);
size_t sz = 0;
if (cursor < strlen(self->source)
&& self->source[cursor] == '-')
{
value[sz++] = '-';
cursor++;
}
while (cursor < strlen(self->source)
&& isdigit(self->source[cursor]))
{
value[sz] = self->source[cursor];
cursor++;
sz++;
}
int is_float = 0;
if (cursor < strlen(self->source)
&& self->source[cursor] == '.')
{
value[sz++] = '.';
is_float = 1;
cursor++;
while (cursor < strlen(self->source)
&& isdigit(self->source[cursor]))
{
value[sz] = self->source[cursor];
cursor++;
sz++;
}
}
if (sz > 0 && is_float)
{
info->position = cursor;
info->type = NODE_FLOAT;
memcpy(info->value, value, GUX_STR_SIZE * sizeof(char));
return 1;
}
return 0;
}
int lexer_scan_string(struct lexer* self,
struct token_info* info)
{
assert(self);
assert(info);
size_t cursor = self->cursor;
char value[GUX_STR_SIZE];
memset(value, 0, GUX_STR_SIZE);
size_t sz = 0;
char delim = ' ';
if (cursor < strlen(self->source)
&& (self->source[cursor] == '\''
|| self->source[cursor] == '"'))
{
delim = self->source[cursor];
cursor++;
}
else
{
return 0;
}
int found = 0;
while (cursor < strlen(self->source))
{
if (self->source[cursor] == delim
&& (cursor == 0 || self->source[cursor - 1] != '\\'))
{
found = 1;
cursor++;
break;
}
value[sz++] = self->source[cursor++];
}
if (found)
{
info->position = cursor;
info->type = NODE_STRING;
memcpy(info->value, value, GUX_STR_SIZE * sizeof(char));
return 1;
}
return 0;
}
void lexer_add_tok(struct lexer* self, void lexer_add_tok(struct lexer* self,
char* sym, char* sym,
enum NodeType type, enum NodeType type,

View File

@ -21,7 +21,7 @@ struct lexer {
struct token_info { struct token_info {
enum NodeType type; enum NodeType type;
char* value; char value[GUX_STR_SIZE];
size_t position; size_t position;
}; };
@ -43,6 +43,15 @@ int lexer_scan_text(struct lexer* self,
char* text, char* text,
struct token_info* info); struct token_info* info);
int lexer_scan_int(struct lexer* self,
struct token_info* info);
int lexer_scan_float(struct lexer* self,
struct token_info* info);
int lexer_scan_string(struct lexer* self,
struct token_info* info);
void lexer_add_tok(struct lexer* self, void lexer_add_tok(struct lexer* self,
char* sym, char* sym,
enum NodeType type, enum NodeType type,

View File

@ -8,7 +8,11 @@
G(NODE_ROOT), \ G(NODE_ROOT), \
G(NODE_SEMICOLON), \ G(NODE_SEMICOLON), \
G(NODE_BOOL), G(NODE_ASSERT), G(NODE_OPAR), \ G(NODE_BOOL), G(NODE_ASSERT), G(NODE_OPAR), \
G(NODE_CPAR), G(NODE_AND), G(NODE_OR), G(NODE_NOT) G(NODE_CPAR), G(NODE_AND), G(NODE_OR), G(NODE_NOT), \
G(NODE_EQ), G(NODE_NE), G(NODE_INT), G(NODE_FLOAT), \
G(NODE_STRING), G(NODE_ADD), G(NODE_SUB), G(NODE_MUL), G(NODE_DIV), \
G(NODE_MOD), G(NODE_POW), G(NODE_LT), G(NODE_LE), G(NODE_GT), \
G(NODE_GE)
GUX_ENUM_H(NodeType, NODE_TYPE); GUX_ENUM_H(NodeType, NODE_TYPE);

View File

@ -1,6 +1,7 @@
#include "parser.h" #include "parser.h"
#include "commons.h" #include "commons.h"
#include "lexer.h" #include "lexer.h"
#include "node.h"
#include "vec.h" #include "vec.h"
void parser_init(struct parser* self) void parser_init(struct parser* self)
@ -230,14 +231,14 @@ struct node* parser_try_new_or(struct parser* self)
struct node* parser_try_new_and(struct parser* self) struct node* parser_try_new_and(struct parser* self)
{ {
struct node* lhs = parser_try_new_not(self); struct node* lhs = parser_try_new_eqne(self);
while (parser_try_consume(self, NODE_AND) == 0) while (parser_try_consume(self, NODE_AND) == 0)
{ {
struct node* node = malloc(sizeof(struct node)); struct node* node = malloc(sizeof(struct node));
node_init(node, NODE_AND, "", parser_current_line(self)); node_init(node, NODE_AND, "", parser_current_line(self));
struct node* rhs = parser_try_new_not(self); struct node* rhs = parser_try_new_eqne(self);
node_add_child(node, lhs); node_add_child(node, lhs);
node_add_child(node, rhs); node_add_child(node, rhs);
@ -248,6 +249,115 @@ struct node* parser_try_new_and(struct parser* self)
return lhs; return lhs;
} }
struct node* parser_try_new_eqne(struct parser* self)
{
struct node* lhs = parser_try_new_cmp(self);
if (parser_type_is(self, NODE_EQ, 0)
|| parser_type_is(self, NODE_NE, 0))
{
struct node* node = malloc(sizeof(struct node));
struct node* current = self->tokens.data[self->cursor];
self->cursor++;
node_init(node, current->type, "", parser_current_line(self));
node_add_child(node, lhs);
node_add_child(node, parser_try_new_cmp(self));
lhs = node;
}
return lhs;
}
struct node* parser_try_new_cmp(struct parser* self)
{
assert(self);
struct node* lhs = parser_try_new_term(self);
if (parser_type_is(self, NODE_LT, 0)
|| parser_type_is(self, NODE_LE, 0)
|| parser_type_is(self, NODE_GT, 0)
|| parser_type_is(self, NODE_GE, 0))
{
struct node* node = malloc(sizeof(struct node));
struct node* current = self->tokens.data[self->cursor];
self->cursor++;
node_init(node, current->type, "", parser_current_line(self));
node_add_child(node, lhs);
node_add_child(node, parser_try_new_term(self));
lhs = node;
}
return lhs;
}
struct node* parser_try_new_term(struct parser* self)
{
assert(self);
struct node* lhs = parser_try_new_factor(self);
while (parser_type_is(self, NODE_ADD, 0)
|| parser_type_is(self, NODE_SUB, 0))
{
struct node* node = malloc(sizeof(struct node));
struct node* tok = self->tokens.data[self->cursor];
node_init(node, tok->type, "", parser_current_line(self));
self->cursor++;
node_add_child(node, lhs);
node_add_child(node, parser_try_new_factor(self));
lhs = node;
}
return lhs;
}
struct node* parser_try_new_factor(struct parser* self)
{
assert(self);
struct node* lhs = parser_try_new_pow(self);
while (parser_type_is(self, NODE_MUL, 0)
|| parser_type_is(self, NODE_DIV, 0)
|| parser_type_is(self, NODE_MOD, 0))
{
struct node* node = malloc(sizeof(struct node));
struct node* tok = self->tokens.data[self->cursor];
node_init(node, tok->type, "", parser_current_line(self));
self->cursor++;
node_add_child(node, lhs);
node_add_child(node, parser_try_new_pow(self));
lhs = node;
}
return lhs;
}
struct node* parser_try_new_pow(struct parser* self)
{
assert(self);
struct node* lhs = parser_try_new_not(self);
if (parser_try_consume(self, NODE_POW) == 0)
{
struct node* node = malloc(sizeof(struct node));
node_init(node, NODE_POW, "", parser_current_line(self));
node_add_child(node, lhs);
node_add_child(node, parser_try_new_not(self));
lhs = node;
}
return lhs;
}
struct node* parser_try_new_not(struct parser* self) struct node* parser_try_new_not(struct parser* self)
{ {
if (parser_try_consume(self, NODE_NOT) == 0) if (parser_try_consume(self, NODE_NOT) == 0)
@ -285,7 +395,25 @@ struct node* parser_try_new_builtin(struct parser* self)
{ {
assert(self); assert(self);
struct node* value = parser_try_consume_new(self, NODE_BOOL); if (parser_type_is(self, NODE_BOOL, 0))
{
return parser_try_consume_new(self, NODE_BOOL);
}
return value; if (parser_type_is(self, NODE_INT, 0))
{
return parser_try_consume_new(self, NODE_INT);
}
if (parser_type_is(self, NODE_FLOAT, 0))
{
return parser_try_consume_new(self, NODE_FLOAT);
}
if (parser_type_is(self, NODE_STRING, 0))
{
return parser_try_consume_new(self, NODE_STRING);
}
return NULL;
} }

View File

@ -29,6 +29,11 @@ struct node* parser_try_new_instr(struct parser* self);
struct node* parser_try_new_expr(struct parser* self); struct node* parser_try_new_expr(struct parser* self);
struct node* parser_try_new_or(struct parser* self); struct node* parser_try_new_or(struct parser* self);
struct node* parser_try_new_and(struct parser* self); struct node* parser_try_new_and(struct parser* self);
struct node* parser_try_new_eqne(struct parser* self);
struct node* parser_try_new_cmp(struct parser* self);
struct node* parser_try_new_term(struct parser* self);
struct node* parser_try_new_factor(struct parser* self);
struct node* parser_try_new_pow(struct parser* self);
struct node* parser_try_new_not(struct parser* self); struct node* parser_try_new_not(struct parser* self);
struct node* parser_try_new_literal(struct parser* self); struct node* parser_try_new_literal(struct parser* self);
struct node* parser_try_new_builtin(struct parser* self); struct node* parser_try_new_builtin(struct parser* self);

View File

@ -1,4 +1,5 @@
#include "type.h" #include "type.h"
#include "commons.h"
#include "vec.h" #include "vec.h"
GUX_ENUM_C(TypeKind, TYPE_KIND); GUX_ENUM_C(TypeKind, TYPE_KIND);
@ -27,7 +28,13 @@ void type_free(struct type* self)
void type_clear(struct type* self) void type_clear(struct type* self)
{ {
assert(self); assert(self);
vec_clear(&self->subtypes);
while (self->subtypes.size > 0)
{
void* element = vec_pop(&self->subtypes);
type_free(element);
free(element);
}
} }
int type_equals(struct type* self, struct type* rhs) int type_equals(struct type* self, struct type* rhs)
@ -89,3 +96,15 @@ size_t type_str(struct type* self, char* buffer, size_t size)
return sz; return sz;
} }
int type_is(struct type* self, char const* repr)
{
assert(self);
assert(repr);
char buffer[GUX_STR_SIZE];
type_str(self, buffer, GUX_STR_SIZE);
int result = strcmp(repr, buffer) == 0;
return result;
}

View File

@ -5,7 +5,8 @@
#include <vec.h> #include <vec.h>
#define TYPE_KIND(G) \ #define TYPE_KIND(G) \
G(TYPE_VOID), G(TYPE_BOOL) G(TYPE_VOID), G(TYPE_BOOL), G(TYPE_INT), \
G(TYPE_FLOAT), G(TYPE_STRING)
GUX_ENUM_H(TypeKind, TYPE_KIND); GUX_ENUM_H(TypeKind, TYPE_KIND);
@ -22,6 +23,6 @@ void type_clear(struct type* self);
int type_equals(struct type* self, struct type* rhs); int type_equals(struct type* self, struct type* rhs);
void type_add_subtype(struct type* self, enum TypeKind kind); void type_add_subtype(struct type* self, enum TypeKind kind);
size_t type_str(struct type* self, char* buffer, size_t size); size_t type_str(struct type* self, char* buffer, size_t size);
int type_is(struct type* self, char const* repr);
#endif #endif

View File

@ -2,11 +2,13 @@
#include "commons.h" #include "commons.h"
#include "node.h" #include "node.h"
#include "type.h" #include "type.h"
#include "type_resolver.h"
void type_checker_init(struct type_checker* self) void type_checker_init(struct type_checker* self)
{ {
assert(self); assert(self);
type_resolver_init(&self->resolver); type_resolver_init(&self->resolver);
memset(self->error_msg, 0, GUX_STR_SIZE);
} }
void type_checker_free(struct type_checker* self) void type_checker_free(struct type_checker* self)
@ -23,10 +25,91 @@ int type_checker_check(struct type_checker* self,
switch (node->type) switch (node->type)
{ {
case NODE_LT:
case NODE_LE:
case NODE_GT:
case NODE_GE: {
struct node* lhs = node->children.data[0];
struct node* rhs = node->children.data[1];
struct type lhs_type;
type_init(&lhs_type, TYPE_VOID);
int solve_lhs = type_resolver_resolve(&self->resolver, lhs, &lhs_type);
struct type rhs_type;
type_init(&rhs_type, TYPE_VOID);
int solve_rhs = type_resolver_resolve(&self->resolver, rhs, &rhs_type);
size_t MSG_SZ = GUX_STR_SIZE * 4;
char lhs_msg[GUX_STR_SIZE];
type_str(&lhs_type, lhs_msg, GUX_STR_SIZE);
char rhs_msg[GUX_STR_SIZE];
type_str(&rhs_type, rhs_msg, GUX_STR_SIZE);
self->error_line = lhs->line;
if (lhs_type.kind != TYPE_INT && lhs_type.kind != TYPE_FLOAT)
{
if (rhs_type.kind == TYPE_INT || rhs_type.kind == TYPE_FLOAT)
{
snprintf(self->error_msg, MSG_SZ,
"wrong type: expected <%s>, got <%s>",
rhs_msg,
lhs_msg);
}
else
{
snprintf(self->error_msg, MSG_SZ,
"wrong type: expected <INT> or <FLOAT>, got <%s>",
lhs_msg);
}
}
else if (rhs_type.kind != TYPE_INT && rhs_type.kind != TYPE_FLOAT)
{
if (lhs_type.kind == TYPE_INT || lhs_type.kind == TYPE_FLOAT)
{
snprintf(self->error_msg, MSG_SZ,
"wrong type: expected <%s>, got <%s>",
lhs_msg,
rhs_msg);
}
else
{
snprintf(self->error_msg, MSG_SZ,
"wrong type: expected <INT> or <FLOAT>, got <%s>",
lhs_msg);
}
}
else if (!type_equals(&lhs_type, &rhs_type))
{
snprintf(self->error_msg, MSG_SZ,
"type mismatch (<%s>, <%s>)",
lhs_msg,
rhs_msg);
}
if (solve_lhs != 0
|| solve_rhs != 0
|| !type_equals(&lhs_type, &rhs_type)
|| lhs_type.subtypes.size > 0
|| rhs_type.subtypes.size > 0
|| (lhs_type.kind != TYPE_INT && lhs_type.kind != TYPE_FLOAT)
|| (rhs_type.kind != TYPE_INT && rhs_type.kind != TYPE_FLOAT))
{
type_free(&lhs_type);
type_free(&rhs_type);
return 1;
}
type_free(&lhs_type);
type_free(&rhs_type);
} return 0;
case NODE_ASSERT: case NODE_ASSERT:
case NODE_NOT: case NODE_NOT:
case NODE_AND: case NODE_AND:
case NODE_OR:{ case NODE_OR: {
for (size_t i=0; i<node->children.size; i++) for (size_t i=0; i<node->children.size; i++)
{ {
if (type_checker_ensure_kind(self, if (type_checker_ensure_kind(self,
@ -38,6 +121,55 @@ int type_checker_check(struct type_checker* self,
} }
} return 0; } return 0;
case NODE_EQ:
case NODE_NE: {
struct type type;
type_init(&type, TYPE_VOID);
type_resolver_resolve(&self->resolver, node->children.data[0], &type);
for (size_t i=1; i<node->children.size; i++)
{
struct type node_type;
type_init(&node_type, TYPE_VOID);
type_resolver_resolve(&self->resolver,
node->children.data[i],
&node_type);
if (!type_equals(&type, &node_type))
{
self->error_line = node->line;
snprintf(self->error_msg,
GUX_STR_SIZE, "cannot compare different types");
type_free(&type);
type_free(&node_type);
return 1;
}
type_free(&node_type);
}
type_free(&type);
} return 0;
case NODE_ADD:
case NODE_SUB:
case NODE_MUL:
case NODE_DIV:
case NODE_MOD:
case NODE_POW: {
struct type type;
type_init(&type, TYPE_VOID);
if (type_resolver_resolve(&self->resolver, node, &type) != 0)
{
type_free(&type);
return 1;
}
type_free(&type);
} return 0;
default: { default: {
for (size_t i=0; i<node->children.size; i++) for (size_t i=0; i<node->children.size; i++)
{ {
@ -66,6 +198,7 @@ int type_checker_ensure_kind(struct type_checker* self,
if (type.kind != kind || type.subtypes.size != 0) if (type.kind != kind || type.subtypes.size != 0)
{ {
self->error_line = node->line; self->error_line = node->line;
snprintf(self->error_msg, GUX_STR_SIZE, snprintf(self->error_msg, GUX_STR_SIZE,
"type mismatch: expected <%s>, got <%s>", "type mismatch: expected <%s>, got <%s>",
TypeKindStr[kind] + strlen("TYPE_"), TypeKindStr[kind] + strlen("TYPE_"),

View File

@ -8,7 +8,7 @@
struct type_checker { struct type_checker {
struct type_resolver resolver; struct type_resolver resolver;
char* error_msg; char error_msg[GUX_STR_SIZE];
int error_line; int error_line;
}; };

View File

@ -24,14 +24,81 @@ int type_resolver_resolve(struct type_resolver* self,
switch (node->type) switch (node->type)
{ {
case NODE_EQ:
case NODE_NE:
case NODE_ASSERT: case NODE_ASSERT:
case NODE_BOOL: case NODE_BOOL:
case NODE_AND: case NODE_AND:
case NODE_OR: case NODE_OR:
case NODE_NOT:{ case NODE_NOT:
case NODE_LT:
case NODE_LE:
case NODE_GT:
case NODE_GE:{
type->kind = TYPE_BOOL; type->kind = TYPE_BOOL;
} return 0; } return 0;
case NODE_INT: {
type->kind = TYPE_INT;
} return 0;
case NODE_FLOAT: {
type->kind = TYPE_FLOAT;
} return 0;
case NODE_STRING: {
type->kind = TYPE_STRING;
} return 0;
case NODE_ADD:
case NODE_SUB:
case NODE_MUL:
case NODE_DIV:
case NODE_MOD:
case NODE_POW:{
struct type lhs;
type_init(&lhs, TYPE_VOID);
type_resolver_resolve(self, node->children.data[0], &lhs);
struct type rhs;
type_init(&rhs, TYPE_VOID);
type_resolver_resolve(self, node->children.data[1], &rhs);
int equals = type_equals(&lhs, &rhs);
if (type_is(&lhs, "INT") && equals)
{
type->kind = TYPE_INT;
}
else if (type_is(&lhs, "FLOAT") && equals)
{
type->kind = TYPE_FLOAT;
}
else if (type_is(&lhs, "STRING") && equals && node->type == NODE_ADD)
{
type->kind = TYPE_STRING;
}
else if (type_is(&lhs, "STRING")
&& type_is(&rhs, "INT") && node->type == NODE_MUL)
{
type->kind = TYPE_STRING;
}
else if (type_is(&lhs, "INT")
&& type_is(&rhs, "STRING") && node->type == NODE_MUL)
{
type->kind = TYPE_STRING;
}
else
{
type_free(&lhs);
type_free(&rhs);
return 1;
}
type_free(&lhs);
type_free(&rhs);
} return 0;
default: { default: {
} return 1; } return 1;
} }

View File

@ -9,9 +9,41 @@ void value_init_bool(struct value* self, int value, int line)
self->line = line; self->line = line;
} }
void value_init_int(struct value* self, int value, int line)
{
assert(self);
type_init(&self->type, TYPE_INT);
self->data.i = value;
self->line = line;
}
void value_init_float(struct value* self, float value, int line)
{
assert(self);
type_init(&self->type, TYPE_FLOAT);
self->data.f = value;
self->line = line;
}
void value_init_string(struct value* self, char* value, int line)
{
assert(self);
type_init(&self->type, TYPE_STRING);
self->data.s = strdup(value);
self->line = line;
}
void value_free(struct value* self) void value_free(struct value* self)
{ {
assert(self); assert(self);
if (self->type.kind == TYPE_STRING)
{
free(self->data.s);
}
type_free(&self->type); type_free(&self->type);
} }
@ -33,6 +65,22 @@ size_t value_str(struct value* self, char* buffer, size_t size)
sz += snprintf(buffer + sz, size - sz, "%s", sz += snprintf(buffer + sz, size - sz, "%s",
self->data.b ? "true" : "false"); self->data.b ? "true" : "false");
} }
else if (self->type.kind == TYPE_INT)
{
sz += snprintf(buffer + sz, size - sz, "%d", self->data.i);
}
else if (self->type.kind == TYPE_FLOAT)
{
sz += snprintf(buffer + sz, size - sz, "%f", self->data.f);
}
else if (self->type.kind == TYPE_STRING)
{
sz += snprintf(buffer + sz, size - sz, "%s", self->data.s);
}
else
{
assert(0);
}
} }
return sz; return sz;
@ -79,3 +127,279 @@ struct value* value_try_new_not(struct value* self)
return res; return res;
} }
struct value* value_try_new_add(struct value* self, struct value* rhs)
{
assert(self);
assert(rhs);
struct value* res = malloc(sizeof(struct value));
if (type_equals(&self->type, &rhs->type) && type_is(&self->type, "INT"))
{
value_init_int(res, self->data.i + rhs->data.i, self->line);
return res;
}
if (type_equals(&self->type, &rhs->type) && type_is(&self->type, "FLOAT"))
{
value_init_float(res, self->data.f + rhs->data.f, self->line);
return res;
}
if (type_equals(&self->type, &rhs->type) && type_is(&self->type, "STRING"))
{
size_t const SZ = strlen(self->data.s) + strlen(rhs->data.s) + 1;
char str[SZ];
snprintf(str, SZ, "%s%s", self->data.s, rhs->data.s);
value_init_string(res, str, self->line);
return res;
}
free(res);
return NULL;
}
struct value* value_try_new_sub(struct value* self, struct value* rhs)
{
assert(self);
assert(rhs);
struct value* res = malloc(sizeof(struct value));
if (type_equals(&self->type, &rhs->type) && type_is(&self->type, "INT"))
{
value_init_int(res, self->data.i - rhs->data.i, self->line);
return res;
}
if (type_equals(&self->type, &rhs->type) && type_is(&self->type, "FLOAT"))
{
value_init_float(res, self->data.f - rhs->data.f, self->line);
return res;
}
free(res);
return NULL;
}
struct value* value_try_new_mul(struct value* self, struct value* rhs)
{
assert(self);
assert(rhs);
struct value* res = malloc(sizeof(struct value));
if (type_equals(&self->type, &rhs->type) && type_is(&self->type, "INT"))
{
value_init_int(res, self->data.i * rhs->data.i, self->line);
return res;
}
if (type_equals(&self->type, &rhs->type) && type_is(&self->type, "FLOAT"))
{
value_init_float(res, self->data.f * rhs->data.f, self->line);
return res;
}
struct value* factor_val = self;
struct value* content_val = rhs;
if (type_is(&factor_val->type, "STRING") && type_is(&content_val->type, "INT"))
{
struct value* tmp = factor_val;
factor_val = content_val;
content_val = tmp;
}
if (type_is(&factor_val->type, "INT") && type_is(&content_val->type, "STRING"))
{
int factor = factor_val->data.i;
char* content = content_val->data.s;
size_t const SZ = factor * strlen(content);
char str[SZ];
for (int i=0; i<factor; i++)
{
snprintf(str + i * strlen(content), SZ, "%s", content);
}
value_init_string(res, str, factor_val->line);
return res;
}
free(res);
return NULL;
}
struct value* value_try_new_div(struct value* self, struct value* rhs)
{
assert(self);
assert(rhs);
struct value* res = malloc(sizeof(struct value));
if (type_equals(&self->type, &rhs->type) && type_is(&self->type, "INT"))
{
value_init_int(res, self->data.i / rhs->data.i, self->line);
return res;
}
if (type_equals(&self->type, &rhs->type) && type_is(&self->type, "FLOAT"))
{
value_init_float(res, self->data.f / rhs->data.f, self->line);
return res;
}
free(res);
return NULL;
}
struct value* value_try_new_mod(struct value* self, struct value* rhs)
{
assert(self);
assert(rhs);
struct value* res = malloc(sizeof(struct value));
if (type_equals(&self->type, &rhs->type) && type_is(&self->type, "INT"))
{
value_init_int(res, self->data.i % rhs->data.i, self->line);
return res;
}
if (type_equals(&self->type, &rhs->type) && type_is(&self->type, "FLOAT"))
{
value_init_float(res, fmod(self->data.f, rhs->data.f), self->line);
return res;
}
free(res);
return NULL;
}
struct value* value_try_new_pow(struct value* self, struct value* rhs)
{
assert(self);
assert(rhs);
struct value* res = malloc(sizeof(struct value));
if (type_equals(&self->type, &rhs->type) && type_is(&self->type, "INT"))
{
value_init_int(res, pow(self->data.i, rhs->data.i), self->line);
return res;
}
if (type_equals(&self->type, &rhs->type) && type_is(&self->type, "FLOAT"))
{
value_init_float(res, powf(self->data.f, rhs->data.f), self->line);
return res;
}
free(res);
return NULL;
}
struct value* value_try_new_lt(struct value* self, struct value* rhs)
{
assert(self);
assert(rhs);
struct value* res = malloc(sizeof(struct value));
if (type_equals(&self->type, &rhs->type) && type_is(&self->type, "INT"))
{
value_init_bool(res, self->data.i < rhs->data.i, self->line);
return res;
}
if (type_equals(&self->type, &rhs->type) && type_is(&self->type, "FLOAT"))
{
value_init_bool(res, self->data.f < rhs->data.f, self->line);
return res;
}
free(res);
return NULL;
}
struct value* value_try_new_le(struct value* self, struct value* rhs)
{
assert(self);
assert(rhs);
struct value* res = malloc(sizeof(struct value));
if (type_equals(&self->type, &rhs->type) && type_is(&self->type, "INT"))
{
value_init_bool(res, self->data.i <= rhs->data.i, self->line);
return res;
}
if (type_equals(&self->type, &rhs->type) && type_is(&self->type, "FLOAT"))
{
value_init_bool(res, self->data.f <= rhs->data.f, self->line);
return res;
}
free(res);
return NULL;
}
struct value* value_try_new_gt(struct value* self, struct value* rhs)
{
assert(self);
assert(rhs);
struct value* res = malloc(sizeof(struct value));
if (type_equals(&self->type, &rhs->type) && type_is(&self->type, "INT"))
{
value_init_bool(res, self->data.i > rhs->data.i, self->line);
return res;
}
if (type_equals(&self->type, &rhs->type) && type_is(&self->type, "FLOAT"))
{
value_init_bool(res, self->data.f > rhs->data.f, self->line);
return res;
}
free(res);
return NULL;
}
struct value* value_try_new_ge(struct value* self, struct value* rhs)
{
assert(self);
assert(rhs);
struct value* res = malloc(sizeof(struct value));
if (type_equals(&self->type, &rhs->type) && type_is(&self->type, "INT"))
{
value_init_bool(res, self->data.i >= rhs->data.i, self->line);
return res;
}
if (type_equals(&self->type, &rhs->type) && type_is(&self->type, "FLOAT"))
{
value_init_bool(res, self->data.f >= rhs->data.f, self->line);
return res;
}
free(res);
return NULL;
}

View File

@ -9,6 +9,9 @@
union value_data { union value_data {
int b; int b;
char* s;
float f;
int i;
}; };
struct value { struct value {
@ -18,6 +21,10 @@ struct value {
}; };
void value_init_bool(struct value* self, int value, int line); void value_init_bool(struct value* self, int value, int line);
void value_init_int(struct value* self, int value, int line);
void value_init_float(struct value* self, float value, int line);
void value_init_string(struct value* self, char* value, int line);
void value_free(struct value* self); void value_free(struct value* self);
size_t value_str(struct value* self, char* buffer, size_t size); size_t value_str(struct value* self, char* buffer, size_t size);
@ -26,4 +33,16 @@ struct value* value_try_new_and(struct value* self, struct value* rhs);
struct value* value_try_new_or(struct value* self, struct value* rhs); struct value* value_try_new_or(struct value* self, struct value* rhs);
struct value* value_try_new_not(struct value* self); struct value* value_try_new_not(struct value* self);
struct value* value_try_new_add(struct value* self, struct value* rhs);
struct value* value_try_new_sub(struct value* self, struct value* rhs);
struct value* value_try_new_mul(struct value* self, struct value* rhs);
struct value* value_try_new_div(struct value* self, struct value* rhs);
struct value* value_try_new_mod(struct value* self, struct value* rhs);
struct value* value_try_new_pow(struct value* self, struct value* rhs);
struct value* value_try_new_lt(struct value* self, struct value* rhs);
struct value* value_try_new_le(struct value* self, struct value* rhs);
struct value* value_try_new_gt(struct value* self, struct value* rhs);
struct value* value_try_new_ge(struct value* self, struct value* rhs);
#endif #endif

View File

@ -14,7 +14,7 @@ static void test_lexer(char const* source, size_t size, ...)
struct lexer lex; struct lexer lex;
lexer_init(&lex, source); lexer_init(&lex, source);
int err = lexer_extract(&lex, &tokens); int err = lexer_extract(&lex, &tokens);
cr_assert_eq(0, err); cr_assert_eq(0, err, "%s", lex.error_msg);
cr_assert_eq(size, tokens.size, cr_assert_eq(size, tokens.size,
"size (%zu) != tokens.size (%zu)", "size (%zu) != tokens.size (%zu)",
size, tokens.size); size, tokens.size);
@ -68,3 +68,42 @@ Test(lexer, comment) {
Test(lexer, bool_arith) { Test(lexer, bool_arith) {
test_lexer("&&||!", 3, "AND", "OR", "NOT"); test_lexer("&&||!", 3, "AND", "OR", "NOT");
} }
Test(lexer, eqne) {
test_lexer("!= ==", 2, "NE", "EQ");
}
Test(lexer, int) {
test_lexer("5 -27", 2, "INT[5]", "INT[-27]");
}
Test(lexer, float) {
test_lexer("0.5 -2.7", 2, "FLOAT[0.5]", "FLOAT[-2.7]");
}
Test(lexer, string) {
test_lexer("'hello world ' \" bim\" '\\\"hello\\\"'", 3,
"STRING[hello world ]",
"STRING[ bim]",
"STRING[\\\"hello\\\"]");
}
Test(lexer, arithemtic) {
test_lexer("+-*/%**", 6,
"ADD",
"SUB",
"MUL",
"DIV",
"MOD",
"POW");
}
Test(lexer, comparisons) {
test_lexer(">>=<<=", 4,
"GT",
"GE",
"LT",
"LE");
}

View File

@ -67,3 +67,44 @@ Test(parser, bool_arith) {
"true && !false || true;"); "true && !false || true;");
} }
Test(parser, eqne) {
test_parser("ROOT(EQ(BOOL[true],BOOL[false]))",
"true == false;");
test_parser("ROOT(NE(BOOL[true],BOOL[false]))",
"true != false;");
}
Test(parser, num) {
test_parser("ROOT(EQ(INT[3],INT[-7]))",
"3 == -7;");
test_parser("ROOT(NE(FLOAT[2.9],FLOAT[-3.]))",
"2.9 != -3.;");
test_parser("ROOT(NE(STRING[bim],STRING[bam]))",
"'bim' != 'bam';");
}
Test(parser, arithmetic) {
test_parser("ROOT(ADD(INT[1],MUL(INT[2],INT[3])))",
"1 + 2 * 3;");
test_parser("ROOT(MUL(ADD(INT[1],INT[2]),INT[3]))",
"(1 + 2) * 3;");
test_parser("ROOT(SUB(INT[1],DIV(INT[2],INT[3])))",
"1 - 2 / 3;");
test_parser("ROOT(DIV(SUB(INT[1],INT[2]),INT[3]))",
"(1 - 2) / 3;");
}
Test(parser, cmp) {
test_parser("ROOT(LT(ADD(INT[1],INT[1]),INT[3]))",
"1 + 1 < 3;");
test_parser("ROOT(AND(LE(INT[0],INT[2]),GE(FLOAT[5.0],FLOAT[1.0])))",
"0 <= 2 && 5.0 >= 1.0;");
}

View File

@ -1,3 +1,4 @@
#include "commons.h"
#include <criterion/criterion.h> #include <criterion/criterion.h>
#include <parser.h> #include <parser.h>
#include <parser.h> #include <parser.h>
@ -14,7 +15,11 @@ static void test_check_ok(char const* source)
struct type_checker tc; struct type_checker tc;
type_checker_init(&tc); type_checker_init(&tc);
cr_assert_eq(type_checker_check(&tc, ast), 0); char buf[GUX_STR_SIZE];
node_str(ast, buf, GUX_STR_SIZE);
cr_assert_eq(type_checker_check(&tc, ast), 0,
"type checker failed: %s", buf);
type_checker_free(&tc); type_checker_free(&tc);
@ -29,12 +34,12 @@ static void test_check_ko(char const* source)
parser_init(&parser); parser_init(&parser);
struct node* ast = parser_try_new_root(&parser, source); struct node* ast = parser_try_new_root(&parser, source);
cr_assert_neq(ast, NULL); cr_assert_neq(ast, NULL, "NULL: %s", source);
struct type_checker tc; struct type_checker tc;
type_checker_init(&tc); type_checker_init(&tc);
cr_assert_neq(type_checker_check(&tc, ast), 0); cr_assert_neq(type_checker_check(&tc, ast), 0, "%s == null", source);
type_checker_free(&tc); type_checker_free(&tc);
@ -48,4 +53,103 @@ Test(type_checker, booleans) {
test_check_ok("true && false;"); test_check_ok("true && false;");
test_check_ok("true || false;"); test_check_ok("true || false;");
test_check_ok("true || !false && false;"); test_check_ok("true || !false && false;");
test_check_ko("7 && true;");
test_check_ko("false && -1;");
test_check_ko("7.0 && true;");
test_check_ko("false && -1.0;");
test_check_ko("'true' && true;");
test_check_ko("false && 'false';");
test_check_ko("7 || true;");
test_check_ko("false || -1;");
test_check_ko("7.0 || true;");
test_check_ko("false || -1.0;");
test_check_ko("'true' || true;");
test_check_ko("false || 'false';");
test_check_ko("!7;");
test_check_ko("!7.0;");
test_check_ko("!'true';");
}
Test(type_checker, arithmetic) {
test_check_ok("1 + 1;");
test_check_ok("1.0 + 1.2;");
test_check_ko("true + false;");
test_check_ok("'aze' + 'popopo';");
test_check_ko("1 - 'salut';");
test_check_ko("1.2 - 15;");
test_check_ko("false - 1.2;");
test_check_ko("\"a\" - true;");
test_check_ko("-17 * false;");
test_check_ko("-2.3 * 'oo';");
test_check_ko("true * 45;");
test_check_ko("'1' * 1.02;");
test_check_ko("441 / 3.1415;");
test_check_ko(".9 / false;");
test_check_ko("true / 'bim';");
test_check_ko("'aze' / 145;");
test_check_ok("33 % 1;");
test_check_ok("3.3 % 1.2;");
test_check_ko("false % false;");
test_check_ko("'' % 'other';");
test_check_ok("1 ** -45;");
test_check_ok("1.2 ** 0.54;");
test_check_ko("true ** false;");
test_check_ko("'coucou' ** 'bam';");
}
Test(type_checker, cmp) {
test_check_ko("-5 < 3.2;");
test_check_ko("-5 < true;");
test_check_ko("-5 < 'salut';");
test_check_ko("3.2 < 5;");
test_check_ko("true < 5;");
test_check_ko("\"5\" < 5;");
test_check_ko("-5 <= 3.2;");
test_check_ko("-5 <= true;");
test_check_ko("-5 <= 'salut';");
test_check_ko("3.2 <= 5;");
test_check_ko("true <= 5;");
test_check_ko("\"5\" <= 5;");
test_check_ko("-5 > 3.2;");
test_check_ko("-5 > true;");
test_check_ko("-5 > 'salut';");
test_check_ko("3.2 > 5;");
test_check_ko("true > 5;");
test_check_ko("\"5\" > 5;");
test_check_ko("-5 >= 3.2;");
test_check_ko("-5 >= true;");
test_check_ko("-5 >= 'salut';");
test_check_ko("3.2 >= 5;");
test_check_ko("true >= 5;");
test_check_ko("\"5\" >= 5;");
test_check_ko("true < true;");
test_check_ko("true <= true;");
test_check_ko("true > true;");
test_check_ko("true >= true;");
test_check_ko("'hello' < 'hello';");
test_check_ko("'hello' <= 'hello';");
test_check_ko("'hello' > 'hello';");
test_check_ko("'hello' >= 'hello';");
test_check_ok("5 > 5;");
test_check_ok("5.1 > 5.2;");
test_check_ok("5 >= 5;");
test_check_ok("5.1 >= 5.2;");
test_check_ok("5 < 5;");
test_check_ok("5.1 < 5.2;");
test_check_ok("5 <= 5;");
test_check_ok("5.1 <= 5.2;");
} }

View File

@ -1,6 +1,7 @@
#ifndef COMMONS_H #ifndef COMMONS_H
#define COMMONS_H #define COMMONS_H
#include <math.h>
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>

View File

@ -44,16 +44,6 @@ void* vec_pop(struct vec* self)
return element; return element;
} }
void vec_clear(struct vec* self)
{
assert(self);
while (self->size > 0)
{
vec_pop(self);
}
}
void vec_free_elements(struct vec* self) void vec_free_elements(struct vec* self)
{ {
assert(self); assert(self);

View File

@ -14,7 +14,6 @@ void vec_free(struct vec* self);
void vec_push(struct vec* self, void* element); void vec_push(struct vec* self, void* element);
void* vec_pop(struct vec* self); void* vec_pop(struct vec* self);
void vec_clear(struct vec* self);
void vec_free_elements(struct vec* self); void vec_free_elements(struct vec* self);

View File

@ -1,14 +0,0 @@
assert true;
assert !false;
assert !!true;
assert true && true;
assert !(true && false);
assert !(false && true);
assert !(false && false);
assert true || true;
assert true || false;
assert false || true;
assert !(false || false);

68
tests/builtins.gux Normal file
View File

@ -0,0 +1,68 @@
############
# BOOLEANS #
############
assert true;
assert !false;
assert !!true;
assert true && true;
assert !(true && false);
assert !(false && true);
assert !(false && false);
assert true || true;
assert true || false;
assert false || true;
assert !(false || false);
assert true == true;
assert false == false;
assert true != false;
assert false != true;
############
# INTEGERS #
############
assert 5 == 5;
assert 5 != 2;
assert 1 + 2 == 3;
assert 1 + -2 == -1;
assert 1 - 2 == -1;
assert 1 - -2 == 3;
assert 3 * 6 == 18;
assert 12 / 2 == 6;
assert 3 / 2 == 1;
assert 12 % 7 == 5;
assert 2 ** 3 == 8;
assert 1 + 2 * 3 == 7;
assert (1 + 2) * 3 == 9;
#########
# FLOAT #
#########
assert 2.3 == 2.3;
assert 2.3 != 2.4;
assert 1.0 + 2.0 == 3.0;
assert 1.0 + -2.0 == -1.0;
assert 1.0 - 2.0 == -1.0;
assert 1.0 - -2.0 == 3.0;
assert 3.0 * 6.0 == 18.0;
assert 12.0 / 2.0 == 6.0;
assert 3.0 / 2.0 == 1.5;
assert 12.0 % 7.0 == 5.0;
assert 2.0 ** 3.0 == 8.0;
###########
# STRINGS #
###########
assert "hello" == "hello";
assert "hello" != "world";
assert 3 * "a" == "aaa";
assert "a" * 3 == "aaa";
assert "a" + "b" == "ab";
assert 2 * "a" + "b" == "aab";
assert 2 * ("a" + 3 * "b") == "abbbabbb";

25
tests/cmp.gux Normal file
View File

@ -0,0 +1,25 @@
assert 5 < 8 == true;
assert 5 < 5 == false;
assert 5 < 4 == false;
assert 5 <= 8 == true;
assert 5 <= 5 == true;
assert 5 <= 4 == false;
assert 14 > 8 == true;
assert 7 > 7 == false;
assert 14 > 32 == false;
assert 14 >= 8 == true;
assert 7 >= 7 == true;
assert 14 >= 32 == false;
assert 5.0 < 8.0 == true;
assert 5.0 < 5.0 == false;
assert 5.0 < 4.0 == false;
assert 5.0 <= 8.0 == true;
assert 5.0 <= 5.0 == true;
assert 5.0 <= 4.0 == false;
assert 14.0 > 8.0 == true;
assert 7.0 > 7.0 == false;
assert 14.0 > 32.0 == false;
assert 14.0 >= 8.0 == true;
assert 7.0 >= 7.0 == true;
assert 14.0 >= 32.0 == false;

View File

@ -1,5 +1,8 @@
#include "vm.h" #include "vm.h"
#include "commons.h" #include "commons.h"
#include "program.h"
#include "type.h"
#include "value.h"
void vm_init(struct vm* self) void vm_init(struct vm* self)
{ {
@ -134,13 +137,190 @@ int vm_exec(struct vm* self, struct program* program)
vm_push(self, program_push_constant(program, not)); vm_push(self, program_push_constant(program, not));
self->pc++; self->pc++;
} break; } break;
case OP_EQ: {
int rhs = vm_pop(self);
int lhs = vm_pop(self);
struct value* lhs_val = program->constant_pool.data[lhs];
struct value* rhs_val = program->constant_pool.data[rhs];
struct value* res = malloc(sizeof(struct value));
if (lhs_val->type.kind == TYPE_BOOL)
{
value_init_bool(res,
lhs_val->data.b == rhs_val->data.b,
lhs_val->line);
}
else if (lhs_val->type.kind == TYPE_INT)
{
value_init_bool(res,
lhs_val->data.i == rhs_val->data.i,
lhs_val->line);
}
else if (lhs_val->type.kind == TYPE_FLOAT)
{
value_init_bool(res,
lhs_val->data.f == rhs_val->data.f,
lhs_val->line);
}
else if (lhs_val->type.kind == TYPE_STRING)
{
value_init_bool(res,
strcmp(lhs_val->data.s, rhs_val->data.s) == 0,
lhs_val->line);
}
else
{
fprintf(stderr, "operation not supported\n");
return 1;
}
vm_push(self, program_push_constant(program, res));
self->pc++;
} break;
case OP_ADD: {
int rhs = vm_pop(self);
int lhs = vm_pop(self);
struct value* lhs_val = program->constant_pool.data[lhs];
struct value* rhs_val = program->constant_pool.data[rhs];
struct value* res = value_try_new_add(lhs_val, rhs_val);
vm_push(self, program_push_constant(program, res));
self->pc++;
} break;
case OP_SUB: {
int rhs = vm_pop(self);
int lhs = vm_pop(self);
struct value* lhs_val = program->constant_pool.data[lhs];
struct value* rhs_val = program->constant_pool.data[rhs];
struct value* res = value_try_new_sub(lhs_val, rhs_val);
vm_push(self, program_push_constant(program, res));
self->pc++;
} break;
case OP_MUL: {
int rhs = vm_pop(self);
int lhs = vm_pop(self);
struct value* lhs_val = program->constant_pool.data[lhs];
struct value* rhs_val = program->constant_pool.data[rhs];
struct value* res = value_try_new_mul(lhs_val, rhs_val);
vm_push(self, program_push_constant(program, res));
self->pc++;
} break;
case OP_DIV: {
int rhs = vm_pop(self);
int lhs = vm_pop(self);
struct value* lhs_val = program->constant_pool.data[lhs];
struct value* rhs_val = program->constant_pool.data[rhs];
struct value* res = value_try_new_div(lhs_val, rhs_val);
vm_push(self, program_push_constant(program, res));
self->pc++;
} break;
case OP_MOD: {
int rhs = vm_pop(self);
int lhs = vm_pop(self);
struct value* lhs_val = program->constant_pool.data[lhs];
struct value* rhs_val = program->constant_pool.data[rhs];
struct value* res = value_try_new_mod(lhs_val, rhs_val);
vm_push(self, program_push_constant(program, res));
self->pc++;
} break;
case OP_POW: {
int rhs = vm_pop(self);
int lhs = vm_pop(self);
struct value* lhs_val = program->constant_pool.data[lhs];
struct value* rhs_val = program->constant_pool.data[rhs];
struct value* res = value_try_new_pow(lhs_val, rhs_val);
vm_push(self, program_push_constant(program, res));
self->pc++;
} break;
case OP_LT: {
int rhs = vm_pop(self);
int lhs = vm_pop(self);
struct value* lhs_val = program->constant_pool.data[lhs];
struct value* rhs_val = program->constant_pool.data[rhs];
struct value* res = value_try_new_lt(lhs_val, rhs_val);
vm_push(self, program_push_constant(program, res));
self->pc++;
} break;
case OP_LE: {
int rhs = vm_pop(self);
int lhs = vm_pop(self);
struct value* lhs_val = program->constant_pool.data[lhs];
struct value* rhs_val = program->constant_pool.data[rhs];
struct value* res = value_try_new_le(lhs_val, rhs_val);
vm_push(self, program_push_constant(program, res));
self->pc++;
} break;
case OP_GT: {
int rhs = vm_pop(self);
int lhs = vm_pop(self);
struct value* lhs_val = program->constant_pool.data[lhs];
struct value* rhs_val = program->constant_pool.data[rhs];
struct value* res = value_try_new_gt(lhs_val, rhs_val);
vm_push(self, program_push_constant(program, res));
self->pc++;
} break;
case OP_GE: {
int rhs = vm_pop(self);
int lhs = vm_pop(self);
struct value* lhs_val = program->constant_pool.data[lhs];
struct value* rhs_val = program->constant_pool.data[rhs];
struct value* res = value_try_new_ge(lhs_val, rhs_val);
vm_push(self, program_push_constant(program, res));
self->pc++;
} break;
default: assert(0);
} }
} }
return 0; return 0;
} }
size_t vm_str(struct vm* self, char* buffer, size_t size) size_t vm_str(struct vm* self, struct program* program,
char* buffer, size_t size)
{ {
assert(self); assert(self);
assert(buffer); assert(buffer);
@ -154,8 +334,13 @@ size_t vm_str(struct vm* self, char* buffer, size_t size)
for (size_t j=0; j<frame->sp; j++) for (size_t j=0; j<frame->sp; j++)
{ {
sz += snprintf(buffer + sz, size - sz, "\t%zu: %d\n", size_t k = frame->sp - 1 - j;
j, frame->stack[j]); struct value* v = program->constant_pool.data[frame->stack[k]];
char val[GUX_STR_SIZE];
value_str(v, val, GUX_STR_SIZE);
sz += snprintf(buffer + sz, size - sz, "\t%zu: %d (%s)\n",
k, frame->stack[k], val);
} }
} }

View File

@ -30,6 +30,7 @@ int vm_pop(struct vm* self);
int vm_exec(struct vm* self, struct program* program); int vm_exec(struct vm* self, struct program* program);
size_t vm_str(struct vm* self, char* buffer, size_t size); size_t vm_str(struct vm* self, struct program* program,
char* buffer, size_t size);
#endif #endif