aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGinger Bill <bill@gingerbill.org>2016-09-02 14:14:12 +0100
committerGinger Bill <bill@gingerbill.org>2016-09-02 14:14:12 +0100
commit25e9b9bc87a5b4fa14fc7d47ca3077849ee5648d (patch)
tree115e165013c52edd77777f9bd64e212e0b29f7c8 /src
parentfa09d805e23c59cb881573a7a1aee5fbc5752ea2 (diff)
min, max, abs
Diffstat (limited to 'src')
-rw-r--r--src/checker/checker.cpp8
-rw-r--r--src/checker/expr.cpp167
-rw-r--r--src/codegen/ssa.cpp32
-rw-r--r--src/gb/gb.h4
-rw-r--r--src/parser.cpp78
-rw-r--r--src/tokenizer.cpp8
6 files changed, 289 insertions, 8 deletions
diff --git a/src/checker/checker.cpp b/src/checker/checker.cpp
index 25bef96de..8dfce197c 100644
--- a/src/checker/checker.cpp
+++ b/src/checker/checker.cpp
@@ -145,6 +145,10 @@ enum BuiltinProcId {
BuiltinProc_ptr_sub,
BuiltinProc_slice_ptr,
+ BuiltinProc_min,
+ BuiltinProc_max,
+ BuiltinProc_abs,
+
BuiltinProc_Count,
};
struct BuiltinProc {
@@ -178,6 +182,10 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = {
{STR_LIT("ptr_offset"), 2, false, Expr_Expr},
{STR_LIT("ptr_sub"), 2, false, Expr_Expr},
{STR_LIT("slice_ptr"), 2, true, Expr_Expr},
+
+ {STR_LIT("min"), 2, false, Expr_Expr},
+ {STR_LIT("max"), 2, false, Expr_Expr},
+ {STR_LIT("abs"), 1, false, Expr_Expr},
};
struct CheckerContext {
diff --git a/src/checker/expr.cpp b/src/checker/expr.cpp
index 39fa66e3d..36f3f50fc 100644
--- a/src/checker/expr.cpp
+++ b/src/checker/expr.cpp
@@ -878,10 +878,11 @@ b32 check_value_is_expressible(Checker *c, ExactValue in_value, Type *type, Exac
} else if (is_type_string(type)) {
return in_value.kind == ExactValue_String;
} else if (is_type_integer(type)) {
- if (in_value.kind != ExactValue_Integer)
+ ExactValue v = exact_value_to_integer(in_value);
+ if (v.kind != ExactValue_Integer)
return false;
- if (out_value) *out_value = in_value;
- i64 i = in_value.value_integer;
+ if (out_value) *out_value = v;
+ i64 i = v.value_integer;
i64 s = 8*type_size_of(c->sizes, c->allocator, type);
u64 umax = ~0ull;
if (s < 64) {
@@ -1282,7 +1283,6 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) {
Type *base_type = get_base_type(type);
if (is_const_expr && is_type_constant_type(base_type)) {
-
if (base_type->kind == Type_Basic) {
if (check_value_is_expressible(c, x->value, base_type, &x->value)) {
can_convert = true;
@@ -1295,10 +1295,12 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) {
if (!can_convert) {
gbString expr_str = expr_to_string(x->expr);
- gbString type_str = type_to_string(type);
+ gbString to_type = type_to_string(type);
+ gbString from_type = type_to_string(x->type);
defer (gb_string_free(expr_str));
- defer (gb_string_free(type_str));
- error(&c->error_collector, ast_node_token(x->expr), "Cannot cast `%s` as `%s`", expr_str, type_str);
+ defer (gb_string_free(to_type));
+ defer (gb_string_free(from_type));
+ error(&c->error_collector, ast_node_token(x->expr), "Cannot cast `%s` as `%s` from `%s`", expr_str, to_type, from_type);
x->mode = Addressing_Invalid;
return;
@@ -2342,6 +2344,157 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
operand->mode = Addressing_Value;
} break;
+ case BuiltinProc_min: {
+ // min :: proc(a, b: comparable) -> comparable
+ Type *type = get_base_type(operand->type);
+ if (!is_type_comparable(type) || !is_type_numeric(type)) {
+ gbString type_str = type_to_string(operand->type);
+ defer (gb_string_free(type_str));
+ error(&c->error_collector, ast_node_token(call),
+ "Expected a comparable numeric type to `min`, got `%s`",
+ type_str);
+ return false;
+ }
+
+ AstNode *other_arg = ce->arg_list->next;
+ Operand a = *operand;
+ Operand b = {};
+ check_expr(c, &b, other_arg);
+ if (b.mode == Addressing_Invalid)
+ return false;
+ if (!is_type_comparable(b.type) || !is_type_numeric(type)) {
+ gbString type_str = type_to_string(b.type);
+ defer (gb_string_free(type_str));
+ error(&c->error_collector, ast_node_token(call),
+ "Expected a comparable numeric type to `min`, got `%s`",
+ type_str);
+ return false;
+ }
+
+
+ if (a.mode == Addressing_Constant &&
+ b.mode == Addressing_Constant) {
+ ExactValue x = a.value;
+ ExactValue y = b.value;
+ Token lt = {Token_Lt};
+
+ operand->mode = Addressing_Constant;
+ if (compare_exact_values(lt, x, y)) {
+ operand->value = x;
+ operand->type = a.type;
+ } else {
+ operand->value = y;
+ operand->type = b.type;
+ }
+ } else {
+ operand->mode = Addressing_Value;
+ operand->type = type;
+
+ if (!are_types_identical(operand->type, b.type)) {
+ gbString type_a = type_to_string(a.type);
+ gbString type_b = type_to_string(b.type);
+ defer (gb_string_free(type_a));
+ defer (gb_string_free(type_b));
+ error(&c->error_collector, ast_node_token(call),
+ "Mismatched types to `min`, `%s` vs `%s`",
+ type_a, type_b);
+ return false;
+ }
+ }
+
+ } break;
+
+ case BuiltinProc_max: {
+ // min :: proc(a, b: comparable) -> comparable
+ Type *type = get_base_type(operand->type);
+ if (!is_type_comparable(type) || !is_type_numeric(type)) {
+ gbString type_str = type_to_string(operand->type);
+ defer (gb_string_free(type_str));
+ error(&c->error_collector, ast_node_token(call),
+ "Expected a comparable numeric type to `max`, got `%s`",
+ type_str);
+ return false;
+ }
+
+ AstNode *other_arg = ce->arg_list->next;
+ Operand a = *operand;
+ Operand b = {};
+ check_expr(c, &b, other_arg);
+ if (b.mode == Addressing_Invalid)
+ return false;
+ if (!is_type_comparable(b.type) || !is_type_numeric(type)) {
+ gbString type_str = type_to_string(b.type);
+ defer (gb_string_free(type_str));
+ error(&c->error_collector, ast_node_token(call),
+ "Expected a comparable numeric type to `max`, got `%s`",
+ type_str);
+ return false;
+ }
+
+
+ if (a.mode == Addressing_Constant &&
+ b.mode == Addressing_Constant) {
+ ExactValue x = a.value;
+ ExactValue y = b.value;
+ Token gt = {Token_Gt};
+
+ operand->mode = Addressing_Constant;
+ if (compare_exact_values(gt, x, y)) {
+ operand->value = x;
+ operand->type = a.type;
+ } else {
+ operand->value = y;
+ operand->type = b.type;
+ }
+ } else {
+ operand->mode = Addressing_Value;
+ operand->type = type;
+
+ if (!are_types_identical(operand->type, b.type)) {
+ gbString type_a = type_to_string(a.type);
+ gbString type_b = type_to_string(b.type);
+ defer (gb_string_free(type_a));
+ defer (gb_string_free(type_b));
+ error(&c->error_collector, ast_node_token(call),
+ "Mismatched types to `max`, `%s` vs `%s`",
+ type_a, type_b);
+ return false;
+ }
+ }
+
+ } break;
+
+ case BuiltinProc_abs: {
+ // abs :: proc(n: numeric) -> numeric
+ Type *type = get_base_type(operand->type);
+ if (!is_type_numeric(type)) {
+ gbString type_str = type_to_string(operand->type);
+ defer (gb_string_free(type_str));
+ error(&c->error_collector, ast_node_token(call),
+ "Expected a numeric type to `abs`, got `%s`",
+ type_str);
+ return false;
+ }
+
+ if (operand->mode == Addressing_Constant) {
+ switch (operand->value.kind) {
+ case ExactValue_Integer:
+ operand->value.value_integer = gb_abs(operand->value.value_integer);
+ break;
+ case ExactValue_Float:
+ operand->value.value_float = gb_abs(operand->value.value_float);
+ break;
+ default:
+ GB_PANIC("Invalid numeric constant");
+ break;
+ }
+ } else {
+ operand->mode = Addressing_Value;
+ }
+
+ operand->type = type;
+ } break;
+
}
return true;
diff --git a/src/codegen/ssa.cpp b/src/codegen/ssa.cpp
index b2eb6c6a4..077a4f218 100644
--- a/src/codegen/ssa.cpp
+++ b/src/codegen/ssa.cpp
@@ -1569,7 +1569,7 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
case_ast_node(i, Ident, expr);
Entity *e = *map_get(&proc->module->info->uses, hash_pointer(expr));
if (e->kind == Entity_Builtin) {
- GB_PANIC("TODO(bill): ssa_build_single_expr Entity_Builtin");
+ GB_PANIC("TODO(bill): ssa_build_single_expr Entity_Builtin `%.*s`", LIT(builtin_procs[e->Builtin.id].name));
return NULL;
}
@@ -2068,6 +2068,36 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
ssa_emit_store(proc, ssa_emit_struct_gep(proc, slice, v_two32, t_int), cap);
return ssa_emit_load(proc, slice);
} break;
+
+ case BuiltinProc_min: {
+ ssaValue *x = ssa_build_expr(proc, ce->arg_list);
+ ssaValue *y = ssa_build_expr(proc, ce->arg_list->next);
+ Type *t = get_base_type(ssa_type(x));
+ Token lt = {Token_Lt};
+ ssaValue *cond = ssa_emit_comp(proc, lt, x, y);
+ return ssa_emit_select(proc, cond, x, y);
+ } break;
+
+ case BuiltinProc_max: {
+ ssaValue *x = ssa_build_expr(proc, ce->arg_list);
+ ssaValue *y = ssa_build_expr(proc, ce->arg_list->next);
+ Type *t = get_base_type(ssa_type(x));
+ Token gt = {Token_Gt};
+ ssaValue *cond = ssa_emit_comp(proc, gt, x, y);
+ return ssa_emit_select(proc, cond, x, y);
+ } break;
+
+ case BuiltinProc_abs: {
+ Token lt = {Token_Lt};
+ Token sub = {Token_Sub};
+
+ ssaValue *x = ssa_build_expr(proc, ce->arg_list);
+ Type *t = ssa_type(x);
+
+ ssaValue *neg_x = ssa_emit_arith(proc, sub, v_zero, x, t);
+ ssaValue *cond = ssa_emit_comp(proc, lt, x, v_zero);
+ return ssa_emit_select(proc, cond, neg_x, x);
+ } break;
}
}
}
diff --git a/src/gb/gb.h b/src/gb/gb.h
index 94671e1fd..fb2681b34 100644
--- a/src/gb/gb.h
+++ b/src/gb/gb.h
@@ -702,6 +702,10 @@ extern "C++" {
#define gb_is_between(x, lower, upper) (((x) >= (lower)) && ((x) <= (upper)))
#endif
+#ifndef gb_abs
+#define gb_abs(x) ((x) < 0 ? -(x) : (x))
+#endif
+
/* NOTE(bill): Very useful bit setting */
#ifndef GB_MASK_SET
#define GB_MASK_SET(var, set, mask) do { \
diff --git a/src/parser.cpp b/src/parser.cpp
index 4a5a8d63e..478e1377a 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -164,6 +164,20 @@ AST_NODE_KIND(_ComplexStmtBegin, "", struct{}) \
AST_NODE_KIND(DeferStmt, "defer statement", struct { Token token; AstNode *stmt; }) \
AST_NODE_KIND(BranchStmt, "branch statement", struct { Token token; }) \
AST_NODE_KIND(UsingStmt, "using statement", struct { Token token; AstNode *node; }) \
+ AST_NODE_KIND(AsmOperand, "assembly operand", struct { \
+ Token string; \
+ AstNode *operand; \
+ }) \
+ AST_NODE_KIND(AsmStmt, "assembly statement", struct { \
+ Token token; \
+ b32 is_volatile; \
+ Token open, close; \
+ Token code_string; \
+ AstNode *output_list; \
+ AstNode *input_list; \
+ AstNode *clobber_list; \
+ isize output_count, input_count, clobber_count; \
+ }) \
\
AST_NODE_KIND(_ComplexStmtEnd, "", struct{}) \
AST_NODE_KIND(_StmtEnd, "", struct{}) \
@@ -348,6 +362,8 @@ Token ast_node_token(AstNode *node) {
return node->BranchStmt.token;
case AstNode_UsingStmt:
return node->UsingStmt.token;
+ case AstNode_AsmStmt:
+ return node->AsmStmt.token;
case AstNode_BadDecl:
return node->BadDecl.begin;
case AstNode_VarDecl:
@@ -684,6 +700,35 @@ gb_inline AstNode *make_using_stmt(AstFile *f, Token token, AstNode *node) {
return result;
}
+gb_inline AstNode *make_asm_operand(AstFile *f, Token string, AstNode *operand) {
+ AstNode *result = make_node(f, AstNode_AsmOperand);
+ result->AsmOperand.string = string;
+ result->AsmOperand.operand = operand;
+ return result;
+
+}
+
+gb_inline AstNode *make_asm_stmt(AstFile *f, Token token, b32 is_volatile, Token open, Token close, Token code_string,
+ AstNode *output_list, AstNode *input_list, AstNode *clobber_list,
+ isize output_count, isize input_count, isize clobber_count) {
+ AstNode *result = make_node(f, AstNode_AsmStmt);
+ result->AsmStmt.token = token;
+ result->AsmStmt.is_volatile = is_volatile;
+ result->AsmStmt.open = open;
+ result->AsmStmt.close = close;
+ result->AsmStmt.code_string = code_string;
+ result->AsmStmt.output_list = output_list;
+ result->AsmStmt.input_list = input_list;
+ result->AsmStmt.clobber_list = clobber_list;
+ result->AsmStmt.output_count = output_count;
+ result->AsmStmt.input_count = input_count;
+ result->AsmStmt.clobber_count = clobber_count;
+ return result;
+}
+
+
+
+
gb_inline AstNode *make_bad_decl(AstFile *f, Token begin, Token end) {
AstNode *result = make_node(f, AstNode_BadDecl);
@@ -2219,6 +2264,37 @@ AstNode *parse_defer_stmt(AstFile *f) {
return make_defer_stmt(f, token, statement);
}
+AstNode *parse_asm_stmt(AstFile *f) {
+ Token token = expect_token(f, Token_asm);
+ b32 is_volatile = false;
+ if (allow_token(f, Token_volatile)) {
+ is_volatile = true;
+ }
+ Token open, close, code_string;
+ open = expect_token(f, Token_OpenBrace);
+ code_string = expect_token(f, Token_String);
+ AstNode *output_list = NULL;
+ AstNode *input_list = NULL;
+ AstNode *clobber_list = NULL;
+ isize output_count = 0;
+ isize input_count = 0;
+ isize clobber_count = 0;
+
+ // TODO(bill): Finish asm statement and determine syntax
+
+ // if (f->cursor[0].kind != Token_CloseBrace) {
+ // expect_token(f, Token_Colon);
+ // }
+
+ close = expect_token(f, Token_CloseBrace);
+
+ return make_asm_stmt(f, token, is_volatile, open, close, code_string,
+ output_list, input_list, clobber_list,
+ output_count, input_count, clobber_count);
+
+}
+
+
AstNode *parse_stmt(AstFile *f) {
AstNode *s = NULL;
@@ -2246,6 +2322,7 @@ AstNode *parse_stmt(AstFile *f) {
case Token_for: return parse_for_stmt(f);
case Token_match: return parse_match_stmt(f);
case Token_defer: return parse_defer_stmt(f);
+ case Token_asm: return parse_asm_stmt(f);
case Token_break:
case Token_continue:
@@ -2255,6 +2332,7 @@ AstNode *parse_stmt(AstFile *f) {
expect_semicolon_after_stmt(f, s);
return s;
+
case Token_using: {
AstNode *node = NULL;
diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp
index 9d9351923..23ba6abd2 100644
--- a/src/tokenizer.cpp
+++ b/src/tokenizer.cpp
@@ -78,6 +78,7 @@ TOKEN_KIND(Token__ComparisonEnd, "_ComparisonEnd"), \
TOKEN_KIND(Token_Period, "."), \
TOKEN_KIND(Token_Comma, ","), \
TOKEN_KIND(Token_Ellipsis, ".."), \
+ TOKEN_KIND(Token_RangeExclusive, "..<"), \
TOKEN_KIND(Token__OperatorEnd, "_OperatorEnd"), \
\
TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
@@ -93,6 +94,7 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
TOKEN_KIND(Token_if, "if"), \
TOKEN_KIND(Token_else, "else"), \
TOKEN_KIND(Token_for, "for"), \
+ TOKEN_KIND(Token_range, "range"), \
TOKEN_KIND(Token_defer, "defer"), \
TOKEN_KIND(Token_return, "return"), \
TOKEN_KIND(Token_struct, "struct"), \
@@ -100,6 +102,8 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
TOKEN_KIND(Token_raw_union, "raw_union"), \
TOKEN_KIND(Token_enum, "enum"), \
TOKEN_KIND(Token_using, "using"), \
+ TOKEN_KIND(Token_asm, "asm"), \
+ TOKEN_KIND(Token_volatile, "volatile"), \
TOKEN_KIND(Token__KeywordEnd, "_KeywordEnd"), \
TOKEN_KIND(Token_Count, "")
@@ -711,6 +715,10 @@ Token tokenizer_get_token(Tokenizer *t) {
} else if (t->curr_rune == '.') { // Could be an ellipsis
advance_to_next_rune(t);
token.kind = Token_Ellipsis;
+ if (t->curr_rune == '<') {
+ advance_to_next_rune(t);
+ token.kind = Token_RangeExclusive;
+ }
}
break;