demo.odin 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845
  1. package main
  2. import "core:fmt"
  3. import "core:strconv"
  4. import "core:mem"
  5. import "core:bits"
  6. import "core:hash"
  7. import "core:math"
  8. import "core:math/rand"
  9. import "core:os"
  10. import "core:sort"
  11. import "core:strings"
  12. import "core:types"
  13. import "core:unicode/utf16"
  14. import "core:unicode/utf8"
  15. import "core:c"
  16. import "core:runtime"
  17. when os.OS == "windows" {
  18. import "core:thread"
  19. import "core:sys/win32"
  20. }
  21. @(link_name="general_stuff")
  22. general_stuff :: proc() {
  23. fmt.println("# general_stuff");
  24. { // `do` for inline statements rather than block
  25. foo :: proc() do fmt.println("Foo!");
  26. if false do foo();
  27. for false do foo();
  28. when false do foo();
  29. if false do foo();
  30. else do foo();
  31. }
  32. { // Removal of `++` and `--` (again)
  33. x: int;
  34. x += 1;
  35. x -= 1;
  36. }
  37. { // Casting syntaxes
  38. i := i32(137);
  39. ptr := &i;
  40. _ = (^f32)(ptr);
  41. // ^f32(ptr) == ^(f32(ptr))
  42. _ = cast(^f32)ptr;
  43. _ = (^f32)(ptr)^;
  44. _ = (cast(^f32)ptr)^;
  45. // Questions: Should there be two ways to do it?
  46. }
  47. /*
  48. * Remove *_val_of built-in procedures
  49. * size_of, align_of, offset_of
  50. * type_of, type_info_of
  51. */
  52. { // `expand_to_tuple` built-in procedure
  53. Foo :: struct {
  54. x: int,
  55. b: bool,
  56. }
  57. f := Foo{137, true};
  58. x, b := expand_to_tuple(f);
  59. fmt.println(f);
  60. fmt.println(x, b);
  61. fmt.println(expand_to_tuple(f));
  62. }
  63. {
  64. // .. open range
  65. for in 0..2 {} // 0, 1, 2
  66. }
  67. { // Multiple sized booleans
  68. x0: bool; // default
  69. x1: b8 = true;
  70. x2: b16 = false;
  71. x3: b32 = true;
  72. x4: b64 = false;
  73. fmt.printf("x0: %T = %v;\n", x0, x0);
  74. fmt.printf("x1: %T = %v;\n", x1, x1);
  75. fmt.printf("x2: %T = %v;\n", x2, x2);
  76. fmt.printf("x3: %T = %v;\n", x3, x3);
  77. fmt.printf("x4: %T = %v;\n", x4, x4);
  78. // Having specific sized booleans is very useful when dealing with foreign code
  79. // and to enforce specific alignment for a boolean, especially within a struct
  80. }
  81. { // `distinct` types
  82. // Originally, all type declarations would create a distinct type unless #type_alias was present.
  83. // Now the behaviour has been reversed. All type declarations create a type alias unless `distinct` is present.
  84. // If the type expression is `struct`, `union`, `enum`, `proc`, or `bit_field`, the types will always been distinct.
  85. Int32 :: i32;
  86. #assert(Int32 == i32);
  87. My_Int32 :: distinct i32;
  88. #assert(My_Int32 != i32);
  89. My_Struct :: struct{x: int};
  90. #assert(My_Struct != struct{x: int});
  91. }
  92. {
  93. X :: 123;
  94. when #defined(X) {
  95. fmt.println("X is defined");
  96. } else {
  97. fmt.println("X is not defined");
  98. }
  99. when #defined(Y) {
  100. fmt.println("Y is defined");
  101. } else {
  102. fmt.println("Y is not defined");
  103. }
  104. }
  105. }
  106. union_type :: proc() {
  107. fmt.println("\n# union_type");
  108. {
  109. val: union{int, bool};
  110. val = 137;
  111. if i, ok := val.(int); ok {
  112. fmt.println(i);
  113. }
  114. val = true;
  115. fmt.println(val);
  116. val = nil;
  117. switch v in val {
  118. case int: fmt.println("int", v);
  119. case bool: fmt.println("bool", v);
  120. case: fmt.println("nil");
  121. }
  122. }
  123. {
  124. // There is a duality between `any` and `union`
  125. // An `any` has a pointer to the data and allows for any type (open)
  126. // A `union` has as binary blob to store the data and allows only certain types (closed)
  127. // The following code is with `any` but has the same syntax
  128. val: any;
  129. val = 137;
  130. if i, ok := val.(int); ok {
  131. fmt.println(i);
  132. }
  133. val = true;
  134. fmt.println(val);
  135. val = nil;
  136. switch v in val {
  137. case int: fmt.println("int", v);
  138. case bool: fmt.println("bool", v);
  139. case: fmt.println("nil");
  140. }
  141. }
  142. Vector3 :: struct {x, y, z: f32};
  143. Quaternion :: struct {x, y, z, w: f32};
  144. // More realistic examples
  145. {
  146. // NOTE(bill): For the above basic examples, you may not have any
  147. // particular use for it. However, my main use for them is not for these
  148. // simple cases. My main use is for hierarchical types. Many prefer
  149. // subtyping, embedding the base data into the derived types. Below is
  150. // an example of this for a basic game Entity.
  151. Entity :: struct {
  152. id: u64,
  153. name: string,
  154. position: Vector3,
  155. orientation: Quaternion,
  156. derived: any,
  157. }
  158. Frog :: struct {
  159. using entity: Entity,
  160. jump_height: f32,
  161. }
  162. Monster :: struct {
  163. using entity: Entity,
  164. is_robot: bool,
  165. is_zombie: bool,
  166. }
  167. // See `parametric_polymorphism` procedure for details
  168. new_entity :: proc($T: typeid) -> ^Entity {
  169. t := new(T);
  170. t.derived = t^;
  171. return t;
  172. }
  173. entity := new_entity(Monster);
  174. switch e in entity.derived {
  175. case Frog:
  176. fmt.println("Ribbit");
  177. case Monster:
  178. if e.is_robot do fmt.println("Robotic");
  179. if e.is_zombie do fmt.println("Grrrr!");
  180. }
  181. }
  182. {
  183. // NOTE(bill): A union can be used to achieve something similar. Instead
  184. // of embedding the base data into the derived types, the derived data
  185. // in embedded into the base type. Below is the same example of the
  186. // basic game Entity but using an union.
  187. Entity :: struct {
  188. id: u64,
  189. name: string,
  190. position: Vector3,
  191. orientation: Quaternion,
  192. derived: union {Frog, Monster},
  193. }
  194. Frog :: struct {
  195. using entity: ^Entity,
  196. jump_height: f32,
  197. }
  198. Monster :: struct {
  199. using entity: ^Entity,
  200. is_robot: bool,
  201. is_zombie: bool,
  202. }
  203. // See `parametric_polymorphism` procedure for details
  204. new_entity :: proc($T: typeid) -> ^Entity {
  205. t := new(Entity);
  206. t.derived = T{entity = t};
  207. return t;
  208. }
  209. entity := new_entity(Monster);
  210. switch e in entity.derived {
  211. case Frog:
  212. fmt.println("Ribbit");
  213. case Monster:
  214. if e.is_robot do fmt.println("Robotic");
  215. if e.is_zombie do fmt.println("Grrrr!");
  216. }
  217. // NOTE(bill): As you can see, the usage code has not changed, only its
  218. // memory layout. Both approaches have their own advantages but they can
  219. // be used together to achieve different results. The subtyping approach
  220. // can allow for a greater control of the memory layout and memory
  221. // allocation, e.g. storing the derivatives together. However, this is
  222. // also its disadvantage. You must either preallocate arrays for each
  223. // derivative separation (which can be easily missed) or preallocate a
  224. // bunch of "raw" memory; determining the maximum size of the derived
  225. // types would require the aid of metaprogramming. Unions solve this
  226. // particular problem as the data is stored with the base data.
  227. // Therefore, it is possible to preallocate, e.g. [100]Entity.
  228. // It should be noted that the union approach can have the same memory
  229. // layout as the any and with the same type restrictions by using a
  230. // pointer type for the derivatives.
  231. /*
  232. Entity :: struct {
  233. ..
  234. derived: union{^Frog, ^Monster},
  235. }
  236. Frog :: struct {
  237. using entity: Entity,
  238. ..
  239. }
  240. Monster :: struct {
  241. using entity: Entity,
  242. ..
  243. }
  244. new_entity :: proc(T: type) -> ^Entity {
  245. t := new(T);
  246. t.derived = t;
  247. return t;
  248. }
  249. */
  250. }
  251. }
  252. parametric_polymorphism :: proc() {
  253. fmt.println("# parametric_polymorphism");
  254. print_value :: proc(value: $T) {
  255. fmt.printf("print_value: %T %v\n", value, value);
  256. }
  257. v1: int = 1;
  258. v2: f32 = 2.1;
  259. v3: f64 = 3.14;
  260. v4: string = "message";
  261. print_value(v1);
  262. print_value(v2);
  263. print_value(v3);
  264. print_value(v4);
  265. fmt.println();
  266. add :: proc(p, q: $T) -> T {
  267. x: T = p + q;
  268. return x;
  269. }
  270. a := add(3, 4);
  271. fmt.printf("a: %T = %v\n", a, a);
  272. b := add(3.2, 4.3);
  273. fmt.printf("b: %T = %v\n", b, b);
  274. // This is how `new` is implemented
  275. alloc_type :: proc($T: typeid) -> ^T {
  276. t := cast(^T)alloc(size_of(T), align_of(T));
  277. t^ = T{}; // Use default initialization value
  278. return t;
  279. }
  280. copy_slice :: proc(dst, src: []$T) -> int {
  281. n := min(len(dst), len(src));
  282. if n > 0 {
  283. mem.copy(&dst[0], &src[0], n*size_of(T));
  284. }
  285. return n;
  286. }
  287. double_params :: proc(a: $A, b: $B) -> A {
  288. return a + A(b);
  289. }
  290. fmt.println(double_params(12, 1.345));
  291. { // Polymorphic Types and Type Specialization
  292. Table_Slot :: struct(Key, Value: typeid) {
  293. occupied: bool,
  294. hash: u32,
  295. key: Key,
  296. value: Value,
  297. }
  298. TABLE_SIZE_MIN :: 32;
  299. Table :: struct(Key, Value: typeid) {
  300. count: int,
  301. allocator: mem.Allocator,
  302. slots: []Table_Slot(Key, Value),
  303. }
  304. // Only allow types that are specializations of a (polymorphic) slice
  305. make_slice :: proc($T: typeid/[]$E, len: int) -> T {
  306. return make(T, len);
  307. }
  308. // Only allow types that are specializations of `Table`
  309. allocate :: proc(table: ^$T/Table, capacity: int) {
  310. c := context;
  311. if table.allocator.procedure != nil do c.allocator = table.allocator;
  312. context = c;
  313. table.slots = make_slice(type_of(table.slots), max(capacity, TABLE_SIZE_MIN));
  314. }
  315. expand :: proc(table: ^$T/Table) {
  316. c := context;
  317. if table.allocator.procedure != nil do c.allocator = table.allocator;
  318. context = c;
  319. old_slots := table.slots;
  320. defer delete(old_slots);
  321. cap := max(2*len(table.slots), TABLE_SIZE_MIN);
  322. allocate(table, cap);
  323. for s in old_slots do if s.occupied {
  324. put(table, s.key, s.value);
  325. }
  326. }
  327. // Polymorphic determination of a polymorphic struct
  328. // put :: proc(table: ^$T/Table, key: T.Key, value: T.Value) {
  329. put :: proc(table: ^Table($Key, $Value), key: Key, value: Value) {
  330. hash := get_hash(key); // Ad-hoc method which would fail in a different scope
  331. index := find_index(table, key, hash);
  332. if index < 0 {
  333. if f64(table.count) >= 0.75*f64(len(table.slots)) {
  334. expand(table);
  335. }
  336. assert(table.count <= len(table.slots));
  337. hash := get_hash(key);
  338. index = int(hash % u32(len(table.slots)));
  339. for table.slots[index].occupied {
  340. if index += 1; index >= len(table.slots) {
  341. index = 0;
  342. }
  343. }
  344. table.count += 1;
  345. }
  346. slot := &table.slots[index];
  347. slot.occupied = true;
  348. slot.hash = hash;
  349. slot.key = key;
  350. slot.value = value;
  351. }
  352. // find :: proc(table: ^$T/Table, key: T.Key) -> (T.Value, bool) {
  353. find :: proc(table: ^Table($Key, $Value), key: Key) -> (Value, bool) {
  354. hash := get_hash(key);
  355. index := find_index(table, key, hash);
  356. if index < 0 {
  357. return Value{}, false;
  358. }
  359. return table.slots[index].value, true;
  360. }
  361. find_index :: proc(table: ^Table($Key, $Value), key: Key, hash: u32) -> int {
  362. if len(table.slots) <= 0 do return -1;
  363. index := int(hash % u32(len(table.slots)));
  364. for table.slots[index].occupied {
  365. if table.slots[index].hash == hash {
  366. if table.slots[index].key == key {
  367. return index;
  368. }
  369. }
  370. if index += 1; index >= len(table.slots) {
  371. index = 0;
  372. }
  373. }
  374. return -1;
  375. }
  376. get_hash :: proc(s: string) -> u32 { // fnv32a
  377. h: u32 = 0x811c9dc5;
  378. for i in 0..len(s)-1 {
  379. h = (h ~ u32(s[i])) * 0x01000193;
  380. }
  381. return h;
  382. }
  383. table: Table(string, int);
  384. for i in 0..36 do put(&table, "Hellope", i);
  385. for i in 0..42 do put(&table, "World!", i);
  386. found, _ := find(&table, "Hellope");
  387. fmt.printf("`found` is %v\n", found);
  388. found, _ = find(&table, "World!");
  389. fmt.printf("`found` is %v\n", found);
  390. // I would not personally design a hash table like this in production
  391. // but this is a nice basic example
  392. // A better approach would either use a `u64` or equivalent for the key
  393. // and let the user specify the hashing function or make the user store
  394. // the hashing procedure with the table
  395. }
  396. { // Parametric polymorphic union
  397. Error :: enum {
  398. Foo0,
  399. Foo1,
  400. Foo2,
  401. Foo3,
  402. }
  403. Para_Union :: union(T: typeid) {T, Error};
  404. r: Para_Union(int);
  405. fmt.println(typeid_of(type_of(r)));
  406. fmt.println(r);
  407. r = 123;
  408. fmt.println(r);
  409. r = Error.Foo0;
  410. fmt.println(r);
  411. }
  412. { // Polymorphic names
  413. foo :: proc($N: $I, $T: typeid) -> (res: [N]T) {
  414. // `N` is the constant value passed
  415. // `I` is the type of N
  416. // `T` is the type passed
  417. fmt.printf("Generating an array of type %v from the value %v of type %v\n",
  418. typeid_of(type_of(res)), N, typeid_of(I));
  419. for i in 0..N-1 {
  420. res[i] = i*i;
  421. }
  422. return;
  423. }
  424. T :: int;
  425. array := foo(4, T);
  426. for v, i in array {
  427. assert(v == T(i*i));
  428. }
  429. }
  430. }
  431. prefix_table := [?]string{
  432. "White",
  433. "Red",
  434. "Green",
  435. "Blue",
  436. "Octarine",
  437. "Black",
  438. };
  439. threading_example :: proc() {
  440. when os.OS == "windows" {
  441. fmt.println("# threading_example");
  442. unordered_remove :: proc(array: ^$D/[dynamic]$T, index: int, loc := #caller_location) {
  443. runtime.bounds_check_error_loc(loc, index, len(array));
  444. n := len(array)-1;
  445. if index != n {
  446. array[index] = array[n];
  447. }
  448. pop(array);
  449. }
  450. ordered_remove :: proc(array: ^$D/[dynamic]$T, index: int, loc := #caller_location) {
  451. runtime.bounds_check_error_loc(loc, index, len(array));
  452. copy(array[index:], array[index+1:]);
  453. pop(array);
  454. }
  455. worker_proc :: proc(t: ^thread.Thread) -> int {
  456. for iteration in 1..5 {
  457. fmt.printf("Thread %d is on iteration %d\n", t.user_index, iteration);
  458. fmt.printf("`%s`: iteration %d\n", prefix_table[t.user_index], iteration);
  459. // win32.sleep(1);
  460. }
  461. return 0;
  462. }
  463. threads := make([dynamic]^thread.Thread, 0, len(prefix_table));
  464. defer delete(threads);
  465. for in prefix_table {
  466. if t := thread.create(worker_proc); t != nil {
  467. t.init_context = context;
  468. t.use_init_context = true;
  469. t.user_index = len(threads);
  470. append(&threads, t);
  471. thread.start(t);
  472. }
  473. }
  474. for len(threads) > 0 {
  475. for i := 0; i < len(threads); /**/ {
  476. if t := threads[i]; thread.is_done(t) {
  477. fmt.printf("Thread %d is done\n", t.user_index);
  478. thread.destroy(t);
  479. ordered_remove(&threads, i);
  480. } else {
  481. i += 1;
  482. }
  483. }
  484. }
  485. }
  486. }
  487. array_programming :: proc() {
  488. fmt.println("# array_programming");
  489. {
  490. a := [3]f32{1, 2, 3};
  491. b := [3]f32{5, 6, 7};
  492. c := a * b;
  493. d := a + b;
  494. e := 1 + (c - d) / 2;
  495. fmt.printf("%.1f\n", e); // [0.5, 3.0, 6.5]
  496. }
  497. {
  498. a := [3]f32{1, 2, 3};
  499. b := swizzle(a, 2, 1, 0);
  500. assert(b == [3]f32{3, 2, 1});
  501. c := swizzle(a, 0, 0);
  502. assert(c == [2]f32{1, 1});
  503. assert(c == 1);
  504. }
  505. {
  506. Vector3 :: distinct [3]f32;
  507. a := Vector3{1, 2, 3};
  508. b := Vector3{5, 6, 7};
  509. c := (a * b)/2 + 1;
  510. d := c.x + c.y + c.z;
  511. fmt.printf("%.1f\n", d); // 22.0
  512. cross :: proc(a, b: Vector3) -> Vector3 {
  513. i := swizzle(a, 1, 2, 0) * swizzle(b, 2, 0, 1);
  514. j := swizzle(a, 2, 0, 1) * swizzle(b, 1, 2, 0);
  515. return i - j;
  516. }
  517. blah :: proc(a: Vector3) -> f32 {
  518. return a.x + a.y + a.z;
  519. }
  520. x := cross(a, b);
  521. fmt.println(x);
  522. fmt.println(blah(x));
  523. }
  524. }
  525. named_proc_return_parameters :: proc() {
  526. fmt.println("# named proc return parameters");
  527. foo0 :: proc() -> int {
  528. return 123;
  529. }
  530. foo1 :: proc() -> (a: int) {
  531. a = 123;
  532. return;
  533. }
  534. foo2 :: proc() -> (a, b: int) {
  535. // Named return values act like variables within the scope
  536. a = 321;
  537. b = 567;
  538. return b, a;
  539. }
  540. fmt.println("foo0 =", foo0()); // 123
  541. fmt.println("foo1 =", foo1()); // 123
  542. fmt.println("foo2 =", foo2()); // 567 321
  543. }
  544. using_enum :: proc() {
  545. fmt.println("# using enum");
  546. using Foo :: enum {A, B, C};
  547. f0 := A;
  548. f1 := B;
  549. f2 := C;
  550. fmt.println(f0, f1, f2);
  551. fmt.println(len(Foo));
  552. // Non-comparsion operations are not allowed with enum
  553. // You must convert to an integer if you want to do this
  554. // x := f0 + f1;
  555. y := int(f0) + int(f1);
  556. }
  557. explicit_procedure_overloading :: proc() {
  558. fmt.println("# explicit procedure overloading");
  559. add_ints :: proc(a, b: int) -> int {
  560. x := a + b;
  561. fmt.println("add_ints", x);
  562. return x;
  563. }
  564. add_floats :: proc(a, b: f32) -> f32 {
  565. x := a + b;
  566. fmt.println("add_floats", x);
  567. return x;
  568. }
  569. add_numbers :: proc(a: int, b: f32, c: u8) -> int {
  570. x := int(a) + int(b) + int(c);
  571. fmt.println("add_numbers", x);
  572. return x;
  573. }
  574. add :: proc[add_ints, add_floats, add_numbers];
  575. add(int(1), int(2));
  576. add(f32(1), f32(2));
  577. add(int(1), f32(2), u8(3));
  578. add(1, 2); // untyped ints coerce to int tighter than f32
  579. add(1.0, 2.0); // untyped floats coerce to f32 tighter than int
  580. add(1, 2, 3); // three parameters
  581. // Ambiguous answers
  582. // add(1.0, 2);
  583. // add(1, 2.0);
  584. }
  585. complete_switch :: proc() {
  586. fmt.println("# complete_switch");
  587. { // enum
  588. using Foo :: enum {
  589. A,
  590. B,
  591. C,
  592. D,
  593. }
  594. b := Foo.B;
  595. f := Foo.A;
  596. #complete switch f {
  597. case A: fmt.println("A");
  598. case B: fmt.println("B");
  599. case C: fmt.println("C");
  600. case D: fmt.println("D");
  601. case: fmt.println("?");
  602. }
  603. }
  604. { // union
  605. Foo :: union {int, bool};
  606. f: Foo = 123;
  607. #complete switch in f {
  608. case int: fmt.println("int");
  609. case bool: fmt.println("bool");
  610. case:
  611. }
  612. }
  613. }
  614. cstring_example :: proc() {
  615. W :: "Hellope";
  616. X :: cstring(W);
  617. Y :: string(X);
  618. w := W;
  619. x: cstring = X;
  620. y: string = Y;
  621. z := string(x);
  622. fmt.println(x, y, z);
  623. fmt.println(len(x), len(y), len(z));
  624. fmt.println(len(W), len(X), len(Y));
  625. // IMPORTANT NOTE for cstring variables
  626. // len(cstring) is O(N)
  627. // cast(cstring)string is O(N)
  628. }
  629. deprecated_attribute :: proc() {
  630. @(deprecated="Use foo_v2 instead")
  631. foo_v1 :: proc(x: int) {
  632. fmt.println("foo_v1");
  633. }
  634. foo_v2 :: proc(x: int) {
  635. fmt.println("foo_v2");
  636. }
  637. // NOTE: Uncomment to see the warning messages
  638. // foo_v1(1);
  639. }
  640. bit_set_type :: proc() {
  641. {
  642. using Day :: enum {
  643. Sunday,
  644. Monday,
  645. Tuesday,
  646. Wednesday,
  647. Thursday,
  648. Friday,
  649. Saturday,
  650. }
  651. Days :: distinct bit_set[Day];
  652. WEEKEND :: Days{Sunday, Saturday};
  653. d: Days;
  654. d = {Sunday, Monday};
  655. x := Tuesday;
  656. e := d | WEEKEND;
  657. e |= {Monday};
  658. fmt.println(d, e);
  659. ok := Saturday in e; // `in` is only allowed for `map` and `bit_set` types
  660. fmt.println(ok);
  661. if Saturday in e {
  662. fmt.println("Saturday in", e);
  663. }
  664. X :: Saturday in WEEKEND; // Constant evaluation
  665. fmt.println(X);
  666. }
  667. {
  668. x: bit_set['A'..'Z'];
  669. assert(size_of(x) == size_of(u32));
  670. y: bit_set[0..8; u16];
  671. fmt.println(typeid_of(type_of(x))); // bit_set[A..Z]
  672. fmt.println(typeid_of(type_of(y))); // bit_set[0..8; u16]
  673. incl(&x, 'F');
  674. assert('F' in x);
  675. excl(&x, 'F');
  676. assert(!('F' in x));
  677. y |= {1, 4, 2};
  678. assert(2 in y);
  679. }
  680. }
  681. diverging_procedures :: proc() {
  682. // Diverging procedures may never return
  683. foo :: proc() -> ! {
  684. fmt.println("I'm a diverging procedure");
  685. }
  686. foo();
  687. }
  688. main :: proc() {
  689. when true {
  690. general_stuff();
  691. union_type();
  692. parametric_polymorphism();
  693. threading_example();
  694. array_programming();
  695. named_proc_return_parameters();
  696. using_enum();
  697. explicit_procedure_overloading();
  698. complete_switch();
  699. cstring_example();
  700. deprecated_attribute();
  701. bit_set_type();
  702. diverging_procedures();
  703. }
  704. }