diff --git a/examples/basic.odin b/examples/basic.odin index 26c522d4c..b41b77bb2 100644 --- a/examples/basic.odin +++ b/examples/basic.odin @@ -2,8 +2,13 @@ #load "win32.odin" #load "file.odin" -print_string :: proc(s: string) { - file_write(file_get_standard(File_Standard.OUTPUT), s as []byte) +print_string_to_buffer :: proc(buf: ^[]byte, s: string) { + for i := 0; i < len(s); i++ { + if !append(buf, s[i]) { + // Buffer is full + return + } + } } byte_reverse :: proc(b: []byte) { @@ -47,19 +52,18 @@ encode_rune :: proc(r: rune) -> ([4]byte, int) { return buf, 4 } -print_rune :: proc(r: rune) { - buf, n := encode_rune(r) - str := buf[:n] as string - print_string(str) +print_rune_to_buffer :: proc(buf: ^[]byte, r: rune) { + b, n := encode_rune(r) + print_string_to_buffer(buf, b[:n] as string) } -print_space :: proc() { print_rune(#rune " ") } -print_nl :: proc() { print_rune(#rune "\n") } +print_space_to_buffer :: proc(buf: ^[]byte) { print_rune_to_buffer(buf, #rune " ") } +print_nl_to_buffer :: proc(buf: ^[]byte) { print_rune_to_buffer(buf, #rune "\n") } -print_int :: proc(i: int) { - print_int_base(i, 10); +print_int_to_buffer :: proc(buf: ^[]byte, i: int) { + print_int_base_to_buffer(buf, i, 10); } -print_int_base :: proc(i, base: int) { +print_int_base_to_buffer :: proc(buffer: ^[]byte, i, base: int) { NUM_TO_CHAR_TABLE :: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@$" buf: [65]byte @@ -85,13 +89,13 @@ print_int_base :: proc(i, base: int) { } byte_reverse(buf[:len]) - print_string(buf[:len] as string) + print_string_to_buffer(buffer, buf[:len] as string) } -print_uint :: proc(i: uint) { - print__uint(i, 10, 0, #rune " ") +print_uint_to_buffer :: proc(buffer: ^[]byte, i: uint) { + print_uint_base_to_buffer(buffer, i, 10, 0, #rune " ") } -print__uint :: proc(i, base: uint, min_width: int, pad_char: byte) { +print_uint_base_to_buffer :: proc(buffer: ^[]byte, i, base: uint, min_width: int, pad_char: byte) { NUM_TO_CHAR_TABLE :: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@$" buf: [65]byte @@ -111,30 +115,30 @@ print__uint :: proc(i, base: uint, min_width: int, pad_char: byte) { } byte_reverse(buf[:len]) - print_string(buf[:len] as string) + print_string_to_buffer(buffer, buf[:len] as string) } -print_bool :: proc(b : bool) { - if b { print_string("true") } - else { print_string("false") } +print_bool_to_buffer :: proc(buffer: ^[]byte, b : bool) { + if b { print_string_to_buffer(buffer, "true") } + else { print_string_to_buffer(buffer, "false") } } -print_pointer :: proc(p: rawptr) #inline { print__uint(p as uint, 16, 0, #rune " ") } +print_pointer_to_buffer :: proc(buffer: ^[]byte, p: rawptr) #inline { print_uint_base_to_buffer(buffer, p as uint, 16, 0, #rune " ") } -print_f32 :: proc(f: f32) #inline { print__f64(f as f64, 7) } -print_f64 :: proc(f: f64) #inline { print__f64(f, 10) } +print_f32_to_buffer :: proc(buffer: ^[]byte, f: f32) #inline { print__f64(buffer, f as f64, 7) } +print_f64_to_buffer :: proc(buffer: ^[]byte, f: f64) #inline { print__f64(buffer, f, 10) } -print__f64 :: proc(f: f64, decimal_places: int) { +print__f64 :: proc(buffer: ^[]byte, f: f64, decimal_places: int) { if f == 0 { - print_rune(#rune "0") + print_rune_to_buffer(buffer, #rune "0") return } if f < 0 { - print_rune(#rune "-") + print_rune_to_buffer(buffer, #rune "-") f = -f } - print_u64 :: proc(i: u64) { + print_u64_to_buffer :: proc(buffer: ^[]byte, i: u64) { NUM_TO_CHAR_TABLE :: "0123456789" buf: [22]byte @@ -149,20 +153,165 @@ print__f64 :: proc(f: f64, decimal_places: int) { i /= 10 } byte_reverse(buf[:len]) - print_string(buf[:len] as string) + print_string_to_buffer(buffer, buf[:len] as string) } i := f as u64 - print_u64(i) + print_u64_to_buffer(buffer, i) f -= i as f64 - print_rune(#rune ".") + print_rune_to_buffer(buffer, #rune ".") mult := 10.0 for decimal_places := 6; decimal_places >= 0; decimal_places-- { i = (f * mult) as u64 - print_u64(i as u64) + print_u64_to_buffer(buffer, i as u64) f -= i as f64 / mult mult *= 10 } } + + + +print_any_to_buffer :: proc(buf: ^[]byte ,arg: any) { + using Type_Info + match type arg.type_info -> info { + case Named: + print_string_to_buffer(buf, "(") + print_string_to_buffer(buf, info.name) + print_string_to_buffer(buf, ")") + + case Integer: + if info.signed { + u: uint = 0; + if arg.data != null { + match info.size { + case 1: u = (arg.data as ^u8)^ as uint + case 2: u = (arg.data as ^u16)^ as uint + case 4: u = (arg.data as ^u32)^ as uint + case 8: u = (arg.data as ^u64)^ as uint + case 16: u = (arg.data as ^u128)^ as uint + } + } + print_uint_to_buffer(buf, u) + } else { + v: int = 0; + if arg.data != null { + match info.size { + case 1: v = (arg.data as ^i8)^ as int + case 2: v = (arg.data as ^i16)^ as int + case 4: v = (arg.data as ^i32)^ as int + case 8: v = (arg.data as ^i64)^ as int + case 16: v = (arg.data as ^i128)^ as int + } + } + print_int_to_buffer(buf, v) + } + + case Float: + f: f64 = 0 + if arg.data != null { + match info.size { + case 4: f = (arg.data as ^f32)^ as f64 + case 8: f = (arg.data as ^f64)^ as f64 + } + } + print_f64_to_buffer(buf, f) + + case String: + s := "" + if arg.data != null { + s = (arg.data as ^string)^ + } + print_string_to_buffer(buf, s) + + case Boolean: + v := false; + if arg.data != null { + v = (arg.data as ^bool)^ + } + print_bool_to_buffer(buf, v) + + case Pointer: + v := null; + if arg.data != null { + v = (arg.data as ^rawptr)^ + } + print_pointer_to_buffer(buf, v) + + case Enum: + v: any + v.data = arg.data + v.type_info = info.base + print_any_to_buffer(buf, v) + + + case Array: print_string_to_buffer(buf, "(array)") + case Slice: print_string_to_buffer(buf, "(slice)") + case Vector: print_string_to_buffer(buf, "(vector)") + + + case Struct: print_string_to_buffer(buf, "(struct)") + case Union: print_string_to_buffer(buf, "(union)") + case Raw_Union: print_string_to_buffer(buf, "(raw_union)") + case Procedure: + print_string_to_buffer(buf, "(procedure 0x") + print_pointer_to_buffer(buf, (arg.data as ^rawptr)^) + print_string_to_buffer(buf, ")") + default: + print_string_to_buffer(buf, "") + } +} + +print_to_buffer :: proc(buf: ^[]byte, args: ..any) { + for i := 0; i < len(args); i++ { + arg := args[i] + + if i > 0 { + print_space_to_buffer(buf) + } + print_any_to_buffer(buf, arg) + } + print_nl_to_buffer(buf) +} + +println_to_buffer :: proc(buf: ^[]byte, args: ..any) { + for i := 0; i < len(args); i++ { + arg := args[i] + + if i > 0 { + print_space_to_buffer(buf) + } + print_any_to_buffer(buf, arg) + } +} + +print :: proc(args: ..any) { + data: [4096]byte + buf := data[:0] + for i := 0; i < len(args); i++ { + arg := args[i] + + if i > 0 { + print_space_to_buffer(^buf) + } + print_any_to_buffer(^buf, arg) + } + file_write(file_get_standard(File_Standard.OUTPUT), buf) +} + + +println :: proc(args: ..any) { + data: [4096]byte + buf := data[:0] + for i := 0; i < len(args); i++ { + arg := args[i] + + if i > 0 { + print_space_to_buffer(^buf) + } + print_any_to_buffer(^buf, arg) + } + print_nl_to_buffer(^buf) + file_write(file_get_standard(File_Standard.OUTPUT), buf) +} diff --git a/examples/demo.odin b/examples/demo.odin index 94007d486..3dd9db53f 100644 --- a/examples/demo.odin +++ b/examples/demo.odin @@ -1,59 +1,6 @@ #load "basic.odin" #load "math.odin" - -print_type_info_kind :: proc(info: ^Type_Info) { - using Type_Info - match type info -> i { - case Named: print_string("Named\n") - case Integer: print_string("Integer\n") - case Float: print_string("Float\n") - case String: print_string("String\n") - case Boolean: print_string("Boolean\n") - case Pointer: print_string("Pointer\n") - case Procedure: print_string("Procedure\n") - case Array: print_string("Array\n") - case Slice: print_string("Slice\n") - case Vector: print_string("Vector\n") - case Struct: print_string("Struct\n") - case Union: print_string("Union\n") - case Raw_Union: print_string("RawUnion\n") - case Enum: print_string("Enum\n") - default: print_string("void\n") - } -} - -println :: proc(args: ..any) { - for i := 0; i < len(args); i++ { - arg := args[i] - - if i > 0 { - print_string(" ") - } - - using Type_Info - match type arg.type_info -> i { - case Named: print_string("Named") - case Integer: print_string("Integer") - case Float: print_string("Float") - case String: print_string("String") - case Boolean: print_string("Boolean") - case Pointer: print_string("Pointer") - case Procedure: print_string("Procedure") - case Array: print_string("Array") - case Slice: print_string("Slice") - case Vector: print_string("Vector") - case Struct: print_string("Struct") - case Union: print_string("Union") - case Raw_Union: print_string("RawUnion") - case Enum: print_string("Enum") - default: print_string("void") - } - } - - print_nl() -} - main :: proc() { i: int s: struct { @@ -63,9 +10,5 @@ main :: proc() { a: any = i - println(137, "Hello", 1.23) - - // print_type_info_kind(a.type_info) - // print_type_info_kind(type_info(s)) - // print_type_info_kind(type_info(p)) + println(137, "Hello", 1.25, true) } diff --git a/src/checker/expr.cpp b/src/checker/expr.cpp index e55efd56d..b5fb1249f 100644 --- a/src/checker/expr.cpp +++ b/src/checker/expr.cpp @@ -2714,6 +2714,8 @@ void check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode GB_ASSERT(call->kind == AstNode_CallExpr); GB_ASSERT(proc_type->kind == Type_Proc); ast_node(ce, CallExpr, call); + + isize error_code = 0; isize param_index = 0; isize param_count = 0; @@ -2723,6 +2725,15 @@ void check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode param_count = proc_type->Proc.params->Tuple.variable_count; } + if (ce->ellipsis.pos.line != 0) { + if (!variadic) { + error(&c->error_collector, ce->ellipsis, + "Cannot use `..` in call to a non-variadic procedure: `%.*s`", + LIT(ce->proc->Ident.string)); + return; + } + } + if (ce->arg_list_count == 0) { if (variadic && param_count-1 == 0) return; @@ -2730,6 +2741,8 @@ void check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode return; } + + if (ce->arg_list_count > param_count && !variadic) { error_code = +1; } else { diff --git a/src/checker/type.cpp b/src/checker/type.cpp index 2ef56111c..8db89a38c 100644 --- a/src/checker/type.cpp +++ b/src/checker/type.cpp @@ -722,7 +722,7 @@ Selection lookup_field(Type *type_, String field_name, b32 is_type, Selection se if (type->kind == Type_Basic) { if (type->Basic.kind == Basic_any) { String type_info_str = make_string("type_info"); - String data_str = make_string("data_str"); + String data_str = make_string("data"); if (entity_any_type_info == NULL) { Token token = {Token_Identifier}; token.string = type_info_str; diff --git a/src/codegen/codegen.cpp b/src/codegen/codegen.cpp index 5d8df5060..13a362ce5 100644 --- a/src/codegen/codegen.cpp +++ b/src/codegen/codegen.cpp @@ -238,7 +238,7 @@ void ssa_gen_tree(ssaGen *s) { case Basic_uint: { tag = ssa_add_local_generated(proc, t_type_info_integer); b32 is_unsigned = (basic_types[t->Basic.kind].flags & BasicFlag_Unsigned) != 0; - ssaValue *bits = ssa_make_value_constant(a, t_int, make_exact_value_integer(8*type_size_of(m->sizes, a, t))); + ssaValue *bits = ssa_make_value_constant(a, t_int, make_exact_value_integer(type_size_of(m->sizes, a, t))); ssaValue *is_signed = ssa_make_value_constant(a, t_bool, make_exact_value_bool(!is_unsigned)); ssa_emit_store(proc, ssa_emit_struct_gep(proc, tag, v_zero32, t_int_ptr), bits); ssa_emit_store(proc, ssa_emit_struct_gep(proc, tag, v_one32, t_bool_ptr), is_signed); @@ -247,7 +247,7 @@ void ssa_gen_tree(ssaGen *s) { case Basic_f32: case Basic_f64: { tag = ssa_add_local_generated(proc, t_type_info_float); - ssaValue *bits = ssa_make_value_constant(a, t_int, make_exact_value_integer(8*type_size_of(m->sizes, a, t))); + ssaValue *bits = ssa_make_value_constant(a, t_int, make_exact_value_integer(type_size_of(m->sizes, a, t))); ssa_emit_store(proc, ssa_emit_struct_gep(proc, tag, v_zero32, t_int_ptr), bits); } break; diff --git a/src/codegen/print_llvm.cpp b/src/codegen/print_llvm.cpp index ea30d910c..cc349588c 100644 --- a/src/codegen/print_llvm.cpp +++ b/src/codegen/print_llvm.cpp @@ -146,7 +146,7 @@ void ssa_print_type(ssaFileBuffer *f, BaseTypeSizes s, Type *t) { case Basic_u16: ssa_fprintf(f, "i16"); break; case Basic_u32: ssa_fprintf(f, "i32"); break; case Basic_u64: ssa_fprintf(f, "i64"); break; - case Basic_u128: ssa_fprintf(f, "u128"); break; + case Basic_u128: ssa_fprintf(f, "i128"); break; case Basic_f32: ssa_fprintf(f, "float"); break; case Basic_f64: ssa_fprintf(f, "double"); break; case Basic_rawptr: ssa_fprintf(f, "%%..rawptr"); break; diff --git a/src/codegen/ssa.cpp b/src/codegen/ssa.cpp index a5fe3c566..fc55600ab 100644 --- a/src/codegen/ssa.cpp +++ b/src/codegen/ssa.cpp @@ -2085,12 +2085,12 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue // append :: proc(s: ^[]Type, item: Type) -> bool AstNode *sptr_node = ce->arg_list; AstNode *item_node = ce->arg_list->next; - ssaValue *slice_ptr = ssa_build_addr(proc, sptr_node).addr; + ssaValue *slice_ptr = ssa_build_expr(proc, sptr_node); ssaValue *slice = ssa_emit_load(proc, slice_ptr); ssaValue *elem = ssa_slice_elem(proc, slice); - ssaValue *len = ssa_slice_len(proc, slice); - ssaValue *cap = ssa_slice_cap(proc, slice); + ssaValue *len = ssa_slice_len(proc, slice); + ssaValue *cap = ssa_slice_cap(proc, slice); Type *elem_type = type_deref(ssa_type(elem)); diff --git a/src/parser.cpp b/src/parser.cpp index ec95e2926..3dd92d096 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -106,6 +106,7 @@ AST_NODE_KIND(_ExprBegin, "", struct{}) \ AstNode *proc, *arg_list; \ isize arg_list_count; \ Token open, close; \ + Token ellipsis; \ CallExprKind kind; \ }) \ AST_NODE_KIND(SliceExpr, "slice expression", struct { \ @@ -511,13 +512,14 @@ gb_inline AstNode *make_paren_expr(AstFile *f, AstNode *expr, Token open, Token return result; } -gb_inline AstNode *make_call_expr(AstFile *f, AstNode *proc, AstNode *arg_list, isize arg_list_count, Token open, Token close) { +gb_inline AstNode *make_call_expr(AstFile *f, AstNode *proc, AstNode *arg_list, isize arg_list_count, Token open, Token close, Token ellipsis) { AstNode *result = make_node(f, AstNode_CallExpr); result->CallExpr.proc = proc; result->CallExpr.arg_list = arg_list; result->CallExpr.arg_list_count = arg_list_count; - result->CallExpr.open = open; - result->CallExpr.close = close; + result->CallExpr.open = open; + result->CallExpr.close = close; + result->CallExpr.ellipsis = ellipsis; return result; } @@ -1296,15 +1298,22 @@ AstNode *parse_call_expr(AstFile *f, AstNode *operand) { AstNode *arg_list_curr = NULL; isize arg_list_count = 0; Token open_paren, close_paren; + Token ellipsis = {}; f->expr_level++; open_paren = expect_token(f, Token_OpenParen); while (f->cursor[0].kind != Token_CloseParen && - f->cursor[0].kind != Token_EOF) { + f->cursor[0].kind != Token_EOF && + ellipsis.pos.line == 0) { if (f->cursor[0].kind == Token_Comma) ast_file_err(f, f->cursor[0], "Expected an expression not a ,"); + if (f->cursor[0].kind == Token_Ellipsis) { + ellipsis = f->cursor[0]; + next_token(f); + } + DLIST_APPEND(arg_list, arg_list_curr, parse_expr(f, false)); arg_list_count++; @@ -1319,7 +1328,7 @@ AstNode *parse_call_expr(AstFile *f, AstNode *operand) { f->expr_level--; close_paren = expect_token(f, Token_CloseParen); - return make_call_expr(f, operand, arg_list, arg_list_count, open_paren, close_paren); + return make_call_expr(f, operand, arg_list, arg_list_count, open_paren, close_paren, ellipsis); } AstNode *parse_atom_expr(AstFile *f, b32 lhs) { @@ -1335,7 +1344,7 @@ AstNode *parse_atom_expr(AstFile *f, b32 lhs) { // TODO(bill): Handle this } AstNode *proc = parse_identifier(f); - operand = make_call_expr(f, proc, operand, 1, ast_node_token(operand), op); + operand = make_call_expr(f, proc, operand, 1, ast_node_token(operand), op, empty_token); } break; case Token_OpenParen: { @@ -1473,7 +1482,7 @@ AstNode *parse_binary_expr(AstFile *f, b32 lhs, i32 prec_in) { AstNode *proc = parse_identifier(f); AstNode *right = parse_binary_expr(f, false, prec+1); expression->next = right; - expression = make_call_expr(f, proc, expression, 2, op, ast_node_token(right)); + expression = make_call_expr(f, proc, expression, 2, op, ast_node_token(right), empty_token); continue; } break;