aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGinger Bill <bill@gingerbill.org>2017-02-26 00:44:26 +0000
committerGinger Bill <bill@gingerbill.org>2017-02-26 00:44:26 +0000
commitc59f6b7d0b582131bed4450bbb9aa1a71d5a01af (patch)
tree34957d43fa0241ffb6678302cae8e77fb7f8488b /src
parent67ed8a9a4ab8fdcfc77036c827b7dfa98025bc8b (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.c27
-rw-r--r--src/check_stmt.c48
-rw-r--r--src/exact_value.c7
-rw-r--r--src/ir.c23
-rw-r--r--src/parser.c22
-rw-r--r--src/tokenizer.c18
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;
diff --git a/src/ir.c b/src/ir.c
index 388f747a3..831a1cf8b 100644
--- a/src/ir.c
+++ b/src/ir.c
@@ -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) {