diff --git a/code/demo.odin b/code/demo.odin index c9cf55616..5d2e53636 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -1,16 +1,12 @@ #import "fmt.odin"; -x := [...]int{1, 2, 3, 4}; main :: proc() { { - - foo :: proc() -> [...]int { - return x; - } - - // foo()[0] = 2; + x := [...]int{1, 2, 3, 4}; + immutable y := ^x; + fmt.println(y^[0]); } /* diff --git a/src/check_expr.c b/src/check_expr.c index 5b91ffd39..25576ae85 100644 --- a/src/check_expr.c +++ b/src/check_expr.c @@ -1030,7 +1030,7 @@ void check_ident(Checker *c, Operand *o, AstNode *n, Type *named_type, Type *typ } o->mode = Addressing_Variable; if (e->Variable.is_immutable) { - o->mode = Addressing_Value; + o->mode = Addressing_Immutable; } break; @@ -2714,7 +2714,9 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h break; case Entity_Variable: // TODO(bill): This is the rule I need? - if (sel.indirect || operand->mode != Addressing_Value) { + if (operand->mode == Addressing_Immutable) { + // Okay + } else if (sel.indirect || operand->mode != Addressing_Value) { operand->mode = Addressing_Variable; } else { operand->mode = Addressing_Value; @@ -4097,6 +4099,16 @@ void check_expr_with_type_hint(Checker *c, Operand *o, AstNode *e, Type *t) { } } +void check_set_mode_with_indirection(Operand *o, bool indirection) { + if (o->mode != Addressing_Immutable) { + if (indirection) { + o->mode = Addressing_Variable; + } else if (o->mode != Addressing_Variable) { + o->mode = Addressing_Value; + } + } +} + bool check_set_index_data(Operand *o, Type *type, bool indirection, i64 *max_count) { Type *t = base_type(type_deref(type)); @@ -4106,9 +4118,7 @@ bool check_set_index_data(Operand *o, Type *type, bool indirection, i64 *max_cou if (o->mode == Addressing_Constant) { *max_count = o->value.value_string.len; } - if (o->mode != Addressing_Variable) { - o->mode = Addressing_Value; - } + check_set_mode_with_indirection(o, indirection); o->type = t_u8; return true; } @@ -4116,22 +4126,13 @@ bool check_set_index_data(Operand *o, Type *type, bool indirection, i64 *max_cou case Type_Array: *max_count = t->Array.count; - if (indirection) { - o->mode = Addressing_Variable; - } else if (o->mode != Addressing_Variable) { - o->mode = Addressing_Value; - } - + check_set_mode_with_indirection(o, indirection); o->type = t->Array.elem; return true; case Type_Vector: *max_count = t->Vector.count; - if (indirection) { - o->mode = Addressing_Variable; - } else if (o->mode != Addressing_Variable) { - o->mode = Addressing_Value; - } + check_set_mode_with_indirection(o, indirection); o->type = t->Vector.elem; return true; @@ -4143,11 +4144,7 @@ bool check_set_index_data(Operand *o, Type *type, bool indirection, i64 *max_cou case Type_DynamicArray: o->type = t->DynamicArray.elem; - if (indirection) { - o->mode = Addressing_Variable; - } else if (o->mode != Addressing_Variable) { - o->mode = Addressing_Value; - } + check_set_mode_with_indirection(o, indirection); return true; } @@ -5183,7 +5180,9 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint } else { Type *t = base_type(o->type); if (t->kind == Type_Pointer) { - o->mode = Addressing_Variable; + if (o->mode != Addressing_Immutable) { + o->mode = Addressing_Variable; + } o->type = t->Pointer.elem; } else { gbString str = expr_to_string(o->expr); diff --git a/src/check_stmt.c b/src/check_stmt.c index 983c9f25f..6769ddb40 100644 --- a/src/check_stmt.c +++ b/src/check_stmt.c @@ -268,17 +268,13 @@ Type *check_assignment_variable(Checker *c, Operand *rhs, AstNode *lhs_node) { AstNode *x = ln->IndexExpr.expr; TypeAndValue *tav = type_and_value_of_expression(&c->info, x); GB_ASSERT(tav != NULL); - switch (tav->mode) { - case Addressing_Variable: - break; - case Addressing_Value: + if (tav->mode != Addressing_Variable) { if (!is_type_pointer(tav->type)) { gbString str = expr_to_string(lhs.expr); error_node(lhs.expr, "Cannot assign to the value of a map `%s`", str); gb_string_free(str); return NULL; } - break; } } } break; @@ -297,7 +293,7 @@ Type *check_assignment_variable(Checker *c, Operand *rhs, AstNode *lhs_node) { } gbString str = expr_to_string(lhs.expr); - if (e != NULL && e->kind == Entity_Variable && e->Variable.is_immutable) { + if (lhs.mode == Addressing_Immutable) { error_node(lhs.expr, "Cannot assign to an immutable: `%s`", str); } else { error_node(lhs.expr, "Cannot assign to `%s`", str); diff --git a/src/checker.c b/src/checker.c index 17af9a44a..5ae1460ad 100644 --- a/src/checker.c +++ b/src/checker.c @@ -6,6 +6,22 @@ typedef enum ExprKind { Expr_Stmt, } ExprKind; +typedef enum AddressingMode { + Addressing_Invalid, + + Addressing_NoValue, + Addressing_Value, + Addressing_Variable, + Addressing_Immutable, + Addressing_Constant, + Addressing_Type, + Addressing_Builtin, + Addressing_Overload, + Addressing_MapIndex, + + Addressing_Count, +} AddressingMode; + // Statements and Declarations typedef enum StmtFlag { Stmt_BreakAllowed = 1<<0, @@ -106,22 +122,6 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = { }; - -typedef enum AddressingMode { - Addressing_Invalid, - - Addressing_NoValue, - Addressing_Value, - Addressing_Variable, - Addressing_Constant, - Addressing_Type, - Addressing_Builtin, - Addressing_Overload, - Addressing_MapIndex, - - Addressing_Count, -} AddressingMode; - #include "types.c" #define MAP_TYPE Entity * @@ -149,7 +149,9 @@ bool is_operand_value(Operand o) { switch (o.mode) { case Addressing_Value: case Addressing_Variable: + case Addressing_Immutable: case Addressing_Constant: + case Addressing_MapIndex: return true; } return false; diff --git a/src/parser.c b/src/parser.c index b5d8f442b..69ea32c48 100644 --- a/src/parser.c +++ b/src/parser.c @@ -2358,7 +2358,7 @@ bool is_token_field_prefix(TokenKind kind) { switch (kind) { case Token_using: case Token_no_alias: - // case Token_immutable: + case Token_immutable: return true; } return false; @@ -2374,7 +2374,7 @@ u32 parse_field_prefixes(AstFile *f) { switch (f->curr_token.kind) { case Token_using: using_count += 1; next_token(f); break; case Token_no_alias: no_alias_count += 1; next_token(f); break; - // case Token_immutable: immutable_count += 1; next_token(f); break; + case Token_immutable: immutable_count += 1; next_token(f); break; } } if (using_count > 1) syntax_error(f->curr_token, "Multiple `using` in this field list"); @@ -3272,7 +3272,7 @@ AstNode *parse_stmt(AstFile *f) { return ast_bad_stmt(f, token, f->curr_token); } break; -#if 0 +#if 1 case Token_immutable: { Token token = expect_token(f, Token_immutable); AstNode *node = parse_stmt(f); diff --git a/src/tokenizer.c b/src/tokenizer.c index f2cabfb02..fc85fd927 100644 --- a/src/tokenizer.c +++ b/src/tokenizer.c @@ -102,6 +102,7 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \ TOKEN_KIND(Token_map, "map"), \ TOKEN_KIND(Token_using, "using"), \ TOKEN_KIND(Token_no_alias, "no_alias"), \ + TOKEN_KIND(Token_immutable, "immutable"), \ TOKEN_KIND(Token_cast, "cast"), \ TOKEN_KIND(Token_transmute, "transmute"), \ TOKEN_KIND(Token_down_cast, "down_cast"), \