diff options
| author | Ginger Bill <bill@gingerbill.org> | 2017-02-26 00:44:26 +0000 |
|---|---|---|
| committer | Ginger Bill <bill@gingerbill.org> | 2017-02-26 00:44:26 +0000 |
| commit | c59f6b7d0b582131bed4450bbb9aa1a71d5a01af (patch) | |
| tree | 34957d43fa0241ffb6678302cae8e77fb7f8488b /src | |
| parent | 67ed8a9a4ab8fdcfc77036c827b7dfa98025bc8b (diff) | |
++ -- statements; add strconv.odin (and replace some of the fmt procs); Fix ~ on 64 bit constants; Fix integer casts from smaller to larger size
Diffstat (limited to 'src')
| -rw-r--r-- | src/check_expr.c | 27 | ||||
| -rw-r--r-- | src/check_stmt.c | 48 | ||||
| -rw-r--r-- | src/exact_value.c | 7 | ||||
| -rw-r--r-- | src/ir.c | 23 | ||||
| -rw-r--r-- | src/parser.c | 22 | ||||
| -rw-r--r-- | src/tokenizer.c | 18 |
6 files changed, 122 insertions, 23 deletions
diff --git a/src/check_expr.c b/src/check_expr.c index f075df688..aa5222d9d 100644 --- a/src/check_expr.c +++ b/src/check_expr.c @@ -197,11 +197,11 @@ i64 check_distance_between_types(Checker *c, Operand *operand, Type *type) { } } - // if (is_type_proc(dst)) { - // if (are_types_identical(src, dst)) { - // return 1; - // } - // } + if (is_type_proc(dst)) { + if (are_types_identical(src, dst)) { + return 3; + } + } if (is_type_any(dst)) { // NOTE(bill): Anything can cast to `Any` @@ -2827,6 +2827,16 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h goto error; } } + + if (entity == NULL && + operand->type != NULL && is_type_untyped(operand->type) && is_type_string(operand->type)) { + String s = operand->value.value_string; + operand->mode = Addressing_Constant; + operand->value = make_exact_value_integer(s.len); + operand->type = t_untyped_integer; + return NULL; + } + if (entity == NULL) { gbString op_str = expr_to_string(op_expr); gbString type_str = type_to_string(operand->type); @@ -5445,9 +5455,10 @@ gbString write_expr_to_string(gbString str, AstNode *node) { case_ast_node(at, ArrayType, node); str = gb_string_appendc(str, "["); - if (at->count->kind == AstNode_UnaryExpr && - at->count->UnaryExpr.op.kind == Token_Hash) { - str = gb_string_appendc(str, "#"); + if (at->count != NULL && + at->count->kind == AstNode_UnaryExpr && + at->count->UnaryExpr.op.kind == Token_Ellipsis) { + str = gb_string_appendc(str, "..."); } else { str = write_expr_to_string(str, at->count); } diff --git a/src/check_stmt.c b/src/check_stmt.c index 90cb6ff61..9c0b0c187 100644 --- a/src/check_stmt.c +++ b/src/check_stmt.c @@ -421,6 +421,49 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { check_stmt(c, ts->stmt, flags); case_end; + case_ast_node(s, IncDecStmt, node); + TokenKind op = s->op.kind; + switch (op) { + case Token_Inc: op = Token_Add; break; + case Token_Dec: op = Token_Sub; break; + default: + error_node(node, "Invalid inc/dec operation"); + return; + } + + Operand x = {0}; + check_expr(c, &x, s->expr); + if (x.mode == Addressing_Invalid) { + return; + } + if (!is_type_integer(x.type) && !is_type_float(x.type)) { + gbString e = expr_to_string(s->expr); + gbString t = type_to_string(x.type); + error_node(node, "%s%.*s used on non-numeric type %s", e, LIT(s->op.string), t); + gb_string_free(t); + gb_string_free(e); + return; + } + AstNode *left = s->expr; + AstNode *right = gb_alloc_item(c->allocator, AstNode); + right->kind = AstNode_BasicLit; + right->BasicLit.pos = s->op.pos; + right->BasicLit.kind = Token_Integer; + right->BasicLit.string = str_lit("1"); + + AstNode *be = gb_alloc_item(c->allocator, AstNode); + be->kind = AstNode_BinaryExpr; + be->BinaryExpr.op = s->op; + be->BinaryExpr.op.kind = op; + be->BinaryExpr.left = left; + be->BinaryExpr.right = right; + check_binary_expr(c, &x, be); + if (x.mode == Addressing_Invalid) { + return; + } + check_assignment_variable(c, &x, left); + case_end; + case_ast_node(as, AssignStmt, node); switch (as->op.kind) { case Token_Eq: { @@ -591,8 +634,9 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { if (fs->post != NULL) { check_stmt(c, fs->post, 0); - if (fs->post->kind != AstNode_AssignStmt) { - error_node(fs->post, "`for` statement post statement must be an assignment"); + if (fs->post->kind != AstNode_AssignStmt && + fs->post->kind != AstNode_IncDecStmt) { + error_node(fs->post, "`for` statement post statement must be a simple statement"); } } check_stmt(c, fs->body, new_flags); diff --git a/src/exact_value.c b/src/exact_value.c index 7c48d126b..57c8ae81d 100644 --- a/src/exact_value.c +++ b/src/exact_value.c @@ -274,8 +274,7 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision) case ExactValue_Invalid: return v; case ExactValue_Integer: - i = v.value_integer; - i = ~i; + i = ~v.value_integer; break; default: goto failure; @@ -283,8 +282,10 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision) // NOTE(bill): unsigned integers will be negative and will need to be // limited to the types precision - if (precision > 0) + // IMPORTANT NOTE(bill): Max precision is 64 bits as that's how integers are stored + if (0 < precision && precision < 64) { i &= ~((~0ll)<<precision); + } return make_exact_value_integer(i); } break; @@ -233,6 +233,7 @@ struct irProcedure { #define IR_CONV_KINDS \ IR_CONV_KIND(trunc) \ IR_CONV_KIND(zext) \ + IR_CONV_KIND(sext) \ IR_CONV_KIND(fptrunc) \ IR_CONV_KIND(fpext) \ IR_CONV_KIND(fptoui) \ @@ -2240,12 +2241,23 @@ irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) { i64 sz = type_size_of(proc->module->allocator, src); i64 dz = type_size_of(proc->module->allocator, dst); irConvKind kind = irConv_trunc; - if (sz == dz) { + if (dz == sz) { // NOTE(bill): In LLVM, all integers are signed and rely upon 2's compliment // NOTE(bill): Copy the value just for type correctness kind = irConv_bitcast; } else if (dz > sz) { kind = irConv_zext; + + // TODO(bill): figure out the rules completely + bool ss = !is_type_unsigned(src); + bool ds = !is_type_unsigned(dst); + if (ss && ds) { + kind = irConv_sext; + } else if (ss) { + kind = irConv_sext; + } else { + kind = irConv_zext; + } } return ir_emit(proc, ir_make_instr_conv(proc, kind, value, src, dst)); @@ -4769,6 +4781,15 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { ir_build_when_stmt(proc, ws); case_end; + case_ast_node(s, IncDecStmt, node); + TokenKind op = Token_Add; + if (s->op.kind == Token_Dec) { + op = Token_Sub; + } + irAddr addr = ir_build_addr(proc, s->expr); + ir_build_assign_op(proc, addr, v_one, op); + case_end; + case_ast_node(vd, ValueDecl, node); if (vd->is_var) { irModule *m = proc->module; diff --git a/src/parser.c b/src/parser.c index f14f37599..8349a8d6b 100644 --- a/src/parser.c +++ b/src/parser.c @@ -186,6 +186,10 @@ AST_NODE_KIND(_StmtBegin, "", i32) \ Token op; \ AstNodeArray lhs, rhs; \ }) \ + AST_NODE_KIND(IncDecStmt, "increment decrement statement", struct { \ + Token op; \ + AstNode *expr; \ + }) \ AST_NODE_KIND(_ComplexStmtBegin, "", i32) \ AST_NODE_KIND(BlockStmt, "block statement", struct { \ AstNodeArray stmts; \ @@ -467,6 +471,7 @@ Token ast_node_token(AstNode *node) { case AstNode_ExprStmt: return ast_node_token(node->ExprStmt.expr); case AstNode_TagStmt: return node->TagStmt.token; case AstNode_AssignStmt: return node->AssignStmt.op; + case AstNode_IncDecStmt: return ast_node_token(node->IncDecStmt.expr); case AstNode_BlockStmt: return node->BlockStmt.open; case AstNode_IfStmt: return node->IfStmt.token; case AstNode_WhenStmt: return node->WhenStmt.token; @@ -802,6 +807,16 @@ AstNode *ast_assign_stmt(AstFile *f, Token op, AstNodeArray lhs, AstNodeArray rh return result; } + +AstNode *ast_inc_dec_stmt(AstFile *f, Token op, AstNode *expr) { + AstNode *result = make_ast_node(f, AstNode_IncDecStmt); + result->IncDecStmt.op = op; + result->IncDecStmt.expr = expr; + return result; +} + + + AstNode *ast_block_stmt(AstFile *f, AstNodeArray stmts, Token open, Token close) { AstNode *result = make_ast_node(f, AstNode_BlockStmt); result->BlockStmt.stmts = stmts; @@ -2272,6 +2287,13 @@ AstNode *parse_simple_stmt(AstFile *f, bool in_stmt_ok) { return ast_bad_stmt(f, token, f->curr_token); } + switch (token.kind) { + case Token_Inc: + case Token_Dec: + next_token(f); + return ast_inc_dec_stmt(f, token, lhs.e[0]); + } + return ast_expr_stmt(f, lhs.e[0]); } diff --git a/src/tokenizer.c b/src/tokenizer.c index 68ab270be..dde3391a1 100644 --- a/src/tokenizer.c +++ b/src/tokenizer.c @@ -51,8 +51,8 @@ TOKEN_KIND(Token__AssignOpBegin, "_AssignOpBegin"), \ TOKEN_KIND(Token__AssignOpEnd, "_AssignOpEnd"), \ TOKEN_KIND(Token_ArrowRight, "->"), \ TOKEN_KIND(Token_ArrowLeft, "<-"), \ - TOKEN_KIND(Token_Increment, "++"), \ - TOKEN_KIND(Token_Decrement, "--"), \ + TOKEN_KIND(Token_Inc, "++"), \ + TOKEN_KIND(Token_Dec, "--"), \ \ TOKEN_KIND(Token__ComparisonBegin, "_ComparisonBegin"), \ TOKEN_KIND(Token_CmpEq, "=="), \ @@ -859,13 +859,13 @@ Token tokenizer_get_token(Tokenizer *t) { case '{': token.kind = Token_OpenBrace; break; case '}': token.kind = Token_CloseBrace; break; - case '*': token.kind = token_kind_variant2(t, Token_Mul, Token_MulEq); break; - case '%': token.kind = token_kind_variant2(t, Token_Mod, Token_ModEq); break; - case '=': token.kind = token_kind_variant2(t, Token_Eq, Token_CmpEq); break; - case '~': token.kind = token_kind_variant2(t, Token_Xor, Token_XorEq); break; - case '!': token.kind = token_kind_variant2(t, Token_Not, Token_NotEq); break; - case '+': token.kind = token_kind_variant3(t, Token_Add, Token_AddEq, '+', Token_Increment); break; - case '-': token.kind = token_kind_variant4(t, Token_Sub, Token_SubEq, '-', Token_Decrement, '>', Token_ArrowRight); break; + case '*': token.kind = token_kind_variant2(t, Token_Mul, Token_MulEq); break; + case '%': token.kind = token_kind_variant2(t, Token_Mod, Token_ModEq); break; + case '=': token.kind = token_kind_variant2(t, Token_Eq, Token_CmpEq); break; + case '~': token.kind = token_kind_variant2(t, Token_Xor, Token_XorEq); break; + case '!': token.kind = token_kind_variant2(t, Token_Not, Token_NotEq); break; + case '+': token.kind = token_kind_variant3(t, Token_Add, Token_AddEq, '+', Token_Inc); break; + case '-': token.kind = token_kind_variant4(t, Token_Sub, Token_SubEq, '-', Token_Dec, '>', Token_ArrowRight); break; case '/': { if (t->curr_rune == '/') { while (t->curr_rune != '\n' && t->curr_rune != GB_RUNE_EOF) { |