From f99f351e01dc8140a36c1a9b5568f5081cfa1e70 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 27 Dec 2019 15:49:52 +0000 Subject: Add constant literal expressions --- src/check_expr.cpp | 252 ++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 212 insertions(+), 40 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 14b188cc0..a0978d4a6 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3108,6 +3108,8 @@ bool check_index_value(CheckerContext *c, bool open_range, Ast *index_value, i64 return false; } + if (value) *value = exact_value_to_i64(exact_value_sub(operand.value, lo)); + return true; } else { // NOTE(bill): Do array bound checking @@ -3144,6 +3146,140 @@ bool check_index_value(CheckerContext *c, bool open_range, Ast *index_value, i64 return true; } +ExactValue get_constant_field_single(CheckerContext *c, ExactValue value, i32 index, bool *success_, bool *finish_) { + if (value.kind == ExactValue_String) { + GB_ASSERT(0 <= index && index < value.value_string.len); + u8 val = value.value_string[index]; + if (success_) *success_ = true; + if (finish_) *finish_ = true; + return exact_value_u64(val); + } + if (value.kind != ExactValue_Compound) { + if (success_) *success_ = true; + if (finish_) *finish_ = true; + return value; + } + + + Ast *node = value.value_compound; + switch (node->kind) { + case_ast_node(cl, CompoundLit, node); + if (cl->elems.count == 0) { + if (success_) *success_ = true; + if (finish_) *finish_ = true; + return empty_exact_value; + } + + if (cl->elems[0]->kind == Ast_FieldValue) { + if (is_type_struct(node->tav.type)) { + for_array(i, cl->elems) { + Ast *elem = cl->elems[i]; + if (elem->kind != Ast_FieldValue) { + continue; + } + ast_node(fv, FieldValue, elem); + String name = fv->field->Ident.token.string; + Selection sub_sel = lookup_field(node->tav.type, name, false); + defer (array_free(&sub_sel.index)); + if (sub_sel.index[0] == index) { + value = fv->value->tav.value; + break; + } + } + } else if (is_type_array(node->tav.type) || is_type_enumerated_array(node->tav.type)) { + for_array(i, cl->elems) { + Ast *elem = cl->elems[i]; + if (elem->kind != Ast_FieldValue) { + continue; + } + ast_node(fv, FieldValue, elem); + if (is_ast_range(fv->field)) { + ast_node(ie, BinaryExpr, fv->field); + TypeAndValue lo_tav = ie->left->tav; + TypeAndValue hi_tav = ie->right->tav; + GB_ASSERT(lo_tav.mode == Addressing_Constant); + GB_ASSERT(hi_tav.mode == Addressing_Constant); + + TokenKind op = ie->op.kind; + i64 lo = exact_value_to_i64(lo_tav.value); + i64 hi = exact_value_to_i64(hi_tav.value); + + i64 corrected_index = index; + + if (is_type_enumerated_array(node->tav.type)) { + Type *bt = base_type(node->tav.type); + GB_ASSERT(bt->kind == Type_EnumeratedArray); + corrected_index = index + exact_value_to_i64(bt->EnumeratedArray.min_value); + } + if (op == Token_Ellipsis) { + if (lo <= corrected_index && corrected_index <= hi) { + TypeAndValue tav = fv->value->tav; + if (success_) *success_ = true; + if (finish_) *finish_ = false; + return tav.value; + } + } else { + if (lo <= corrected_index && corrected_index < hi) { + TypeAndValue tav = fv->value->tav; + if (success_) *success_ = true; + if (finish_) *finish_ = false; + return tav.value; + } + } + } else { + TypeAndValue index_tav = fv->field->tav; + GB_ASSERT(index_tav.mode == Addressing_Constant); + ExactValue index_value = index_tav.value; + if (is_type_enumerated_array(node->tav.type)) { + Type *bt = base_type(node->tav.type); + GB_ASSERT(bt->kind == Type_EnumeratedArray); + index_value = exact_value_sub(index_value, bt->EnumeratedArray.min_value); + } + + i64 field_index = exact_value_to_i64(index_value); + if (index == field_index) { + TypeAndValue tav = fv->value->tav; + value = tav.value; + break; + } + } + + } + } + } else { + i32 count = (i32)cl->elems.count; + if (count < index) { + if (success_) *success_ = false; + if (finish_) *finish_ = true; + return empty_exact_value; + } + TypeAndValue tav = cl->elems[index]->tav; + if (tav.mode == Addressing_Constant) { + if (success_) *success_ = true; + if (finish_) *finish_ = false; + return tav.value; + } else { + GB_ASSERT(is_type_untyped_nil(tav.type)); + if (success_) *success_ = true; + if (finish_) *finish_ = false; + return tav.value; + } + } + + case_end; + + default: + // TODO(bill): Should this be a general fallback? + if (success_) *success_ = true; + if (finish_) *finish_ = true; + return empty_exact_value; + } + + if (finish_) *finish_ = false; + return value; +} + + ExactValue get_constant_field(CheckerContext *c, Operand const *operand, Selection sel, bool *success_) { if (operand->mode != Addressing_Constant) { @@ -3169,39 +3305,11 @@ ExactValue get_constant_field(CheckerContext *c, Operand const *operand, Selecti i32 index = sel.index[0]; sel = sub_selection(sel, 1); - Ast *node = value.value_compound; - switch (node->kind) { - case_ast_node(cl, CompoundLit, node); - if (cl->elems.count == 0) { - if (success_) *success_ = true; - return empty_exact_value; - } - - if (cl->elems[0]->kind == Ast_FieldValue) { - GB_PANIC("TODO"); - } else { - i32 count = (i32)cl->elems.count; - if (count < index) { - if (success_) *success_ = false; - return empty_exact_value; - } - TypeAndValue tav = cl->elems[index]->tav; - if (tav.mode == Addressing_Constant) { - value = tav.value; - } else { - GB_ASSERT(is_type_untyped_nil(tav.type)); - value = tav.value; - } - } - - case_end; - - default: - if (success_) *success_ = true; - return empty_exact_value; + bool finish = false; + value = get_constant_field_single(c, value, index, success_, &finish); + if (finish) { + return value; } - - depth += 1; } if (success_) *success_ = true; @@ -3366,6 +3474,8 @@ Entity *check_selector(CheckerContext *c, Operand *operand, Ast *node, Type *typ operand->expr = node; operand->value = field_value; operand->type = entity->type; + add_entity_use(c, selector, entity); + add_type_and_value(c->info, operand->expr, operand->mode, operand->type, operand->value); return entity; } @@ -3389,6 +3499,8 @@ Entity *check_selector(CheckerContext *c, Operand *operand, Ast *node, Type *typ operand->expr = node; operand->value = field_value; operand->type = entity->type; + add_entity_use(c, selector, entity); + add_type_and_value(c->info, operand->expr, operand->mode, operand->type, operand->value); return entity; } @@ -7002,6 +7114,13 @@ bool check_set_index_data(Operand *o, Type *t, bool indirection, i64 *max_count, } o->type = t_u8; return true; + } else if (t->Basic.kind == Basic_UntypedString) { + if (o->mode == Addressing_Constant) { + *max_count = o->value.value_string.len; + o->type = t_u8; + return true; + } + return false; } break; @@ -7733,6 +7852,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type error(elem, "Expected a constant integer as an array field"); continue; } + // add_type_and_value(c->info, op_index.expr, op_index.mode, op_index.type, op_index.value); i64 index = exact_value_to_i64(op_index.value); @@ -7913,13 +8033,13 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type // NOTE(bill): These are sanity checks for invalid enum values - if (max_type_count >= 0 && (lo < total_lo || lo >= total_hi)) { + if (max_type_count >= 0 && (lo < total_lo || lo > total_hi)) { gbString lo_str = expr_to_string(x.expr); error(elem, "Index %s is out of bounds (%.*s .. %.*s) for %.*s", lo_str, LIT(total_lo_string), LIT(total_hi_string), LIT(context_name)); gb_string_free(lo_str); continue; } - if (max_type_count >= 0 && (hi < 0 || hi >= max_type_count)) { + if (max_type_count >= 0 && (hi < 0 || hi > total_hi)) { gbString hi_str = expr_to_string(y.expr); error(elem, "Index %s is out of bounds (%.*s .. %.*s) for %.*s", hi_str, LIT(total_lo_string), LIT(total_hi_string), LIT(context_name)); gb_string_free(hi_str); @@ -7946,7 +8066,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type i64 index = exact_value_to_i64(op_index.value); - if (max_type_count >= 0 && (index < total_lo || index >= total_hi)) { + if (max_type_count >= 0 && (index < total_lo || index > total_hi)) { gbString idx_str = expr_to_string(op_index.expr); error(elem, "Index %s is out of bounds (%.*s .. %.*s) for %.*s", idx_str, LIT(total_lo_string), LIT(total_hi_string), LIT(context_name)); gb_string_free(idx_str); @@ -8506,7 +8626,15 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type bool valid = check_set_index_data(o, t, is_ptr, &max_count, o->type); if (is_const) { - valid = false; + if (is_type_array(t)) { + // Okay + } else if (is_type_enumerated_array(t)) { + // Okay + } else if (is_type_string(t)) { + // Okay + } else { + valid = false; + } } if (!valid) { @@ -8515,7 +8643,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type defer (gb_string_free(str)); defer (gb_string_free(type_str)); if (is_const) { - error(o->expr, "Cannot index a constant '%s'", str); + error(o->expr, "Cannot index constant '%s' of type '%s'", str, type_str); } else { error(o->expr, "Cannot index '%s' of type '%s'", str, type_str); } @@ -8542,6 +8670,20 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type i64 index = 0; bool ok = check_index_value(c, false, ie->index, max_count, &index, index_type_hint); + if (is_const) { + if (index < 0) { + gbString str = expr_to_string(o->expr); + error(o->expr, "Cannot index a constant '%s'", str); + gb_string_free(str); + o->mode = Addressing_Invalid; + o->expr = node; + return kind; + } else if (ok) { + ExactValue value = type_and_value_of_expr(ie->expr).value; + o->mode = Addressing_Constant; + o->value = get_constant_field_single(c, value, cast(i32)index, nullptr, nullptr); + } + } node->viral_state_flags |= ie->index->viral_state_flags; case_end; @@ -8563,7 +8705,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type Type *t = base_type(type_deref(o->type)); switch (t->kind) { case Type_Basic: - if (t->Basic.kind == Basic_string) { + if (t->Basic.kind == Basic_string || t->Basic.kind == Basic_UntypedString) { valid = true; if (o->mode == Addressing_Constant) { max_count = o->value.value_string.len; @@ -8651,6 +8793,36 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type } } + if (is_type_string(t) && max_count >= 0) { + bool all_constant = true; + for (isize i = 0; i < gb_count_of(nodes); i++) { + if (nodes[i] != nullptr) { + TypeAndValue tav = type_and_value_of_expr(nodes[i]); + if (tav.mode != Addressing_Constant) { + all_constant = false; + break; + } + } + } + if (!all_constant) { + gbString str = expr_to_string(o->expr); + error(o->expr, "Cannot slice '%s' with non-constant indices", str); + gb_string_free(str); + o->mode = Addressing_Value; // NOTE(bill): Keep subsequent values going without erring + o->expr = node; + return kind; + } + + String s = {}; + if (o->value.kind == ExactValue_String) { + s = o->value.value_string; + } + + o->mode = Addressing_Constant; + o->type = t; + o->value = exact_value_string(substring(s, indices[0], indices[1])); + } + case_end; @@ -8729,9 +8901,9 @@ ExprKind check_expr_base(CheckerContext *c, Operand *o, Ast *node, Type *type_hi if (type != nullptr && is_type_untyped(type)) { add_untyped(&c->checker->info, node, false, o->mode, type, value); - } else { - add_type_and_value(&c->checker->info, node, o->mode, type, value); } + add_type_and_value(&c->checker->info, node, o->mode, type, value); + return kind; } -- cgit v1.2.3