return str.{ buf.data, len };
}
-str_format :: (format: str, buffer: [] u8, va: ..any) -> str {
- return str_format_va(format, buffer, ~~va);
+str_format :: (buffer: [] u8, format: str, va: ..any) -> str {
+ return str_format_va(buffer, format, ~~va);
}
-str_format_va :: (format: str, buffer: [] u8, va: [] any) -> str {
+str_format_va :: (buffer: [] u8, format: str, va: [] any) -> str {
Output :: struct {
data: ^u8;
count: u32;
Format :: struct {
pretty_printing := false;
quote_strings := false;
+ dereference := false;
digits_after_decimal := cast(u32) 4;
indentation := cast(u32) 0;
ch = format[i];
switch ch {
+ case #char "*" {
+ i += 1;
+ formatting.dereference = true;
+ }
+
case #char "." {
i += 1;
print_any :: (output: ^Output, formatting: Format, v: any) {
use package builtin.type_info
- array :: package core.array
+ array :: package core.array;
+
+ if formatting.dereference {
+ ti := get_type_info(v.type);
+ if ti.kind == .Pointer {
+ formatting.dereference = false;
+
+ new_any: any;
+ new_any.type = (cast(^Type_Info_Pointer) ti).to;
+ new_any.data = *(cast(^rawptr) v.data);
+ print_any(output, formatting, new_any);
+ return;
+ }
+ }
switch v.type {
case bool {
write_format :: (use writer: ^Writer, format: str, va: ..any) {
// POTENTIAL BUG: this buffer will need to be bigger (or dynamic).
buffer: [2048] u8;
- write_str(writer, conv.str_format_va(format, ~~buffer, ~~va));
+ write_str(writer, conv.str_format_va(buffer, format, va));
}
write_escaped_str :: (use writer: ^Writer, s: str) {
printf :: (format: str, va: ..any) {
buffer: [8196] u8;
- print(conv.str_format_va(format, ~~buffer, ~~va));
+ print(conv.str_format_va(buffer, format, va));
}
// This works on both slices and arrays
AstAddressOf* make_address_of(bh_allocator a, AstTyped* node);
AstLocal* make_local(bh_allocator a, OnyxToken* token, AstType* type_node);
AstNode* make_symbol(bh_allocator a, OnyxToken* sym);
+AstUnaryOp* make_cast(bh_allocator a, AstTyped* expr, Type* to);
void arguments_initialize(Arguments* args);
b32 fill_in_arguments(Arguments* args, AstNode* provider, char** err_msg);
return (node->kind == Ast_Kind_Unary_Op) && (((AstUnaryOp *) node)->operation == Unary_Op_Auto_Cast);
}
+static inline Type* get_expression_type(AstTyped* expr) {
+ switch (expr->kind) {
+ case Ast_Kind_Block: case Ast_Kind_If: case Ast_Kind_While: return NULL;
+ default: return expr->type;
+ }
+}
+
static inline CallingConvention type_function_get_cc(Type* type) {
if (type == NULL) return CC_Undefined;
if (type->kind != Type_Kind_Function) return CC_Undefined;
buf : [256] u8;
_, loc := io.stream_tell(reader.stream);
- s := conv.str_format("Bad wasm value type {} at {x}", ~~buf, cast(i32) byte, loc);
+ s := conv.str_format(buf, "Bad wasm value type {} at {x}", cast(i32) byte, loc);
assert(false, s);
}
}
case #default {
buffer: [128] u8;
conv :: package core.conv
- assert(false, conv.str_format("Bad section number {}", ~~buffer, cast(i32) section_number));
+ assert(false, conv.str_format(buffer, "Bad section number {}", cast(i32) section_number));
}
}
AstNode* resolved = try_symbol_resolve_from_node((AstNode *) ast_type, node->token);
if (resolved == NULL) return 0;
- *pnode = (AstTyped *) resolved;
+ if (permanent) *pnode = (AstTyped *) resolved;
return 1;
}
}
// HACK: NullProcHack
+ // The null_proc matches any procedure, and because of that, will cause a runtime error if you
+ // try to call it.
if (type->kind == Type_Kind_Function && (node->flags & Ast_Flag_Proc_Is_Null) != 0) return 1;
- if (types_are_compatible(node->type, type)) return 1;
+ // The normal case where everything works perfectly.
+ Type* node_type = get_expression_type(node);
+ if (types_are_compatible(node_type, type)) return 1;
+
+ // Here are some of the ways you can unify a node with a type if the type of the
+ // node does not match the given type:
+ //
+ // If the nodes type is a function type and that function has an automatic return
+ // value placeholder, fill in that placeholder with the actual type.
// :AutoReturnType
- if (node->type && node->type->kind == Type_Kind_Function
- && node->type->Function.return_type == &type_auto_return
+ if (node_type && node_type->kind == Type_Kind_Function
+ && node_type->Function.return_type == &type_auto_return
&& type->kind == Type_Kind_Function) {
- node->type->Function.return_type = type->Function.return_type;
+ node_type->Function.return_type = type->Function.return_type;
return 1;
}
+
+ // If the node is an auto cast (~~) node, then check to see if the cast is legal
+ // to the destination type, and if it is change the type to cast to.
if (node_is_auto_cast((AstNode *) node)) {
char* dummy;
- Type* from_type = ((AstUnaryOp *) node)->expr->type;
+ Type* from_type = get_expression_type(((AstUnaryOp *) node)->expr);
if (!from_type || !cast_is_legal(from_type, type, &dummy)) {
return 0;
} else {
- ((AstUnaryOp *) node)->type = type;
+ if (permanent) ((AstUnaryOp *) node)->type = type;
return 1;
}
}
+
+ // If the destination type is a slice, then automatically convert arrays, dynamic
+ // arrays, and var args, if they are the same type. This is big convenience feature
+ // that makes working with arrays much easier.
+ // [N] T -> [] T
+ // [..] T -> [] T
+ // ..T -> [] T
+ else if (node_type && type->kind == Type_Kind_Slice) {
+ if (node_type->kind == Type_Kind_Array || node_type->kind == Type_Kind_DynArray || node_type->kind == Type_Kind_VarArgs) {
+ char* dummy;
+ if (cast_is_legal(node_type, type, &dummy)) {
+ *pnode = (AstTyped *) make_cast(context.ast_alloc, node, type);
+ return 1;
+ }
+ }
+ }
+
+ // If the node is a numeric literal, try to convert it to the destination type.
else if (node->kind == Ast_Kind_NumLit) {
if (convert_numlit_to_type((AstNumLit *) node, type)) return 1;
}
+
+ // If the node is a compound expression, and it doesn't have a type created,
+ // recursive call this function with the individual components of the compound
+ // expression.
else if (node->kind == Ast_Kind_Compound) {
if (type->kind != Type_Kind_Compound) return 0;
return 1;
}
+
else if (node->kind == Ast_Kind_If_Expression) {
AstIfExpression* if_expr = (AstIfExpression *) node;
b32 false_success = unify_node_and_type_(&if_expr->false_expr, type, permanent);
if (true_success && false_success) {
- if_expr->type = type;
+ if (permanent) if_expr->type = type;
return 1;
} else {
return 0;
}
}
+
else if (node->kind == Ast_Kind_Alias) {
AstAlias* alias = (AstAlias *) node;
return unify_node_and_type_(&alias->alias, type, permanent);
return 0;
}
+ // CLEANUP: These error messages should be a lot better and actually
+ // provide the types of the things in question.
if (to->kind == Type_Kind_Slice && from->kind == Type_Kind_Array) {
if (!types_are_compatible(to->Slice.elem, from->Array.elem)) {
*err_msg = "Array to slice cast is not valid here because the types are different.";
}
}
+ if (to->kind == Type_Kind_Slice && from->kind == Type_Kind_DynArray) {
+ if (!types_are_compatible(to->Slice.elem, from->DynArray.elem)) {
+ *err_msg = "Dynmaic array to slice cast is not valid here because the types are different.";
+ return 0;
+ } else {
+ return 1;
+ }
+ }
+
if (to->kind == Type_Kind_Slice && from->kind == Type_Kind_VarArgs) {
if (!types_are_compatible(to->Slice.elem, from->VarArgs.elem)) {
*err_msg = "Variadic argument to slice cast is not valid here because the types are different.";
return symbol;
}
+AstUnaryOp* make_cast(bh_allocator a, AstTyped* expr, Type* to) {
+ AstUnaryOp* cast = onyx_ast_node_new(a, sizeof(AstUnaryOp), Ast_Kind_Unary_Op);
+ cast->token = expr->token;
+ cast->operation = Unary_Op_Cast;
+ cast->expr = expr;
+ cast->type = to;
+ return cast;
+}
+
void arguments_initialize(Arguments* args) {
if (args->values == NULL) bh_arr_new(global_heap_allocator, args->values, 2);
if (args->named_values == NULL) bh_arr_new(global_heap_allocator, args->named_values, 2);
if (binop->left->type == NULL) {
resolve_expression_type(binop->right);
- if (binop->right->type == NULL) {
+ Type* right_type = get_expression_type(binop->right);
+ if (right_type == NULL) {
if (binop->right->entity == NULL || binop->right->entity->state > Entity_State_Check_Types) {
ERROR(binop->token->pos, "Could not resolve type of right hand side to infer.");
}
}
- if (binop->right->type->kind == Type_Kind_Compound) {
+ if (right_type->kind == Type_Kind_Compound) {
AstCompound* lhs = (AstCompound *) binop->left;
if (lhs->kind != Ast_Kind_Compound) {
ERROR_(binop->token->pos,
binop->right->type->Compound.count);
}
- i32 expr_count = binop->right->type->Compound.count;
+ i32 expr_count = right_type->Compound.count;
if (bh_arr_length(lhs->exprs) != expr_count) {
ERROR_(binop->token->pos,
"Expected left hand side to have %d expressions.",
}
fori (i, 0, expr_count) {
- lhs->exprs[i]->type = binop->right->type->Compound.types[i];
+ lhs->exprs[i]->type = right_type->Compound.types[i];
}
lhs->type = type_build_compound_type(context.ast_alloc, lhs);
} else {
- binop->left->type = binop->right->type;
+ binop->left->type = right_type;
}
}
return;
}
+ if (to->kind == Type_Kind_Slice && from->kind == Type_Kind_DynArray) {
+ WI(WI_DROP);
+ WI(WI_DROP);
+ WI(WI_DROP);
+ *pcode = code;
+ return;
+ }
+
if (to->kind == Type_Kind_Slice && from->kind == Type_Kind_VarArgs) {
// Nothing needs to be done because they are identical
*pcode = code;