ADD: array literals.

main
bog 2023-08-24 11:55:54 +02:00
parent 6013d65776
commit c2e9880c99
18 changed files with 400 additions and 64 deletions

View File

@ -40,7 +40,10 @@ executable(
'src/utils.c',
'src/opcodes.c',
'src/program.c',
'src/value.c',
'src/array.c',
'src/type.c',
'src/compiler.c',
'src/cstatic.c',

112
src/array.c Normal file
View File

@ -0,0 +1,112 @@
#include "array.h"
#include "value.h"
void array_init(array* self, type* elements_type)
{
assert(self);
self->type = type_new_clone(elements_type);
self->children.size = 0;
self->children.capacity = 1;
self->children.data = malloc(sizeof(struct value*)
* self->children.capacity);
}
void array_free(array* self)
{
assert(self);
for (size_t i=0; i<self->children.size; i++)
{
value_free((value*) 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;
type_free(self->type);
free(self->type); self->type = NULL;
}
void array_push(array* self, struct value* element)
{
assert(self);
assert(element);
if (self->children.size >= self->children.capacity)
{
self->children.capacity *= 2;
self->children.data = realloc(
self->children.data,
sizeof(struct value*)
* self->children.capacity
);
}
self->children.data[self->children.size] =
(struct value*) value_new_clone((value*) element);
self->children.size++;
}
size_t array_str(array* self, char* buffer, size_t size)
{
assert(self);
size_t sz = 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 += value_str((value*)self->children.data[i],
buffer + sz, size - sz);
}
sz += snprintf(buffer + sz, size - sz, "]");
return sz;
}
int array_equals(array* self, array* rhs)
{
assert(self);
assert(rhs);
if (self->children.size != rhs->children.size)
{
return 0;
}
for (size_t i=0; i<self->children.size; i++)
{
if (!value_equals(
(value*) self->children.data[i],
(value*) rhs->children.data[i]
))
{
return 0;
}
}
return 1;
}
array* array_new_clone(array* self)
{
array* clone = malloc(sizeof(array));
array_init(clone, self->type);
for (size_t i=0; i<self->children.size; i++)
{
array_push(clone, self->children.data[i]);
}
return clone;
}

27
src/array.h Normal file
View File

@ -0,0 +1,27 @@
#ifndef ARRAY_H
#define ARRAY_H
#include "commons.h"
#include "type.h"
struct value;
typedef struct {
type* type;
struct {
size_t size;
size_t capacity;
struct value** data;
} children;
} array;
void array_init(array* self, type* elements_type);
void array_free(array* self);
void array_push(array* self, struct value* element);
size_t array_str(array* self, char* buffer, size_t size);
int array_equals(array* self, array* rhs);
array* array_new_clone(array* self);
#endif

View File

@ -163,6 +163,11 @@ void compile_node(compiler* self, node* root, program* prog)
compile_children(self, root, prog);
program_add_instr(prog, OP_NOT, NO_PARAM);
}
else if (root->type == NODE_ARRAY)
{
compile_children(self, root, prog);
program_add_instr(prog, OP_MKARRAY, root->children.size);
}
else
{
compile_children(self, root, prog);

View File

@ -54,6 +54,11 @@ int cstatic_resolve(cstatic* self, node* ast)
return TY_STRING;
}
else if (ast->type == NODE_ARRAY)
{
return TY_ARRAY;
}
else if (ast->type == NODE_BOOLEAN
|| ast->type == NODE_EQ
|| ast->type == NODE_NE)
@ -93,6 +98,31 @@ int cstatic_check(cstatic* self, node* ast, char* msg, size_t size)
}
}
// Arrays
if (ast->type == NODE_ARRAY)
{
assert(ast->children.size > 0);
int ty = cstatic_resolve(self, ast->children.data[0]);
for (size_t i=1; i<ast->children.size; i++)
{
int status = cstatic_check_type(
self,
ast->children.data[i],
msg,
size,
ty,
TYPE_END
);
if (!status)
{
return status;
}
}
return 1;
}
// String Operations
if (ast->type == NODE_ADD)

View File

@ -12,11 +12,11 @@ WHITESPACES [ \t]+
BOOLEAN true|false
INTEGER -?[0-9]+
FLOAT -?[0-9]+\.[0-9]+
STRING \"[^\"]*\"
STRING \"[^"]*\"
%%
"\n" { line++; }
{COMMENT} {}
"\n" { line++; }
{WHITESPACES} {}
"assert" { return ASSERT; }
@ -34,6 +34,8 @@ STRING \"[^\"]*\"
"!" { return NOT; }
"(" { return OPAR; }
")" { return CPAR; }
"[" { return OSQUARE; }
"]" { return CSQUARE; }
{BOOLEAN} {
yylval.str = yytext;

View File

@ -22,10 +22,6 @@ int main(int argc, char** argv)
yyin = stdin;
}
node* n = malloc(sizeof(node));
node_init(n, NODE_PROG, "", 1);
stack_push(n);
yyparse();
ast = stack_pop();

View File

@ -9,7 +9,8 @@
G(NODE_EQ), G(NODE_NE), \
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)
G(NODE_MUL), G(NODE_DIV), G(NODE_MOD), G(NODE_POW), \
G(NODE_ARRAY)
#include "mutils.h"

View File

@ -27,7 +27,8 @@
G(OP_FUADD), \
G(OP_FUSUB), \
G(OP_CAT), \
G(OP_SMUL)
G(OP_SMUL), \
G(OP_MKARRAY)
enum Opcodes {
OPCODES(GEN_ENUM)

View File

@ -18,11 +18,12 @@
%union {
char* str;
void* node_val;
size_t n_children;
};
%left ASSERT
%token <str> BOOLEAN INTEGER FLOAT STRING
%type <n_children> expr exprs prog;
%left EQ NE
%left AND
%left OR
@ -30,26 +31,37 @@
%left MUL DIV MOD
%left POW
%left NOT
%type <node_val> expr;
%token OPAR CPAR
%token OPAR CPAR OSQUARE CSQUARE
%%
prog:
| exprs {
{
node* n = malloc(sizeof(node));
node_init(n, NODE_PROG, "", line);
stack_push(n);
$$ = 0;
}
| exprs {
node* n = malloc(sizeof(node));
node_init(n, NODE_PROG, "", line);
for (size_t i=0; i<$1; i++)
{
node_add_child(n, stack_pop());
}
stack_push(n);
$$ = $1;
}
;
exprs:
exprs expr {
node* parent = stack_top();
node_add_child(parent, $2);
}
exprs expr { $$ = $1 + $2; }
| expr {
node* parent = stack_top();
node_add_child(parent, $1);
}
| expr { $$ = $1; }
;
@ -57,115 +69,170 @@ expr:
ASSERT expr {
node *n = malloc(sizeof(node));
node_init(n, NODE_ASSERT, "", line);
node_add_child(n, $2);
$$ = n;
node_add_child(n, stack_pop());
stack_push(n);
$$ = 1;
}
| ADD expr {
node *n = malloc(sizeof(node));
node_init(n, NODE_UADD, "", line);
node_add_child(n, $2);
$$ = n;
node_add_child(n, stack_pop());
stack_push(n);
$$ = 1;
}
| SUB expr {
node *n = malloc(sizeof(node));
node_init(n, NODE_USUB, "", line);
node_add_child(n, $2);
$$ = n;
node_add_child(n, stack_pop());
stack_push(n);
$$ = 1;
}
| 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;
node* rhs = stack_pop();
node* lhs = stack_pop();
node_add_child(n, lhs);
node_add_child(n, rhs);
stack_push(n);
$$ = 1;
}
| 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;
node* rhs = stack_pop();
node* lhs = stack_pop();
node_add_child(n, lhs);
node_add_child(n, rhs);
stack_push(n);
$$ = 1;
}
| 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;
node* rhs = stack_pop();
node* lhs = stack_pop();
node_add_child(n, lhs);
node_add_child(n, rhs);
stack_push(n);
$$ = 1;
}
| 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;
node* rhs = stack_pop();
node* lhs = stack_pop();
node_add_child(n, lhs);
node_add_child(n, rhs);
stack_push(n);
$$ = 1;
}
| 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;
node* rhs = stack_pop();
node* lhs = stack_pop();
node_add_child(n, lhs);
node_add_child(n, rhs);
stack_push(n);
$$ = 1;
}
| 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;
node* rhs = stack_pop();
node* lhs = stack_pop();
node_add_child(n, lhs);
node_add_child(n, rhs);
stack_push(n);
$$ = 1;
}
| 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;
node* rhs = stack_pop();
node* lhs = stack_pop();
node_add_child(n, lhs);
node_add_child(n, rhs);
stack_push(n);
$$ = 1;
}
| 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;
node* rhs = stack_pop();
node* lhs = stack_pop();
node_add_child(n, lhs);
node_add_child(n, rhs);
stack_push(n);
$$ = 1;
}
| 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;
node* rhs = stack_pop();
node* lhs = stack_pop();
node_add_child(n, lhs);
node_add_child(n, rhs);
stack_push(n);
$$ = 1;
}
| 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;
node* rhs = stack_pop();
node* lhs = stack_pop();
node_add_child(n, lhs);
node_add_child(n, rhs);
stack_push(n);
$$ = 1;
}
| NOT expr {
node *n = malloc(sizeof(node));
node_init(n, NODE_NOT, "", line);
node_add_child(n, $2);
$$ = n;
node_add_child(n, stack_pop());
stack_push(n);
$$ = 1;
}
| OPAR expr CPAR {
$$ = $2;
}
| OSQUARE exprs CSQUARE {
node *n = malloc(sizeof(node));
node_init(n, NODE_ARRAY, "", line);
node* elements[$2];
for (size_t i=0; i<$2; i++)
{
elements[i] = stack_pop();
}
for (size_t i=0; i<$2; i++)
{
node_add_child(n, elements[$2 - 1 - i]);
}
stack_push(n);
$$ = 1;
}
| STRING {
node* n = malloc(sizeof(node));
size_t const SZ = strlen($1);
@ -174,25 +241,29 @@ expr:
str[SZ - 2] = '\0';
node_init(n, NODE_STRING, str, line);
$$ = n;
stack_push(n);
$$ = 1;
}
| BOOLEAN {
node* n = malloc(sizeof(node));
node_init(n, NODE_BOOLEAN, $1, line);
$$ = n;
stack_push(n);
$$ = 1;
}
| INTEGER {
node* n = malloc(sizeof(node));
node_init(n, NODE_INTEGER, $1, line);
$$ = n;
stack_push(n);
$$ = 1;
}
| FLOAT {
node* n = malloc(sizeof(node));
node_init(n, NODE_FLOAT, $1, line);
$$ = n;
stack_push(n);
$$ = 1;
}
;

View File

@ -1,6 +1,5 @@
#include "type.h"
char const* TypesStr[] = { TYPES(GEN_STRING) };
void type_init(type* self, int base_type)

View File

@ -1,5 +1,5 @@
#ifndef TYPE_H
#define TYPE
#define TYPE_H
#include "commons.h"
@ -9,6 +9,7 @@
G(TY_INTEGER), \
G(TY_FLOAT), \
G(TY_STRING), \
G(TY_ARRAY), \
G(TY_TYPE_COUNT)
enum Types {

View File

@ -1,4 +1,5 @@
#include "value.h"
#include "array.h"
void value_init_boolean(value* self, int boolean, int lineno)
{
@ -42,6 +43,18 @@ void value_init_string(value* self, char* str, int lineno)
type_init(self->type, TY_STRING);
}
void value_init_array(value* self, array* arr, int lineno)
{
assert(self);
self->val.array_val = array_new_clone(arr);
self->lineno = lineno;
self->type = malloc(sizeof(type));
type_init(self->type, TY_ARRAY);
}
void value_free(value* self)
{
assert(self);
@ -53,6 +66,14 @@ void value_free(value* self)
self->val.string = NULL;
}
if (self->type->base_type == TY_ARRAY
&& self->val.array_val != NULL)
{
array_free(self->val.array_val);
free(self->val.array_val);
self->val.array_val = NULL;
}
type_free(self->type);
free(self->type);
self->type = NULL;
@ -70,6 +91,11 @@ value* value_new_clone(value* self)
clone->val.string = str_new(self->val.string);
}
if (self->type->base_type == TY_ARRAY)
{
clone->val.array_val = array_new_clone(self->val.array_val);
}
clone->lineno = self->lineno;
return clone;
@ -106,6 +132,11 @@ int value_equals(value* self, value* rhs)
return strcmp(self->val.string, rhs->val.string) == 0;
}
if (self->type->base_type == TY_ARRAY)
{
return array_equals(self->val.array_val, rhs->val.array_val);
}
size_t const SZ = 512;
char ty_str[SZ];
@ -126,6 +157,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_ARRAY:
return array_str(self->val.array_val, buffer, size);
case TY_STRING:
return snprintf(buffer, size, "%s",
self->val.string);

View File

@ -3,6 +3,7 @@
#include "commons.h"
#include "type.h"
#include "array.h"
typedef struct {
type* type;
@ -12,6 +13,7 @@ typedef struct {
int integer;
float real_float;
char* string;
array* array_val;
} val;
} value;
@ -19,6 +21,7 @@ void value_init_boolean(value* self, int boolean, int lineno);
void value_init_integer(value* self, int integer, int lineno);
void value_init_float(value* self, float real_float, int lineno);
void value_init_string(value* self, char* string, int lineno);
void value_init_array(value* self, array* arr, int lineno);
void value_free(value* self);

View File

@ -69,6 +69,8 @@ void vm_exec(vm* self, program* prog)
case OP_SMUL: vm_smul(self); break;
case OP_CAT: vm_cat(self); break;
case OP_MKARRAY: vm_mkarray(self, param); break;
default: {
fprintf(stderr, "unknown opcode %s\n",
OpcodesStr[opcode]);
@ -546,3 +548,38 @@ void vm_cat(vm* self)
self->pc++;
}
void vm_mkarray(vm* self, int param)
{
value* elements[param];
for (int i=0; i<param; i++)
{
elements[param - 1 - i] = vm_pop_value(self);
}
array* arr = malloc(sizeof(array));
array_init(arr, elements[0]->type);
value* arr_val = malloc(sizeof(value));
for (int i=0; i<param; i++)
{
array_push(arr, (struct value*) elements[i]);
}
value_init_array(arr_val, arr, elements[0]->lineno);
vm_push_value(self, arr_val);
for (int i=0; i<param; i++)
{
value_free(elements[i]);
free(elements[i]);
}
array_free(arr);
free(arr);
self->pc++;
}

View File

@ -52,5 +52,6 @@ void vm_assert(vm* self);
void vm_smul(vm* self);
void vm_cat(vm* self);
void vm_mkarray(vm* self, int param);
#endif

2
tests/err_ty_array.wuz Normal file
View File

@ -0,0 +1,2 @@
[]
[1 2 3 "4"]

11
tests/test_array.wuz Normal file
View File

@ -0,0 +1,11 @@
assert [1 - 2 3] == [-1 3]
assert [1 -2 3] == [1 -2 3]
assert [1 2 3] == [1 2 3]
assert ["a" "b" "c"] == ["a" "b" "c"]
assert [1 2 3] != [7 2 3]
assert [1 2 3] != [1 2 3 4]
assert ["a" "b" "c"] != ["ac" "b" "c"]
assert ["a" "b" "c"] != ["a" "b" "c" "d"]