add generic arrays

This commit is contained in:
r4 2021-12-30 17:59:28 +01:00
parent 6f91a71306
commit f6b74f8f97
7 changed files with 162 additions and 5 deletions

20
ir.c
View File

@ -21,6 +21,7 @@ const char *irinstr_str[IRInstrEnumSize] = {
[IRJnz] = "jnz", [IRJnz] = "jnz",
[IRCallInternal] = "calli", [IRCallInternal] = "calli",
[IRAddrOf] = "addrof", [IRAddrOf] = "addrof",
[IRArrMake] = "mkarr",
}; };
#define IRLIST_INIT_CAP_LONG 4096 #define IRLIST_INIT_CAP_LONG 4096
@ -86,13 +87,16 @@ void irlist_term(IRList *v) {
case IRJnz: case IRJnz:
free_irparam(&i->tok.CJmp.condition, true); free_irparam(&i->tok.CJmp.condition, true);
break; break;
case IRCallInternal: { case IRCallInternal:
size_t n_args = i->tok.CallI.n_args; for (size_t j = 0; j < i->tok.CallI.n_args; j++)
for (size_t j = 0; j < n_args; j++)
free_irparam(&i->tok.CallI.args[j], true); free_irparam(&i->tok.CallI.args[j], true);
free(i->tok.CallI.args); free(i->tok.CallI.args);
break; break;
} case IRArrMake:
for (size_t j = 0; j < i->tok.ArrMake.len; j++)
free_irparam(&i->tok.ArrMake.vals[j], true);
free(i->tok.ArrMake.vals);
break;
default: default:
ASSERT_UNREACHED(); ASSERT_UNREACHED();
} }
@ -198,6 +202,14 @@ void print_ir(IRList *v, const BuiltinFunc *builtin_funcs) {
} }
break; break;
} }
case IRArrMake: {
printf(" %%%zx", i->tok.ArrMake.arr_addr);
for (size_t j = 0; j < i->tok.ArrMake.len; j++) {
printf(" ");
print_irparam(&i->tok.ArrMake.vals[j]);
}
break;
}
default: ASSERT_UNREACHED(); default: ASSERT_UNREACHED();
} }
printf(" ; %zu:%zu", i->tok.ln, i->tok.col); printf(" ; %zu:%zu", i->tok.ln, i->tok.col);

7
ir.h
View File

@ -51,6 +51,7 @@ enum IRInstr {
IRJnz, IRJnz,
IRCallInternal, IRCallInternal,
IRAddrOf, IRAddrOf,
IRArrMake,
IRInstrEnumSize, IRInstrEnumSize,
}; };
typedef enum IRInstr IRInstr; typedef enum IRInstr IRInstr;
@ -106,6 +107,12 @@ typedef struct IRTok {
size_t n_args; size_t n_args;
IRParam *args; IRParam *args;
} CallI; } CallI;
struct {
size_t arr_addr;
size_t len, cap;
IRParam *vals;
} ArrMake;
}; };
} IRTok; } IRTok;

2
lex.c
View File

@ -247,6 +247,8 @@ TokList lex(const char *s) {
case '}': case '}':
case '(': case '(':
case ')': case ')':
case '[':
case ']':
case ',': case ',':
case '+': case '+':
case '-': case '-':

98
parse.c
View File

@ -66,6 +66,9 @@ static void set_irtok_dest_addr(IRTok *t, size_t addr) {
case IRCallInternal: case IRCallInternal:
t->CallI.ret_addr = addr; t->CallI.ret_addr = addr;
break; break;
case IRArrMake:
t->ArrMake.arr_addr = addr;
break;
default: default:
ASSERT_UNREACHED(); ASSERT_UNREACHED();
} }
@ -313,7 +316,7 @@ static ExprRet expr(IRList *out_ir, TokList *toks, Map *funcs, Scope *parent_sc,
eval_func_in_place = false; eval_func_in_place = false;
if (t->next->tok.kind == TokOp) { if (t->next->tok.kind == TokOp) {
if (t->next->tok.Op == OpComma) { if (t->next->tok.Op == OpComma) {
toklist_del(toks, t->next, t->next); /* delete right parenthesis */ toklist_del(toks, t->next, t->next); /* delete comma */
continue; continue;
} else if (t->next->tok.Op == OpRParen) { } else if (t->next->tok.Op == OpRParen) {
toklist_del(toks, t->next, t->next); /* delete right parenthesis */ toklist_del(toks, t->next, t->next); /* delete right parenthesis */
@ -394,6 +397,99 @@ static ExprRet expr(IRList *out_ir, TokList *toks, Map *funcs, Scope *parent_sc,
} }
} }
/* Collapse array. */
else if (t->tok.kind == TokOp && t->tok.Op == OpLBrack) {
TokListItem *lbrack = t;
bool eval_immediately = true;
size_t elems_len = 0;
size_t elems_cap = 0;
IRParam *elems = NULL;
if (t->next->tok.kind == TokOp && t->next->tok.Op == OpRBrack) {
/* empty array */
toklist_del(toks, t->next, t->next); /* delete right bracket */
} else {
elems_cap = 16;
elems = xmalloc(sizeof(IRParam) * elems_cap);
for (;;) {
if (elems_len+1 > elems_cap)
elems = xrealloc(elems, (elems_cap *= 2));
IRParam e;
TRY_RET_ELSE(e = expr_into_irparam(out_ir, toks, funcs, &sc, t->next), (ExprRet){0}, free(elems));
if (e.kind != IRParamLiteral)
eval_immediately = false;
elems[elems_len++] = e;
if (t->next->tok.kind == TokOp) {
if (t->next->tok.Op == OpComma) {
toklist_del(toks, t->next, t->next); /* delete comma */
continue;
} else if (t->next->tok.Op == OpRBrack) {
toklist_del(toks, t->next, t->next); /* delete right bracket */
break;
}
}
mark_err(&t->next->tok);
set_err("Expected ',' or ']' after array element");
free(elems);
return (ExprRet){0};
}
}
if (eval_immediately) {
/* turn array into value */
Value arr = {
.type = TypeArr,
.Arr = {
.type = TypeVoid,
.is_string = false,
.dynamically_allocated = false,
.vals = NULL,
.len = elems_len,
.cap = elems_len ? elems_cap : 0,
},
};
if (elems_len) {
Type arr_ty = elems[0].Literal.type;
void *arr_vals = xmalloc(type_size[arr_ty] * elems_cap);
for (size_t i = 0; i < elems_len; i++) {
Value *v = &elems[i].Literal;
if (v->type != arr_ty) {
free(arr_vals);
free(elems);
set_err("Type of array item %zu (%s) differs from array type (%s)", i, type_str[v->type], type_str[arr_ty]);
return (ExprRet){0};
}
memcpy((uint8_t*)arr_vals + type_size[arr_ty] * i, &v->Void, type_size[arr_ty]);
}
arr.Arr.type = arr_ty;
arr.Arr.vals = arr_vals;
}
/* set lbracket to collapsed array value */
lbrack->tok.kind = TokVal;
lbrack->tok.Val = arr;
/* free the now no longer needed element IRParam values */
free(elems);
} else {
/* array initialization IR instruction */
IRTok ir_tok = {
.ln = lbrack->tok.ln,
.col = lbrack->tok.col,
.instr = IRArrMake,
.ArrMake = {
.arr_addr = 0,
.len = elems_len,
.cap = elems_cap,
.vals = elems,
},
};
/* return if we've just evaluated the last instruction */
ExprRet ret;
if (expr_flush_ir_and_maybe_return(out_ir, toks, ir_tok, start, &sc, lbrack, &ret))
return ret;
}
}
/* Collapse unary operation. */ /* Collapse unary operation. */
if (perform_unary) { if (perform_unary) {
Tok *v = &t->tok; /* what we want to perform the operation on */ Tok *v = &t->tok; /* what we want to perform the operation on */

3
tok.c
View File

@ -117,6 +117,7 @@ int8_t op_prec[OperatorEnumSize] = {
[OpNewLn] = PREC_DELIM, [OpNewLn] = PREC_DELIM,
[OpLCurl] = PREC_DELIM, [OpLCurl] = PREC_DELIM,
[OpRParen] = PREC_DELIM, [OpRParen] = PREC_DELIM,
[OpRBrack] = PREC_DELIM,
[OpComma] = PREC_DELIM, [OpComma] = PREC_DELIM,
[OpAnd] = 0, [OpAnd] = 0,
[OpOr] = 0, [OpOr] = 0,
@ -137,6 +138,8 @@ const char *op_str[OperatorEnumSize] = {
[OpRCurl] = "}", [OpRCurl] = "}",
[OpLParen] = "(", [OpLParen] = "(",
[OpRParen] = ")", [OpRParen] = ")",
[OpLBrack] = "[",
[OpRBrack] = "]",
[OpComma] = ",", [OpComma] = ",",
[OpAdd] = "+", [OpAdd] = "+",
[OpSub] = "-", [OpSub] = "-",

2
tok.h
View File

@ -51,6 +51,8 @@ enum Operator {
OpRCurl = '}', OpRCurl = '}',
OpLParen = '(', OpLParen = '(',
OpRParen = ')', OpRParen = ')',
OpLBrack = '[',
OpRBrack = ']',
OpComma = ',', OpComma = ',',
OpAdd = '+', OpAdd = '+',
OpSub = '-', OpSub = '-',

35
vm.c
View File

@ -92,6 +92,8 @@ void run(IRList *ir, const BuiltinFunc *builtin_funcs) {
} }
case IRAddrOf: { case IRAddrOf: {
if (instr->Unary.val.kind != IRParamAddr) { if (instr->Unary.val.kind != IRParamAddr) {
free(fn_args);
stack_term(&s);
set_err("Unable to take the address of a literal"); set_err("Unable to take the address of a literal");
return; return;
} }
@ -174,6 +176,39 @@ void run(IRList *ir, const BuiltinFunc *builtin_funcs) {
} }
break; break;
} }
case IRArrMake: {
size_t arr_len = instr->ArrMake.len, arr_cap = instr->ArrMake.cap;
Value arr = {
.type = TypeArr,
.Arr = {
.type = TypeVoid,
.is_string = false,
.dynamically_allocated = true,
.vals = NULL,
.len = arr_len,
.cap = arr_len ? arr_cap : 0,
},
};
if (arr_len) {
Type arr_ty = irparam_to_val(&s, &instr->ArrMake.vals[0])->type;
void *arr_vals = xmalloc(type_size[arr_ty] * arr_cap);
for (size_t j = 0; j < arr_len; j++) {
Value *v = irparam_to_val(&s, &instr->ArrMake.vals[j]);
if (v->type != arr_ty) {
free(arr_vals);
free(fn_args);
stack_term(&s);
set_err("Type of array item %zu (%s) differs from array type (%s)", j, type_str[v->type], type_str[arr_ty]);
return;
}
memcpy((uint8_t*)arr_vals + type_size[arr_ty] * j, &v->Void, type_size[arr_ty]);
}
arr.Arr.type = arr_ty;
arr.Arr.vals = arr_vals;
}
stack_assign(&s, instr->ArrMake.arr_addr, &arr);
break;
}
default: default:
ASSERT_UNREACHED(); ASSERT_UNREACHED();
} }