add generic arrays
This commit is contained in:
parent
6f91a71306
commit
f6b74f8f97
20
ir.c
20
ir.c
@ -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
7
ir.h
@ -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
2
lex.c
@ -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
98
parse.c
@ -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
3
tok.c
@ -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
2
tok.h
@ -51,6 +51,8 @@ enum Operator {
|
|||||||
OpRCurl = '}',
|
OpRCurl = '}',
|
||||||
OpLParen = '(',
|
OpLParen = '(',
|
||||||
OpRParen = ')',
|
OpRParen = ')',
|
||||||
|
OpLBrack = '[',
|
||||||
|
OpRBrack = ']',
|
||||||
OpComma = ',',
|
OpComma = ',',
|
||||||
OpAdd = '+',
|
OpAdd = '+',
|
||||||
OpSub = '-',
|
OpSub = '-',
|
||||||
|
35
vm.c
35
vm.c
@ -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();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user