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/utils.c',
'src/opcodes.c', 'src/opcodes.c',
'src/program.c', 'src/program.c',
'src/value.c', 'src/value.c',
'src/array.c',
'src/type.c', 'src/type.c',
'src/compiler.c', 'src/compiler.c',
'src/cstatic.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); compile_children(self, root, prog);
program_add_instr(prog, OP_NOT, NO_PARAM); 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 else
{ {
compile_children(self, root, prog); compile_children(self, root, prog);

View File

@ -54,6 +54,11 @@ int cstatic_resolve(cstatic* self, node* ast)
return TY_STRING; return TY_STRING;
} }
else if (ast->type == NODE_ARRAY)
{
return TY_ARRAY;
}
else if (ast->type == NODE_BOOLEAN else if (ast->type == NODE_BOOLEAN
|| ast->type == NODE_EQ || ast->type == NODE_EQ
|| ast->type == NODE_NE) || 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 // String Operations
if (ast->type == NODE_ADD) if (ast->type == NODE_ADD)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,4 +1,5 @@
#include "value.h" #include "value.h"
#include "array.h"
void value_init_boolean(value* self, int boolean, int lineno) 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); 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) void value_free(value* self)
{ {
assert(self); assert(self);
@ -53,6 +66,14 @@ void value_free(value* self)
self->val.string = NULL; 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); type_free(self->type);
free(self->type); free(self->type);
self->type = NULL; self->type = NULL;
@ -70,6 +91,11 @@ value* value_new_clone(value* self)
clone->val.string = str_new(self->val.string); 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; clone->lineno = self->lineno;
return clone; return clone;
@ -106,6 +132,11 @@ int value_equals(value* self, value* rhs)
return strcmp(self->val.string, rhs->val.string) == 0; 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; size_t const SZ = 512;
char ty_str[SZ]; char ty_str[SZ];
@ -126,6 +157,9 @@ size_t value_str(value* self, char* buffer, size_t size)
return snprintf(buffer, size, "%s", return snprintf(buffer, size, "%s",
self->val.boolean == 0 self->val.boolean == 0
? "false" : "true"); ? "false" : "true");
case TY_ARRAY:
return array_str(self->val.array_val, buffer, size);
case TY_STRING: case TY_STRING:
return snprintf(buffer, size, "%s", return snprintf(buffer, size, "%s",
self->val.string); self->val.string);

View File

@ -3,6 +3,7 @@
#include "commons.h" #include "commons.h"
#include "type.h" #include "type.h"
#include "array.h"
typedef struct { typedef struct {
type* type; type* type;
@ -12,6 +13,7 @@ typedef struct {
int integer; int integer;
float real_float; float real_float;
char* string; char* string;
array* array_val;
} val; } val;
} value; } 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_integer(value* self, int integer, int lineno);
void value_init_float(value* self, float real_float, 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_string(value* self, char* string, int lineno);
void value_init_array(value* self, array* arr, int lineno);
void value_free(value* self); 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_SMUL: vm_smul(self); break;
case OP_CAT: vm_cat(self); break; case OP_CAT: vm_cat(self); break;
case OP_MKARRAY: vm_mkarray(self, param); break;
default: { default: {
fprintf(stderr, "unknown opcode %s\n", fprintf(stderr, "unknown opcode %s\n",
OpcodesStr[opcode]); OpcodesStr[opcode]);
@ -546,3 +548,38 @@ void vm_cat(vm* self)
self->pc++; 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_smul(vm* self);
void vm_cat(vm* self); void vm_cat(vm* self);
void vm_mkarray(vm* self, int param);
#endif #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"]