Overhaul of constructors, making it more consistent and correct. Also
changed T(), T, T_t, T_s type names to T(), T$$info, T$$type, T$$struct for unambiguity
This commit is contained in:
parent
2c4324670f
commit
147e0f0269
4
Makefile
4
Makefile
@ -66,14 +66,14 @@ test: $(TESTS)
|
||||
@echo -e '\x1b[32;7m ALL TESTS PASSED! \x1b[m'
|
||||
|
||||
clean:
|
||||
rm -f tomo *.o stdlib/*.o libtomo.so test/*.tm.{c,h,o,testresult} examples/**/*.tm.{c,h,o}
|
||||
rm -f tomo *.o stdlib/*.o libtomo.so test/*.tm.{c,h,o,testresult} examples/**/*.tm.{c,h,o} examples/*.tm.{c,h,o}
|
||||
|
||||
%: %.md
|
||||
pandoc --lua-filter=.pandoc/bold-code.lua -s $< -t man -o $@
|
||||
|
||||
examples:
|
||||
./tomo examples/learnxiny.tm
|
||||
./tomo -IL examples/vectors examples/base64 examples/log examples/ini examples/game examples/http examples/threads examples/tomodeps examples/tomo-install examples/wrap
|
||||
./tomo examples/learnxiny.tm
|
||||
|
||||
install: tomo libtomo.so tomo.1
|
||||
mkdir -p -m 755 "$(PREFIX)/man/man1" "$(PREFIX)/bin" "$(PREFIX)/include/tomo" "$(PREFIX)/lib" "$(PREFIX)/share/tomo/modules"
|
||||
|
191
compile.c
191
compile.c
@ -13,6 +13,7 @@
|
||||
#include "enums.h"
|
||||
#include "environment.h"
|
||||
#include "stdlib/integers.h"
|
||||
#include "stdlib/nums.h"
|
||||
#include "stdlib/patterns.h"
|
||||
#include "stdlib/text.h"
|
||||
#include "stdlib/util.h"
|
||||
@ -102,22 +103,20 @@ static bool promote(env_t *env, ast_t *ast, CORD *code, type_t *actual, type_t *
|
||||
return true;
|
||||
}
|
||||
|
||||
if (actual->tag == IntType && needed->tag == BigIntType) {
|
||||
*code = CORD_all("I(", *code, ")");
|
||||
return true;
|
||||
// Numeric promotions/demotions
|
||||
if ((is_numeric_type(actual) || actual->tag == BoolType) && (is_numeric_type(needed) || needed->tag == BoolType)) {
|
||||
arg_ast_t *args = new(arg_ast_t, .value=FakeAST(InlineCCode, .code=*code, .type=actual));
|
||||
binding_t *constructor = NULL;
|
||||
if ((constructor=get_constructor(env, needed, args, needed))
|
||||
|| (constructor=get_constructor(env, actual, args, needed))) {
|
||||
auto fn = Match(constructor->type, FunctionType);
|
||||
if (fn->args->next == NULL) {
|
||||
*code = CORD_all(constructor->code, "(", compile_arguments(env, ast, fn->args, args), ")");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((actual->tag == IntType || actual->tag == BigIntType) && needed->tag == NumType) {
|
||||
*code = CORD_all(type_to_cord(actual), "_to_", type_to_cord(needed), "(", *code, ")");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (actual->tag == NumType && needed->tag == IntType)
|
||||
return false;
|
||||
|
||||
if (actual->tag == IntType || actual->tag == NumType)
|
||||
return true;
|
||||
|
||||
if (needed->tag == EnumType) {
|
||||
const char *tag = enum_single_value_tag(needed, actual);
|
||||
binding_t *b = get_binding(Match(needed, EnumType)->env, tag);
|
||||
@ -527,7 +526,7 @@ CORD compile_type(type_t *t)
|
||||
else if (streq(text->lang, "Shell"))
|
||||
return "Shell_t";
|
||||
else
|
||||
return CORD_all(namespace_prefix(text->env, text->env->namespace->parent), text->lang, "_t");
|
||||
return CORD_all(namespace_prefix(text->env, text->env->namespace->parent), text->lang, "$$type");
|
||||
}
|
||||
case ArrayType: return "Array_t";
|
||||
case SetType: return "Table_t";
|
||||
@ -547,11 +546,11 @@ CORD compile_type(type_t *t)
|
||||
case PointerType: return CORD_cat(compile_type(Match(t, PointerType)->pointed), "*");
|
||||
case StructType: {
|
||||
auto s = Match(t, StructType);
|
||||
return CORD_all("struct ", namespace_prefix(s->env, s->env->namespace->parent), s->name, "_s");
|
||||
return CORD_all("struct ", namespace_prefix(s->env, s->env->namespace->parent), s->name, "$$struct");
|
||||
}
|
||||
case EnumType: {
|
||||
auto e = Match(t, EnumType);
|
||||
return CORD_all(namespace_prefix(e->env, e->env->namespace->parent), e->name, "_t");
|
||||
return CORD_all(namespace_prefix(e->env, e->env->namespace->parent), e->name, "$$type");
|
||||
}
|
||||
case OptionalType: {
|
||||
type_t *nonnull = Match(t, OptionalType)->type;
|
||||
@ -570,7 +569,7 @@ CORD compile_type(type_t *t)
|
||||
if (nonnull == MATCH_TYPE)
|
||||
return "OptionalMatch_t";
|
||||
auto s = Match(nonnull, StructType);
|
||||
return CORD_all(namespace_prefix(s->env, s->env->namespace->parent), "$Optional", s->name, "_t");
|
||||
return CORD_all(namespace_prefix(s->env, s->env->namespace->parent), "$Optional", s->name, "$$type");
|
||||
}
|
||||
default:
|
||||
compiler_err(NULL, NULL, NULL, "Optional types are not supported for: %T", t);
|
||||
@ -1848,10 +1847,18 @@ CORD compile_to_pointer_depth(env_t *env, ast_t *ast, int64_t target_depth, bool
|
||||
|
||||
CORD compile_to_type(env_t *env, ast_t *ast, type_t *t)
|
||||
{
|
||||
if (ast->tag == Int && is_numeric_type(t))
|
||||
if (ast->tag == Int && is_numeric_type(t)) {
|
||||
return compile_int_to_type(env, ast, t);
|
||||
if (ast->tag == None && Match(ast, None)->type == NULL)
|
||||
} else if (ast->tag == Num && t->tag == NumType) {
|
||||
double n = Match(ast, Num)->n;
|
||||
switch (Match(t, NumType)->bits) {
|
||||
case TYPE_NBITS64: return CORD_asprintf("N64(%.20g)", n);
|
||||
case TYPE_NBITS32: return CORD_asprintf("N32(%.10g)", n);
|
||||
default: code_err(ast, "This is not a valid number bit width");
|
||||
}
|
||||
} else if (ast->tag == None && Match(ast, None)->type == NULL) {
|
||||
return compile_none(t);
|
||||
}
|
||||
|
||||
type_t *actual = get_type(env, ast);
|
||||
|
||||
@ -1886,7 +1893,7 @@ CORD compile_int_to_type(env_t *env, ast_t *ast, type_t *target)
|
||||
CORD code = compile(env, ast);
|
||||
type_t *actual_type = get_type(env, ast);
|
||||
if (!promote(env, ast, &code, actual_type, target))
|
||||
code = CORD_all(type_to_cord(actual_type), "_to_", type_to_cord(target), "(", code, ", no)");
|
||||
code_err(ast, "I couldn't promote this %T to a %T", actual_type, target);
|
||||
return code;
|
||||
}
|
||||
|
||||
@ -1968,9 +1975,10 @@ CORD compile_arguments(env_t *env, ast_t *call_ast, arg_t *spec_args, arg_ast_t
|
||||
OptionalInt_t int_val = Int$from_str(Match(call_arg->value, Int)->str);
|
||||
if (int_val.small == 0)
|
||||
code_err(call_arg->value, "Failed to parse this integer");
|
||||
double n = Int_to_Num(int_val);
|
||||
value = CORD_asprintf(Match(spec_arg->type, NumType)->bits == TYPE_NBITS64
|
||||
? "N64(%.20g)" : "N32(%.10g)", n);
|
||||
if (Match(spec_arg->type, NumType)->bits == TYPE_NBITS64)
|
||||
value = CORD_asprintf("N64(%.20g)", Num$from_int(int_val, false));
|
||||
else
|
||||
value = CORD_asprintf("N32(%.10g)", (double)Num32$from_int(int_val, false));
|
||||
} else {
|
||||
env_t *arg_env = with_enum_scope(env, spec_arg->type);
|
||||
value = compile_maybe_incref(arg_env, call_arg->value, spec_arg->type);
|
||||
@ -1994,9 +2002,10 @@ CORD compile_arguments(env_t *env, ast_t *call_ast, arg_t *spec_args, arg_ast_t
|
||||
OptionalInt_t int_val = Int$from_str(Match(call_arg->value, Int)->str);
|
||||
if (int_val.small == 0)
|
||||
code_err(call_arg->value, "Failed to parse this integer");
|
||||
double n = Int_to_Num(int_val);
|
||||
value = CORD_asprintf(Match(spec_arg->type, NumType)->bits == TYPE_NBITS64
|
||||
? "N64(%.20g)" : "N32(%.10g)", n);
|
||||
if (Match(spec_arg->type, NumType)->bits == TYPE_NBITS64)
|
||||
value = CORD_asprintf("N64(%.20g)", Num$from_int(int_val, false));
|
||||
else
|
||||
value = CORD_asprintf("N32(%.10g)", (double)Num32$from_int(int_val, false));
|
||||
} else {
|
||||
env_t *arg_env = with_enum_scope(env, spec_arg->type);
|
||||
value = compile_maybe_incref(arg_env, call_arg->value, spec_arg->type);
|
||||
@ -2226,22 +2235,6 @@ static ast_t *add_to_set_comprehension(ast_t *item, ast_t *subject)
|
||||
return WrapAST(item, MethodCall, .name="add", .self=subject, .args=new(arg_ast_t, .value=item));
|
||||
}
|
||||
|
||||
static CORD compile_num_to_type(ast_t *ast, type_t *type)
|
||||
{
|
||||
double n = Match(ast, Num)->n;
|
||||
|
||||
if (type->tag != NumType)
|
||||
code_err(ast, "I can't compile a number literal to a %T", type);
|
||||
|
||||
switch (Match(type, NumType)->bits) {
|
||||
case TYPE_NBITS64:
|
||||
return CORD_asprintf("N64(%.20g)", n);
|
||||
case TYPE_NBITS32:
|
||||
return CORD_asprintf("N32(%.10g)", n);
|
||||
default: code_err(ast, "This is not a valid number bit width");
|
||||
}
|
||||
}
|
||||
|
||||
CORD compile(env_t *env, ast_t *ast)
|
||||
{
|
||||
switch (ast->tag) {
|
||||
@ -2273,7 +2266,7 @@ CORD compile(env_t *env, ast_t *ast)
|
||||
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) {
|
||||
return CORD_asprintf("Int64_to_Int(%s)", str);
|
||||
return CORD_asprintf("Int$from_int64(%s)", str);
|
||||
} else {
|
||||
return CORD_asprintf("Int$from_str(\"%s\")", str);
|
||||
}
|
||||
@ -3012,7 +3005,6 @@ CORD compile(env_t *env, ast_t *ast)
|
||||
if (entry->b->type->tag == ModuleType)
|
||||
continue;
|
||||
binding_t *b = get_binding(env, entry->name);
|
||||
if (!b) printf("Couldn't find: %s\n", entry->name);
|
||||
assert(b);
|
||||
CORD binding_code = b->code;
|
||||
if (entry->b->type->tag == ArrayType)
|
||||
@ -3371,6 +3363,12 @@ CORD compile(env_t *env, ast_t *ast)
|
||||
} else if (fn_t->tag == TypeInfoType) {
|
||||
type_t *t = Match(fn_t, TypeInfoType)->type;
|
||||
|
||||
// Literal constructors for numeric types like `Byte(123)` should not go through any conversion, just a cast:
|
||||
if (is_numeric_type(t) && call->args && !call->args->next && call->args->value->tag == Int)
|
||||
return compile_to_type(env, call->args->value, t);
|
||||
else if (t->tag == NumType && call->args && !call->args->next && call->args->value->tag == Num)
|
||||
return compile_to_type(env, call->args->value, t);
|
||||
|
||||
binding_t *constructor = get_constructor(env, t, call->args, t);
|
||||
if (constructor) {
|
||||
arg_t *arg_spec = Match(constructor->type, FunctionType)->args;
|
||||
@ -3378,65 +3376,7 @@ CORD compile(env_t *env, ast_t *ast)
|
||||
}
|
||||
|
||||
type_t *actual = call->args ? get_type(env, call->args->value) : NULL;
|
||||
if (t->tag == StructType) {
|
||||
// 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 (is_numeric_type(t) && call->args && call->args->value->tag == Int) {
|
||||
if (call->args->next)
|
||||
code_err(call->args->next->value, "This is too many arguments to an integer literal constructor");
|
||||
return compile_int_to_type(env, call->args->value, t);
|
||||
} else if (t->tag == NumType && call->args && call->args->value->tag == Num) {
|
||||
if (call->args->next)
|
||||
code_err(call->args->next->value, "This is too many arguments to a number literal constructor");
|
||||
return compile_num_to_type(call->args->value, t);
|
||||
} else if (t->tag == NumType || t->tag == BigIntType) {
|
||||
if (!call->args) code_err(ast, "This constructor needs a value");
|
||||
if (!call->args)
|
||||
code_err(ast, "This constructor requires an argument!");
|
||||
|
||||
if (type_eq(actual, t)) {
|
||||
if (call->args->next)
|
||||
code_err(ast, "This is too many arguments!");
|
||||
return compile(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);
|
||||
if (is_numeric_type(actual)) {
|
||||
return CORD_all(type_to_cord(actual), "_to_", type_to_cord(t), "(", arg_code, ")");
|
||||
} else if (actual->tag == BoolType) {
|
||||
if (t->tag == NumType) {
|
||||
return CORD_all("((", compile_type(t), ")(", arg_code, "))");
|
||||
} else {
|
||||
return CORD_all("I((int)(", arg_code, "))");
|
||||
}
|
||||
} else {
|
||||
code_err(ast, "You cannot convert a %T to a %T this way.", actual, t);
|
||||
}
|
||||
} else if (t->tag == IntType || t->tag == ByteType) {
|
||||
if (!call->args)
|
||||
code_err(ast, "This constructor requires an argument!");
|
||||
|
||||
if (type_eq(actual, t)) {
|
||||
if (call->args->next)
|
||||
code_err(ast, "This is too many arguments!");
|
||||
return compile(env, call->args->value);
|
||||
}
|
||||
|
||||
if (is_numeric_type(actual)) {
|
||||
arg_t *args = new(arg_t, .name="i", .type=actual, .next=new(arg_t, .name="truncate", .type=Type(BoolType),
|
||||
.default_val=FakeAST(Bool, false)));
|
||||
CORD arg_code = compile_arguments(env, ast, args, call->args);
|
||||
return CORD_all(type_to_cord(actual), "_to_", type_to_cord(t), "(", arg_code, ")");
|
||||
} else if (actual->tag == BoolType) {
|
||||
arg_t *args = new(arg_t, .name="i", .type=actual);
|
||||
CORD arg_code = compile_arguments(env, ast, args, call->args);
|
||||
return CORD_all("((", compile_type(t),")(", arg_code, "))");
|
||||
} else {
|
||||
code_err(ast, "You cannot convert a %T to a %T this way.", actual, t);
|
||||
}
|
||||
} else if (t->tag == TextType) {
|
||||
if (t->tag == TextType) {
|
||||
if (!call->args) code_err(ast, "This constructor needs a value");
|
||||
const char *lang = Match(t, TextType)->lang;
|
||||
if (lang)
|
||||
@ -3458,11 +3398,6 @@ CORD compile(env_t *env, ast_t *ast)
|
||||
else if (call->args->value->tag == TextJoin && Match(call->args->value, TextJoin)->children->next == NULL)
|
||||
return compile_string_literal(Match(Match(call->args->value, TextJoin)->children->ast, TextLiteral)->cord);
|
||||
return CORD_all("Text$as_c_string(", expr_as_text(env, compile(env, call->args->value), actual, "no"), ")");
|
||||
} else if (t->tag == MomentType) {
|
||||
// Moment constructor:
|
||||
binding_t *new_binding = get_binding(Match(fn_t, TypeInfoType)->env, "new");
|
||||
CORD arg_code = compile_arguments(env, ast, Match(new_binding->type, FunctionType)->args, call->args);
|
||||
return CORD_all(new_binding->code, "(", arg_code, ")");
|
||||
} else {
|
||||
code_err(call->fn, "This is not a type that has a constructor");
|
||||
}
|
||||
@ -3726,7 +3661,7 @@ CORD compile(env_t *env, ast_t *ast)
|
||||
CORD text = compile_to_pointer_depth(env, f->fielded, 0, false);
|
||||
return CORD_all("((Text_t)", text, ")");
|
||||
} else if (streq(f->field, "length")) {
|
||||
return CORD_all("Int64_to_Int((", compile_to_pointer_depth(env, f->fielded, 0, false), ").length)");
|
||||
return CORD_all("Int$from_int64((", compile_to_pointer_depth(env, f->fielded, 0, false), ").length)");
|
||||
}
|
||||
code_err(ast, "There is no '%s' field on %T values", f->field, value_t);
|
||||
}
|
||||
@ -3763,19 +3698,19 @@ CORD compile(env_t *env, ast_t *ast)
|
||||
}
|
||||
case ArrayType: {
|
||||
if (streq(f->field, "length"))
|
||||
return CORD_all("Int64_to_Int((", compile_to_pointer_depth(env, f->fielded, 0, false), ").length)");
|
||||
return CORD_all("Int$from_int64((", compile_to_pointer_depth(env, f->fielded, 0, false), ").length)");
|
||||
code_err(ast, "There is no %s field on arrays", f->field);
|
||||
}
|
||||
case SetType: {
|
||||
if (streq(f->field, "items"))
|
||||
return CORD_all("ARRAY_COPY((", compile_to_pointer_depth(env, f->fielded, 0, false), ").entries)");
|
||||
else if (streq(f->field, "length"))
|
||||
return CORD_all("Int64_to_Int((", compile_to_pointer_depth(env, f->fielded, 0, false), ").entries.length)");
|
||||
return CORD_all("Int$from_int64((", compile_to_pointer_depth(env, f->fielded, 0, false), ").entries.length)");
|
||||
code_err(ast, "There is no '%s' field on sets", f->field);
|
||||
}
|
||||
case TableType: {
|
||||
if (streq(f->field, "length")) {
|
||||
return CORD_all("Int64_to_Int((", compile_to_pointer_depth(env, f->fielded, 0, false), ").entries.length)");
|
||||
return CORD_all("Int$from_int64((", compile_to_pointer_depth(env, f->fielded, 0, false), ").entries.length)");
|
||||
} else if (streq(f->field, "keys")) {
|
||||
return CORD_all("ARRAY_COPY((", compile_to_pointer_depth(env, f->fielded, 0, false), ").entries)");
|
||||
} else if (streq(f->field, "values")) {
|
||||
@ -3835,12 +3770,14 @@ CORD compile(env_t *env, ast_t *ast)
|
||||
type_t *item_type = Match(container_t, ArrayType)->item_type;
|
||||
CORD arr = compile_to_pointer_depth(env, indexing->indexed, 0, false);
|
||||
file_t *f = indexing->index->file;
|
||||
CORD index_code = indexing->index->tag == Int
|
||||
? compile_int_to_type(env, indexing->index, Type(IntType, .bits=TYPE_IBITS64))
|
||||
: (index_t->tag == BigIntType ? CORD_all("Int64$from_int(", compile(env, indexing->index), ", no)")
|
||||
: CORD_all("(Int64_t)(", compile(env, indexing->index), ")"));
|
||||
if (indexing->unchecked)
|
||||
return CORD_all("Array_get_unchecked(", compile_type(item_type), ", ", arr, ", ",
|
||||
compile_int_to_type(env, indexing->index, Type(IntType, .bits=TYPE_IBITS64)), ")");
|
||||
return CORD_all("Array_get_unchecked(", compile_type(item_type), ", ", arr, ", ", index_code, ")");
|
||||
else
|
||||
return CORD_all("Array_get(", compile_type(item_type), ", ", arr, ", ",
|
||||
compile_int_to_type(env, indexing->index, Type(IntType, .bits=TYPE_IBITS64)), ", ",
|
||||
return CORD_all("Array_get(", compile_type(item_type), ", ", arr, ", ", index_code, ", ",
|
||||
CORD_asprintf("%ld", (int64_t)(indexing->index->start - f->text)), ", ",
|
||||
CORD_asprintf("%ld", (int64_t)(indexing->index->end - f->text)),
|
||||
")");
|
||||
@ -3912,15 +3849,15 @@ CORD compile_type_info(env_t *env, type_t *t)
|
||||
return "&Shell$info";
|
||||
else if (streq(text->lang, "Path"))
|
||||
return "&Path$info";
|
||||
return CORD_all("(&", namespace_prefix(text->env, text->env->namespace->parent), text->lang, ")");
|
||||
return CORD_all("(&", namespace_prefix(text->env, text->env->namespace->parent), text->lang, "$$info)");
|
||||
}
|
||||
case StructType: {
|
||||
auto s = Match(t, StructType);
|
||||
return CORD_all("(&", namespace_prefix(s->env, s->env->namespace->parent), s->name, ")");
|
||||
return CORD_all("(&", namespace_prefix(s->env, s->env->namespace->parent), s->name, "$$info)");
|
||||
}
|
||||
case EnumType: {
|
||||
auto e = Match(t, EnumType);
|
||||
return CORD_all("(&", namespace_prefix(e->env, e->env->namespace->parent), e->name, ")");
|
||||
return CORD_all("(&", namespace_prefix(e->env, e->env->namespace->parent), e->name, "$$info)");
|
||||
}
|
||||
case ArrayType: {
|
||||
type_t *item_t = Match(t, ArrayType)->item_type;
|
||||
@ -4295,7 +4232,7 @@ CORD compile_top_level_code(env_t *env, ast_t *ast)
|
||||
}
|
||||
case LangDef: {
|
||||
auto def = Match(ast, LangDef);
|
||||
CORD code = CORD_asprintf("public const TypeInfo_t %r%s = {%zu, %zu, .metamethods=Text$metamethods, .tag=TextInfo, .TextInfo={%r}};\n",
|
||||
CORD code = CORD_asprintf("public const TypeInfo_t %r%s$$info = {%zu, %zu, .metamethods=Text$metamethods, .tag=TextInfo, .TextInfo={%r}};\n",
|
||||
namespace_prefix(env, env->namespace), def->name, sizeof(Text_t), __alignof__(Text_t),
|
||||
CORD_quoted(def->name));
|
||||
env_t *ns_env = namespace_env(env, def->name);
|
||||
@ -4429,9 +4366,9 @@ CORD compile_statement_type_header(env_t *env, ast_t *ast)
|
||||
return CORD_all(
|
||||
// Constructor macro:
|
||||
"#define ", namespace_prefix(env, env->namespace), def->name,
|
||||
"(text) ((", namespace_prefix(env, env->namespace), def->name, "_t){.length=sizeof(text)-1, .tag=TEXT_ASCII, .ascii=\"\" text})\n"
|
||||
"(text) ((", namespace_prefix(env, env->namespace), def->name, "$$type){.length=sizeof(text)-1, .tag=TEXT_ASCII, .ascii=\"\" text})\n"
|
||||
"#define ", namespace_prefix(env, env->namespace), def->name,
|
||||
"s(...) ((", namespace_prefix(env, env->namespace), def->name, "_t)Texts(__VA_ARGS__))\n"
|
||||
"s(...) ((", namespace_prefix(env, env->namespace), def->name, "$$type)Texts(__VA_ARGS__))\n"
|
||||
"extern const TypeInfo_t ", full_name, ";\n"
|
||||
);
|
||||
}
|
||||
@ -4539,19 +4476,19 @@ static void _make_typedefs(compile_typedef_info_t *info, ast_t *ast)
|
||||
if (ast->tag == StructDef) {
|
||||
auto def = Match(ast, StructDef);
|
||||
CORD full_name = CORD_cat(namespace_prefix(info->env, info->env->namespace), def->name);
|
||||
*info->header = CORD_all(*info->header, "typedef struct ", full_name, "_s ", full_name, "_t;\n");
|
||||
*info->header = CORD_all(*info->header, "typedef struct ", full_name, "$$struct ", full_name, "$$type;\n");
|
||||
} else if (ast->tag == EnumDef) {
|
||||
auto def = Match(ast, EnumDef);
|
||||
CORD full_name = CORD_cat(namespace_prefix(info->env, info->env->namespace), def->name);
|
||||
*info->header = CORD_all(*info->header, "typedef struct ", full_name, "_s ", full_name, "_t;\n");
|
||||
*info->header = CORD_all(*info->header, "typedef struct ", full_name, "$$struct ", full_name, "$$type;\n");
|
||||
|
||||
for (tag_ast_t *tag = def->tags; tag; tag = tag->next) {
|
||||
if (!tag->fields) continue;
|
||||
*info->header = CORD_all(*info->header, "typedef struct ", full_name, "$", tag->name, "_s ", full_name, "$", tag->name, "_t;\n");
|
||||
*info->header = CORD_all(*info->header, "typedef struct ", full_name, "$", tag->name, "$$struct ", full_name, "$", tag->name, "$$type;\n");
|
||||
}
|
||||
} else if (ast->tag == LangDef) {
|
||||
auto def = Match(ast, LangDef);
|
||||
*info->header = CORD_all(*info->header, "typedef Text_t ", namespace_prefix(info->env, info->env->namespace), def->name, "_t;\n");
|
||||
*info->header = CORD_all(*info->header, "typedef Text_t ", namespace_prefix(info->env, info->env->namespace), def->name, "$$type;\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
14
enums.c
14
enums.c
@ -34,7 +34,7 @@ CORD compile_enum_typeinfo(env_t *env, ast_t *ast)
|
||||
|
||||
type_t *t = Table$str_get(*env->types, def->name);
|
||||
const char *metamethods = is_packed_data(t) ? "PackedDataEnum$metamethods" : "Enum$metamethods";
|
||||
CORD typeinfo = CORD_asprintf("public const TypeInfo_t %r = {%zu, %zu, .metamethods=%s, {.tag=EnumInfo, .EnumInfo={.name=\"%s\", "
|
||||
CORD typeinfo = CORD_asprintf("public const TypeInfo_t %r$$info = {%zu, %zu, .metamethods=%s, {.tag=EnumInfo, .EnumInfo={.name=\"%s\", "
|
||||
".num_tags=%d, .tags=(NamedType_t[]){",
|
||||
full_name, type_size(t), type_align(t), metamethods, def->name, num_tags);
|
||||
|
||||
@ -66,8 +66,8 @@ CORD compile_enum_constructors(env_t *env, ast_t *ast)
|
||||
if (field->next) arg_sig = CORD_cat(arg_sig, ", ");
|
||||
}
|
||||
if (arg_sig == CORD_EMPTY) arg_sig = "void";
|
||||
CORD constructor_impl = CORD_all("public inline ", full_name, "_t ", full_name, "$tagged$", tag->name, "(", arg_sig, ") { return (",
|
||||
full_name, "_t){.tag=", full_name, "$tag$", tag->name, ", .$", tag->name, "={");
|
||||
CORD constructor_impl = CORD_all("public inline ", full_name, "$$type ", full_name, "$tagged$", tag->name, "(", arg_sig, ") { return (",
|
||||
full_name, "$$type){.tag=", full_name, "$tag$", tag->name, ", .$", tag->name, "={");
|
||||
for (arg_ast_t *field = tag->fields; field; field = field->next) {
|
||||
constructor_impl = CORD_all(constructor_impl, "$", field->name);
|
||||
if (field->next) constructor_impl = CORD_cat(constructor_impl, ", ");
|
||||
@ -83,7 +83,7 @@ CORD compile_enum_header(env_t *env, ast_t *ast)
|
||||
auto def = Match(ast, EnumDef);
|
||||
CORD full_name = CORD_all(namespace_prefix(env, env->namespace), def->name);
|
||||
CORD all_defs = CORD_EMPTY;
|
||||
CORD enum_def = CORD_all("struct ", full_name, "_s {\n"
|
||||
CORD enum_def = CORD_all("struct ", full_name, "$$struct {\n"
|
||||
"\tenum { ", full_name, "$null=0, ");
|
||||
|
||||
bool has_any_tags_with_fields = false;
|
||||
@ -100,14 +100,14 @@ CORD compile_enum_header(env_t *env, ast_t *ast)
|
||||
if (!tag->fields) continue;
|
||||
CORD field_def = compile_struct_header(env, WrapAST(ast, StructDef, .name=CORD_to_const_char_star(CORD_all(def->name, "$", tag->name)), .fields=tag->fields));
|
||||
all_defs = CORD_all(all_defs, field_def);
|
||||
enum_def = CORD_all(enum_def, full_name, "$", tag->name, "_t $", tag->name, ";\n");
|
||||
enum_def = CORD_all(enum_def, full_name, "$", tag->name, "$$type $", tag->name, ";\n");
|
||||
}
|
||||
enum_def = CORD_all(enum_def, "};\n");
|
||||
}
|
||||
enum_def = CORD_all(enum_def, "};\n");
|
||||
all_defs = CORD_all(all_defs, enum_def);
|
||||
|
||||
all_defs = CORD_all(all_defs, "extern const TypeInfo_t ", full_name, ";\n");
|
||||
all_defs = CORD_all(all_defs, "extern const TypeInfo_t ", full_name, "$$info;\n");
|
||||
for (tag_ast_t *tag = def->tags; tag; tag = tag->next) {
|
||||
if (!tag->fields) continue;
|
||||
|
||||
@ -118,7 +118,7 @@ CORD compile_enum_header(env_t *env, ast_t *ast)
|
||||
if (field->next) arg_sig = CORD_all(arg_sig, ", ");
|
||||
}
|
||||
if (arg_sig == CORD_EMPTY) arg_sig = "void";
|
||||
CORD constructor_def = CORD_all(full_name, "_t ", full_name, "$tagged$", tag->name, "(", arg_sig, ");\n");
|
||||
CORD constructor_def = CORD_all(full_name, "$$type ", full_name, "$tagged$", tag->name, "(", arg_sig, ");\n");
|
||||
all_defs = CORD_all(all_defs, constructor_def);
|
||||
}
|
||||
return all_defs;
|
||||
|
129
environment.c
129
environment.c
@ -469,27 +469,114 @@ env_t *new_compilation_unit(CORD libname)
|
||||
}
|
||||
|
||||
// Conversion constructors:
|
||||
#define ADD_CONSTRUCTOR(ns_env, identifier, typestr) Array$insert(&ns_env->namespace->constructors, ((binding_t[1]){{.code=identifier, .type=Match(parse_type_string(ns_env, typestr), ClosureType)->fn}}), I(0), sizeof(binding_t))
|
||||
{
|
||||
env_t *ns_env = namespace_env(env, "Pattern");
|
||||
ADD_CONSTRUCTOR(ns_env, "Pattern$escape_text", "func(text:Text -> Pattern)");
|
||||
ADD_CONSTRUCTOR(ns_env, "Int$value_as_text", "func(i:Int -> Pattern)");
|
||||
}
|
||||
{
|
||||
env_t *ns_env = namespace_env(env, "Path");
|
||||
ADD_CONSTRUCTOR(ns_env, "Path$escape_text", "func(text:Text -> Path)");
|
||||
ADD_CONSTRUCTOR(ns_env, "Path$escape_path", "func(path:Path -> Path)");
|
||||
ADD_CONSTRUCTOR(ns_env, "Int$value_as_text", "func(i:Int -> Path)");
|
||||
}
|
||||
{
|
||||
env_t *ns_env = namespace_env(env, "Shell");
|
||||
ADD_CONSTRUCTOR(ns_env, "Shell$escape_text", "func(text:Text -> Shell)");
|
||||
ADD_CONSTRUCTOR(ns_env, "Shell$escape_text", "func(path:Path -> Shell)");
|
||||
ADD_CONSTRUCTOR(ns_env, "Shell$escape_text_array", "func(texts:[Text] -> Shell)");
|
||||
ADD_CONSTRUCTOR(ns_env, "Shell$escape_text_array", "func(paths:[Path] -> Shell)");
|
||||
ADD_CONSTRUCTOR(ns_env, "Int$value_as_text", "func(i:Int -> Shell)");
|
||||
}
|
||||
#undef ADD_CONSTRUCTOR
|
||||
#define ADD_CONSTRUCTORS(type_name, ...) do {\
|
||||
env_t *ns_env = namespace_env(env, type_name); \
|
||||
struct { const char *c_name, *type_str; } constructor_infos[] = {__VA_ARGS__}; \
|
||||
for (size_t i = 0; i < sizeof(constructor_infos)/sizeof(constructor_infos[0]); i++) { \
|
||||
type_t *t = parse_type_string(ns_env, constructor_infos[i].type_str); \
|
||||
Array$insert(&ns_env->namespace->constructors, \
|
||||
((binding_t[1]){{.code=constructor_infos[i].c_name, \
|
||||
.type=Match(t, ClosureType)->fn}}), I(0), sizeof(binding_t)); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
ADD_CONSTRUCTORS("Bool",
|
||||
{"Bool$from_byte", "func(b:Byte -> Bool)"},
|
||||
{"Bool$from_int8", "func(i:Int8 -> Bool)"},
|
||||
{"Bool$from_int16", "func(i:Int16 -> Bool)"},
|
||||
{"Bool$from_int32", "func(i:Int32 -> Bool)"},
|
||||
{"Bool$from_int64", "func(i:Int64 -> Bool)"},
|
||||
{"Bool$from_int", "func(i:Int -> Bool)"});
|
||||
ADD_CONSTRUCTORS("Byte",
|
||||
{"Byte$from_bool", "func(b:Bool -> Byte)"},
|
||||
{"Byte$from_int8", "func(i:Int8 -> Byte)"},
|
||||
{"Byte$from_int16", "func(i:Int16, truncate=no -> Byte)"},
|
||||
{"Byte$from_int32", "func(i:Int32, truncate=no -> Byte)"},
|
||||
{"Byte$from_int64", "func(i:Int64, truncate=no -> Byte)"},
|
||||
{"Byte$from_int", "func(i:Int, truncate=no -> Byte)"});
|
||||
ADD_CONSTRUCTORS("Int",
|
||||
{"Int$from_bool", "func(b:Bool -> Int)"},
|
||||
{"Int$from_byte", "func(b:Byte -> Int)"},
|
||||
{"Int$from_int8", "func(i:Int8 -> Int)"},
|
||||
{"Int$from_int16", "func(i:Int16 -> Int)"},
|
||||
{"Int$from_int32", "func(i:Int32 -> Int)"},
|
||||
{"Int$from_int64", "func(i:Int64 -> Int)"},
|
||||
{"Int$from_num", "func(n:Num, truncate=no -> Int)"},
|
||||
{"Int$from_num32", "func(n:Num32, truncate=no -> Int)"});
|
||||
ADD_CONSTRUCTORS("Int64",
|
||||
{"Int64$from_bool", "func(b:Bool -> Int64)"},
|
||||
{"Int64$from_byte", "func(b:Byte -> Int64)"},
|
||||
{"Int64$from_int8", "func(i:Int8 -> Int64)"},
|
||||
{"Int64$from_int16", "func(i:Int16 -> Int64)"},
|
||||
{"Int64$from_int32", "func(i:Int32 -> Int64)"},
|
||||
{"Int64$from_int", "func(i:Int, truncate=no -> Int64)"},
|
||||
{"Int64$from_num", "func(n:Num, truncate=no -> Int64)"},
|
||||
{"Int64$from_num32", "func(n:Num32, truncate=no -> Int64)"});
|
||||
ADD_CONSTRUCTORS("Int32",
|
||||
{"Int32$from_bool", "func(b:Bool -> Int32)"},
|
||||
{"Int32$from_byte", "func(b:Byte -> Int32)"},
|
||||
{"Int32$from_int8", "func(i:Int8 -> Int32)"},
|
||||
{"Int32$from_int16", "func(i:Int16 -> Int32)"},
|
||||
{"Int32$from_int64", "func(i:Int64, truncate=no -> Int32)"},
|
||||
{"Int32$from_int", "func(i:Int, truncate=no -> Int32)"},
|
||||
{"Int32$from_num", "func(n:Num, truncate=no -> Int32)"},
|
||||
{"Int32$from_num32", "func(n:Num32, truncate=no -> Int32)"});
|
||||
ADD_CONSTRUCTORS("Int16",
|
||||
{"Int16$from_bool", "func(b:Bool -> Int16)"},
|
||||
{"Int16$from_byte", "func(b:Byte -> Int16)"},
|
||||
{"Int16$from_int8", "func(i:Int8 -> Int16)"},
|
||||
{"Int16$from_int32", "func(i:Int32, truncate=no -> Int16)"},
|
||||
{"Int16$from_int64", "func(i:Int64, truncate=no -> Int16)"},
|
||||
{"Int16$from_int", "func(i:Int, truncate=no -> Int16)"},
|
||||
{"Int16$from_num", "func(n:Num, truncate=no -> Int16)"},
|
||||
{"Int16$from_num32", "func(n:Num32, truncate=no -> Int16)"});
|
||||
ADD_CONSTRUCTORS("Int8",
|
||||
{"Int8$from_bool", "func(b:Bool -> Int8)"},
|
||||
{"Int8$from_byte", "func(b:Byte -> Int8)"},
|
||||
{"Int8$from_int16", "func(i:Int16, truncate=no -> Int8)"},
|
||||
{"Int8$from_int32", "func(i:Int32, truncate=no -> Int8)"},
|
||||
{"Int8$from_int64", "func(i:Int64, truncate=no -> Int8)"},
|
||||
{"Int8$from_int", "func(i:Int, truncate=no -> Int8)"},
|
||||
{"Int8$from_num", "func(n:Num, truncate=no -> Int8)"},
|
||||
{"Int8$from_num32", "func(n:Num32, truncate=no -> Int8)"});
|
||||
ADD_CONSTRUCTORS("Num",
|
||||
{"Num$from_bool", "func(b:Bool -> Num)"},
|
||||
{"Num$from_byte", "func(b:Byte -> Num)"},
|
||||
{"Num$from_int8", "func(i:Int8 -> Num)"},
|
||||
{"Num$from_int16", "func(i:Int16 -> Num)"},
|
||||
{"Num$from_int32", "func(i:Int32 -> Num)"},
|
||||
{"Num$from_int64", "func(i:Int64, truncate=no -> Num)"},
|
||||
{"Num$from_int", "func(i:Int, truncate=no -> Num)"},
|
||||
{"Num$from_num32", "func(n:Num32 -> Num)"});
|
||||
ADD_CONSTRUCTORS("Num32",
|
||||
{"Num32$from_bool", "func(b:Bool -> Num32)"},
|
||||
{"Num32$from_byte", "func(b:Byte -> Num32)"},
|
||||
{"Num32$from_int8", "func(i:Int8 -> Num32)"},
|
||||
{"Num32$from_int16", "func(i:Int16 -> Num32)"},
|
||||
{"Num32$from_int32", "func(i:Int32, truncate=no -> Num32)"},
|
||||
{"Num32$from_int64", "func(i:Int64, truncate=no -> Num32)"},
|
||||
{"Num32$from_int", "func(i:Int, truncate=no -> Num32)"},
|
||||
{"Num32$from_num", "func(n:Num -> Num32)"});
|
||||
ADD_CONSTRUCTORS("Pattern",
|
||||
{"Pattern$escape_text", "func(text:Text -> Pattern)"},
|
||||
{"Int$value_as_text", "func(i:Int -> Pattern)"});
|
||||
ADD_CONSTRUCTORS("Path",
|
||||
{"Path$escape_text", "func(text:Text -> Path)"},
|
||||
{"Path$escape_path", "func(path:Path -> Path)"},
|
||||
{"Int$value_as_text", "func(i:Int -> Path)"});
|
||||
ADD_CONSTRUCTORS("Shell",
|
||||
{"Shell$escape_text", "func(text:Text -> Shell)"},
|
||||
{"Shell$escape_text", "func(path:Path -> Shell)"},
|
||||
{"Shell$escape_text_array", "func(texts:[Text] -> Shell)"},
|
||||
{"Shell$escape_text_array", "func(paths:[Path] -> Shell)"},
|
||||
{"Int$value_as_text", "func(i:Int -> Shell)"});
|
||||
ADD_CONSTRUCTORS("Moment",
|
||||
{"Moment$now", "func(-> Moment)"},
|
||||
{"Moment$new", "func(year,month,day:Int,hour,minute=0,second=0.0,timezone=none:Text -> Moment)"},
|
||||
{"Moment$from_unix_timestamp", "func(timestamp:Int64 -> Moment)"});
|
||||
ADD_CONSTRUCTORS("RNG", {"RNG$new", "func(-> RNG)"});
|
||||
ADD_CONSTRUCTORS("Thread", {"Thread$new", "func(fn:func() -> Thread)"});
|
||||
#undef ADD_CONSTRUCTORS
|
||||
|
||||
set_binding(namespace_env(env, "Shell"), "without_escaping",
|
||||
Type(FunctionType, .args=new(arg_t, .name="text", .type=TEXT_TYPE),
|
||||
|
@ -83,11 +83,13 @@ struct IVec2(x,y:Int):
|
||||
func divided_by(v:IVec2, divisor:Int->IVec2; inline):
|
||||
return IVec2(v.x/divisor, v.y/divisor)
|
||||
func length(v:IVec2->Num; inline):
|
||||
return Num.sqrt(v.x*v.x + v.y*v.y)
|
||||
x := Num(v.x)
|
||||
y := Num(v.y)
|
||||
return Num.sqrt(x*x + y*y)
|
||||
func dist(a,b:IVec2->Num; inline):
|
||||
return a:minus(b):length()
|
||||
func angle(v:IVec2->Num; inline):
|
||||
return Num.atan2(v.y, v.x)
|
||||
return Num.atan2(Num(v.y), Num(v.x))
|
||||
|
||||
struct IVec3(x,y,z:Int):
|
||||
ZERO := IVec3(0, 0, 0)
|
||||
@ -106,7 +108,10 @@ struct IVec3(x,y,z:Int):
|
||||
func divided_by(v:IVec3, divisor:Int->IVec3; inline):
|
||||
return IVec3(v.x/divisor, v.y/divisor, v.z/divisor)
|
||||
func length(v:IVec3->Num; inline):
|
||||
return Num.sqrt(v.x*v.x + v.y*v.y + v.z*v.z)
|
||||
x := Num(v.x)
|
||||
y := Num(v.y)
|
||||
z := Num(v.z)
|
||||
return Num.sqrt(x*x + y*y + z*z)
|
||||
func dist(a,b:IVec3->Num; inline):
|
||||
return a:minus(b):length()
|
||||
|
||||
|
28
repl.c
28
repl.c
@ -177,10 +177,10 @@ static Int_t ast_to_int(env_t *env, ast_t *ast)
|
||||
number_t num;
|
||||
eval(env, ast, &num);
|
||||
switch (Match(t, IntType)->bits) {
|
||||
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);
|
||||
case TYPE_IBITS64: return Int$from_int64((int64_t)num.i64);
|
||||
case TYPE_IBITS32: return Int$from_int32(num.i32);
|
||||
case TYPE_IBITS16: return Int$from_int16(num.i16);
|
||||
case TYPE_IBITS8: return Int$from_int8(num.i8);
|
||||
default: errx(1, "Invalid int bits");
|
||||
}
|
||||
}
|
||||
@ -196,12 +196,12 @@ static double ast_to_num(env_t *env, ast_t *ast)
|
||||
number_t num;
|
||||
eval(env, ast, &num);
|
||||
if (t->tag == BigIntType)
|
||||
return Int_to_Num(num.integer);
|
||||
return Num$from_int(num.integer, false);
|
||||
switch (Match(t, IntType)->bits) {
|
||||
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;
|
||||
case TYPE_IBITS64: return Num$from_int64(num.i64, false);
|
||||
case TYPE_IBITS32: return Num$from_int32(num.i32);
|
||||
case TYPE_IBITS16: return Num$from_int16(num.i16);
|
||||
case TYPE_IBITS8: return Num$from_int8(num.i8);
|
||||
default: errx(1, "Invalid int bits");
|
||||
}
|
||||
}
|
||||
@ -401,10 +401,10 @@ void eval(env_t *env, ast_t *ast, void *dest)
|
||||
return; \
|
||||
} \
|
||||
switch (Match(t, IntType)->bits) { \
|
||||
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; \
|
||||
case 8: *(int8_t*)dest = Int_to_Int8(result, false); return; \
|
||||
case 64: *(int64_t*)dest = Int64$from_int(result, false); return; \
|
||||
case 32: *(int32_t*)dest = Int32$from_int(result, false); return; \
|
||||
case 16: *(int16_t*)dest = Int16$from_int(result, false); return; \
|
||||
case 8: *(int8_t*)dest = Int8$from_int(result, false); return; \
|
||||
default: errx(1, "Invalid int bits"); \
|
||||
} \
|
||||
break; \
|
||||
@ -467,7 +467,7 @@ void eval(env_t *env, ast_t *ast, void *dest)
|
||||
case ArrayType: {
|
||||
Array_t arr;
|
||||
eval(env, index->indexed, &arr);
|
||||
int64_t raw_index = Int_to_Int64(ast_to_int(env, index->index), false);
|
||||
int64_t raw_index = Int64$from_int(ast_to_int(env, index->index), false);
|
||||
int64_t index_int = raw_index;
|
||||
if (index_int < 1) index_int = arr.length + index_int + 1;
|
||||
if (index_int < 1 || index_int > arr.length)
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include "arrays.h"
|
||||
#include "integers.h"
|
||||
#include "math.h"
|
||||
#include "metamethods.h"
|
||||
#include "optionals.h"
|
||||
#include "rng.h"
|
||||
@ -51,7 +52,7 @@ public void Array$compact(Array_t *arr, int64_t padded_item_size)
|
||||
|
||||
public void Array$insert(Array_t *arr, const void *item, Int_t int_index, int64_t padded_item_size)
|
||||
{
|
||||
int64_t index = Int_to_Int64(int_index, false);
|
||||
int64_t index = Int64$from_int(int_index, false);
|
||||
if (index <= 0) index = arr->length + index + 1;
|
||||
|
||||
if (index < 1) index = 1;
|
||||
@ -90,7 +91,7 @@ public void Array$insert(Array_t *arr, const void *item, Int_t int_index, int64_
|
||||
|
||||
public void Array$insert_all(Array_t *arr, Array_t to_insert, Int_t int_index, int64_t padded_item_size)
|
||||
{
|
||||
int64_t index = Int_to_Int64(int_index, false);
|
||||
int64_t index = Int64$from_int(int_index, false);
|
||||
if (to_insert.length == 0)
|
||||
return;
|
||||
|
||||
@ -163,10 +164,10 @@ public void Array$insert_all(Array_t *arr, Array_t to_insert, Int_t int_index, i
|
||||
|
||||
public void Array$remove_at(Array_t *arr, Int_t int_index, Int_t int_count, int64_t padded_item_size)
|
||||
{
|
||||
int64_t index = Int_to_Int64(int_index, false);
|
||||
int64_t index = Int64$from_int(int_index, false);
|
||||
if (index < 1) index = arr->length + index + 1;
|
||||
|
||||
int64_t count = Int_to_Int64(int_count, false);
|
||||
int64_t count = Int64$from_int(int_count, false);
|
||||
if (index < 1 || index > (int64_t)arr->length || count < 1) return;
|
||||
|
||||
if (count > arr->length - index + 1)
|
||||
@ -297,7 +298,7 @@ public Table_t Array$counts(Array_t arr, const TypeInfo_t *type)
|
||||
|
||||
public Array_t Array$sample(Array_t arr, Int_t int_n, Array_t weights, RNG_t rng, int64_t padded_item_size)
|
||||
{
|
||||
int64_t n = Int_to_Int64(int_n, false);
|
||||
int64_t n = Int64$from_int(int_n, false);
|
||||
if (n < 0)
|
||||
fail("Cannot select a negative number of values");
|
||||
|
||||
@ -399,7 +400,7 @@ public Array_t Array$to(Array_t array, Int_t last)
|
||||
|
||||
public Array_t Array$by(Array_t array, Int_t int_stride, int64_t padded_item_size)
|
||||
{
|
||||
int64_t stride = Int_to_Int64(int_stride, false);
|
||||
int64_t stride = Int64$from_int(int_stride, false);
|
||||
// In the unlikely event that the stride value would be too large to fit in
|
||||
// a 15-bit integer, fall back to creating a copy of the array:
|
||||
if (unlikely(array.stride*stride < ARRAY_MIN_STRIDE || array.stride*stride > ARRAY_MAX_STRIDE)) {
|
||||
@ -434,11 +435,11 @@ public Array_t Array$by(Array_t array, Int_t int_stride, int64_t padded_item_siz
|
||||
public Array_t Array$slice(Array_t array, Int_t int_first, Int_t int_last)
|
||||
|
||||
{
|
||||
int64_t first = Int_to_Int64(int_first, false);
|
||||
int64_t first = Int64$from_int(int_first, false);
|
||||
if (first < 0)
|
||||
first = array.length + first + 1;
|
||||
|
||||
int64_t last = Int_to_Int64(int_last, false);
|
||||
int64_t last = Int64$from_int(int_last, false);
|
||||
if (last < 0)
|
||||
last = array.length + last + 1;
|
||||
|
||||
|
@ -69,7 +69,7 @@ void Array$remove_item(Array_t *arr, void *item, Int_t max_removals, const TypeI
|
||||
#define Array$pop(arr_expr, index_expr, item_type, nonnone_var, nonnone_expr, none_expr, padded_item_size) ({ \
|
||||
Array_t *arr = arr_expr; \
|
||||
Int_t index = index_expr; \
|
||||
int64_t index64 = Int_to_Int64(index, false); \
|
||||
int64_t index64 = Int64$from_int(index, false); \
|
||||
int64_t off = index64 + (index64 < 0) * (arr->length + 1) - 1; \
|
||||
(off >= 0 && off < arr->length) ? ({ \
|
||||
item_type nonnone_var = *(item_type*)(arr->data + off*arr->stride); \
|
||||
|
@ -9,12 +9,17 @@
|
||||
#include "optionals.h"
|
||||
#include "util.h"
|
||||
|
||||
#define Bool_t bool
|
||||
#define yes (Bool_t)true
|
||||
#define no (Bool_t)false
|
||||
|
||||
PUREFUNC Text_t Bool$as_text(const void *b, bool colorize, const TypeInfo_t *type);
|
||||
OptionalBool_t Bool$parse(Text_t text);
|
||||
MACROLIKE Bool_t Bool$from_int(Int_t i) { return (i.small != 0); }
|
||||
MACROLIKE Bool_t Bool$from_int64(Int64_t i) { return (i != 0); }
|
||||
MACROLIKE Bool_t Bool$from_int32(Int32_t i) { return (i != 0); }
|
||||
MACROLIKE Bool_t Bool$from_int16(Int16_t i) { return (i != 0); }
|
||||
MACROLIKE Bool_t Bool$from_int8(Int8_t i) { return (i != 0); }
|
||||
MACROLIKE Bool_t Bool$from_byte(uint8_t b) { return (b != 0); }
|
||||
|
||||
extern const TypeInfo_t Bool$info;
|
||||
|
||||
|
@ -30,6 +30,29 @@ public Text_t Byte$hex(Byte_t byte, bool uppercase, bool prefix) {
|
||||
return text;
|
||||
}
|
||||
|
||||
public PUREFUNC Byte_t Byte$from_int(Int_t i, bool truncate) {
|
||||
if unlikely (truncate && Int$compare_value(i, I_small(0xFF)) > 0)
|
||||
fail("This value is too large to convert to a byte without truncation: %k", (Text_t[1]){Int$value_as_text(i)});
|
||||
else if unlikely (truncate && Int$compare_value(i, I_small(0)) < 0)
|
||||
fail("Negative values can't be converted to bytes: %k", (Text_t[1]){Int$value_as_text(i)});
|
||||
return (i.small != 0);
|
||||
}
|
||||
public PUREFUNC Byte_t Byte$from_int64(Int64_t i, bool truncate) {
|
||||
if unlikely (truncate && i != (Int64_t)(Byte_t)i)
|
||||
fail("This value can't be converted to a byte without truncation: %ld", i);
|
||||
return (Byte_t)i;
|
||||
}
|
||||
public PUREFUNC Byte_t Byte$from_int32(Int32_t i, bool truncate) {
|
||||
if unlikely (truncate && i != (Int32_t)(Byte_t)i)
|
||||
fail("This value can't be converted to a byte without truncation: %d", i);
|
||||
return (Byte_t)i;
|
||||
}
|
||||
public PUREFUNC Byte_t Byte$from_int16(Int16_t i, bool truncate) {
|
||||
if unlikely (truncate && i != (Int16_t)(Byte_t)i)
|
||||
fail("This value can't be converted to a byte without truncation: %d", i);
|
||||
return (Byte_t)i;
|
||||
}
|
||||
|
||||
public const TypeInfo_t Byte$info = {
|
||||
.size=sizeof(Byte_t),
|
||||
.align=__alignof__(Byte_t),
|
||||
|
@ -5,23 +5,21 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "datatypes.h"
|
||||
#include "stdlib.h"
|
||||
#include "types.h"
|
||||
#include "util.h"
|
||||
|
||||
#define Byte_t uint8_t
|
||||
#define Byte(b) ((Byte_t)(b))
|
||||
|
||||
PUREFUNC Text_t Byte$as_text(const void *b, bool colorize, const TypeInfo_t *type);
|
||||
|
||||
#define Byte_to_Int64(b, _) ((Int64_t)(b))
|
||||
#define Byte_to_Int32(b, _) ((Int32_t)(b))
|
||||
#define Byte_to_Int16(b, _) ((Int16_t)(b))
|
||||
#define Byte_to_Int8(b, _) ((Int8_t)(b))
|
||||
|
||||
#define Int64_to_Byte(b, _) ((Byte_t)(b))
|
||||
#define Int32_to_Byte(b, _) ((Byte_t)(b))
|
||||
#define Int16_to_Byte(b, _) ((Byte_t)(b))
|
||||
#define Int8_to_Byte(b, _) ((Byte_t)(b))
|
||||
Byte_t Byte$from_int(Int_t i, bool truncate);
|
||||
Byte_t Byte$from_int64(int64_t i, bool truncate);
|
||||
Byte_t Byte$from_int32(int32_t i, bool truncate);
|
||||
Byte_t Byte$from_int16(int16_t i, bool truncate);
|
||||
MACROLIKE Byte_t Byte$from_int8(int8_t i) { return (Byte_t)i; }
|
||||
MACROLIKE Byte_t Byte$from_bool(bool b) { return (Byte_t)b; }
|
||||
|
||||
extern const Byte_t Byte$min;
|
||||
extern const Byte_t Byte$max;
|
||||
|
@ -19,6 +19,16 @@
|
||||
#define ARRAY_MAX_DATA_REFCOUNT MAX_FOR_N_BITS(ARRAY_REFCOUNT_BITS)
|
||||
#define ARRAY_MAX_FREE_ENTRIES MAX_FOR_N_BITS(ARRAY_FREE_BITS)
|
||||
|
||||
#define Num_t double
|
||||
#define Num32_t float
|
||||
|
||||
#define Int64_t int64_t
|
||||
#define Int32_t int32_t
|
||||
#define Int16_t int16_t
|
||||
#define Int8_t int8_t
|
||||
#define Byte_t uint8_t
|
||||
#define Bool_t bool
|
||||
|
||||
typedef union {
|
||||
int64_t small;
|
||||
mpz_t *big;
|
||||
|
@ -74,7 +74,7 @@ public PUREFUNC uint64_t Int$hash(const void *vx, const TypeInfo_t*) {
|
||||
}
|
||||
|
||||
public Text_t Int$format(Int_t i, Int_t digits_int) {
|
||||
int64_t digits = Int_to_Int64(digits_int, false);
|
||||
int64_t digits = Int64$from_int(digits_int, false);
|
||||
if (likely(i.small & 1)) {
|
||||
return Text$format("%0.*ld", digits, (i.small)>>2);
|
||||
} else {
|
||||
@ -97,7 +97,7 @@ public Text_t Int$hex(Int_t i, Int_t digits_int, bool uppercase, bool prefix) {
|
||||
if (Int$is_negative(i))
|
||||
return Text$concat(Text("-"), Int$hex(Int$negative(i), digits_int, uppercase, prefix));
|
||||
|
||||
int64_t digits = Int_to_Int64(digits_int, false);
|
||||
int64_t digits = Int64$from_int(digits_int, false);
|
||||
if (likely(i.small & 1)) {
|
||||
const char *hex_fmt = uppercase ? (prefix ? "0x%0.*lX" : "%0.*lX") : (prefix ? "0x%0.*lx" : "%0.*lx");
|
||||
return Text$format(hex_fmt, digits, (i.small)>>2);
|
||||
@ -124,7 +124,7 @@ public Text_t Int$octal(Int_t i, Int_t digits_int, bool prefix) {
|
||||
if (Int$is_negative(i))
|
||||
return Text$concat(Text("-"), Int$octal(Int$negative(i), digits_int, prefix));
|
||||
|
||||
int64_t digits = Int_to_Int64(digits_int, false);
|
||||
int64_t digits = Int64$from_int(digits_int, false);
|
||||
if (likely(i.small & 1)) {
|
||||
const char *octal_fmt = prefix ? "0o%0.*lo" : "%0.*lo";
|
||||
return Text$format(octal_fmt, digits, (i.small)>>2);
|
||||
@ -221,7 +221,7 @@ public Int_t Int$slow_modulo1(Int_t x, Int_t modulus)
|
||||
|
||||
public Int_t Int$slow_left_shifted(Int_t x, Int_t y)
|
||||
{
|
||||
mp_bitcnt_t bits = (mp_bitcnt_t)Int_to_Int64(y, false);
|
||||
mp_bitcnt_t bits = (mp_bitcnt_t)Int64$from_int(y, false);
|
||||
mpz_t result;
|
||||
mpz_init_set_int(result, x);
|
||||
mpz_mul_2exp(result, result, bits);
|
||||
@ -230,7 +230,7 @@ public Int_t Int$slow_left_shifted(Int_t x, Int_t y)
|
||||
|
||||
public Int_t Int$slow_right_shifted(Int_t x, Int_t y)
|
||||
{
|
||||
mp_bitcnt_t bits = (mp_bitcnt_t)Int_to_Int64(y, false);
|
||||
mp_bitcnt_t bits = (mp_bitcnt_t)Int64$from_int(y, false);
|
||||
mpz_t result;
|
||||
mpz_init_set_int(result, x);
|
||||
mpz_tdiv_q_2exp(result, result, bits);
|
||||
@ -300,7 +300,7 @@ public Int_t Int$abs(Int_t x)
|
||||
|
||||
public Int_t Int$power(Int_t base, Int_t exponent)
|
||||
{
|
||||
int64_t exp = Int_to_Int64(exponent, false);
|
||||
int64_t exp = Int64$from_int(exponent, false);
|
||||
if (unlikely(exp < 0))
|
||||
fail("Cannot take a negative power of an integer!");
|
||||
mpz_t result;
|
||||
@ -397,7 +397,7 @@ public bool Int$is_prime(Int_t x, Int_t reps)
|
||||
mpz_init_set_int(p, x);
|
||||
if (unlikely(Int$compare_value(reps, I(9999)) > 0))
|
||||
fail("Number of prime-test repetitions should not be above 9999");
|
||||
int reps_int = Int_to_Int32(reps, false);
|
||||
int reps_int = Int32$from_int(reps, false);
|
||||
return (mpz_probab_prime_p(p, reps_int) != 0);
|
||||
}
|
||||
|
||||
@ -426,7 +426,7 @@ public Int_t Int$choose(Int_t n, Int_t k)
|
||||
mpz_t ret;
|
||||
mpz_init(ret);
|
||||
|
||||
int64_t k_i64 = Int_to_Int64(k, false);
|
||||
int64_t k_i64 = Int64$from_int(k, false);
|
||||
if unlikely (k_i64 < 0)
|
||||
fail("Negative inputs are not supported for choose()");
|
||||
|
||||
@ -444,7 +444,7 @@ public Int_t Int$factorial(Int_t n)
|
||||
{
|
||||
mpz_t ret;
|
||||
mpz_init(ret);
|
||||
int64_t n_i64 = Int_to_Int64(n, false);
|
||||
int64_t n_i64 = Int64$from_int(n, false);
|
||||
if unlikely (n_i64 < 0)
|
||||
fail("Factorials are not defined for negative numbers");
|
||||
mpz_fac_ui(ret, (unsigned long)n_i64);
|
||||
@ -556,15 +556,14 @@ public void Int32$deserialize(FILE *in, void *outval, Array_t*, const TypeInfo_t
|
||||
return *(c_type*)x == *(c_type*)y; \
|
||||
} \
|
||||
public Text_t KindOfInt ## $format(c_type i, Int_t digits_int) { \
|
||||
Int_t as_int = KindOfInt##_to_Int(i); \
|
||||
return Int$format(as_int, digits_int); \
|
||||
return Text$format("%0*ld", Int32$from_int(digits_int, false), i); \
|
||||
} \
|
||||
public Text_t KindOfInt ## $hex(c_type i, Int_t digits_int, bool uppercase, bool prefix) { \
|
||||
Int_t as_int = KindOfInt##_to_Int(i); \
|
||||
Int_t as_int = Int$from_int64((int64_t)i); \
|
||||
return Int$hex(as_int, digits_int, uppercase, prefix); \
|
||||
} \
|
||||
public Text_t KindOfInt ## $octal(c_type i, Int_t digits_int, bool prefix) { \
|
||||
Int_t as_int = KindOfInt##_to_Int(i); \
|
||||
Int_t as_int = Int$from_int64((int64_t)i); \
|
||||
return Int$octal(as_int, digits_int, prefix); \
|
||||
} \
|
||||
public Array_t KindOfInt ## $bits(c_type x) { \
|
||||
@ -615,7 +614,7 @@ public void Int32$deserialize(FILE *in, void *outval, Array_t*, const TypeInfo_t
|
||||
if (Int$compare_value(full_int, I(max_val)) > 0) { \
|
||||
return (Optional ## KindOfInt ## _t){.is_none=true}; \
|
||||
} \
|
||||
return (Optional ## KindOfInt ## _t){.i=Int_to_ ## KindOfInt(full_int, true)}; \
|
||||
return (Optional ## KindOfInt ## _t){.i=KindOfInt##$from_int(full_int, true)}; \
|
||||
} \
|
||||
public CONSTFUNC c_type KindOfInt ## $gcd(c_type x, c_type y) { \
|
||||
if (x == 0 || y == 0) return 0; \
|
||||
|
@ -8,15 +8,10 @@
|
||||
#include <gmp.h>
|
||||
|
||||
#include "datatypes.h"
|
||||
#include "nums.h"
|
||||
#include "stdlib.h"
|
||||
#include "types.h"
|
||||
#include "util.h"
|
||||
|
||||
#define Int64_t int64_t
|
||||
#define Int32_t int32_t
|
||||
#define Int16_t int16_t
|
||||
#define Int8_t int8_t
|
||||
#define I64(x) ((int64_t)x)
|
||||
#define I32(x) ((int32_t)x)
|
||||
#define I16(x) ((int16_t)x)
|
||||
@ -40,6 +35,8 @@
|
||||
MACROLIKE PUREFUNC c_type type_name ## $clamped(c_type x, c_type min, c_type max) { \
|
||||
return x < min ? min : (x > max ? max : x); \
|
||||
} \
|
||||
MACROLIKE CONSTFUNC c_type type_name ## $from_byte(Byte_t b) { return (c_type)b; } \
|
||||
MACROLIKE CONSTFUNC c_type type_name ## $from_bool(Bool_t b) { return (c_type)b; } \
|
||||
CONSTFUNC c_type type_name ## $gcd(c_type x, c_type y); \
|
||||
extern const c_type type_name ## $min, type_name##$max; \
|
||||
extern const TypeInfo_t type_name ## $info; \
|
||||
@ -126,8 +123,8 @@ OptionalInt_t Int$sqrt(Int_t i);
|
||||
else mpz_init_set(mpz, *(i).big); \
|
||||
} while (0)
|
||||
|
||||
#define I(i) ((i) >= SMALLEST_SMALL_INT && (i) <= BIGGEST_SMALL_INT ? ((Int_t){.small=(int64_t)((uint64_t)(i)<<2)|1}) : Int64_to_Int(i))
|
||||
#define I_small(i) ((Int_t){.small=(int64_t)((uint64_t)(i)<<2)|1})
|
||||
#define I(i) _Generic(i, int8_t: I_small(i), int16_t: I_small(i), default: Int$from_int64(i))
|
||||
#define I_is_zero(i) ((i).small == 1)
|
||||
|
||||
Int_t Int$slow_plus(Int_t x, Int_t y);
|
||||
@ -273,113 +270,104 @@ MACROLIKE PUREFUNC bool Int$is_negative(Int_t x) {
|
||||
return Int$compare_value(x, I_small(0)) < 0;
|
||||
}
|
||||
|
||||
// Conversion functions:
|
||||
// Constructors/conversion functions:
|
||||
|
||||
MACROLIKE Int_t Int64_to_Int(int64_t i)
|
||||
{
|
||||
// Int constructors:
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wfloat-equal"
|
||||
MACROLIKE PUREFUNC Int_t Int$from_num(double n, bool truncate) {
|
||||
mpz_t result;
|
||||
mpz_init_set_d(result, n);
|
||||
if unlikely (!truncate && mpz_get_d(result) != n)
|
||||
fail("Could not convert to an integer without truncation: %g", n);
|
||||
return Int$from_mpz(result);
|
||||
}
|
||||
#pragma GCC diagnostic pop
|
||||
MACROLIKE PUREFUNC Int_t Int$from_num32(float n, bool truncate) { return Int$from_num((double)n, truncate); }
|
||||
MACROLIKE Int_t Int$from_int64(int64_t i) {
|
||||
if likely (i >= SMALLEST_SMALL_INT && i <= BIGGEST_SMALL_INT)
|
||||
return (Int_t){.small=(i<<2)|1};
|
||||
mpz_t result;
|
||||
mpz_init_set_si(result, i);
|
||||
return Int$from_mpz(result);
|
||||
}
|
||||
MACROLIKE CONSTFUNC Int_t Int$from_int32(Int32_t i) { return Int$from_int64((Int32_t)i); }
|
||||
MACROLIKE CONSTFUNC Int_t Int$from_int16(Int16_t i) { return I_small(i); }
|
||||
MACROLIKE CONSTFUNC Int_t Int$from_int8(Int8_t i) { return I_small(i); }
|
||||
MACROLIKE CONSTFUNC Int_t Int$from_byte(Byte_t b) { return I_small(b); }
|
||||
MACROLIKE CONSTFUNC Int_t Int$from_bool(Bool_t b) { return I_small(b); }
|
||||
|
||||
#define Int32_to_Int(i, ...) Int64_to_Int(i)
|
||||
#define Int16_to_Int(i, ...) Int64_to_Int(i)
|
||||
#define Int8_to_Int(i, ...) Int64_to_Int(i)
|
||||
#define Int32_to_Int64(i, ...) (Int64_t)(i)
|
||||
#define Int16_to_Int64(i, ...) (Int64_t)(i)
|
||||
#define Int8_to_Int64(i, ...) (Int64_t)(i)
|
||||
#define Int16_to_Int32(i, ...) (Int32_t)(i)
|
||||
#define Int8_to_Int32(i, ...) (Int32_t)(i)
|
||||
#define Int8_to_Int16(i, ...) (Int16_t)(i)
|
||||
|
||||
MACROLIKE PUREFUNC Int64_t Int_to_Int64(Int_t i, bool truncate) {
|
||||
// Int64 constructors
|
||||
MACROLIKE PUREFUNC Int64_t Int64$from_int(Int_t i, bool truncate) {
|
||||
if likely (i.small & 1)
|
||||
return (int64_t)(i.small >> 2);
|
||||
if (!truncate && unlikely(!mpz_fits_slong_p(*i.big)))
|
||||
fail("Integer is too big to fit in a 64-bit integer!");
|
||||
fail("Integer is too big to fit in a 64-bit integer: %k", (Text_t[1]){Int$value_as_text(i)});
|
||||
return mpz_get_si(*i.big);
|
||||
}
|
||||
MACROLIKE CONSTFUNC Int64_t Int64$from_int32(Int32_t i) { return (Int64_t)i; }
|
||||
MACROLIKE CONSTFUNC Int64_t Int64$from_int16(Int16_t i) { return (Int64_t)i; }
|
||||
MACROLIKE CONSTFUNC Int64_t Int64$from_int8(Int8_t i) { return (Int64_t)i; }
|
||||
|
||||
MACROLIKE PUREFUNC Int32_t Int_to_Int32(Int_t i, bool truncate) {
|
||||
int64_t i64 = Int_to_Int64(i, truncate);
|
||||
// Int32 constructors
|
||||
MACROLIKE PUREFUNC Int32_t Int32$from_int(Int_t i, bool truncate) {
|
||||
int64_t i64 = Int64$from_int(i, truncate);
|
||||
int32_t i32 = (int32_t)i64;
|
||||
if (!truncate && unlikely(i64 != i32))
|
||||
fail("Integer is too big to fit in a 32-bit integer!");
|
||||
fail("Integer is too big to fit in a 32-bit integer: %k", (Text_t[1]){Int$value_as_text(i)});
|
||||
return i32;
|
||||
}
|
||||
MACROLIKE PUREFUNC Int32_t Int32$from_int64(Int64_t i, bool truncate) {
|
||||
if (!truncate && unlikely(i != (Int64_t)(Int32_t)i))
|
||||
fail("Integer is too big to fit in a 32-bit integer: %ld", i);
|
||||
return (Int32_t)i;
|
||||
}
|
||||
MACROLIKE CONSTFUNC Int32_t Int32$from_int16(Int16_t i) { return (Int32_t)i; }
|
||||
MACROLIKE CONSTFUNC Int32_t Int32$from_int8(Int8_t i) { return (Int32_t)i; }
|
||||
|
||||
MACROLIKE PUREFUNC Int16_t Int_to_Int16(Int_t i, bool truncate) {
|
||||
int64_t i64 = Int_to_Int64(i, truncate);
|
||||
// Int16 constructors
|
||||
MACROLIKE PUREFUNC Int16_t Int16$from_int(Int_t i, bool truncate) {
|
||||
int64_t i64 = Int64$from_int(i, truncate);
|
||||
int16_t i16 = (int16_t)i64;
|
||||
if (!truncate && unlikely(i64 != i16))
|
||||
fail("Integer is too big to fit in a 16-bit integer!");
|
||||
return i16;
|
||||
}
|
||||
|
||||
MACROLIKE PUREFUNC Int8_t Int_to_Int8(Int_t i, bool truncate) {
|
||||
int64_t i64 = Int_to_Int64(i, truncate);
|
||||
MACROLIKE PUREFUNC Int16_t Int16$from_int64(Int64_t i, bool truncate) {
|
||||
if (!truncate && unlikely(i != (Int64_t)(Int16_t)i))
|
||||
fail("Integer is too big to fit in a 16-bit integer: %ld", i);
|
||||
return (Int16_t)i;
|
||||
}
|
||||
MACROLIKE PUREFUNC Int16_t Int16$from_int32(Int32_t i, bool truncate) {
|
||||
if (!truncate && unlikely(i != (Int32_t)(Int16_t)i))
|
||||
fail("Integer is too big to fit in a 16-bit integer: %ld", i);
|
||||
return (Int16_t)i;
|
||||
}
|
||||
MACROLIKE CONSTFUNC Int16_t Int16$from_int8(Int8_t i) { return (Int16_t)i; }
|
||||
|
||||
// Int8 constructors
|
||||
MACROLIKE PUREFUNC Int8_t Int8$from_int(Int_t i, bool truncate) {
|
||||
int64_t i64 = Int64$from_int(i, truncate);
|
||||
int8_t i8 = (int8_t)i64;
|
||||
if (!truncate && unlikely(i64 != i8))
|
||||
fail("Integer is too big to fit in an 8-bit integer!");
|
||||
return i8;
|
||||
}
|
||||
|
||||
MACROLIKE PUREFUNC Int_t Num_to_Int(double n)
|
||||
{
|
||||
mpz_t result;
|
||||
mpz_init_set_d(result, n);
|
||||
return Int$from_mpz(result);
|
||||
MACROLIKE PUREFUNC Int8_t Int8$from_int64(Int64_t i, bool truncate) {
|
||||
if (!truncate && unlikely(i != (Int64_t)(Int8_t)i))
|
||||
fail("Integer is too big to fit in a 8-bit integer: %ld", i);
|
||||
return (Int8_t)i;
|
||||
}
|
||||
|
||||
MACROLIKE PUREFUNC double Int_to_Num(Int_t i)
|
||||
{
|
||||
if likely (i.small & 1)
|
||||
return (double)(i.small >> 2);
|
||||
|
||||
return mpz_get_d(*i.big);
|
||||
MACROLIKE PUREFUNC Int8_t Int8$from_int32(Int32_t i, bool truncate) {
|
||||
if (!truncate && unlikely(i != (Int32_t)(Int8_t)i))
|
||||
fail("Integer is too big to fit in a 8-bit integer: %ld", i);
|
||||
return (Int8_t)i;
|
||||
}
|
||||
MACROLIKE PUREFUNC Int8_t Int8$from_int16(Int16_t i, bool truncate) {
|
||||
if (!truncate && unlikely(i != (Int16_t)(Int8_t)i))
|
||||
fail("Integer is too big to fit in a 8-bit integer: %ld", i);
|
||||
return (Int8_t)i;
|
||||
}
|
||||
|
||||
#define Int_to_Num32(i) (Num32_t)Int_to_Num(i)
|
||||
|
||||
#define CONVERSION_FUNC(hi, lo) \
|
||||
MACROLIKE PUREFUNC int##lo##_t Int##hi##_to_Int##lo(int##hi##_t i, bool truncate) { \
|
||||
if (!truncate && unlikely(i != (int##lo##_t)i)) \
|
||||
fail("Cannot truncate the Int" #hi " %ld to an Int" #lo, (int64_t)i); \
|
||||
return (int##lo##_t)i; \
|
||||
}
|
||||
|
||||
CONVERSION_FUNC(64, 32)
|
||||
CONVERSION_FUNC(64, 16)
|
||||
CONVERSION_FUNC(64, 8)
|
||||
CONVERSION_FUNC(32, 16)
|
||||
CONVERSION_FUNC(32, 8)
|
||||
CONVERSION_FUNC(16, 8)
|
||||
#undef CONVERSION_FUNC
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wfloat-equal"
|
||||
#define CONVERSION_FUNC(num, int_type) \
|
||||
MACROLIKE PUREFUNC int_type##_t num##_to_##int_type(num##_t n, bool truncate) { \
|
||||
num##_t rounded = (num##_t)round((double)n); \
|
||||
if (!truncate && unlikely((num##_t)(int_type##_t)rounded != rounded)) \
|
||||
fail("Cannot truncate the " #num " %g to an " #int_type, (double)rounded); \
|
||||
return (int_type##_t)rounded; \
|
||||
} \
|
||||
MACROLIKE PUREFUNC num##_t int_type##_to_##num(int_type##_t n) { \
|
||||
return (num##_t)n; \
|
||||
}
|
||||
|
||||
CONVERSION_FUNC(Num, Int64)
|
||||
CONVERSION_FUNC(Num, Int32)
|
||||
CONVERSION_FUNC(Num, Int16)
|
||||
CONVERSION_FUNC(Num, Int8)
|
||||
CONVERSION_FUNC(Num32, Int64)
|
||||
CONVERSION_FUNC(Num32, Int32)
|
||||
CONVERSION_FUNC(Num32, Int16)
|
||||
CONVERSION_FUNC(Num32, Int8)
|
||||
#pragma GCC diagnostic pop
|
||||
#undef CONVERSION_FUNC
|
||||
|
||||
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#include "datatypes.h"
|
||||
#include "math.h"
|
||||
#include "moments.h"
|
||||
#include "optionals.h"
|
||||
#include "patterns.h"
|
||||
@ -60,11 +61,11 @@ public Moment_t Moment$now(void)
|
||||
public Moment_t Moment$new(Int_t year, Int_t month, Int_t day, Int_t hour, Int_t minute, double second, OptionalText_t timezone)
|
||||
{
|
||||
struct tm info = {
|
||||
.tm_min=Int_to_Int32(minute, false),
|
||||
.tm_hour=Int_to_Int32(hour, false),
|
||||
.tm_mday=Int_to_Int32(day, false),
|
||||
.tm_mon=Int_to_Int32(month, false) - 1,
|
||||
.tm_year=Int_to_Int32(year, false) - 1900,
|
||||
.tm_min=Int32$from_int(minute, false),
|
||||
.tm_hour=Int32$from_int(hour, false),
|
||||
.tm_mday=Int32$from_int(day, false),
|
||||
.tm_mon=Int32$from_int(month, false) - 1,
|
||||
.tm_year=Int32$from_int(year, false) - 1900,
|
||||
.tm_isdst=-1,
|
||||
};
|
||||
|
||||
@ -81,9 +82,9 @@ public Moment_t Moment$after(Moment_t moment, double seconds, double minutes, do
|
||||
struct tm info = {};
|
||||
WITH_TIMEZONE(timezone, localtime_r(&moment.tv_sec, &info));
|
||||
|
||||
info.tm_mday += Int_to_Int32(days, false) + 7*Int_to_Int32(weeks, false);
|
||||
info.tm_mon += Int_to_Int32(months, false);
|
||||
info.tm_year += Int_to_Int32(years, false);
|
||||
info.tm_mday += Int32$from_int(days, false) + 7*Int32$from_int(weeks, false);
|
||||
info.tm_mon += Int32$from_int(months, false);
|
||||
info.tm_year += Int32$from_int(years, false);
|
||||
|
||||
time_t t = mktime(&info);
|
||||
return (Moment_t){
|
||||
|
@ -50,11 +50,11 @@ public CONSTFUNC bool Num$near(double a, double b, double ratio, double absolute
|
||||
}
|
||||
|
||||
public Text_t Num$format(double f, Int_t precision) {
|
||||
return Text$format("%.*f", (int)Int_to_Int64(precision, false), f);
|
||||
return Text$format("%.*f", (int)Int64$from_int(precision, false), f);
|
||||
}
|
||||
|
||||
public Text_t Num$scientific(double f, Int_t precision) {
|
||||
return Text$format("%.*e", (int)Int_to_Int64(precision, false), f);
|
||||
return Text$format("%.*e", (int)Int64$from_int(precision, false), f);
|
||||
}
|
||||
|
||||
public CONSTFUNC double Num$mod(double num, double modulus) {
|
||||
@ -125,11 +125,11 @@ public CONSTFUNC bool Num32$near(float a, float b, float ratio, float absolute)
|
||||
}
|
||||
|
||||
public Text_t Num32$format(float f, Int_t precision) {
|
||||
return Text$format("%.*f", (int)Int_to_Int64(precision, false), (double)f);
|
||||
return Text$format("%.*f", (int)Int64$from_int(precision, false), (double)f);
|
||||
}
|
||||
|
||||
public Text_t Num32$scientific(float f, Int_t precision) {
|
||||
return Text$format("%.*e", (int)Int_to_Int64(precision, false), (double)f);
|
||||
return Text$format("%.*e", (int)Int64$from_int(precision, false), (double)f);
|
||||
}
|
||||
|
||||
public CONSTFUNC float Num32$mod(float num, float modulus) {
|
||||
|
@ -6,15 +6,16 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "datatypes.h"
|
||||
#include "integers.h"
|
||||
#include "stdlib.h"
|
||||
#include "types.h"
|
||||
#include "util.h"
|
||||
|
||||
#define Num_t double
|
||||
#define Num32_t float
|
||||
#define OptionalNum_t double
|
||||
#define OptionalNum32_t float
|
||||
#define N32(n) ((float)n)
|
||||
#define N64(n) ((double)n)
|
||||
#define N32(n) ((float)(n))
|
||||
#define N64(n) ((double)(n))
|
||||
|
||||
Text_t Num$as_text(const void *f, bool colorize, const TypeInfo_t *type);
|
||||
PUREFUNC int32_t Num$compare(const void *x, const void *y, const TypeInfo_t *type);
|
||||
@ -32,6 +33,38 @@ OptionalNum_t Num$parse(Text_t text);
|
||||
MACROLIKE CONSTFUNC double Num$clamped(double x, double low, double high) {
|
||||
return (x <= low) ? low : (x >= high ? high : x);
|
||||
}
|
||||
MACROLIKE CONSTFUNC double Num$from_num32(Num32_t n) { return (double)n; }
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wfloat-equal"
|
||||
MACROLIKE CONSTFUNC double Num$from_int(Int_t i, bool truncate) {
|
||||
if likely (i.small & 0x1) {
|
||||
double ret = (double)(i.small >> 2);
|
||||
if unlikely (!truncate && (int64_t)ret != (i.small >> 2))
|
||||
fail("Could not convert integer to 64-bit floating point without losing precision: %ld", i.small >> 2);
|
||||
return ret;
|
||||
} else {
|
||||
double ret = mpz_get_d(*i.big);
|
||||
if (!truncate) {
|
||||
mpz_t roundtrip;
|
||||
mpz_init_set_d(roundtrip, ret);
|
||||
if unlikely (mpz_cmp(*i.big, roundtrip) != 0)
|
||||
fail("Could not convert integer to 64-bit floating point without losing precision: %k", (Text_t[1]){Int$value_as_text(i)});
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
#pragma GCC diagnostic pop
|
||||
MACROLIKE CONSTFUNC double Num$from_int64(Int64_t i, bool truncate) {
|
||||
double n = (double)i;
|
||||
if unlikely (!truncate && (Int64_t)n != i)
|
||||
fail("Could not convert integer to 64-bit floating point without losing precision: %ld", i);
|
||||
return n;
|
||||
}
|
||||
MACROLIKE CONSTFUNC double Num$from_int32(Int32_t i) { return (double)i; }
|
||||
MACROLIKE CONSTFUNC double Num$from_int16(Int16_t i) { return (double)i; }
|
||||
MACROLIKE CONSTFUNC double Num$from_int8(Int8_t i) { return (double)i; }
|
||||
MACROLIKE CONSTFUNC double Num$from_byte(Byte_t i) { return (double)i; }
|
||||
|
||||
extern const TypeInfo_t Num$info;
|
||||
|
||||
Text_t Num32$as_text(const void *f, bool colorize, const TypeInfo_t *type);
|
||||
@ -50,9 +83,43 @@ float Num32$nan(Text_t tag);
|
||||
MACROLIKE CONSTFUNC float Num32$clamped(float x, float low, float high) {
|
||||
return (x <= low) ? low : (x >= high ? high : x);
|
||||
}
|
||||
MACROLIKE CONSTFUNC float Num32$from_num(Num_t n) { return (float)n; }
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wfloat-equal"
|
||||
MACROLIKE CONSTFUNC float Num32$from_int(Int_t i, bool truncate) {
|
||||
if likely (i.small & 0x1) {
|
||||
float ret = (float)(i.small >> 2);
|
||||
if unlikely (!truncate && (int64_t)ret != (i.small >> 2))
|
||||
fail("Could not convert integer to 32-bit floating point without losing precision: %ld", i.small >> 2);
|
||||
return ret;
|
||||
} else {
|
||||
float ret = (float)mpz_get_d(*i.big);
|
||||
if (!truncate) {
|
||||
mpz_t roundtrip;
|
||||
mpz_init_set_d(roundtrip, ret);
|
||||
if unlikely (mpz_cmp(*i.big, roundtrip) != 0)
|
||||
fail("Could not convert integer to 32-bit floating point without losing precision: %k", (Text_t[1]){Int$value_as_text(i)});
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
#pragma GCC diagnostic pop
|
||||
MACROLIKE CONSTFUNC float Num32$from_int64(Int64_t i, bool truncate) {
|
||||
float n = (float)i;
|
||||
if unlikely (!truncate && (Int64_t)n != i)
|
||||
fail("Could not convert integer to 32-bit floating point without losing precision: %ld", i);
|
||||
return n;
|
||||
}
|
||||
MACROLIKE CONSTFUNC float Num32$from_int32(Int32_t i, bool truncate) {
|
||||
float n = (float)i;
|
||||
if unlikely (!truncate && (Int32_t)n != i)
|
||||
fail("Could not convert integer to 32-bit floating point without losing precision: %d", i);
|
||||
return n;
|
||||
}
|
||||
MACROLIKE CONSTFUNC float Num32$from_int16(Int16_t i) { return (float)i; }
|
||||
MACROLIKE CONSTFUNC float Num32$from_int8(Int8_t i) { return (float)i; }
|
||||
MACROLIKE CONSTFUNC float Num32$from_byte(Byte_t i) { return (float)i; }
|
||||
|
||||
extern const TypeInfo_t Num32$info;
|
||||
|
||||
#define Num_to_Num32(n) ((Num32_t)(n))
|
||||
#define Num32_to_Num(n) ((Num_t)(n))
|
||||
|
||||
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "integers.h"
|
||||
#include "metamethods.h"
|
||||
#include "moments.h"
|
||||
#include "nums.h"
|
||||
#include "patterns.h"
|
||||
#include "text.h"
|
||||
#include "threads.h"
|
||||
|
@ -277,7 +277,7 @@ public OptionalArray_t Path$read_bytes(Path_t path, OptionalInt_t count)
|
||||
if (fstat(fd, &sb) != 0)
|
||||
return NONE_ARRAY;
|
||||
|
||||
int64_t const target_count = count.small ? Int_to_Int64(count, false) : INT64_MAX;
|
||||
int64_t const target_count = count.small ? Int64$from_int(count, false) : INT64_MAX;
|
||||
if (target_count < 0)
|
||||
fail("Cannot read a negative number of bytes!");
|
||||
|
||||
|
@ -807,7 +807,7 @@ static int64_t _find(Text_t text, Pattern_t pattern, int64_t first, int64_t last
|
||||
|
||||
public OptionalMatch_t Text$find(Text_t text, Pattern_t pattern, Int_t from_index)
|
||||
{
|
||||
int64_t first = Int_to_Int64(from_index, false);
|
||||
int64_t first = Int64$from_int(from_index, false);
|
||||
if (first == 0) fail("Invalid index: 0");
|
||||
if (first < 0) first = text.length + first + 1;
|
||||
if (first > text.length || first < 1)
|
||||
@ -874,7 +874,7 @@ public Array_t Text$find_all(Text_t text, Pattern_t pattern)
|
||||
OptionalMatch_t m = Text$find(text, pattern, I(i));
|
||||
if (!m.index.small)
|
||||
break;
|
||||
i = Int_to_Int64(m.index, false) + m.text.length;
|
||||
i = Int64$from_int(m.index, false) + m.text.length;
|
||||
Array$insert(&matches, &m, I_small(0), sizeof(Match_t));
|
||||
}
|
||||
return matches;
|
||||
@ -888,7 +888,7 @@ typedef struct {
|
||||
|
||||
static OptionalMatch_t next_match(match_iter_state_t *state)
|
||||
{
|
||||
if (Int_to_Int64(state->i, false) > state->state.stack[0].text.length)
|
||||
if (Int64$from_int(state->i, false) > state->state.stack[0].text.length)
|
||||
return NONE_MATCH;
|
||||
|
||||
OptionalMatch_t m = Text$find(state->state.stack[0].text, state->pattern, state->i);
|
||||
|
@ -251,7 +251,7 @@ public Byte_t RNG$byte(RNG_t rng)
|
||||
|
||||
public Array_t RNG$bytes(RNG_t rng, Int_t count)
|
||||
{
|
||||
int64_t n = Int_to_Int64(count, false);
|
||||
int64_t n = Int64$from_int(count, false);
|
||||
Byte_t *r = GC_MALLOC_ATOMIC(sizeof(Byte_t[n]));
|
||||
random_bytes(rng, r, sizeof(Byte_t[n]));
|
||||
return (Array_t){.data=r, .length=n, .stride=1, .atomic=1};
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "integers.h"
|
||||
#include "optionals.h"
|
||||
#include "metamethods.h"
|
||||
#include "nums.h"
|
||||
#include "patterns.h"
|
||||
#include "paths.h"
|
||||
#include "rng.h"
|
||||
|
@ -505,7 +505,7 @@ public Text_t Text$repeat(Text_t text, Int_t count)
|
||||
if (Int$compare_value(result_len, I(1l<<40)) > 0)
|
||||
fail("Text repeating would produce too big of an result!");
|
||||
|
||||
int64_t count64 = Int_to_Int64(count, false);
|
||||
int64_t count64 = Int64$from_int(count, false);
|
||||
Text_t ret = text;
|
||||
for (int64_t c = 1; c < count64; c++)
|
||||
ret = concat2(ret, text);
|
||||
@ -514,8 +514,8 @@ public Text_t Text$repeat(Text_t text, Int_t count)
|
||||
|
||||
public Text_t Text$slice(Text_t text, Int_t first_int, Int_t last_int)
|
||||
{
|
||||
int64_t first = Int_to_Int64(first_int, false);
|
||||
int64_t last = Int_to_Int64(last_int, false);
|
||||
int64_t first = Int64$from_int(first_int, false);
|
||||
int64_t last = Int64$from_int(last_int, false);
|
||||
if (first == 0) fail("Invalid index: 0");
|
||||
if (last == 0) return EMPTY_TEXT;
|
||||
|
||||
@ -604,14 +604,14 @@ public Text_t Text$reversed(Text_t text)
|
||||
|
||||
public PUREFUNC Text_t Text$cluster(Text_t text, Int_t index_int)
|
||||
{
|
||||
int64_t index = Int_to_Int64(index_int, false);
|
||||
int64_t index = Int64$from_int(index_int, false);
|
||||
if (index == 0) fail("Invalid index: 0");
|
||||
|
||||
if (index < 0) index = text.length + index + 1;
|
||||
|
||||
if (index > text.length || index < 1)
|
||||
fail("Invalid index: %ld is beyond the length of the text (length = %ld)",
|
||||
Int_to_Int64(index_int, false), text.length);
|
||||
Int64$from_int(index_int, false), text.length);
|
||||
|
||||
while (text.tag == TEXT_CONCAT) {
|
||||
if (index <= text.left->length)
|
||||
|
15
structs.c
15
structs.c
@ -27,7 +27,7 @@ CORD compile_struct_typeinfo(env_t *env, ast_t *ast)
|
||||
short_name = strrchr(short_name, '$') + 1;
|
||||
|
||||
const char *metamethods = is_packed_data(t) ? "PackedData$metamethods" : "Struct$metamethods";
|
||||
CORD typeinfo = CORD_asprintf("public const TypeInfo_t %r = {.size=%zu, .align=%zu, .metamethods=%s, "
|
||||
CORD typeinfo = CORD_asprintf("public const TypeInfo_t %r$$info = {.size=%zu, .align=%zu, .metamethods=%s, "
|
||||
".tag=StructInfo, .StructInfo.name=\"%s\"%s, "
|
||||
".StructInfo.num_fields=%ld",
|
||||
full_name, type_size(t), type_align(t), metamethods, short_name, def->secret ? ", .StructInfo.is_secret=true" : "",
|
||||
@ -55,23 +55,26 @@ CORD compile_struct_header(env_t *env, ast_t *ast)
|
||||
CORD type_code = compile_type(field_t);
|
||||
fields = CORD_all(fields, type_code, " $", field->name, field_t->tag == BoolType ? ":1" : CORD_EMPTY, ";\n");
|
||||
}
|
||||
CORD struct_code = CORD_all("struct ", full_name, "_s {\n");
|
||||
CORD struct_code = CORD_all("struct ", full_name, "$$struct {\n");
|
||||
struct_code = CORD_all(struct_code, "};\n");
|
||||
type_t *t = Table$str_get(*env->types, def->name);
|
||||
return CORD_all(
|
||||
"struct ", full_name, "_s {\n",
|
||||
"struct ", full_name, "$$struct {\n",
|
||||
fields,
|
||||
"};\n",
|
||||
"typedef struct {\n",
|
||||
"union {\n",
|
||||
full_name, "_t value;\n"
|
||||
full_name, "$$type value;\n"
|
||||
"struct {\n"
|
||||
"char _padding[", heap_strf("%zu", unpadded_struct_size(t)), "];\n",
|
||||
"Bool_t is_none:1;\n"
|
||||
"};\n"
|
||||
"};\n"
|
||||
"} ", namespace_prefix(env, env->namespace), "$Optional", def->name, "_t;\n"
|
||||
"extern const TypeInfo_t ", full_name, ";\n");
|
||||
"} ", namespace_prefix(env, env->namespace), "$Optional", def->name, "$$type;\n"
|
||||
// Constructor macro:
|
||||
"#define ", namespace_prefix(env, env->namespace), def->name,
|
||||
"(...) ((", namespace_prefix(env, env->namespace), def->name, "$$type){__VA_ARGS__})\n"
|
||||
"extern const TypeInfo_t ", full_name, "$$info;\n");
|
||||
}
|
||||
|
||||
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
|
||||
|
@ -63,7 +63,7 @@ func main():
|
||||
>> Int8(123):hex()
|
||||
= "0x7B"
|
||||
|
||||
>> Int(2.1)
|
||||
>> Int(2.1, truncate=yes)
|
||||
= 2 : Int
|
||||
|
||||
do:
|
||||
|
@ -1,7 +1,7 @@
|
||||
|
||||
struct Foo(x:Int, y:Int):
|
||||
func len(f:Foo->Num):
|
||||
return Num.sqrt(f.x*f.x + f.y*f.y)!
|
||||
return Num.sqrt(Num(f.x*f.x + f.y*f.y))!
|
||||
|
||||
func main():
|
||||
>> 3 _min_ 5
|
||||
|
@ -36,5 +36,5 @@ func main():
|
||||
= [30, 50, 100, 20, 90, 10, 80, 40, 70, 60]
|
||||
>> nums:random(rng=rng)
|
||||
= 70
|
||||
>> nums:sample(10, weights=[1.0/i for i in nums.length], rng=rng)
|
||||
>> nums:sample(10, weights=[1.0/Num(i) for i in nums.length], rng=rng)
|
||||
= [10, 20, 10, 10, 30, 70, 10, 40, 60, 80]
|
||||
|
8
tomo.c
8
tomo.c
@ -230,19 +230,19 @@ static void _make_typedefs_for_library(libheader_info_t *info, ast_t *ast)
|
||||
if (ast->tag == StructDef) {
|
||||
auto def = Match(ast, StructDef);
|
||||
CORD full_name = CORD_cat(namespace_prefix(info->env, info->env->namespace), def->name);
|
||||
CORD_put(CORD_all("typedef struct ", full_name, "_s ", full_name, "_t;\n"), info->output);
|
||||
CORD_put(CORD_all("typedef struct ", full_name, "$$struct ", full_name, "$$type;\n"), info->output);
|
||||
} else if (ast->tag == EnumDef) {
|
||||
auto def = Match(ast, EnumDef);
|
||||
CORD full_name = CORD_cat(namespace_prefix(info->env, info->env->namespace), def->name);
|
||||
CORD_put(CORD_all("typedef struct ", full_name, "_s ", full_name, "_t;\n"), info->output);
|
||||
CORD_put(CORD_all("typedef struct ", full_name, "$$struct ", full_name, "$$type;\n"), info->output);
|
||||
|
||||
for (tag_ast_t *tag = def->tags; tag; tag = tag->next) {
|
||||
if (!tag->fields) continue;
|
||||
CORD_put(CORD_all("typedef struct ", full_name, "$", tag->name, "_s ", full_name, "$", tag->name, "_t;\n"), info->output);
|
||||
CORD_put(CORD_all("typedef struct ", full_name, "$", tag->name, "$$struct ", full_name, "$", tag->name, "$$type;\n"), info->output);
|
||||
}
|
||||
} else if (ast->tag == LangDef) {
|
||||
auto def = Match(ast, LangDef);
|
||||
CORD_put(CORD_all("typedef Text_t ", namespace_prefix(info->env, info->env->namespace), def->name, "_t;\n"), info->output);
|
||||
CORD_put(CORD_all("typedef Text_t ", namespace_prefix(info->env, info->env->namespace), def->name, "$$type;\n"), info->output);
|
||||
}
|
||||
}
|
||||
|
||||
|
108
typecheck.c
108
typecheck.c
@ -13,6 +13,7 @@
|
||||
#include "environment.h"
|
||||
#include "parse.h"
|
||||
#include "stdlib/patterns.h"
|
||||
#include "stdlib/tables.h"
|
||||
#include "stdlib/text.h"
|
||||
#include "stdlib/util.h"
|
||||
#include "typecheck.h"
|
||||
@ -233,7 +234,7 @@ void prebind_statement(env_t *env, ast_t *statement)
|
||||
type_t *type = Type(StructType, .name=def->name, .opaque=true, .env=ns_env); // placeholder
|
||||
Table$str_set(env->types, def->name, type);
|
||||
set_binding(env, def->name, Type(TypeInfoType, .name=def->name, .type=type, .env=ns_env),
|
||||
CORD_all(namespace_prefix(env, env->namespace), def->name));
|
||||
CORD_all(namespace_prefix(env, env->namespace), def->name, "$$info"));
|
||||
for (ast_list_t *stmt = def->namespace ? Match(def->namespace, Block)->statements : NULL; stmt; stmt = stmt->next)
|
||||
prebind_statement(ns_env, stmt->ast);
|
||||
break;
|
||||
@ -247,7 +248,7 @@ void prebind_statement(env_t *env, ast_t *statement)
|
||||
type_t *type = Type(EnumType, .name=def->name, .opaque=true, .env=ns_env); // placeholder
|
||||
Table$str_set(env->types, def->name, type);
|
||||
set_binding(env, def->name, Type(TypeInfoType, .name=def->name, .type=type, .env=ns_env),
|
||||
CORD_all(namespace_prefix(env, env->namespace), def->name));
|
||||
CORD_all(namespace_prefix(env, env->namespace), def->name, "$$info"));
|
||||
for (ast_list_t *stmt = def->namespace ? Match(def->namespace, Block)->statements : NULL; stmt; stmt = stmt->next)
|
||||
prebind_statement(ns_env, stmt->ast);
|
||||
break;
|
||||
@ -261,7 +262,7 @@ void prebind_statement(env_t *env, ast_t *statement)
|
||||
type_t *type = Type(TextType, .lang=def->name, .env=ns_env);
|
||||
Table$str_set(env->types, def->name, type);
|
||||
set_binding(env, def->name, Type(TypeInfoType, .name=def->name, .type=type, .env=ns_env),
|
||||
CORD_all(namespace_prefix(env, env->namespace), def->name));
|
||||
CORD_all(namespace_prefix(env, env->namespace), def->name, "$$info"));
|
||||
for (ast_list_t *stmt = def->namespace ? Match(def->namespace, Block)->statements : NULL; stmt; stmt = stmt->next)
|
||||
prebind_statement(ns_env, stmt->ast);
|
||||
break;
|
||||
@ -338,6 +339,12 @@ void bind_statement(env_t *env, ast_t *statement)
|
||||
REVERSE_LIST(fields);
|
||||
type->__data.StructType.fields = fields; // populate placeholder
|
||||
type->__data.StructType.opaque = false;
|
||||
|
||||
// Default constructor:
|
||||
type_t *constructor_t = Type(FunctionType, .args=fields, .ret=type);
|
||||
Array$insert(&ns_env->namespace->constructors,
|
||||
new(binding_t, .code=CORD_all(namespace_prefix(env, env->namespace), def->name), .type=constructor_t),
|
||||
I(0), sizeof(binding_t));
|
||||
|
||||
for (ast_list_t *stmt = def->namespace ? Match(def->namespace, Block)->statements : NULL; stmt; stmt = stmt->next) {
|
||||
bind_statement(ns_env, stmt->ast);
|
||||
@ -381,7 +388,7 @@ void bind_statement(env_t *env, ast_t *statement)
|
||||
type_t *constructor_t = Type(FunctionType, .args=Match(tag->type, StructType)->fields, .ret=type);
|
||||
set_binding(ns_env, tag->name, constructor_t, CORD_all(namespace_prefix(env, env->namespace), def->name, "$tagged$", tag->name));
|
||||
} else { // Empty singleton value:
|
||||
CORD code = CORD_all("(", namespace_prefix(env, env->namespace), def->name, "_t){", namespace_prefix(env, env->namespace), def->name, "$tag$", tag->name, "}");
|
||||
CORD code = CORD_all("((", namespace_prefix(env, env->namespace), def->name, "$$type){", namespace_prefix(env, env->namespace), def->name, "$tag$", tag->name, "})");
|
||||
set_binding(ns_env, tag->name, type, code);
|
||||
}
|
||||
Table$str_set(env->types, heap_strf("%s$%s", def->name, tag->name), tag->type);
|
||||
@ -400,7 +407,7 @@ void bind_statement(env_t *env, ast_t *statement)
|
||||
|
||||
set_binding(ns_env, "without_escaping",
|
||||
Type(FunctionType, .args=new(arg_t, .name="text", .type=TEXT_TYPE), .ret=type),
|
||||
CORD_all("(", namespace_prefix(env, env->namespace), def->name, "_t)"));
|
||||
CORD_all("(", namespace_prefix(env, env->namespace), def->name, "$$type)"));
|
||||
|
||||
for (ast_list_t *stmt = def->namespace ? Match(def->namespace, Block)->statements : NULL; stmt; stmt = stmt->next)
|
||||
bind_statement(ns_env, stmt->ast);
|
||||
@ -1369,56 +1376,69 @@ type_t *get_arg_type(env_t *env, arg_t *arg)
|
||||
return get_type(env, arg->default_val);
|
||||
}
|
||||
|
||||
bool is_valid_call(env_t *env, arg_t *spec_args, arg_ast_t *call_args, bool promotion_allowed)
|
||||
Table_t *get_arg_bindings(env_t *env, arg_t *spec_args, arg_ast_t *call_args, bool promotion_allowed)
|
||||
{
|
||||
Table_t used_args = {};
|
||||
for (arg_t *spec_arg = spec_args; spec_arg; spec_arg = spec_arg->next) {
|
||||
type_t *spec_type = get_arg_type(env, spec_arg);
|
||||
int64_t i = 1;
|
||||
// Find keyword:
|
||||
if (spec_arg->name) {
|
||||
for (arg_ast_t *call_arg = call_args; call_arg; call_arg = call_arg->next) {
|
||||
if (call_arg->name && streq(call_arg->name, spec_arg->name)) {
|
||||
type_t *call_type = get_arg_ast_type(env, call_arg);
|
||||
if (!(type_eq(call_type, spec_type) || (promotion_allowed && can_promote(call_type, spec_type))))
|
||||
return false;
|
||||
Table$str_set(&used_args, call_arg->name, call_arg);
|
||||
goto found_it;
|
||||
}
|
||||
}
|
||||
|
||||
// Populate keyword args:
|
||||
for (arg_ast_t *call_arg = call_args; call_arg; call_arg = call_arg->next) {
|
||||
if (!call_arg->name) continue;
|
||||
|
||||
type_t *call_type = get_arg_ast_type(env, call_arg);
|
||||
for (arg_t *spec_arg = spec_args; spec_arg; spec_arg = spec_arg->next) {
|
||||
if (!streq(call_arg->name, spec_arg->name)) continue;
|
||||
type_t *spec_type = get_arg_type(env, spec_arg);
|
||||
if (!(type_eq(call_type, spec_type) || (promotion_allowed && can_promote(call_type, spec_type))
|
||||
|| (!promotion_allowed && call_arg->value->tag == Int && is_numeric_type(spec_type))
|
||||
|| (!promotion_allowed && call_arg->value->tag == Num && spec_type->tag == NumType)))
|
||||
return NULL;
|
||||
Table$str_set(&used_args, call_arg->name, call_arg);
|
||||
goto next_call_arg;
|
||||
}
|
||||
// Find positional:
|
||||
for (arg_ast_t *call_arg = call_args; call_arg; call_arg = call_arg->next) {
|
||||
if (call_arg->name) continue;
|
||||
const char *pseudoname = heap_strf("%ld", i++);
|
||||
if (!Table$str_get(used_args, pseudoname)) {
|
||||
type_t *call_type = get_arg_ast_type(env, call_arg);
|
||||
if (!(type_eq(call_type, spec_type) || (promotion_allowed && can_promote(call_type, spec_type))))
|
||||
return false;
|
||||
Table$str_set(&used_args, pseudoname, call_arg);
|
||||
goto found_it;
|
||||
}
|
||||
return NULL;
|
||||
next_call_arg:;
|
||||
}
|
||||
|
||||
arg_ast_t *unused_args = call_args;
|
||||
for (arg_t *spec_arg = spec_args; spec_arg; spec_arg = spec_arg->next) {
|
||||
arg_ast_t *keyworded = Table$str_get(used_args, spec_arg->name);
|
||||
if (keyworded) continue;
|
||||
|
||||
type_t *spec_type = get_arg_type(env, spec_arg);
|
||||
for (; unused_args; unused_args = unused_args->next) {
|
||||
if (unused_args->name) continue; // Already handled the keyword args
|
||||
type_t *call_type = get_arg_ast_type(env, unused_args);
|
||||
if (!(type_eq(call_type, spec_type) || (promotion_allowed && can_promote(call_type, spec_type))
|
||||
|| (!promotion_allowed && unused_args->value->tag == Int && is_numeric_type(spec_type))
|
||||
|| (!promotion_allowed && unused_args->value->tag == Num && spec_type->tag == NumType)))
|
||||
return NULL; // Positional arg trying to fill in
|
||||
Table$str_set(&used_args, spec_arg->name, unused_args);
|
||||
unused_args = unused_args->next;
|
||||
goto found_it;
|
||||
}
|
||||
|
||||
if (spec_arg->default_val)
|
||||
goto found_it;
|
||||
|
||||
return false;
|
||||
return NULL;
|
||||
found_it: continue;
|
||||
}
|
||||
|
||||
int64_t i = 1;
|
||||
for (arg_ast_t *call_arg = call_args; call_arg; call_arg = call_arg->next) {
|
||||
if (call_arg->name) {
|
||||
if (!Table$str_get(used_args, call_arg->name))
|
||||
return false;
|
||||
} else {
|
||||
const char *pseudoname = heap_strf("%ld", i++);
|
||||
if (!Table$str_get(used_args, pseudoname))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
while (unused_args && unused_args->name)
|
||||
unused_args = unused_args->next;
|
||||
|
||||
if (unused_args != NULL)
|
||||
return NULL;
|
||||
|
||||
Table_t *ret = new(Table_t);
|
||||
*ret = used_args;
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool is_valid_call(env_t *env, arg_t *spec_args, arg_ast_t *call_args, bool promotion_allowed)
|
||||
{
|
||||
Table_t *arg_bindings = get_arg_bindings(env, spec_args, call_args, promotion_allowed);
|
||||
return (arg_bindings != NULL);
|
||||
}
|
||||
|
||||
PUREFUNC bool can_be_mutated(env_t *env, ast_t *ast)
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include "ast.h"
|
||||
#include "environment.h"
|
||||
#include "stdlib/datatypes.h"
|
||||
#include "types.h"
|
||||
|
||||
type_t *parse_type_ast(env_t *env, type_ast_t *ast);
|
||||
@ -25,6 +26,7 @@ PUREFUNC bool can_be_mutated(env_t *env, ast_t *ast);
|
||||
type_t *parse_type_string(env_t *env, const char *str);
|
||||
type_t *get_method_type(env_t *env, ast_t *self, const char *name);
|
||||
PUREFUNC bool is_constant(env_t *env, ast_t *ast);
|
||||
Table_t *get_arg_bindings(env_t *env, arg_t *spec_args, arg_ast_t *call_args, bool promotion_allowed);
|
||||
bool is_valid_call(env_t *env, arg_t *spec_args, arg_ast_t *call_args, bool promotion_allowed);
|
||||
|
||||
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
|
||||
|
Loading…
Reference in New Issue
Block a user