Split BigIntType out of IntType and switch to using enums for the size

of ints/nums
This commit is contained in:
Bruce Hill 2024-08-18 11:49:51 -04:00
parent 8b94c2c7f1
commit 752ab8212c
10 changed files with 176 additions and 174 deletions

4
ast.c
View File

@ -99,8 +99,8 @@ CORD ast_to_xml(ast_t *ast)
T(Nil, "<Nil>%r</Nil>", type_ast_to_xml(data.type))
T(Bool, "<Bool value=\"%s\" />", data.b ? "yes" : "no")
T(Var, "<Var>%s</Var>", data.name)
T(Int, "<Int bits=\"%ld\">%s</Int>", data.bits, data.str)
T(Num, "<Num bits=\"%ld\">%g</Num>", data.bits, data.n)
T(Int, "<Int bits=\"%d\">%s</Int>", data.bits, data.str)
T(Num, "<Num bits=\"%d\">%g</Num>", data.bits, data.n)
T(TextLiteral, "%r", xml_escape(data.cord))
T(TextJoin, "<Text%r>%r</Text>", data.lang ? CORD_all(" lang=\"", data.lang, "\"") : CORD_EMPTY, ast_list_to_xml(data.children))
T(Declare, "<Declare var=\"%r\">%r</Declare>", ast_to_xml(data.var), ast_to_xml(data.value))

4
ast.h
View File

@ -144,11 +144,11 @@ struct ast_s {
} Var;
struct {
const char *str;
int64_t bits;
enum { IBITS_UNSPECIFIED=0, IBITS8=8, IBITS16=16, IBITS32=32, IBITS64=64 } bits;
} Int;
struct {
double n;
int64_t bits;
enum { NBITS_UNSPECIFIED=0, NBITS32=32, NBITS64=64 } bits;
} Num;
struct {
CORD cord;

125
compile.c
View File

@ -32,7 +32,7 @@ static bool promote(env_t *env, CORD *code, type_t *actual, type_t *needed)
if (!can_promote(actual, needed))
return false;
if (actual->tag == IntType && needed->tag == IntType && Match(needed, IntType)->bits == 0) {
if (actual->tag == IntType && needed->tag == BigIntType) {
*code = CORD_all("I(", *code, ")");
return true;
}
@ -156,8 +156,9 @@ CORD compile_type(type_t *t)
case MemoryType: return "void";
case BoolType: return "Bool_t";
case CStringType: return "char*";
case IntType: return Match(t, IntType)->bits == 0 ? "Int_t" : CORD_asprintf("Int%ld_t", Match(t, IntType)->bits);
case NumType: return Match(t, NumType)->bits == 64 ? "Num_t" : CORD_asprintf("Num%ld_t", Match(t, NumType)->bits);
case BigIntType: return "Int_t";
case IntType: return CORD_asprintf("Int%ld_t", Match(t, IntType)->bits);
case NumType: return Match(t, NumType)->bits == TYPE_NBITS64 ? "Num_t" : CORD_asprintf("Num%ld_t", Match(t, NumType)->bits);
case TextType: {
auto text = Match(t, TextType);
return text->lang ? CORD_all(namespace_prefix(text->env->libname, text->env->namespace->parent), text->lang, "_t") : "Text_t";
@ -540,7 +541,7 @@ CORD compile_statement(env_t *env, ast_t *ast)
case BINOP_POWER: {
if (lhs_t->tag != NumType)
code_err(ast, "'^=' is only supported for Num types");
if (lhs_t->tag == NumType && Match(lhs_t, NumType)->bits == 32)
if (lhs_t->tag == NumType && Match(lhs_t, NumType)->bits == TYPE_NBITS32)
return CORD_all(lhs, " = powf(", lhs, ", ", rhs, ");");
else
return CORD_all(lhs, " = pow(", lhs, ", ", rhs, ");");
@ -1248,26 +1249,28 @@ env_t *with_enum_scope(env_t *env, type_t *t)
CORD compile_int_to_type(env_t *env, ast_t *ast, type_t *target)
{
int64_t target_bits = Match(target, IntType)->bits;
if (target->tag == BigIntType)
return compile(env, ast);
int64_t target_bits = (int64_t)Match(target, IntType)->bits;
Int_t int_val = Int$from_text(Match(ast, Int)->str);
mpz_t i;
mpz_init_set_int(i, int_val);
switch (target_bits) {
case 0: return compile(env, ast);
case 64:
case TYPE_IBITS64:
if (mpz_cmp_si(i, INT64_MAX) <= 0 && mpz_cmp_si(i, INT64_MIN) >= 0)
return CORD_asprintf("I64(%s)", Match(ast, Int)->str);
break;
case 32:
case TYPE_IBITS32:
if (mpz_cmp_si(i, INT32_MAX) <= 0 && mpz_cmp_si(i, INT32_MIN) >= 0)
return CORD_asprintf("I32(%s)", Match(ast, Int)->str);
break;
case 16:
case TYPE_IBITS16:
if (mpz_cmp_si(i, INT16_MAX) <= 0 && mpz_cmp_si(i, INT16_MIN) >= 0)
return CORD_asprintf("I16(%s)", Match(ast, Int)->str);
break;
case 8:
case TYPE_IBITS8:
if (mpz_cmp_si(i, INT8_MAX) <= 0 && mpz_cmp_si(i, INT8_MIN) >= 0)
return CORD_asprintf("I8(%s)", Match(ast, Int)->str);
break;
@ -1292,7 +1295,7 @@ CORD compile_arguments(env_t *env, ast_t *call_ast, arg_t *spec_args, arg_ast_t
} else if (spec_arg->type->tag == NumType && call_arg->value->tag == Int) {
Int_t int_val = Int$from_text(Match(call_arg->value, Int)->str);
double n = Int_to_Num(int_val);
value = CORD_asprintf(Match(spec_arg->type, NumType)->bits == 64
value = CORD_asprintf(Match(spec_arg->type, NumType)->bits == TYPE_NBITS64
? "N64(%.9g)" : "N32(%.9g)", n);
} else {
env_t *arg_env = with_enum_scope(env, spec_arg->type);
@ -1320,7 +1323,7 @@ CORD compile_arguments(env_t *env, ast_t *call_ast, arg_t *spec_args, arg_ast_t
} else if (spec_arg->type->tag == NumType && call_arg->value->tag == Int) {
Int_t int_val = Int$from_text(Match(call_arg->value, Int)->str);
double n = Int_to_Num(int_val);
value = CORD_asprintf(Match(spec_arg->type, NumType)->bits == 64
value = CORD_asprintf(Match(spec_arg->type, NumType)->bits == TYPE_NBITS64
? "N64(%.9g)" : "N32(%.9g)", n);
} else {
env_t *arg_env = with_enum_scope(env, spec_arg->type);
@ -1454,7 +1457,7 @@ CORD compile(env_t *env, ast_t *ast)
mpz_init_set_int(i, int_val);
switch (Match(ast, Int)->bits) {
case 0:
case IBITS_UNSPECIFIED:
if (mpz_cmpabs_ui(i, BIGGEST_SMALL_INT) <= 0) {
return CORD_asprintf("I_small(%s)", str);
} else if (mpz_cmp_si(i, INT64_MAX) <= 0 && mpz_cmp_si(i, INT64_MIN) >= 0) {
@ -1462,19 +1465,19 @@ CORD compile(env_t *env, ast_t *ast)
} else {
return CORD_asprintf("Int$from_text(\"%s\")", str);
}
case 64:
case IBITS64:
if ((mpz_cmp_si(i, INT64_MAX) < 0) && (mpz_cmp_si(i, INT64_MIN) > 0))
return CORD_asprintf("I64(%s)", str);
code_err(ast, "This value cannot fit in a 64-bit integer");
case 32:
case IBITS32:
if ((mpz_cmp_si(i, INT32_MAX) < 0) && (mpz_cmp_si(i, INT32_MIN) > 0))
return CORD_asprintf("I32(%s)", str);
code_err(ast, "This value cannot fit in a 32-bit integer");
case 16:
case IBITS16:
if ((mpz_cmp_si(i, INT16_MAX) < 0) && (mpz_cmp_si(i, INT16_MIN) > 0))
return CORD_asprintf("I16(%s)", str);
code_err(ast, "This value cannot fit in a 16-bit integer");
case 8:
case IBITS8:
if ((mpz_cmp_si(i, INT8_MAX) < 0) && (mpz_cmp_si(i, INT8_MIN) > 0))
return CORD_asprintf("I8(%s)", str);
code_err(ast, "This value cannot fit in a 8-bit integer");
@ -1482,7 +1485,13 @@ CORD compile(env_t *env, ast_t *ast)
}
}
case Num: {
return CORD_asprintf(Match(ast, Num)->bits == 64 ? "N64(%.9g)" : "N32(%.9g)", Match(ast, Num)->n);
switch (Match(ast, Num)->bits) {
case NBITS_UNSPECIFIED: case NBITS64:
return CORD_asprintf("N64(%.9g)", Match(ast, Num)->n);
case NBITS32:
return CORD_asprintf("N32(%.9g)", Match(ast, Num)->n);
default: code_err(ast, "This is not a valid number bit width");
}
}
case Length: {
ast_t *expr = Match(ast, Length)->value;
@ -1588,7 +1597,7 @@ CORD compile(env_t *env, ast_t *ast)
case BINOP_POWER: {
if (operand_t->tag != NumType)
code_err(ast, "Exponentiation is only supported for Num types");
if (operand_t->tag == NumType && Match(operand_t, NumType)->bits == 32)
if (operand_t->tag == NumType && Match(operand_t, NumType)->bits == TYPE_NBITS32)
return CORD_all("powf(", lhs, ", ", rhs, ")");
else
return CORD_all("pow(", lhs, ", ", rhs, ")");
@ -1635,11 +1644,9 @@ CORD compile(env_t *env, ast_t *ast)
}
case BINOP_EQ: {
switch (operand_t->tag) {
case IntType:
if (Match(operand_t, IntType)->bits == 0)
return CORD_all("Int$equal_value(", lhs, ", ", rhs, ")");
return CORD_all("(", lhs, " == ", rhs, ")");
case BoolType: case NumType: case PointerType: case FunctionType:
case BigIntType:
return CORD_all("Int$equal_value(", lhs, ", ", rhs, ")");
case BoolType: case IntType: case NumType: case PointerType: case FunctionType:
return CORD_all("(", lhs, " == ", rhs, ")");
default:
return CORD_asprintf("generic_equal(stack(%r), stack(%r), %r)", lhs, rhs, compile_type_info(env, operand_t));
@ -1647,11 +1654,9 @@ CORD compile(env_t *env, ast_t *ast)
}
case BINOP_NE: {
switch (operand_t->tag) {
case IntType:
if (Match(operand_t, IntType)->bits == 0)
return CORD_all("!Int$equal_value(", lhs, ", ", rhs, ")");
return CORD_all("(", lhs, " != ", rhs, ")");
case BoolType: case NumType: case PointerType: case FunctionType:
case BigIntType:
return CORD_all("!Int$equal_value(", lhs, ", ", rhs, ")");
case BoolType: case IntType: case NumType: case PointerType: case FunctionType:
return CORD_all("(", lhs, " != ", rhs, ")");
default:
return CORD_asprintf("!generic_equal(stack(%r), stack(%r), %r)", lhs, rhs, compile_type_info(env, operand_t));
@ -1659,11 +1664,9 @@ CORD compile(env_t *env, ast_t *ast)
}
case BINOP_LT: {
switch (operand_t->tag) {
case IntType:
if (Match(operand_t, IntType)->bits == 0)
return CORD_all("(Int$compare_value(", lhs, ", ", rhs, ") < 0)");
return CORD_all("(", lhs, " != ", rhs, ")");
case BoolType: case NumType: case PointerType: case FunctionType:
case BigIntType:
return CORD_all("(Int$compare_value(", lhs, ", ", rhs, ") < 0)");
case BoolType: case IntType: case NumType: case PointerType: case FunctionType:
return CORD_all("(", lhs, " < ", rhs, ")");
default:
return CORD_asprintf("(generic_compare(stack(%r), stack(%r), %r) < 0)", lhs, rhs, compile_type_info(env, operand_t));
@ -1671,11 +1674,9 @@ CORD compile(env_t *env, ast_t *ast)
}
case BINOP_LE: {
switch (operand_t->tag) {
case IntType:
if (Match(operand_t, IntType)->bits == 0)
return CORD_all("(Int$compare_value(", lhs, ", ", rhs, ") <= 0)");
return CORD_all("(", lhs, " != ", rhs, ")");
case BoolType: case NumType: case PointerType: case FunctionType:
case BigIntType:
return CORD_all("(Int$compare_value(", lhs, ", ", rhs, ") <= 0)");
case BoolType: case IntType: case NumType: case PointerType: case FunctionType:
return CORD_all("(", lhs, " <= ", rhs, ")");
default:
return CORD_asprintf("(generic_compare(stack(%r), stack(%r), %r) <= 0)", lhs, rhs, compile_type_info(env, operand_t));
@ -1683,11 +1684,9 @@ CORD compile(env_t *env, ast_t *ast)
}
case BINOP_GT: {
switch (operand_t->tag) {
case IntType:
if (Match(operand_t, IntType)->bits == 0)
return CORD_all("(Int$compare_value(", lhs, ", ", rhs, ") > 0)");
return CORD_all("(", lhs, " != ", rhs, ")");
case BoolType: case NumType: case PointerType: case FunctionType:
case BigIntType:
return CORD_all("(Int$compare_value(", lhs, ", ", rhs, ") > 0)");
case BoolType: case IntType: case NumType: case PointerType: case FunctionType:
return CORD_all("(", lhs, " > ", rhs, ")");
default:
return CORD_asprintf("(generic_compare(stack(%r), stack(%r), %r) > 0)", lhs, rhs, compile_type_info(env, operand_t));
@ -1695,11 +1694,9 @@ CORD compile(env_t *env, ast_t *ast)
}
case BINOP_GE: {
switch (operand_t->tag) {
case IntType:
if (Match(operand_t, IntType)->bits == 0)
return CORD_all("(Int$compare_value(", lhs, ", ", rhs, ") >= 0)");
return CORD_all("(", lhs, " != ", rhs, ")");
case BoolType: case NumType: case PointerType: case FunctionType:
case BigIntType:
return CORD_all("(Int$compare_value(", lhs, ", ", rhs, ") >= 0)");
case BoolType: case IntType: case NumType: case PointerType: case FunctionType:
return CORD_all("(", lhs, " >= ", rhs, ")");
default:
return CORD_asprintf("(generic_compare(stack(%r), stack(%r), %r) >= 0)", lhs, rhs, compile_type_info(env, operand_t));
@ -1865,7 +1862,7 @@ CORD compile(env_t *env, ast_t *ast)
type_t *key_t = get_type(expr_env, key);
CORD comparison;
if (key_t->tag == IntType && Match(key_t, IntType)->bits == 0)
if (key_t->tag == BigIntType)
comparison = CORD_all("(Int$compare_value(", lhs_key, ", ", rhs_key, ")", (ast->tag == Min ? "<=" : ">="), "0)");
else if (key_t->tag == IntType || key_t->tag == NumType || key_t->tag == BoolType || key_t->tag == PointerType)
comparison = CORD_all("((", lhs_key, ")", (ast->tag == Min ? "<=" : ">="), "(", rhs_key, "))");
@ -2161,25 +2158,25 @@ CORD compile(env_t *env, ast_t *ast)
if (streq(call->name, "insert")) {
CORD self = compile_to_pointer_depth(env, call->self, 1, false);
arg_t *arg_spec = new(arg_t, .name="item", .type=item_t,
.next=new(arg_t, .name="at", .type=INT_TYPE, .default_val=FakeAST(Int, .str="0", .bits=0)));
.next=new(arg_t, .name="at", .type=INT_TYPE, .default_val=FakeAST(Int, .str="0")));
return CORD_all("Array$insert_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
padded_item_size, ")");
} else if (streq(call->name, "insert_all")) {
CORD self = compile_to_pointer_depth(env, call->self, 1, false);
arg_t *arg_spec = new(arg_t, .name="items", .type=self_value_t,
.next=new(arg_t, .name="at", .type=INT_TYPE, .default_val=FakeAST(Int, .str="0", .bits=0)));
.next=new(arg_t, .name="at", .type=INT_TYPE, .default_val=FakeAST(Int, .str="0")));
return CORD_all("Array$insert_all(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
padded_item_size, ")");
} else if (streq(call->name, "remove_at")) {
CORD self = compile_to_pointer_depth(env, call->self, 1, false);
arg_t *arg_spec = new(arg_t, .name="index", .type=INT_TYPE, .default_val=FakeAST(Int, .str="-1", .bits=0),
.next=new(arg_t, .name="count", .type=INT_TYPE, .default_val=FakeAST(Int, .str="1", .bits=0)));
arg_t *arg_spec = new(arg_t, .name="index", .type=INT_TYPE, .default_val=FakeAST(Int, .str="-1"),
.next=new(arg_t, .name="count", .type=INT_TYPE, .default_val=FakeAST(Int, .str="1")));
return CORD_all("Array$remove_at(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
padded_item_size, ")");
} else if (streq(call->name, "remove_item")) {
CORD self = compile_to_pointer_depth(env, call->self, 1, false);
arg_t *arg_spec = new(arg_t, .name="item", .type=item_t,
.next=new(arg_t, .name="max_count", .type=INT_TYPE, .default_val=FakeAST(Int, .str="-1", .bits=0)));
.next=new(arg_t, .name="max_count", .type=INT_TYPE, .default_val=FakeAST(Int, .str="-1")));
return CORD_all("Array$remove_item_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
compile_type_info(env, self_value_t), ")");
} else if (streq(call->name, "random")) {
@ -2194,7 +2191,7 @@ CORD compile(env_t *env, ast_t *ast)
} else if (streq(call->name, "sample")) {
CORD self = compile_to_pointer_depth(env, call->self, 0, false);
arg_t *arg_spec = new(arg_t, .name="count", .type=INT_TYPE,
.next=new(arg_t, .name="weights", .type=Type(ArrayType, .item_type=Type(NumType, .bits=64)),
.next=new(arg_t, .name="weights", .type=Type(ArrayType, .item_type=Type(NumType)),
.default_val=FakeAST(Array, .item_type=new(type_ast_t, .tag=VarTypeAST, .__data.VarTypeAST.name="Num"))));
return CORD_all("Array$sample(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
padded_item_size, ")");
@ -2212,7 +2209,7 @@ CORD compile(env_t *env, ast_t *ast)
if (call->args) {
type_t *item_ptr = Type(PointerType, .pointed=item_t, .is_stack=true, .is_readonly=true);
type_t *fn_t = Type(FunctionType, .args=new(arg_t, .name="x", .type=item_ptr, .next=new(arg_t, .name="y", .type=item_ptr)),
.ret=Type(IntType, .bits=32));
.ret=Type(IntType, .bits=TYPE_IBITS32));
arg_t *arg_spec = new(arg_t, .name="by", .type=Type(ClosureType, .fn=fn_t));
comparison = compile_arguments(env, ast, arg_spec, call->args);
} else {
@ -2225,7 +2222,7 @@ CORD compile(env_t *env, ast_t *ast)
if (call->args) {
type_t *item_ptr = Type(PointerType, .pointed=item_t, .is_stack=true);
type_t *fn_t = Type(FunctionType, .args=new(arg_t, .name="x", .type=item_ptr, .next=new(arg_t, .name="y", .type=item_ptr)),
.ret=Type(IntType, .bits=32));
.ret=Type(IntType, .bits=TYPE_IBITS32));
arg_t *arg_spec = new(arg_t, .name="by", .type=Type(ClosureType, .fn=fn_t));
comparison = compile_arguments(env, ast, arg_spec, call->args);
} else {
@ -2236,7 +2233,7 @@ CORD compile(env_t *env, ast_t *ast)
CORD self = compile_to_pointer_depth(env, call->self, 1, false);
type_t *item_ptr = Type(PointerType, .pointed=item_t, .is_stack=true);
type_t *fn_t = Type(FunctionType, .args=new(arg_t, .name="x", .type=item_ptr, .next=new(arg_t, .name="y", .type=item_ptr)),
.ret=Type(IntType, .bits=32));
.ret=Type(IntType, .bits=TYPE_IBITS32));
ast_t *default_cmp = FakeAST(InlineCCode,
.code=CORD_all("((closure_t){.fn=generic_compare, .userdata=(void*)",
compile_type_info(env, item_t), "})"),
@ -2249,7 +2246,7 @@ CORD compile(env_t *env, ast_t *ast)
CORD self = compile_to_pointer_depth(env, call->self, 1, false);
type_t *item_ptr = Type(PointerType, .pointed=item_t, .is_stack=true);
type_t *fn_t = Type(FunctionType, .args=new(arg_t, .name="x", .type=item_ptr, .next=new(arg_t, .name="y", .type=item_ptr)),
.ret=Type(IntType, .bits=32));
.ret=Type(IntType, .bits=TYPE_IBITS32));
ast_t *default_cmp = FakeAST(InlineCCode,
.code=CORD_all("((closure_t){.fn=generic_compare, .userdata=(void*)",
compile_type_info(env, item_t), "})"),
@ -2261,7 +2258,7 @@ CORD compile(env_t *env, ast_t *ast)
CORD self = compile_to_pointer_depth(env, call->self, 0, false);
type_t *item_ptr = Type(PointerType, .pointed=item_t, .is_stack=true);
type_t *fn_t = Type(FunctionType, .args=new(arg_t, .name="x", .type=item_ptr, .next=new(arg_t, .name="y", .type=item_ptr)),
.ret=Type(IntType, .bits=32));
.ret=Type(IntType, .bits=TYPE_IBITS32));
ast_t *default_cmp = FakeAST(InlineCCode,
.code=CORD_all("((closure_t){.fn=generic_compare, .userdata=(void*)",
compile_type_info(env, item_t), "})"),
@ -2436,8 +2433,8 @@ CORD compile(env_t *env, ast_t *ast)
if (!(table->value_type->tag == IntType || table->value_type->tag == NumType))
code_err(ast, "bump() is only supported for tables with numeric value types, not %T", self_value_t);
ast_t *one = table->value_type->tag == IntType
? FakeAST(Int, .str="1", .bits=Match(table->value_type, IntType)->bits)
: FakeAST(Num, .n=1, .bits=Match(table->value_type, NumType)->bits);
? FakeAST(Int, .str="1")
: FakeAST(Num, .n=1);
arg_t *arg_spec = new(arg_t, .name="key", .type=table->key_type,
.next=new(arg_t, .name="amount", .type=table->value_type, .default_val=one));
return CORD_all("Table$bump(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
@ -2479,7 +2476,7 @@ CORD compile(env_t *env, ast_t *ast)
// Struct constructor:
fn_t = Type(FunctionType, .args=Match(t, StructType)->fields, .ret=t);
return CORD_all("((", compile_type(t), "){", compile_arguments(env, ast, Match(fn_t, FunctionType)->args, call->args), "})");
} else if (t->tag == NumType || (t->tag == IntType && Match(t, IntType)->bits == 0)) {
} else if (t->tag == NumType || t->tag == BigIntType) {
type_t *actual = get_type(env, call->args->value);
arg_t *args = new(arg_t, .name="i", .type=actual); // No truncation argument
CORD arg_code = compile_arguments(env, ast, args, call->args);

View File

@ -87,7 +87,7 @@ env_t *new_compilation_unit(CORD *libname)
{"from_text", "Bool$from_text", "func(text:Text, success=!&Bool)->Bool"},
{"random", "Bool$random", "func(p=0.5)->Bool"},
)},
{"Int", Type(IntType, .bits=0), "Int_t", "$Int", TypedArray(ns_entry_t,
{"Int", Type(BigIntType), "Int_t", "$Int", TypedArray(ns_entry_t,
{"format", "Int$format", "func(i:Int, digits=0)->Text"},
{"hex", "Int$hex", "func(i:Int, digits=0, uppercase=yes, prefix=yes)->Text"},
{"octal", "Int$octal", "func(i:Int, digits=0, prefix=yes)->Text"},
@ -111,7 +111,7 @@ env_t *new_compilation_unit(CORD *libname)
{"sqrt", "Int$sqrt", "func(x:Int)->Int"},
{"power", "Int$power", "func(base:Int,exponent:Int)->Int"},
)},
{"Int64", Type(IntType, .bits=64), "Int64_t", "$Int64", TypedArray(ns_entry_t,
{"Int64", Type(IntType, .bits=TYPE_IBITS64), "Int64_t", "$Int64", TypedArray(ns_entry_t,
{"format", "Int64$format", "func(i:Int64, digits=0)->Text"},
{"hex", "Int64$hex", "func(i:Int64, digits=0, uppercase=yes, prefix=yes)->Text"},
{"octal", "Int64$octal", "func(i:Int64, digits=0, prefix=yes)->Text"},
@ -126,7 +126,7 @@ env_t *new_compilation_unit(CORD *libname)
{"modulo", "Int64$modulo", "func(x:Int64,y:Int64)->Int64"},
{"modulo1", "Int64$modulo1", "func(x:Int64,y:Int64)->Int64"},
)},
{"Int32", Type(IntType, .bits=32), "Int32_t", "$Int32", TypedArray(ns_entry_t,
{"Int32", Type(IntType, .bits=TYPE_IBITS32), "Int32_t", "$Int32", TypedArray(ns_entry_t,
{"format", "Int32$format", "func(i:Int32, digits=0)->Text"},
{"hex", "Int32$hex", "func(i:Int32, digits=0, uppercase=yes, prefix=yes)->Text"},
{"octal", "Int32$octal", "func(i:Int32, digits=0, prefix=yes)->Text"},
@ -141,7 +141,7 @@ env_t *new_compilation_unit(CORD *libname)
{"modulo", "Int32$modulo", "func(x:Int32,y:Int32)->Int32"},
{"modulo1", "Int32$modulo1", "func(x:Int32,y:Int32)->Int32"},
)},
{"Int16", Type(IntType, .bits=16), "Int16_t", "$Int16", TypedArray(ns_entry_t,
{"Int16", Type(IntType, .bits=TYPE_IBITS16), "Int16_t", "$Int16", TypedArray(ns_entry_t,
{"format", "Int16$format", "func(i:Int16, digits=0)->Text"},
{"hex", "Int16$hex", "func(i:Int16, digits=0, uppercase=yes, prefix=yes)->Text"},
{"octal", "Int16$octal", "func(i:Int16, digits=0, prefix=yes)->Text"},
@ -156,7 +156,7 @@ env_t *new_compilation_unit(CORD *libname)
{"modulo", "Int16$modulo", "func(x:Int16,y:Int16)->Int16"},
{"modulo1", "Int16$modulo1", "func(x:Int16,y:Int16)->Int16"},
)},
{"Int8", Type(IntType, .bits=8), "Int8_t", "$Int8", TypedArray(ns_entry_t,
{"Int8", Type(IntType, .bits=TYPE_IBITS8), "Int8_t", "$Int8", TypedArray(ns_entry_t,
{"format", "Int8$format", "func(i:Int8, digits=0)->Text"},
{"hex", "Int8$hex", "func(i:Int8, digits=0, uppercase=yes, prefix=yes)->Text"},
{"octal", "Int8$octal", "func(i:Int8, digits=0, prefix=yes)->Text"},
@ -174,7 +174,7 @@ env_t *new_compilation_unit(CORD *libname)
#define C(name) {#name, "M_"#name, "Num"}
#define F(name) {#name, #name, "func(n:Num)->Num"}
#define F2(name) {#name, #name, "func(x:Num, y:Num)->Num"}
{"Num", Type(NumType, .bits=64), "Num_t", "$Num", TypedArray(ns_entry_t,
{"Num", Type(NumType, .bits=TYPE_NBITS64), "Num_t", "$Num", TypedArray(ns_entry_t,
{"near", "Num$near", "func(x:Num, y:Num, ratio=1e-9, min_epsilon=1e-9)->Bool"},
{"format", "Num$format", "func(n:Num, precision=0)->Text"},
{"scientific", "Num$scientific", "func(n:Num, precision=0)->Text"},
@ -202,7 +202,7 @@ env_t *new_compilation_unit(CORD *libname)
#define C(name) {#name, "(Num32_t)(M_"#name")", "Num32"}
#define F(name) {#name, #name"f", "func(n:Num32)->Num32"}
#define F2(name) {#name, #name"f", "func(x:Num32, y:Num32)->Num32"}
{"Num32", Type(NumType, .bits=32), "Num32_t", "$Num32", TypedArray(ns_entry_t,
{"Num32", Type(NumType, .bits=TYPE_NBITS32), "Num32_t", "$Num32", TypedArray(ns_entry_t,
{"near", "Num32$near", "func(x:Num32, y:Num32, ratio=1e-9f32, min_epsilon=1e-9f32)->Bool"},
{"format", "Num32$format", "func(n:Num32, precision=0)->Text"},
{"scientific", "Num32$scientific", "func(n:Num32, precision=0)->Text"},

19
parse.c
View File

@ -468,11 +468,11 @@ PARSER(parse_int) {
}
match(&pos, "_");
int64_t bits = 0;
if (match(&pos, "i64")) bits = 64;
else if (match(&pos, "i32")) bits = 32;
else if (match(&pos, "i16")) bits = 16;
else if (match(&pos, "i8")) bits = 8;
auto bits = IBITS_UNSPECIFIED;
if (match(&pos, "i64")) bits = IBITS64;
else if (match(&pos, "i32")) bits = IBITS32;
else if (match(&pos, "i16")) bits = IBITS16;
else if (match(&pos, "i8")) bits = IBITS8;
// else if (match(&pos, ".") || match(&pos, "e")) return NULL; // looks like a float
@ -624,14 +624,13 @@ PARSER(parse_num) {
if (negative) d *= -1;
int64_t bits = 64;
auto bits = NBITS_UNSPECIFIED;
match(&pos, "_");
if (match(&pos, "f64")) bits = 64;
else if (match(&pos, "f32")) bits = 32;
if (match(&pos, "f64")) bits = NBITS64;
else if (match(&pos, "f32")) bits = NBITS32;
if (match(&pos, "%")) {
if (match(&pos, "%"))
d /= 100.;
}
return NewAST(ctx->file, start, pos, Num, .n=d, .bits=bits);
}

49
repl.c
View File

@ -103,18 +103,19 @@ const TypeInfo *type_to_type_info(type_t *t)
case VoidType: return &$Void;
case MemoryType: return &$Memory;
case BoolType: return &$Bool;
case BigIntType: return &$Int;
case IntType:
switch (Match(t, IntType)->bits) {
case 0: case 64: return &$Int;
case 32: return &$Int32;
case 16: return &$Int16;
case 8: return &$Int8;
case TYPE_IBITS64: return &$Int64;
case TYPE_IBITS32: return &$Int32;
case TYPE_IBITS16: return &$Int16;
case TYPE_IBITS8: return &$Int8;
default: errx(1, "Invalid bits");
}
case NumType:
switch (Match(t, NumType)->bits) {
case 0: case 64: return &$Num;
case 32: return &$Num32;
case TYPE_NBITS64: return &$Num;
case TYPE_NBITS32: return &$Num32;
default: errx(1, "Invalid bits");
}
case TextType: return &$Text;
@ -161,15 +162,19 @@ static Int_t ast_to_int(env_t *env, ast_t *ast)
{
type_t *t = get_type(env, ast);
switch (t->tag) {
case BigIntType: {
number_t num;
eval(env, ast, &num);
return num.integer;
}
case IntType: {
number_t num;
eval(env, ast, &num);
switch (Match(t, IntType)->bits) {
case 0: return num.integer;
case 64: return Int64_to_Int((int64_t)num.i64);
case 32: return Int32_to_Int(num.i32);
case 16: return Int16_to_Int(num.i16);
case 8: return Int8_to_Int(num.i8);
case TYPE_IBITS64: return Int64_to_Int((int64_t)num.i64);
case TYPE_IBITS32: return Int32_to_Int(num.i32);
case TYPE_IBITS16: return Int16_to_Int(num.i16);
case TYPE_IBITS8: return Int8_to_Int(num.i8);
default: errx(1, "Invalid int bits");
}
}
@ -181,22 +186,23 @@ static double ast_to_num(env_t *env, ast_t *ast)
{
type_t *t = get_type(env, ast);
switch (t->tag) {
case IntType: {
case BigIntType: case IntType: {
number_t num;
eval(env, ast, &num);
if (t->tag == BigIntType)
return Int_to_Num(num.integer);
switch (Match(t, IntType)->bits) {
case 0: return Int_to_Num(num.integer);
case 64: return (double)num.i64;
case 32: return (double)num.i32;
case 16: return (double)num.i16;
case 8: return (double)num.i8;
case TYPE_IBITS64: return (double)num.i64;
case TYPE_IBITS32: return (double)num.i32;
case TYPE_IBITS16: return (double)num.i16;
case TYPE_IBITS8: return (double)num.i8;
default: errx(1, "Invalid int bits");
}
}
case NumType: {
number_t num;
eval(env, ast, &num);
return Match(t, NumType)->bits == 32 ? (double)num.n32 : (double)num.n64;
return Match(t, NumType)->bits == TYPE_NBITS32 ? (double)num.n32 : (double)num.n64;
}
default: repl_err(NULL, "Cannot convert to number");
}
@ -388,13 +394,16 @@ void eval(env_t *env, ast_t *ast, void *dest)
}
case BinaryOp: {
auto binop = Match(ast, BinaryOp);
if (t->tag == IntType) {
if (t->tag == IntType || t->tag == BigIntType) {
#define CASE_OP(OP_NAME, method_name) case BINOP_##OP_NAME: {\
Int_t lhs = ast_to_int(env, binop->lhs); \
Int_t rhs = ast_to_int(env, binop->rhs); \
Int_t result = Int$ ## method_name (lhs, rhs); \
if (t->tag == BigIntType) {\
*(Int_t*)dest = result; \
return; \
} \
switch (Match(t, IntType)->bits) { \
case 0: *(Int_t*)dest = result; return; \
case 64: *(int64_t*)dest = Int_to_Int64(result, false); return; \
case 32: *(int32_t*)dest = Int_to_Int32(result, false); return; \
case 16: *(int16_t*)dest = Int_to_Int16(result, false); return; \

View File

@ -47,13 +47,10 @@ static CORD compile_compare_method(env_t *env, ast_t *ast)
for (arg_ast_t *field = def->fields; field; field = field->next) {
type_t *field_type = get_arg_ast_type(env, field);
switch (field_type->tag) {
case IntType:
if (Match(field_type, IntType)->bits == 0)
cmp_func = CORD_all(cmp_func, "diff = Int$compare_value(x->$", field->name, ", y->$", field->name, ");");
else
cmp_func = CORD_all(cmp_func, "diff = (x->$", field->name, " > y->$", field->name, ") - (x->$", field->name, " < y->$", field->name, ");");
case BigIntType:
cmp_func = CORD_all(cmp_func, "diff = Int$compare_value(x->$", field->name, ", y->$", field->name, ");");
break;
case BoolType: case NumType: case PointerType: case FunctionType:
case BoolType: case IntType: case NumType: case PointerType: case FunctionType:
cmp_func = CORD_all(cmp_func, "diff = (x->$", field->name, " > y->$", field->name, ") - (x->$", field->name, " < y->$", field->name, ");");
break;
case TextType:
@ -83,13 +80,10 @@ static CORD compile_equals_method(env_t *env, ast_t *ast)
condition = CORD_all(condition, " && ");
type_t *field_type = get_arg_ast_type(env, field);
switch (field_type->tag) {
case IntType:
if (Match(field_type, IntType)->bits == 0)
condition = CORD_all(condition, "Int$equal_value(x->$", field->name, ", y->$", field->name, ")");
else
condition = CORD_all(condition, "(x->$", field->name, " == y->$", field->name, ")");
case BigIntType:
condition = CORD_all(condition, "Int$equal_value(x->$", field->name, ", y->$", field->name, ")");
break;
case BoolType: case NumType: case PointerType: case FunctionType:
case BoolType: case IntType: case NumType: case PointerType: case FunctionType:
condition = CORD_all(condition, "(x->$", field->name, " == y->$", field->name, ")");
break;
case TextType:
@ -144,24 +138,15 @@ void compile_struct_def(env_t *env, ast_t *ast)
if (struct_->fields && !struct_->fields->next) { // Single member, can just use its methods
type_t *member_t = struct_->fields->type;
switch (member_t->tag) {
case NumType:
case IntType: case NumType:
typeinfo = CORD_all(typeinfo, ".compare=(void*)", type_to_cord(member_t), "$compare, "
".equal=(void*)", type_to_cord(member_t), "$equal, ");
goto got_methods;
case TextType:
case BigIntType: case TextType:
typeinfo = CORD_all(typeinfo, ".hash=(void*)", type_to_cord(member_t), "$hash", ", ",
".compare=(void*)", type_to_cord(member_t), "$compare, "
".equal=(void*)", type_to_cord(member_t), "$equal, ");
goto got_methods;
case IntType:
if (Match(member_t, IntType)->bits == 0)
typeinfo = CORD_all(typeinfo, ".hash=(void*)Int$hash", ", ",
".compare=(void*)Int$compare, "
".equal=(void*)Int$equal, ");
else
typeinfo = CORD_all(typeinfo, ".compare=(void*)", type_to_cord(member_t), "$compare, "
".equal=(void*)", type_to_cord(member_t), "$equal, ");
goto got_methods;
case BoolType: goto got_methods;
default: break;
}

View File

@ -116,15 +116,11 @@ type_t *parse_type_ast(env_t *env, type_ast_t *ast)
type_t *get_math_type(env_t *env, ast_t *ast, type_t *lhs_t, type_t *rhs_t)
{
(void)env;
if (lhs_t->tag == IntType && rhs_t->tag == IntType)
return Match(lhs_t, IntType)->bits >= Match(rhs_t, IntType)->bits ? lhs_t : rhs_t;
else if (lhs_t->tag == NumType && rhs_t->tag == NumType)
return Match(lhs_t, NumType)->bits >= Match(rhs_t, NumType)->bits ? lhs_t : rhs_t;
else if (lhs_t->tag == NumType && rhs_t->tag == IntType)
return lhs_t;
else if (rhs_t->tag == NumType && lhs_t->tag == IntType)
return rhs_t;
switch (compare_precision(lhs_t, rhs_t)) {
case NUM_PRECISION_EQUAL: case NUM_PRECISION_MORE: return lhs_t;
case NUM_PRECISION_LESS: return rhs_t;
default: return NULL;
}
code_err(ast, "Math operations between %T and %T are not supported", lhs_t, rhs_t);
}
@ -456,11 +452,24 @@ type_t *get_type(env_t *env, ast_t *ast)
}
case Int: {
auto i = Match(ast, Int);
return Type(IntType, .bits=i->bits);
switch (i->bits) {
case IBITS_UNSPECIFIED: return Type(BigIntType);
case IBITS8: return Type(IntType, .bits=TYPE_IBITS8);
case IBITS16: return Type(IntType, .bits=TYPE_IBITS16);
case IBITS32: return Type(IntType, .bits=TYPE_IBITS32);
case IBITS64: return Type(IntType, .bits=TYPE_IBITS64);
default: errx(1, "Invalid integer bits");
}
}
case Num: {
auto n = Match(ast, Num);
return Type(NumType, .bits=n->bits);
switch (n->bits) {
case NBITS_UNSPECIFIED: case NBITS64:
return Type(NumType, .bits=TYPE_NBITS64);
case NBITS32:
return Type(NumType, .bits=TYPE_NBITS32);
default: errx(1, "Invalid num bits");
}
}
case HeapAllocate: {
type_t *pointed = get_type(env, Match(ast, HeapAllocate)->value);
@ -987,12 +996,12 @@ type_t *get_type(env_t *env, ast_t *ast)
return Type(BoolType);
}
case BINOP_CMP:
return Type(IntType, .bits=32);
return Type(IntType, .bits=TYPE_IBITS32);
case BINOP_POWER: {
type_t *result = get_math_type(env, ast, lhs_t, rhs_t);
if (result->tag == NumType)
return result;
return Type(NumType, .bits=64);
return Type(NumType, .bits=TYPE_NBITS64);
}
default: {
return get_math_type(env, ast, lhs_t, rhs_t);
@ -1351,7 +1360,7 @@ bool is_constant(env_t *env, ast_t *ast)
case Bool: case Num: case Nil: case TextLiteral: return true;
case Int: {
auto info = Match(ast, Int);
if (info->bits == 0) {
if (info->bits == IBITS_UNSPECIFIED) {
Int_t int_val = Int$from_text(info->str);
mpz_t i;
mpz_init_set_int(i, int_val);

57
types.c
View File

@ -19,8 +19,9 @@ CORD type_to_cord(type_t *t) {
case BoolType: return "Bool";
case CStringType: return "CString";
case TextType: return Match(t, TextType)->lang ? Match(t, TextType)->lang : "Text";
case IntType: return Match(t, IntType)->bits == 0 ? "Int" : CORD_asprintf("Int%ld", Match(t, IntType)->bits);
case NumType: return Match(t, NumType)->bits == 64 ? "Num" : CORD_asprintf("Num%ld", Match(t, NumType)->bits);
case BigIntType: return "Int";
case IntType: return CORD_asprintf("Int%d", Match(t, IntType)->bits);
case NumType: return Match(t, NumType)->bits == TYPE_NBITS32 ? "Num32" : "Num";
case ArrayType: {
auto array = Match(t, ArrayType);
return CORD_asprintf("[%r]", type_to_cord(array->item_type));
@ -154,14 +155,14 @@ static inline double type_min_magnitude(type_t *t)
{
switch (t->tag) {
case BoolType: return (double)false;
case BigIntType: return -1./0.;
case IntType: {
switch (Match(t, IntType)->bits) {
case 0: return -1./0.;
case 8: return (double)INT8_MIN;
case 16: return (double)INT16_MIN;
case 32: return (double)INT32_MIN;
case 64: return (double)INT64_MIN;
default: return NAN;
case TYPE_IBITS8: return (double)INT8_MIN;
case TYPE_IBITS16: return (double)INT16_MIN;
case TYPE_IBITS32: return (double)INT32_MIN;
case TYPE_IBITS64: return (double)INT64_MIN;
default: errx(1, "Invalid integer bit size");
}
}
case NumType: return -1./0.;
@ -173,14 +174,14 @@ static inline double type_max_magnitude(type_t *t)
{
switch (t->tag) {
case BoolType: return (double)true;
case BigIntType: return 1./0.;
case IntType: {
switch (Match(t, IntType)->bits) {
case 0: return 1./0.;
case 8: return (double)INT8_MAX;
case 16: return (double)INT16_MAX;
case 32: return (double)INT32_MAX;
case 64: return (double)INT64_MAX;
default: return NAN;
case TYPE_IBITS8: return (double)INT8_MAX;
case TYPE_IBITS16: return (double)INT16_MAX;
case TYPE_IBITS32: return (double)INT32_MAX;
case TYPE_IBITS64: return (double)INT64_MAX;
default: errx(1, "Invalid integer bit size");
}
}
case NumType: return 1./0.;
@ -211,7 +212,7 @@ bool has_heap_memory(type_t *t)
case TableType: return true;
case SetType: return true;
case PointerType: return true;
case IntType: return (Match(t, IntType)->bits == 0);
case BigIntType: return true;
case StructType: {
for (arg_t *field = Match(t, StructType)->fields; field; field = field->next) {
if (has_heap_memory(field->type))
@ -452,17 +453,17 @@ size_t type_size(type_t *t)
case MemoryType: errx(1, "Memory has undefined type size");
case BoolType: return sizeof(bool);
case CStringType: return sizeof(char*);
case BigIntType: return sizeof(Int_t);
case IntType: {
switch (Match(t, IntType)->bits) {
case 0: return sizeof(Int_t);
case 64: return sizeof(int64_t);
case 32: return sizeof(int32_t);
case 16: return sizeof(int16_t);
case 8: return sizeof(int8_t);
default: return 0;
case TYPE_IBITS64: return sizeof(int64_t);
case TYPE_IBITS32: return sizeof(int32_t);
case TYPE_IBITS16: return sizeof(int16_t);
case TYPE_IBITS8: return sizeof(int8_t);
default: errx(1, "Invalid integer bit size");
}
}
case NumType: return Match(t, NumType)->bits/8;
case NumType: return Match(t, NumType)->bits == TYPE_NBITS64 ? sizeof(double) : sizeof(float);
case TextType: return sizeof(CORD);
case ArrayType: return sizeof(array_t);
case SetType: return sizeof(table_t);
@ -515,17 +516,17 @@ size_t type_align(type_t *t)
case MemoryType: errx(1, "Memory has undefined type alignment");
case BoolType: return __alignof__(bool);
case CStringType: return __alignof__(char*);
case BigIntType: return __alignof__(Int_t);
case IntType: {
switch (Match(t, IntType)->bits) {
case 0: return __alignof__(Int_t);
case 64: return __alignof__(int64_t);
case 32: return __alignof__(int32_t);
case 16: return __alignof__(int16_t);
case 8: return __alignof__(int8_t);
case TYPE_IBITS64: return __alignof__(int64_t);
case TYPE_IBITS32: return __alignof__(int32_t);
case TYPE_IBITS16: return __alignof__(int16_t);
case TYPE_IBITS8: return __alignof__(int8_t);
default: return 0;
}
}
case NumType: return Match(t, NumType)->bits/8;
case NumType: return Match(t, NumType)->bits == TYPE_NBITS64 ? __alignof__(double) : __alignof__(float);
case TextType: return __alignof__(CORD);
case SetType: return __alignof__(table_t);
case ArrayType: return __alignof__(array_t);

10
types.h
View File

@ -43,6 +43,7 @@ struct type_s {
VoidType,
MemoryType,
BoolType,
BigIntType,
IntType,
NumType,
CStringType,
@ -66,11 +67,12 @@ struct type_s {
struct {
type_t *ret;
} ReturnType;
struct {} BigIntType;
struct {
int64_t bits;
enum { TYPE_IBITS8=8, TYPE_IBITS16=16, TYPE_IBITS32=32, TYPE_IBITS64=64 } bits;
} IntType;
struct {
int64_t bits;
enum { TYPE_NBITS32=32, TYPE_NBITS64=64 } bits;
} NumType;
struct {} CStringType;
struct {
@ -121,8 +123,8 @@ struct type_s {
};
#define Type(typetag, ...) new(type_t, .tag=typetag, .__data.typetag={__VA_ARGS__})
#define INT_TYPE Type(IntType, .bits=0)
#define NUM_TYPE Type(NumType, .bits=64)
#define INT_TYPE Type(BigIntType)
#define NUM_TYPE Type(NumType, .bits=TYPE_NBITS64)
int printf_pointer_size(const struct printf_info *info, size_t n, int argtypes[n], int size[n]);
int printf_type(FILE *stream, const struct printf_info *info, const void *const args[]);