bh_arr(InterfaceParam) params;
bh_arr(InterfaceConstraint) exprs;
+
+ b32 is_intrinsic: 1;
};
typedef enum ConstraintPhase {
Type* polymorphic_struct_lookup(AstPolyStructType* ps_type, bh_arr(AstPolySolution) slns, OnyxFilePos pos, b32 error_if_failed);
+b32 resolve_intrinsic_interface_constraint(AstConstraint *constraint);
+
// NOTE: Useful inlined functions
static inline b32 is_lval(AstNode* node) {
node = strip_aliases(node);
break;
}
- default: assert(0);
+ // This is not the right thing to return here. In theory it should
+ // try to extract the type of the first element of the array and then
+ // use that as the `array_type`. Then only if there are no elements in the
+ // array should it return TYPE_MATCH_FAILED;
+ default: return TYPE_MATCH_FAILED;
}
node->type = array_type;
return pct;
}
+
+
+b32 resolve_intrinsic_interface_constraint(AstConstraint *constraint) {
+ AstInterface *interface = constraint->interface;
+ Type* type = type_build_from_ast(context.ast_alloc, constraint->type_args[0]);
+ if (!type) return 0;
+
+ if (!strcmp(interface->name, "type_is_bool")) return type_is_bool(type);
+ if (!strcmp(interface->name, "type_is_int")) return type_is_integer(type);
+ if (!strcmp(interface->name, "type_is_float")) return type->kind == Type_Kind_Basic && (type->Basic.flags & Basic_Flag_Float);
+ if (!strcmp(interface->name, "type_is_number")) return type->kind == Type_Kind_Basic && (type->Basic.flags & Basic_Flag_Numeric);
+ if (!strcmp(interface->name, "type_is_simd")) return type->kind == Type_Kind_Basic && (type->Basic.flags & Basic_Flag_SIMD);
+ if (!strcmp(interface->name, "type_is_pointer")) return type_is_pointer(type) || type_is_rawptr(type);
+ if (!strcmp(interface->name, "type_is_enum")) return type->kind == Type_Kind_Enum;
+ if (!strcmp(interface->name, "type_is_simple")) return type->kind == Type_Kind_Basic
+ || type->kind == Type_Kind_Enum
+ || type->kind == Type_Kind_Pointer;
+ if (!strcmp(interface->name, "type_is_array")) return type->kind == Type_Kind_Array;
+ if (!strcmp(interface->name, "type_is_slice")) return type->kind == Type_Kind_Slice;
+ if (!strcmp(interface->name, "type_is_struct")) return type->kind == Type_Kind_Struct;
+ if (!strcmp(interface->name, "type_is_compound")) return type->kind == Type_Kind_Array
+ || type->kind == Type_Kind_Slice
+ || type->kind == Type_Kind_DynArray
+ || type->kind == Type_Kind_Struct;
+
+ return 0;
+}
onyx_ast_node_kind_string(constraint->interface->kind));
}
+ // #intrinsic interfaces
+ if (constraint->interface->is_intrinsic) {
+ b32 success = resolve_intrinsic_interface_constraint(constraint);
+ if (success) {
+ *constraint->report_status = Constraint_Check_Status_Success;
+ return Check_Complete;
+ } else {
+ *constraint->report_status = Constraint_Check_Status_Failed;
+ return Check_Failed;
+ }
+ }
+
bh_arr_new(global_heap_allocator, constraint->exprs, bh_arr_length(constraint->interface->exprs));
bh_arr_each(InterfaceConstraint, ic, constraint->interface->exprs) {
InterfaceConstraint new_ic = {0};
strncat(constraint_map, "'", 511);
}
- onyx_report_error(constraint->exprs[constraint->expr_idx].expr->token->pos, Error_Critical, "Failed to satisfy constraint where %s.", constraint_map);
+ OnyxFilePos error_pos;
+ if (constraint->exprs) {
+ error_pos = constraint->exprs[constraint->expr_idx].expr->token->pos;
+ } else {
+ error_pos = constraint->interface->token->pos;
+ }
+
+ onyx_report_error(error_pos, Error_Critical, "Failed to satisfy constraint where %s.", constraint_map);
onyx_report_error(constraint->token->pos, Error_Critical, "Here is where the interface was used.");
onyx_report_error(pos, Error_Critical, "Here is the code that caused this constraint to be checked.");
expect_token(parser, ',');
}
+ if (parse_possible_directive(parser, "intrinsic")) {
+ interface->is_intrinsic = 1;
+ return interface;
+ }
+
bh_arr_new(global_heap_allocator, interface->exprs, 2);
expect_token(parser, '{');
};
}
+use core.intrinsics.types {type_is_struct}
+
+//
+// `from_array` has two almost identical implementations,
+// but the details are important here. Normally, `from_array`
+// returns an iterator by value, unless the array is of
+// structures, then it returns an iterator by pointer.
+// This seems weird, but in practice it is closer to what
+// you want, as you don't want to have to copy every structure
+// out of the array. While for primitives, you don't want to
+// dereference it everywhere.
+from_array :: #match #local {}
+
#overload
-as_iterator :: from_array
-from_array :: (arr: [] $T) => generator(
+from_array :: (arr: [] $T/type_is_struct) => generator(
^.{ data = arr.data, count = arr.count, current = 0 },
(use ctx: ^$T) -> (typeof ctx.data, bool) {
}
);
+#overload
+from_array :: (arr: [] $T) => generator(
+ ^.{ data = arr.data, count = arr.count, current = 0 },
+
+ (use ctx: ^$T) -> (typeof *ctx.data, bool) {
+ if current < count {
+ defer current += 1;
+ return data[current], true;
+ }
+
+ return .{}, false;
+ }
+);
+
+
+#overload
+as_iterator :: from_array
+
#overload
as_iterator :: (x: ^[..] $T) -> Iterator(T) {
Context :: struct (T: type_expr) {
--- /dev/null
+package core.intrinsics.types
+
+//
+// Simple: bool, number, simd, pointer, enum
+// Number: int, float
+// Int: u8, .., u64 i8, .., i64
+// Float: f32 f64
+// Simd: v128 i8x16 i16x8 i32x4 i64x2 f32x4 f64x2
+// Pointer: ^T rawptr
+// Compound: array, slice, struct
+// Array: [$N] $T
+// Slice: [] $T
+
+type_is_bool :: interface (t: $T) #intrinsic
+type_is_int :: interface (t: $T) #intrinsic
+type_is_float :: interface (t: $T) #intrinsic
+type_is_number :: interface (t: $T) #intrinsic
+type_is_simd :: interface (t: $T) #intrinsic
+type_is_pointer :: interface (t: $T) #intrinsic
+type_is_enum :: interface (t: $T) #intrinsic
+type_is_simple :: interface (t: $T) #intrinsic
+type_is_array :: interface (t: $T) #intrinsic
+type_is_slice :: interface (t: $T) #intrinsic
+type_is_struct :: interface (t: $T) #intrinsic
+type_is_compound :: interface (t: $T) #intrinsic
+
arg_parse :: (c_args: [] cstr, output: any) -> bool {
arg_iter := iter.as_iterator(c_args)
- |> iter.map((x) => string.from_cstr(*x));
+ |> iter.map(string.from_cstr);
defer arg_iter.close(arg_iter.data);
use runtime.info;
#load "./intrinsics/onyx"
#load "./intrinsics/wasm"
+#load "./intrinsics/type_interfaces"
#load "./io/io"
#load "./io/stream"
nums := io.read_all(^reader)
|> string.split(#char ",")
|> iter.as_iterator()
- |> iter.map((x) => cast(i32) conv.str_to_i64(*x))
+ |> iter.map((x) => cast(i32) conv.parse_int(x))
|> iter.to_array();
min := array.fold(nums, nums[0], math.min);
return iter.concat(
iter.as_iterator(edges)
|> iter.filter(name_copy, (x, n) => x.a == *n)
- |> iter.map((x) => x.b),
+ |> iter.map(x => x.b),
iter.as_iterator(edges)
|> iter.filter(name_copy, (x, n) => x.b == *n)
- |> iter.map((x) => x.a)
+ |> iter.map(x => x.a)
);
}
string.strip_whitespace(^line);
if line.count == 0 do break;
- parts := string.split(line, #char ",", allocator=context.temp_allocator)
- |> iter.as_iterator()
- |> iter.map((x) => cast(i32) conv.str_to_i64(*x));
+ parts := string.split_iter(line, #char ",")
+ |> iter.map(x => cast(i32) conv.parse_int(x));
x, _ := iter.take_one(parts);
y, _ := iter.take_one(parts);