From 664c2cd7a587feb18f02378506bdade2503343d3 Mon Sep 17 00:00:00 2001 From: Ginger Bill Date: Wed, 21 Sep 2016 23:26:31 +0100 Subject: [PATCH] Fix enum type comparison; Start demo 003 code --- README.md | 7 + code/demo.odin | 308 ++++++++++++++++++++++++++++++++++++---- code/game.odin | 2 +- code/math.odin | 8 +- code/test.odin | 35 ++++- core/win32.odin | 2 +- src/checker/checker.cpp | 2 +- src/checker/type.cpp | 8 +- src/codegen/ssa.cpp | 3 +- src/main.cpp | 2 +- src/parser.cpp | 32 ++++- 11 files changed, 361 insertions(+), 48 deletions(-) diff --git a/README.md b/README.md index c553d2296..81daa4303 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,13 @@ Odin in an open source programming language that is simple to read, comprehend and reason with. +## Requirements + +* x86-64 +* Windows +* MSVC installed +* call `vcvarsall.bat` to setup the path + ## Warnings * This is still highly in development and the language's design is quite volatile. diff --git a/code/demo.odin b/code/demo.odin index 08f3dedde..19d997c33 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -2,33 +2,293 @@ #import "os.odin" + main :: proc() { - Fruit :: enum { - APPLE, - BANANA, - GRAPE, - MELON, - PEACH, - TOMATO, - } - - fruit_ti := type_info(Fruit) - name := (fruit_ti as ^Type_Info.Named).name // Unsafe casts - info := type_info_base(fruit_ti) as ^Type_Info.Enum // Unsafe casts - - fmt.printf("% :: enum ", name); - fmt.fprint_type(os.stdout, info.base) - fmt.printf(" {\n") - for i := 0; i < info.values.count; i++ { - fmt.printf("\t%\t= %,\n", info.names[i], info.values[i]) - } - fmt.printf("}\n") - - Vector3 :: struct {x, y, z: f32} - v := Vector3{x = 1, y = 4, z = 9} - fmt.println(v) + // struct_padding() + // bounds_checking() + // type_introspection() + // any_type() + crazy_introspection() + // namespaces_and_files() + // miscellany() } +struct_padding :: proc() { + { + A :: struct { + a: u8 + b: u32 + c: u16 + } + + B :: struct { + a: [7]u8 + b: [3]u16 + c: u8 + d: u16 + } + + fmt.println("size_of(A):", size_of(A)) + fmt.println("size_of(B):", size_of(B)) + + // n.b. http://cbloomrants.blogspot.co.uk/2012/07/07-23-12-structs-are-not-what-you-want.html + } + { + A :: struct #ordered { + a: u8 + b: u32 + c: u16 + } + + B :: struct #ordered { + a: [7]u8 + b: [3]u16 + c: u8 + d: u16 + } + + fmt.println("size_of(A):", size_of(A)) + fmt.println("size_of(B):", size_of(B)) + + // C-style structure layout + } + { + A :: struct #packed { + a: u8 + b: u32 + c: u16 + } + + B :: struct #packed { + a: [7]u8 + b: [3]u16 + c: u8 + d: u16 + } + + fmt.println("size_of(A):", size_of(A)) + fmt.println("size_of(B):", size_of(B)) + + // Useful for explicit layout + } + + // Member sorting by priority + // Alignment desc. + // Size desc. + // source order asc. + + /* + A :: struct { + a: u8 + b: u32 + c: u16 + } + + B :: struct { + a: [7]u8 + b: [3]u16 + c: u8 + d: u16 + } + + Equivalent too + + A :: struct #ordered { + b: u32 + c: u16 + a: u8 + } + + B :: struct #ordered { + b: [3]u16 + d: u16 + a: [7]u8 + c: u8 + } + */ +} + +bounds_checking :: proc() { + x: [4]int + // x[-1] = 0; // Compile Time + // x[4] = 0; // Compile Time + + /*{ + a, b := -1, 4; + x[a] = 0; // Runtime Time + x[b] = 0; // Runtime Time + }*/ + + // Works for arrays, strings, slices, and related procedures & operations + + { + base: [10]int + s := base[2:6] + a, b := -1, 6 + + #no_bounds_check { + s[a] = 0; + // #bounds_check s[b] = 0; + } + + #no_bounds_check + if s[a] == 0 { + // Do whatever + } + + // Bounds checking can be toggled explicit + // on a per statement basis. + // _any statement_ + } +} + +type_introspection :: proc() { + + info: ^Type_Info + x: int + + info = type_info(int) // by type + info = type_info(x) // by value + // See: runtime.odin + + match type i : info { + case Type_Info.Integer: + fmt.println("integer!") + case Type_Info.Float: + fmt.println("float!") + default: + fmt.println("potato!") + } + + // Unsafe cast + integer_info := info as ^Type_Info.Integer +} + +any_type :: proc() { + a: any + + x := 123 + y := 6.28 + z := "Yo-Yo Ma" + // All types can be implicit cast to `any` + a = x + a = y + a = z + a = a + + // any has two members + // data - rawptr to the data + // type_info - pointer to the type info + + fmt.println(x, y, z) + // See: Implementation +} + +crazy_introspection :: proc() { + { + Fruit :: enum { + APPLE, + BANANA, + GRAPE, + MELON, + PEACH, + TOMATO, + } + + s: string + s = enum_to_string(Fruit.PEACH) + fmt.println(s) + + f := Fruit.GRAPE + s = enum_to_string(f) + fmt.println(s) + + fmt.println(f) + } + + + { + // NOTE(bill): This is not safe code and I would not recommend this at all + // I'd recommend you use `match type` to get the subtype rather than + // casting pointers + + Fruit :: enum { + APPLE, + BANANA, + GRAPE, + MELON, + PEACH, + TOMATO, + } + + fruit_ti := type_info(Fruit) + name := (fruit_ti as ^Type_Info.Named).name // Unsafe casts + info := type_info_base(fruit_ti) as ^Type_Info.Enum // Unsafe casts + + fmt.printf("% :: enum ", name); + fmt.fprint_type(os.stdout, info.base) + fmt.printf(" {\n") + for i := 0; i < info.values.count; i++ { + fmt.printf("\t%\t= %,\n", info.names[i], info.values[i]) + } + fmt.printf("}\n") + } + + { + Vector3 :: struct {x, y, z: f32} + + a := Vector3{x = 1, y = 4, z = 9} + fmt.println(a) + b := Vector3{x = 9, y = 3, z = 1} + fmt.println(b) + + // NOTE(bill): See fmt.odin + } + + // n.b. This pretty much "solves" serialization (to strings) +} + + +namespaces_and_files :: proc() { + /* + // Non-exporting import + #import "file.odin" + #import "file.odin" as file + #import "file.odin" as . + #import "file.odin" as _ + + // Exporting import + #load "file.odin" + */ + + // Talk about scope rules and diagram +} + +miscellany :: proc() { + /* + win32 `__imp__` prefix + #dll_import + #dll_export + + Change exported name/symbol for linking + #link_name + + Custom calling conventions + #stdcall + #fastcall + + Runtime stuff + #shared_global_scope + */ + + // assert(false) + // compile_assert(false) + // panic("Panic message goes here") +} + + + + // #import "fmt.odin" as fmt diff --git a/code/game.odin b/code/game.odin index fd1bcfa70..123f89982 100644 --- a/code/game.odin +++ b/code/game.odin @@ -206,7 +206,7 @@ run :: proc() { display_window(^window) ms_to_sleep := (16 - 1000*dt) as i32 if ms_to_sleep > 0 { - sleep_ms(ms_to_sleep) + win32.Sleep(ms_to_sleep) } } } diff --git a/code/math.odin b/code/math.odin index 5fea41adc..e9554f6b5 100644 --- a/code/math.odin +++ b/code/math.odin @@ -96,7 +96,7 @@ remainder :: proc(x, y: f32) -> f32 { fmod :: proc(x, y: f32) -> f32 { y = abs(y) result := remainder(abs(x), y) - if fsign(result) < 0 { + if sign32(result) < 0 { result += y } return copy_sign(result, x) @@ -120,9 +120,9 @@ cross :: proc(x, y: Vec3) -> Vec3 { } -vec2_mag :: proc(v: Vec2) -> f32 { return fsqrt(dot2(v, v)) } -vec3_mag :: proc(v: Vec3) -> f32 { return fsqrt(dot3(v, v)) } -vec4_mag :: proc(v: Vec4) -> f32 { return fsqrt(dot4(v, v)) } +vec2_mag :: proc(v: Vec2) -> f32 { return sqrt32(dot2(v, v)) } +vec3_mag :: proc(v: Vec3) -> f32 { return sqrt32(dot3(v, v)) } +vec4_mag :: proc(v: Vec4) -> f32 { return sqrt32(dot4(v, v)) } vec2_norm :: proc(v: Vec2) -> Vec2 { return v / Vec2{vec2_mag(v)} } vec3_norm :: proc(v: Vec3) -> Vec3 { return v / Vec3{vec3_mag(v)} } diff --git a/code/test.odin b/code/test.odin index b99a832c1..48f992ffa 100644 --- a/code/test.odin +++ b/code/test.odin @@ -1,5 +1,38 @@ #import "fmt.odin" -thing :: proc() #link_name "frankerooney" { +thing :: proc() { fmt.println("Hello!") } + +/* +#import "fmt.odin" as fmt + +thing :: proc() { + fmt.println("Hello!") +} +*/ + +/* +#import "fmt.odin" as . + +thing :: proc() { + println("Hello!") +} +*/ + +/* +#import "fmt.odin" as _ + +thing :: proc() { + // println("Hello!") +} +*/ + + +/* +#load "fmt.odin" + +thing :: proc() { + println("Hello!") +} +*/ diff --git a/core/win32.odin b/core/win32.odin index a1fac63f0..e5301edd4 100644 --- a/core/win32.odin +++ b/core/win32.odin @@ -22,7 +22,7 @@ INVALID_HANDLE_VALUE :: (-1 as int) as HANDLE CS_VREDRAW :: 0x0001 CS_HREDRAW :: 0x0002 CS_OWNDC :: 0x0020 -CW_USEDEFAULT :: 0x80000000 +CW_USEDEFAULT :: -0x80000000 WS_OVERLAPPED :: 0 WS_MAXIMIZEBOX :: 0x00010000 diff --git a/src/checker/checker.cpp b/src/checker/checker.cpp index 6a209cf08..bb093de0d 100644 --- a/src/checker/checker.cpp +++ b/src/checker/checker.cpp @@ -418,7 +418,7 @@ Entity *scope_insert_entity(Scope *s, Entity *entity) { void check_scope_usage(Checker *c, Scope *scope) { // TODO(bill): Use this? -#if 1 +#if 0 gb_for_array(i, scope->elements.entries) { auto *entry = scope->elements.entries + i; Entity *e = entry->value; diff --git a/src/checker/type.cpp b/src/checker/type.cpp index c8fe672f7..ae415b3d5 100644 --- a/src/checker/type.cpp +++ b/src/checker/type.cpp @@ -599,12 +599,8 @@ b32 are_types_identical(Type *x, Type *y) { break; case TypeRecord_Enum: - if (are_types_identical(x->Record.enum_base, y->Record.enum_base)) { - if (x->Record.field_count == y->Record.field_count) { - return x->Record.fields == y->Record.fields; - } - } - return false; + // NOTE(bill): Each enum is unique + return x == y; } } } diff --git a/src/codegen/ssa.cpp b/src/codegen/ssa.cpp index b45bbe5d5..959e3faf8 100644 --- a/src/codegen/ssa.cpp +++ b/src/codegen/ssa.cpp @@ -1348,9 +1348,8 @@ isize ssa_type_info_index(CheckerInfo *info, Type *type) { } } if (entry_index < 0) { - gb_printf_err("%s\n", type_to_string(type)); + compiler_error("Type_Info for `%s` could not be found", type_to_string(type)); } - GB_ASSERT(entry_index >= 0); return entry_index; } diff --git a/src/main.cpp b/src/main.cpp index e4bf5fb7d..1e0528863 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -22,7 +22,7 @@ i32 win32_exec_command_line_app(char *fmt, ...) { va_end(va); if (CreateProcessA(NULL, cmd_line, - NULL, NULL, true, 0, NULL, NULL, + NULL, NULL, true, 0, NULL, NULL, &start_info, &pi)) { WaitForSingleObject(pi.hProcess, INFINITE); diff --git a/src/parser.cpp b/src/parser.cpp index 2ae1dd2aa..0fcb7110a 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1499,7 +1499,14 @@ AstNode *parse_atom_expr(AstFile *f, b32 lhs) { case Token_OpenBrace: { if (!lhs && is_literal_type(operand) && f->expr_level >= 0) { - operand = parse_literal_value(f, operand); + if (f->cursor[0].pos.line == f->cursor[-1].pos.line) { + // TODO(bill): This is a hack due to optional semicolons + // TODO(bill): It's probably much better to solve this by changing + // the syntax for struct literals and array literals + operand = parse_literal_value(f, operand); + } else { + loop = false; + } } else { loop = false; } @@ -1553,13 +1560,24 @@ AstNode *parse_binary_expr(AstFile *f, b32 lhs, i32 prec_in) { switch (op.kind) { case Token_DoublePrime: { + // TODO(bill): Properly define semantic for in-fix and post-fix calls AstNode *proc = parse_identifier(f); - AstNode *right = parse_binary_expr(f, false, prec+1); - gbArray(AstNode *) args; - gb_array_init_reserve(args, gb_arena_allocator(&f->arena), 2); - gb_array_append(args, expression); - gb_array_append(args, right); - expression = make_call_expr(f, proc, args, op, ast_node_token(right), empty_token); + /* if (f->cursor[0].kind == Token_OpenParen) { + AstNode *call = parse_call_expr(f, proc); + gb_array_append(call->CallExpr.args, expression); + for (isize i = gb_array_count(call->CallExpr.args)-1; i > 0; i--) { + gb_swap(AstNode *, call->CallExpr.args[i], call->CallExpr.args[i-1]); + } + + expression = call; + } else */{ + AstNode *right = parse_binary_expr(f, false, prec+1); + gbArray(AstNode *) args; + gb_array_init_reserve(args, gb_arena_allocator(&f->arena), 2); + gb_array_append(args, expression); + gb_array_append(args, right); + expression = make_call_expr(f, proc, args, op, ast_node_token(right), empty_token); + } continue; } break;