Initial Demo001 code for tour of language

This commit is contained in:
Ginger Bill
2016-08-19 15:35:48 +01:00
parent ddb15e73c0
commit 745237459a
7 changed files with 582 additions and 38 deletions

View File

@@ -45,7 +45,7 @@ pushd %build_dir%
cl %compiler_settings% "..\src\main.cpp" ^
/link %linker_settings% -OUT:%exe_name% ^
&& odin run ..\examples/main.odin
&& odin run ..\examples/demo001.odin
:do_not_compile_exe

525
examples/demo001.odin Normal file
View File

@@ -0,0 +1,525 @@
#load "basic.odin"
#load "math.odin"
// #load "game.odin"
main :: proc() {
_ = hellope();
procedures();
variables();
constants();
types();
data_control();
// run_game();
}
hellope :: proc() -> int {
print_string("Hellope, 世界\n");
return 1;
}
apple, banana, carrot: bool;
box, carboard: bool = true, false;
hellope_value := hellope();
variables :: proc() {
i: int; // initialized with zero value
j: int = 1;
x, y: int = 1, 2;
// Type inference
apple, banana, carrot := true, 123, "carrot";
// Basic Types of the Language
//
// bool
//
// i8 i16 i32 i64 i128
// u8 u16 u32 u64 u128
//
// f32 f64
//
// int uint (size_of(int) = size_of(rawptr))
//
// rawptr
//
// string
//
// byte - alias for u8
// rune - alias for i32 // Unicode Codepoint
//
// untyped bool - "untyped" types can implicitly convert to any of the "typed" types
// untyped integer
// untyped float
// untyped pointer
// untyped string
// untyped rune
// // Zero values
zero_numeric := 0;
zero_boolean := false;
zero_pointer := null;
zero_string1 := ""; // Escaped string
zero_string2 := ``; // Raw string
// Unary operators
// +a
// -a
// ~a
// !a
// Binary operators
// a + b
// a - b
// a ~ b
// a | b
// a * b
// a / b
// a % b
// a & b
// a &~ b == a & (~b)
// a << b
// a >> b
// a as Type
// a transmute Type
// a == b
// a != b
// a < b
// a > b
// a <= b
// a >= b
}
procedures :: proc() {
add :: proc(x: int, y: int) -> int {
return x + y;
}
print_int(add(3, 4)); // 7
print_rune('\n');
add_v2 :: proc(x, y: int) -> int {
return x + y;
}
swap_strings :: proc(x, y: string) -> (string, string) {
return y, x;
}
a, b := swap_strings("Hellope\n", "World\n");
print_string(a);
print_string(b);
a, b = b, a; // Quirk of grammar the of multiple assignments
print_string(a);
print_string(b);
// Not hints, it's mandatory
proc1 :: proc(a, b: int) #inline {
print_int(a + b);
}
proc2 :: proc(a, b: int) #no_inline {
print_int(a + b);
}
}
TAU :: 6.28318530718;
constants :: proc() {
TAU :: 6.28318530718; // untyped float
WORLD_JAPANESE :: "世界"; // untyped string
TAU_32 : f32 : 6.28318530718;
TAU_AS_32 :: 6.28318530718 as f32;
}
nl :: proc() { print_rune('\n'); }
types :: proc() {
x: int = 123;
y := x; // y: int = x;
// z: f32 = x; // invalid
z: f32 = x as f32;
ptr_z := ^z; // Pascal notation
ptr_z^ = 123; // Derefence Notation
print_f32(z); nl();
// ^z - pointer to z
// z^ - z from pointer
f32_array: [12]f32; // Array of 12 f32
f32_array[0] = 2;
f32_array[1] = 3;
// f32_array[-1] = 2; // Error - compile time check
// f32_array[13] = 2; // Error - compile time check
f32_array_len := len(f32_array); // builtin procedure
f32_array_cap := cap(f32_array); // == len(f32_array)
api: [2]^f32;
papi: ^[2]^f32;
f32_slice: []f32; // Array reference
f32_slice = f32_array[0:5];
f32_slice = f32_array[:5];
f32_slice = f32_array[:]; // f32_array[0:len(f32_array)-1];
f32_slice = f32_array[1:5:7]; // low:1, high:5, capacity:7
append_success := append(^f32_slice, 1);
_ = append(^f32_slice, 2);
_ = copy(f32_array[0:2], f32_array[2:4]); // You can use memcpy/memmove if you want
s := "Hellope World";
sub_string := s[5:10];
v0: {4}f32; // Vector of 4 f32
v0[0] = 1;
v0[1] = 3;
v0[2] = 6;
v0[3] = 10;
v1 := v0 + v0; // Simd Arithmetic
v1 = v1 - v0;
v1 *= v0; // i.e. hadamard product
v1 /= v0;
// builtin procedure
v2 := swizzle(v0, 3, 2, 1, 0); // {10, 6, 3, 1}
v3: {4}bool = v0 == v2;
// LLVM rant?
type Vec4: {4}f32;
type Array3Int: [3]int;
type Vec3: struct {
x, y, z: f32
}
type BinaryNode: struct {
left, right: ^BinaryNode, // same format as procedure argument
data: rawptr,
}
type AddProc: proc(a, b: int) -> int
type Packed: struct #packed {
a: u8,
b: u16,
c: u32,
}
static_assert(size_of(Packed) == 7);
{
type MyInt: int
x: int = 1;
y: MyInt = 2;
// z := x + y; // Failure - types cannot implicit convert*
z := x as MyInt + y; // Type cast using `as`
}
{
// From: Quake III Arena
Q_rsqrt :: proc(number: f32) -> f32 {
i: i32;
x2, y: f32;
THREE_HALFS :: 1.5;
x2 = number * 0.5;
y = number;
i = (^y as ^i32)^; // evil floating point bit level hacking
i = 0x5f3759df - i>>1; // what the fuck?
y = (^i as ^f32)^;
y = y * (THREE_HALFS - (x2 * y *y)); // 1st iteration
// y = y * (THREE_HALFS - (x2 * y *y)); // 2nd iteration, this can be removed
return y;
}
Q_rsqrt_v2 :: proc(number: f32) -> f32 {
THREE_HALFS :: 1.5;
x2 := number * 0.5;
y := number;
i := y transmute i32; // evil floating point bit level hacking
i = 0x5f3759df - i>>1; // what the fuck?
y = i transmute f32;
y = y * (THREE_HALFS - (x2 * y *y)); // 1st iteration
// y = y * (THREE_HALFS - (x2 * y *y)); // 2nd iteration, this can be removed
return y;
}
// transmute only works if the size of the types are equal
/{
// in C
union {
i32 i;
f32 y;
};
}/
}
{ // Compound Literals
a := [3]int{1, 2, 3};
b := [3]int{};
c := [..]int{1, 2, 3};
d := []int{1, 2, 3}; // slice
e := {4}f32{1, 2, 3, 4};
f := {4}f32{1}; // broadcasts to all
// g := {4}f32{1, 2}; // require either 1 or 4 elements
type Vec2: {2}f32;
h := Vec2{1, 2};
i := Vec2{5} * h; // For strong type safety
// FORENOTE: 5 * h was originally allowed but it was an edge case in the
// compiler I didn't think it was enough to justify have it it.
print_f32(i[0]); print_rune(',');
print_f32(i[1]); print_rune('\n');
}
{
do_thing :: proc(p: proc(a, b: int) -> int) {
print_int(p(3, 4)); nl();
}
add :: proc(a, b: int) -> int {
return a + b;
}
add_lambda := proc(a, b: int) -> int {
return a - b;
}; // note semicolon
do_thing(add);
do_thing(add_lambda);
do_thing(proc(a, b: int) -> int {
return a * b;
});
}
{ // strings and runes
escaped := "Hellope World\n";
raw := `Hellope World\n`;
print_string(escaped);
print_string(raw); nl();
// Crap shader example
shader_string :=
`#version 410
layout (location = 0) in vec3 a_position;
layout (location = 1) in vec3 a_normal;
layout (location = 2) in vec2 a_tex_coord;
out vec3 v_position;
out vec3 v_normal;
out vec2 v_tex_coord;
uniform mat4 u_model_view;
uniform mat3 u_normal;
uniform mat4 u_proj;
uniform mat4 u_mvp;
void main() {
v_tex_coord = a_tex_coord;
v_normal = normalize(u_normal * a_normal);
v_position = vec3(u_model_view * vec4(a_position, 1.0));
gl_Position = u_mvp * vec4(a_position, 1.0);
}`;
knot1 := '⌘';
knot2 := '\u2318'; // 16 bit
knot3 := '\U00002318'; // 32 bit
knot4 := "\xe2\x8c\x98"; // Note it's a string, should I allow untyped string -> untyped rune casts?
// String ideas "nicked" from Go, so far. I think I might change how some of it works later.
}
{ // size, align, offset
type Thing: struct {
a: u8,
b: u16,
c, d, e: u32,
}
s := size_of(Thing);
a := align_of(Thing);
o := offset_of(Thing, b);
t: Thing;
sv := size_of_val(t);
av := align_of_val(t);
ov := offset_of_val(t.b);
}
}
data_control :: proc() {
sum := 0;
for i := 0; i < 12; i++ {
sum += 1;
}
print_string("sum = "); print_int(sum); nl();
sum = 1;
for ; sum < 1000000; {
sum += sum;
}
print_string("sum = "); print_int(sum); nl();
sum = 1;
for sum < 1000000 {
sum += sum;
}
print_string("sum = "); print_int(sum); nl();
// loop
// for { } == for true {}
// Question: Should I separate all these concepts and rename it?
//
// range - iterable
// for - c style
// while
// loop - while true
// Notes:
// conditions _must_ a boolean expression
// i++ and i-- are statements, not expressions
x := 2;
if x < 3 {
print_string("x < 2\n");
}
// Unified initializer syntax - same as for statements
if x := 2; x < 3 {
print_string("x < 2\n");
}
if x := 4; x < 3 {
print_string("Never called\n");
} else {
print_string("This is called\n");
}
{ // String comparison
a := "Hellope";
b := "World";
if a < b {
print_string("a < b\n");
}
if a != b {
print_string("a != b\n");
}
}
{
defer print_string("日本語\n");
print_string("Japanese\n");
}
{
defer print_string("1\n");
defer print_string("2\n");
defer print_string("3\n");
}
{
// C strings, yuk!
to_c_string :: proc(s: string) -> ^u8 {
c := heap_alloc(len(s)+1) as ^u8;
mem_copy(c, ^s[0], len(s));
c[len(s)] = 0;
return c;
}
fopen :: proc(filename, mode: ^u8) -> rawptr #foreign
fclose :: proc(f: rawptr) -> i32 #foreign
filename := to_c_string("../examples/base.odin");
mode := to_c_string("rb");
defer heap_free(filename);
defer heap_free(mode);
f := fopen(filename, mode);
if f == null {
// handle error
}
defer if f != null {
_ = fclose(f);
}
// rest of code
// Better version
/{
type File: struct { filename: string }
type FileError: int
open_file :: proc(filename: string) -> (File, FileError) { ... }
close_file :: proc(f: ^File) { ... }
f, err := open_file("Test");
if err != 0 {
// handle error
}
defer close_file(^f);
}/
}
for i := 0; i < 100; i++ {
blah := heap_alloc(100 * size_of(int)) as ^int;
defer {
defer print_string("!");
defer print_string("heap_free");
heap_free(blah);
}
if i == 3 {
// defers called
continue;
}
if i == 5 {
// defers called
return;
}
if i == 8 {
// defers called
break; // never happens
}
}
defer print_string("It'll never happen, mate 1");
print_string("It'll never happen, mate 2");
print_string("It'll never happen, mate 3");
}

View File

@@ -125,8 +125,7 @@ display_window :: proc(w: ^Window) {
main :: proc() {
run_game :: proc() {
win32_proc :: proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT #no_inline {
if msg == WM_DESTROY || msg == WM_CLOSE || msg == WM_QUIT {
ExitProcess(0);
@@ -134,9 +133,7 @@ main :: proc() {
}
return DefWindowProcA(hwnd, msg, wparam, lparam);
}
print_f64(13.37);
print_rune('\n');
/*
window, window_success := make_window("Odin Language Demo", 854, 480, win32_proc);
if !window_success {
return;
@@ -189,5 +186,4 @@ main :: proc() {
sleep_ms(ms_to_sleep);
}
}
*/
}

View File

@@ -196,10 +196,13 @@ void ssa_print_type(gbFile *f, BaseTypeSizes s, Type *t) {
}
void ssa_print_exact_value(gbFile *f, ssaModule *m, ExactValue value, Type *type) {
type = get_base_type(type);
if (is_type_float(type)) {
value = exact_value_to_float(value);
} else if (is_type_integer(type)) {
value = exact_value_to_integer(value);
} else if (is_type_pointer(type)) {
value = exact_value_to_integer(value);
}
switch (value.kind) {
@@ -212,7 +215,7 @@ void ssa_print_exact_value(gbFile *f, ssaModule *m, ExactValue value, Type *type
ssa_fprintf(f, "\"");
} break;
case ExactValue_Integer: {
if (is_type_pointer(get_base_type(type))) {
if (is_type_pointer(type)) {
if (value.value_integer == 0) {
ssa_fprintf(f, "null");
} else {
@@ -235,14 +238,14 @@ void ssa_print_exact_value(gbFile *f, ssaModule *m, ExactValue value, Type *type
ssa_fprintf(f, "0x%016llx", u);
} break;
case ExactValue_Pointer:
if (value.value_float == NULL) {
if (value.value_pointer == NULL) {
ssa_fprintf(f, "null");
} else {
GB_PANIC("TODO(bill): ExactValue_Pointer");
}
break;
default:
GB_PANIC("Invalid ExactValue");
GB_PANIC("Invalid ExactValue: %d", value.kind);
break;
}
}

View File

@@ -908,7 +908,9 @@ ssaValue *ssa_lvalue_store(ssaProcedure *proc, ssaLvalue lval, ssaValue *value)
if (lval.is_vector) {
// HACK(bill): Fix how lvalues for vectors work
ssaValue *v = ssa_emit_load(proc, lval.address);
ssaValue *out = ssa_emit(proc, ssa_make_instr_insert_element(proc, v, value, lval.index));
Type *elem_type = get_base_type(ssa_value_type(v))->vector.elem;
ssaValue *elem = ssa_emit_conv(proc, value, elem_type);
ssaValue *out = ssa_emit(proc, ssa_make_instr_insert_element(proc, v, elem, lval.index));
return ssa_emit_store(proc, lval.address, out);
}
return ssa_emit_store(proc, lval.address, value);
@@ -1401,22 +1403,22 @@ ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *t) {
return ssa_emit_load(proc, slice);
}
if (is_type_vector(dst)) {
Type *dst_elem = dst->vector.elem;
value = ssa_emit_conv(proc, value, dst_elem);
ssaValue *v = ssa_add_local_generated(proc, t);
v = ssa_emit_load(proc, v);
v = ssa_emit(proc, ssa_make_instr_insert_element(proc, v, value, v_zero32));
// NOTE(bill): Broadcast lowest value to all values
isize index_count = dst->vector.count;
i32 *indices = gb_alloc_array(proc->module->allocator, i32, index_count);
for (isize i = 0; i < index_count; i++) {
indices[i] = 0;
}
// if (is_type_vector(dst)) {
// Type *dst_elem = dst->vector.elem;
// value = ssa_emit_conv(proc, value, dst_elem);
// ssaValue *v = ssa_add_local_generated(proc, t);
// v = ssa_emit_load(proc, v);
// v = ssa_emit(proc, ssa_make_instr_insert_element(proc, v, value, v_zero32));
// // NOTE(bill): Broadcast lowest value to all values
// isize index_count = dst->vector.count;
// i32 *indices = gb_alloc_array(proc->module->allocator, i32, index_count);
// for (isize i = 0; i < index_count; i++) {
// indices[i] = 0;
// }
v = ssa_emit(proc, ssa_make_instr_shuffle_vector(proc, v, indices, index_count));
return v;
}
// v = ssa_emit(proc, ssa_make_instr_shuffle_vector(proc, v, indices, index_count));
// return v;
// }
gb_printf_err("Not Identical %s != %s\n", type_to_string(src_type), type_to_string(t));
@@ -1606,10 +1608,10 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
for (AstNode *elem = cl->elem_list;
elem != NULL;
elem = elem->next, index++) {
ssaValue *field_expr = ssa_build_expr(proc, elem);
Type *t = ssa_value_type(field_expr);
ssaValue *field_elem = ssa_build_expr(proc, elem);
Type *t = ssa_value_type(field_elem);
GB_ASSERT(t->kind != Type_Tuple);
ssaValue *ev = ssa_emit_conv(proc, field_expr, et);
ssaValue *ev = ssa_emit_conv(proc, field_elem, et);
ssaValue *i = ssa_make_value_constant(proc->module->allocator, t_int, make_exact_value_integer(index));
result = ssa_emit(proc, ssa_make_instr_insert_element(proc, result, ev, i));
}
@@ -1619,7 +1621,9 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
for (isize i = 0; i < index_count; i++) {
indices[i] = 0;
}
return ssa_emit(proc, ssa_make_instr_shuffle_vector(proc, result, indices, index_count));
ssaValue *sv = ssa_emit(proc, ssa_make_instr_shuffle_vector(proc, result, indices, index_count));
ssa_emit_store(proc, v, sv);
return ssa_emit_load(proc, v);
}
return result;
@@ -1761,15 +1765,20 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
AstNode *sptr_node = ce->arg_list;
AstNode *item_node = ce->arg_list->next;
ssaValue *slice = ssa_build_addr(proc, sptr_node).address;
ssaValue *item_value = ssa_build_expr(proc, item_node);
Type *item_type = ssa_value_type(item_value);
ssaValue *item = ssa_add_local_generated(proc, item_type);
ssa_emit_store(proc, item, item_value);
ssaValue *elem = ssa_slice_elem(proc, slice);
ssaValue *len = ssa_slice_len(proc, slice);
ssaValue *cap = ssa_slice_cap(proc, slice);
Type *elem_type = type_deref(get_base_type(ssa_value_type(elem)));
ssaValue *item_value = ssa_build_expr(proc, item_node);
item_value = ssa_emit_conv(proc, item_value, elem_type);
ssaValue *item = ssa_add_local_generated(proc, elem_type);
ssa_emit_store(proc, item, item_value);
// NOTE(bill): Check if can append is possible
Token lt = {Token_Lt};
ssaValue *cond = ssa_emit_comp(proc, lt, len, cap);
@@ -1781,9 +1790,13 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
// Add new slice item
ssaValue *offset = ssa_emit_ptr_offset(proc, elem, len);
i64 item_size = type_size_of(proc->module->sizes, proc->module->allocator, item_type);
i64 item_size = type_size_of(proc->module->sizes, proc->module->allocator, elem_type);
ssaValue *byte_count = ssa_make_value_constant(proc->module->allocator, t_int,
make_exact_value_integer(item_size));
offset = ssa_emit_conv(proc, offset, t_rawptr);
item = ssa_emit_ptr_offset(proc, item, v_zero);
ssa_value_set_type(item, make_type_pointer(proc->module->allocator, ssa_value_type(item)));
item = ssa_emit_conv(proc, item, t_rawptr);
ssa_emit(proc, ssa_make_instr_copy_memory(proc, offset, item, byte_count, 1, false));
// Increment slice length
@@ -1847,6 +1860,11 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
}
}
auto *pt = &proc_type_->proc.params->tuple;
for (isize i = 0; i < arg_count; i++) {
args[i] = ssa_emit_conv(proc, args[i], pt->variables[i]->type);
}
ssaValue *call = ssa_make_instr_call(proc, value, args, arg_count, type->results);
return ssa_emit(proc, call);
case_end;

View File

@@ -108,6 +108,8 @@ ExactValue exact_value_to_integer(ExactValue v) {
return v;
case ExactValue_Float:
return make_exact_value_integer(cast(i64)v.value_float);
case ExactValue_Pointer:
return make_exact_value_integer(cast(i64)cast(intptr)v.value_pointer);
}
ExactValue r = {ExactValue_Invalid};
return r;

View File

@@ -371,18 +371,18 @@ void tokenizer_skip_whitespace(Tokenizer *t) {
if (t->read_curr[0] == '/') { // Line comment //
while (t->curr_rune != '\n')
advance_to_next_rune(t);
} else if (t->read_curr[0] == '*') { // (Nested) Block comment /**/
} else if (t->read_curr[0] == '{') { // (Nested) Block comment /{}/
isize comment_scope = 1;
for (;;) {
advance_to_next_rune(t);
if (t->curr_rune == '/') {
advance_to_next_rune(t);
if (t->curr_rune == '*') {
if (t->curr_rune == '{') {
advance_to_next_rune(t);
comment_scope++;
}
}
if (t->curr_rune == '*') {
if (t->curr_rune == '}') {
advance_to_next_rune(t);
if (t->curr_rune == '/') {
advance_to_next_rune(t);