├── .gitignore ├── AUTHORS ├── LICENSE ├── README.md ├── STYLE-GUIDE.md ├── TODO.md ├── docs ├── articles │ ├── programming-with-interaction-nets.md │ └── 反应网编程.md └── references │ ├── 1990-interaction-nets.pdf │ └── 1997-interaction-combinators.pdf ├── examples ├── combinators │ ├── CDE.fth │ └── forever.play.fth ├── core │ ├── print-return-stack.test.fth │ ├── print-return-stack.test.fth.out │ ├── print-value-stack.test.fth │ ├── print-value-stack.test.fth.out │ ├── print-worker.test.fth │ └── print-worker.test.fth.out ├── datatypes │ ├── bool.fth │ ├── bool.test.fth │ ├── bool.test.fth.out │ ├── diff-list.fth │ ├── diff-list.test.fth │ ├── diff-list.test.fth.out │ ├── list.fth │ ├── list.test.fth │ ├── list.test.fth.out │ ├── nat-big-mul.test.fth │ ├── nat-big-mul.test.fth.out │ ├── nat.fth │ ├── nat.test.fth │ ├── nat.test.fth.out │ └── trivial.fth ├── primitives │ ├── bool.fth │ ├── console.test.fth │ ├── console.test.fth.out │ ├── float.fth │ ├── int.fth │ └── value.fth ├── readme │ ├── list.fth │ ├── list.play.fth │ ├── nat.fth │ └── nat.play.fth └── tests │ ├── empty-file.test.fth │ ├── empty-file.test.fth.out │ ├── line-comment.test.fth │ ├── line-comment.test.fth.out │ ├── local.fth │ ├── square.fth │ ├── undefined-node.error.fth │ └── undefined-node.error.fth.err ├── makefile ├── run-examples.sh └── src ├── commands ├── deps.h ├── index.h ├── info_command.c ├── run_command.c ├── test_packages_command.c └── test_self_command.c ├── config.h ├── core ├── connect.c ├── connect.h ├── deps.h ├── frame.c ├── frame.h ├── function.c ├── function.h ├── index.h ├── mod.c ├── mod.h ├── opcode.c ├── opcode.h ├── primitive.c ├── primitive.h ├── rule.c ├── rule.h ├── scheduler.c ├── scheduler.h ├── task.c ├── task.h ├── types.h ├── worker.c ├── worker.h ├── worker_add_task.c ├── worker_apply.c ├── worker_disconnect_node.c ├── worker_handle_task.c ├── worker_reconnect_node.c ├── worker_run_until.c ├── worker_work.c ├── worker_work_parallelly.c └── worker_work_sequentially.c ├── deps.h ├── flags.c ├── flags.h ├── inet-forth.c ├── lang ├── checks.c ├── checks.h ├── compile.h ├── compile_function.c ├── compile_one.c ├── define.c ├── define.h ├── deps.h ├── execute.c ├── execute.h ├── index.h ├── load.c ├── load.h └── types.h ├── net ├── allocated_node_iter.c ├── allocated_node_iter.h ├── connected_node_iter.c ├── connected_node_iter.h ├── deps.h ├── index.h ├── node.c ├── node.h ├── node_adjacency.c ├── node_adjacency.h ├── node_allocator.c ├── node_allocator.h ├── node_ctor.c ├── node_ctor.h ├── port_info.c ├── port_info.h ├── principal_wire.c ├── principal_wire.h ├── test_node.c ├── test_node.h ├── test_node_allocated_node_iter.c ├── test_node_allocator_overhead.c ├── test_node_allocator_throughput.c ├── types.h ├── wire.c └── wire.h ├── packages └── std │ ├── allocator │ ├── allocator.c │ ├── allocator.h │ ├── deps.h │ ├── index.h │ ├── test_allocator.c │ ├── test_allocator.h │ ├── test_allocator_thread_safe.c │ ├── test_allocator_throughput.c │ └── types.h │ ├── array │ ├── array.c │ ├── array.h │ ├── deps.h │ ├── index.h │ ├── string_array.c │ ├── string_array.h │ ├── test_array.c │ ├── test_array.h │ └── types.h │ ├── blob │ ├── blob.c │ ├── blob.h │ ├── deps.h │ ├── index.h │ ├── test_blob.c │ ├── test_blob.h │ └── types.h │ ├── char │ ├── char.c │ ├── char.h │ ├── deps.h │ ├── index.h │ ├── test_char.c │ ├── test_char.h │ └── types.h │ ├── code │ ├── code.c │ ├── code.h │ ├── deps.h │ ├── index.h │ ├── test_code.c │ └── test_code.h │ ├── commander │ ├── cmd_default.h │ ├── cmd_default_help.c │ ├── cmd_default_version.c │ ├── command.c │ ├── command.h │ ├── commander.c │ ├── commander.h │ ├── deps.h │ ├── index.h │ └── types.h │ ├── deque │ ├── deps.h │ ├── deque.c │ ├── deque.h │ ├── index.h │ ├── test_deque.c │ ├── test_deque.h │ ├── test_deque_throughput.c │ └── types.h │ ├── file │ ├── abc.txt │ ├── deps.h │ ├── file.c │ ├── file.h │ ├── index.h │ ├── test_file.c │ ├── test_file.h │ └── types.h │ ├── hash │ ├── deps.h │ ├── hash.c │ ├── hash.h │ ├── hash_primes.h │ ├── index.h │ ├── test_hash.c │ ├── test_hash.h │ └── types.h │ ├── index.h │ ├── int │ ├── deps.h │ ├── index.h │ ├── int.c │ ├── int.h │ ├── test_int.c │ └── test_int.h │ ├── lexer │ ├── deps.h │ ├── index.h │ ├── lexer.c │ ├── lexer.h │ ├── test_lexer.c │ ├── test_lexer.h │ ├── token.c │ ├── token.h │ └── types.h │ ├── list │ ├── deps.h │ ├── index.h │ ├── list.c │ ├── list.h │ ├── string_list.c │ ├── string_list.h │ ├── test_list.c │ ├── test_list.h │ └── types.h │ ├── memory │ ├── deps.h │ ├── destroy.c │ ├── destroy.h │ ├── index.h │ ├── memory.c │ ├── memory.h │ ├── new.h │ ├── test_memory.c │ ├── test_memory.h │ └── types.h │ ├── path │ ├── deps.h │ ├── index.h │ ├── path.c │ ├── path.h │ ├── test_path.c │ ├── test_path.h │ └── types.h │ ├── queue │ ├── deps.h │ ├── index.h │ ├── queue.c │ ├── queue.h │ ├── test_queue.c │ ├── test_queue.h │ ├── test_queue_multi_thread.c │ ├── test_queue_single_thread.c │ ├── test_queue_throughput.c │ └── types.h │ ├── set │ ├── deps.h │ ├── index.h │ ├── set.c │ ├── set.h │ ├── test_set.c │ ├── test_set.h │ └── types.h │ ├── sexp │ ├── deps.h │ ├── index.h │ ├── sexp.c │ ├── sexp.h │ ├── test_sexp.c │ ├── test_sexp.h │ └── types.h │ ├── stack │ ├── deps.h │ ├── index.h │ ├── stack.c │ ├── stack.h │ ├── string_stack.c │ ├── string_stack.h │ ├── test_stack.c │ ├── test_stack.h │ └── types.h │ ├── string │ ├── deps.h │ ├── index.h │ ├── string.c │ ├── string.h │ ├── test_string.c │ └── test_string.h │ ├── test │ ├── deps.h │ ├── index.h │ ├── test.c │ ├── test.h │ ├── test_test.c │ ├── test_test.h │ └── types.h │ ├── test_std.c │ ├── test_std.h │ ├── text │ ├── deps.h │ ├── index.h │ ├── test_text.c │ ├── test_text.h │ ├── text.c │ ├── text.h │ └── types.h │ ├── thread │ ├── atomics.h │ ├── deps.h │ ├── fast_spinlock.c │ ├── fast_spinlock.h │ ├── index.h │ ├── mutex.c │ ├── mutex.h │ ├── spinlock.c │ ├── spinlock.h │ ├── test_thread.c │ ├── test_thread.h │ ├── test_thread_count_to_big.c │ ├── test_thread_counter_atomic.c │ ├── test_thread_counter_non_atomic.c │ ├── test_thread_counter_stat.c │ ├── test_thread_counter_stat_eventual.c │ ├── test_thread_mutex.c │ ├── test_thread_start.c │ ├── test_thread_weak_memory_dekker.c │ ├── test_thread_weak_memory_dekker_atomic.c │ ├── test_thread_weak_memory_dekker_relaxed.c │ ├── thread.c │ ├── thread.h │ └── types.h │ ├── time │ ├── deps.h │ ├── index.h │ ├── test_time.c │ ├── test_time.h │ ├── time.c │ ├── time.h │ └── types.h │ ├── utf8 │ ├── deps.h │ ├── index.h │ ├── test_utf8.c │ ├── test_utf8.h │ ├── types.h │ ├── utf8.c │ ├── utf8.h │ ├── utf8_iter.c │ └── utf8_iter.h │ └── vec │ ├── deps.h │ ├── index.h │ ├── test_vec.c │ ├── test_vec.h │ ├── test_vec2.c │ ├── test_vec2.h │ ├── types.h │ ├── vec2.c │ └── vec2.h ├── prelude ├── console.c ├── console.h ├── deps.h ├── function.c ├── function.h ├── import_prelude.c ├── import_prelude.h ├── index.h ├── net.c ├── net.h ├── testing.c ├── testing.h ├── types.h ├── value.c ├── value.h ├── worker.c └── worker.h └── value ├── constant_table.c ├── constant_table.h ├── deps.h ├── index.h ├── types.h ├── value.c ├── value.h ├── xbool.c ├── xbool.h ├── xfloat.c ├── xfloat.h ├── xint.c ├── xint.h ├── xobject.c └── xobject.h /.gitignore: -------------------------------------------------------------------------------- 1 | # .vscode 2 | .vscode 3 | 4 | # c 5 | tmp 6 | 7 | *.o 8 | 9 | # build 10 | 11 | bin 12 | lib 13 | 14 | # emacs 15 | *~ 16 | *#* 17 | .#* 18 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Xie Yuheng | 谢宇恒 2 | -------------------------------------------------------------------------------- /STYLE-GUIDE.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Style Guide 3 | --- 4 | 5 | **In general, observe the style of existing code and respect it.** 6 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | # example 2 | 3 | [example] more examples from the paper 4 | 5 | # deque 6 | 7 | [deque] `deque_t` -- use mod queue for real -- not just list + lock 8 | 9 | # core 10 | 11 | [core] `node_t` -- use `spinlock_t` 12 | 13 | # primitive value 14 | 15 | [design] write `list-map` as example -- use explicit `dup` -- keep linear variable simple 16 | 17 | - use `{ ... }` for un-named program -- just program, no closure over linear variables 18 | - another solution is to use quoted symbol to reference defined program 19 | 20 | # player 21 | 22 | [player] bring back `player_t` 23 | [player] use real physics force 24 | [player] `node_physics_simulate` -- move by `velocity` and clear `force` for every `node_model` 25 | [player] remove `node_physics_fake_simulate` 26 | -------------------------------------------------------------------------------- /docs/references/1990-interaction-nets.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cicada-lang/inet-forth/d11c34b36846198fa0f48c00fd5502a18705e37b/docs/references/1990-interaction-nets.pdf -------------------------------------------------------------------------------- /docs/references/1997-interaction-combinators.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cicada-lang/inet-forth/d11c34b36846198fa0f48c00fd5502a18705e37b/docs/references/1997-interaction-combinators.pdf -------------------------------------------------------------------------------- /examples/combinators/CDE.fth: -------------------------------------------------------------------------------- 1 | // C: construct 2 | // D: duplicate 3 | // E: erase 4 | 5 | define-node C car cdr -- value! end 6 | define-node D target! -- first second end 7 | define-node E target! -- end 8 | 9 | define-rule C C 10 | ( top-car top-cdr ) 11 | ( lower-car lower-cdr ) 12 | top-car lower-cdr connect 13 | top-cdr lower-car connect 14 | end 15 | 16 | define-rule D D 17 | ( top-first top-second ) 18 | ( lower-first lower-second ) 19 | top-first lower-first connect 20 | top-second lower-second connect 21 | end 22 | 23 | define-rule E E end 24 | 25 | define-rule E C 26 | ( car cdr ) 27 | car E cdr E 28 | end 29 | 30 | define-rule E D 31 | ( first second ) 32 | first E second E 33 | end 34 | 35 | define-rule C D 36 | ( first second ) 37 | ( car cdr ) 38 | car D ( car-first car-second ) 39 | cdr D ( cdr-first cdr-second ) 40 | car-first cdr-first C first connect 41 | car-second cdr-second C second connect 42 | end 43 | -------------------------------------------------------------------------------- /examples/combinators/forever.play.fth: -------------------------------------------------------------------------------- 1 | import C D E "CDE.fth" 2 | 3 | define E-value link E end 4 | 5 | define forever 6 | link ( car car-op ) 7 | car E-value C 8 | D ( first second ) 9 | first E 10 | car-op second connect 11 | end 12 | 13 | forever 14 | -------------------------------------------------------------------------------- /examples/core/print-return-stack.test.fth: -------------------------------------------------------------------------------- 1 | define main 2 | print-return-stack 3 | print-return-stack 4 | print-return-stack 5 | end 6 | 7 | main 8 | -------------------------------------------------------------------------------- /examples/core/print-return-stack.test.fth.out: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | (literal print-return-stack) 5 | (apply 0) 6 | (literal print-return-stack) <<< 7 | (apply 0) 8 | (literal print-return-stack) 9 | (apply 0) 10 | 11 | 12 | 13 | 14 | 15 | 16 | (literal print-return-stack) 17 | (apply 0) 18 | (literal print-return-stack) 19 | (apply 0) 20 | (literal print-return-stack) <<< 21 | (apply 0) 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /examples/core/print-value-stack.test.fth: -------------------------------------------------------------------------------- 1 | define-node sole -- value! end 2 | 3 | sole sole sole 4 | print-value-stack 5 | sole sole sole 6 | -------------------------------------------------------------------------------- /examples/core/print-value-stack.test.fth.out: -------------------------------------------------------------------------------- 1 | 2 | (sole₁)-value!-< 3 | (sole₂)-value!-< 4 | (sole₃)-value!-< 5 | 6 | -------------------------------------------------------------------------------- /examples/core/print-worker.test.fth: -------------------------------------------------------------------------------- 1 | define-node sole -- value! end 2 | 3 | define main 4 | print-worker 5 | sole 6 | print-worker 7 | sole 8 | print-worker 9 | end 10 | 11 | main 12 | -------------------------------------------------------------------------------- /examples/core/print-worker.test.fth.out: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | (literal print-worker) 6 | (apply 0) 7 | (literal (sole)) <<< 8 | (apply 0) 9 | (literal print-worker) 10 | (apply 0) 11 | (literal (sole)) 12 | (apply 0) 13 | (literal print-worker) 14 | (apply 0) 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | (literal print-worker) 27 | (apply 0) 28 | (literal (sole)) 29 | (apply 0) 30 | (literal print-worker) 31 | (apply 0) 32 | (literal (sole)) <<< 33 | (apply 0) 34 | (literal print-worker) 35 | (apply 0) 36 | 37 | 38 | 39 | 40 | (sole₁)-value!-< 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | (sole₁)-value!-< 49 | (sole₂)-value!-< 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /examples/datatypes/bool.fth: -------------------------------------------------------------------------------- 1 | define-node t -- value! end 2 | define-node f -- value! end 3 | 4 | define-node bool-erase target! -- end 5 | 6 | define-rule t bool-erase end 7 | define-rule f bool-erase end 8 | 9 | define-node conj x! y -- z end 10 | define-node conj-t y! -- z end 11 | 12 | define-rule t conj swap conj-t connect end 13 | define-rule f conj f connect bool-erase end 14 | 15 | define-rule t conj-t t connect end 16 | define-rule f conj-t f connect end 17 | 18 | define-node disj x! y -- z end 19 | define-node disj-f y! -- z end 20 | 21 | define-rule t disj t connect bool-erase end 22 | define-rule f disj swap disj-f connect end 23 | 24 | define-rule t disj-f t connect end 25 | define-rule f disj-f f connect end 26 | -------------------------------------------------------------------------------- /examples/datatypes/bool.test.fth: -------------------------------------------------------------------------------- 1 | import t f conj disj "bool.fth" 2 | 3 | t t conj 4 | f t conj conj 5 | t t disj 6 | f t disj disj 7 | disj 8 | 9 | inspect-run -------------------------------------------------------------------------------- /examples/datatypes/bool.test.fth.out: -------------------------------------------------------------------------------- 1 | 2 | :root (disj₁₅) 3 | 4 | (disj₁₅)-x!-<>-z-(conj₇) 5 | (disj₁₅)-y-<>-z-(disj₁₄) 6 | 7 | (disj₁₄)-x!-<>-z-(disj₁₀) 8 | (disj₁₄)-y-<>-z-(disj₁₃) 9 | (disj₁₄)-z-<>-y-(disj₁₅) 10 | 11 | (disj₁₃)-x!-<>-!value-(f₁₁) 12 | (disj₁₃)-y-<>-!value-(t₁₂) 13 | (disj₁₃)-z-<>-y-(disj₁₄) 14 | 15 | (t₁₂)-value!-<>-y-(disj₁₃) 16 | 17 | (f₁₁)-value!-<>-!x-(disj₁₃) 18 | 19 | (disj₁₀)-x!-<>-!value-(t₈) 20 | (disj₁₀)-y-<>-!value-(t₉) 21 | (disj₁₀)-z-<>-!x-(disj₁₄) 22 | 23 | (t₉)-value!-<>-y-(disj₁₀) 24 | 25 | (t₈)-value!-<>-!x-(disj₁₀) 26 | 27 | (conj₇)-x!-<>-z-(conj₃) 28 | (conj₇)-y-<>-z-(conj₆) 29 | (conj₇)-z-<>-!x-(disj₁₅) 30 | 31 | (conj₆)-x!-<>-!value-(f₄) 32 | (conj₆)-y-<>-!value-(t₅) 33 | (conj₆)-z-<>-y-(conj₇) 34 | 35 | (t₅)-value!-<>-y-(conj₆) 36 | 37 | (f₄)-value!-<>-!x-(conj₆) 38 | 39 | (conj₃)-x!-<>-!value-(t₁) 40 | (conj₃)-y-<>-!value-(t₂) 41 | (conj₃)-z-<>-!x-(conj₇) 42 | 43 | (t₂)-value!-<>-y-(conj₃) 44 | 45 | (t₁)-value!-<>-!x-(conj₃) 46 | 47 | 48 | 49 | :root (t₁₅) 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /examples/datatypes/diff-list.fth: -------------------------------------------------------------------------------- 1 | define-node diff front -- back value! end 2 | define-node diff-append target! rest -- result end 3 | define-node diff-open new-back target! -- old-back end 4 | 5 | // plug the front of the `target` to the back of `rest`. 6 | 7 | define-rule diff diff-append 8 | ( rest result ) ( front back ) 9 | front diff result connect 10 | rest diff-open back connect 11 | end 12 | 13 | define-rule diff diff-open 14 | ( new-back old-back ) ( front back ) 15 | back new-back connect 16 | front old-back connect 17 | end 18 | -------------------------------------------------------------------------------- /examples/datatypes/diff-list.test.fth: -------------------------------------------------------------------------------- 1 | import diff diff-append "diff-list.fth" 2 | import null cons append "list.fth" 3 | import sole "trivial.fth" 4 | 5 | define sole-diff-list 6 | link ( front front-op ) 7 | front diff ( back value ) 8 | back sole cons sole cons 9 | front-op connect 10 | value 11 | end 12 | 13 | sole-diff-list 14 | sole-diff-list 15 | diff-append 16 | inspect-run 17 | -------------------------------------------------------------------------------- /examples/datatypes/diff-list.test.fth.out: -------------------------------------------------------------------------------- 1 | 2 | :root (diff-append₁₁) 3 | 4 | (diff-append₁₁)-target!-<>-!value-(diff₁) 5 | (diff-append₁₁)-rest-<>-!value-(diff₆) 6 | 7 | (diff₆)-back-<>-tail-(cons₈) 8 | (diff₆)-front-<>-!value-(cons₁₀) 9 | (diff₆)-value!-<>-rest-(diff-append₁₁) 10 | 11 | (cons₁₀)-value!-<>-front-(diff₆) 12 | (cons₁₀)-tail-<>-!value-(cons₈) 13 | (cons₁₀)-head-<>-!value-(sole₉) 14 | 15 | (sole₉)-value!-<>-head-(cons₁₀) 16 | 17 | (cons₈)-tail-<>-back-(diff₆) 18 | (cons₈)-head-<>-!value-(sole₇) 19 | (cons₈)-value!-<>-tail-(cons₁₀) 20 | 21 | (sole₇)-value!-<>-head-(cons₈) 22 | 23 | (diff₁)-back-<>-tail-(cons₃) 24 | (diff₁)-front-<>-!value-(cons₅) 25 | (diff₁)-value!-<>-!target-(diff-append₁₁) 26 | 27 | (cons₅)-value!-<>-front-(diff₁) 28 | (cons₅)-tail-<>-!value-(cons₃) 29 | (cons₅)-head-<>-!value-(sole₄) 30 | 31 | (sole₄)-value!-<>-head-(cons₅) 32 | 33 | (cons₃)-tail-<>-back-(diff₁) 34 | (cons₃)-head-<>-!value-(sole₂) 35 | (cons₃)-value!-<>-tail-(cons₅) 36 | 37 | (sole₂)-value!-<>-head-(cons₃) 38 | 39 | 40 | 41 | :root (diff₁₁) 42 | 43 | (diff₁₁)-front-<>-!value-(cons₅) 44 | (diff₁₁)-back-<>-tail-(cons₈) 45 | 46 | (cons₈)-head-<>-!value-(sole₇) 47 | (cons₈)-value!-<>-tail-(cons₁₀) 48 | (cons₈)-tail-<>-back-(diff₁₁) 49 | 50 | (cons₁₀)-value!-<>-tail-(cons₃) 51 | (cons₁₀)-tail-<>-!value-(cons₈) 52 | (cons₁₀)-head-<>-!value-(sole₉) 53 | 54 | (sole₉)-value!-<>-head-(cons₁₀) 55 | 56 | (cons₃)-head-<>-!value-(sole₂) 57 | (cons₃)-value!-<>-tail-(cons₅) 58 | (cons₃)-tail-<>-!value-(cons₁₀) 59 | 60 | (cons₅)-tail-<>-!value-(cons₃) 61 | (cons₅)-head-<>-!value-(sole₄) 62 | (cons₅)-value!-<>-front-(diff₁₁) 63 | 64 | (sole₄)-value!-<>-head-(cons₅) 65 | 66 | (sole₂)-value!-<>-head-(cons₃) 67 | 68 | (sole₇)-value!-<>-head-(cons₈) 69 | 70 | 71 | -------------------------------------------------------------------------------- /examples/datatypes/list.fth: -------------------------------------------------------------------------------- 1 | define-node null -- value! end 2 | define-node cons tail head -- value! end 3 | define-node append target! rest -- result end 4 | 5 | define-rule null append 6 | ( rest result ) 7 | rest result connect 8 | end 9 | 10 | define-rule cons append 11 | ( rest result ) ( tail head ) 12 | tail rest append 13 | head cons result connect 14 | end 15 | -------------------------------------------------------------------------------- /examples/datatypes/list.test.fth: -------------------------------------------------------------------------------- 1 | import null cons append "list.fth" 2 | import sole "trivial.fth" 3 | 4 | null sole cons sole cons sole cons 5 | null sole cons sole cons sole cons 6 | append 7 | 8 | inspect-run -------------------------------------------------------------------------------- /examples/datatypes/list.test.fth.out: -------------------------------------------------------------------------------- 1 | 2 | :root (append₁₅) 3 | 4 | (append₁₅)-target!-<>-!value-(cons₇) 5 | (append₁₅)-rest-<>-!value-(cons₁₄) 6 | 7 | (cons₁₄)-tail-<>-!value-(cons₁₂) 8 | (cons₁₄)-head-<>-!value-(sole₁₃) 9 | (cons₁₄)-value!-<>-rest-(append₁₅) 10 | 11 | (sole₁₃)-value!-<>-head-(cons₁₄) 12 | 13 | (cons₁₂)-tail-<>-!value-(cons₁₀) 14 | (cons₁₂)-head-<>-!value-(sole₁₁) 15 | (cons₁₂)-value!-<>-tail-(cons₁₄) 16 | 17 | (sole₁₁)-value!-<>-head-(cons₁₂) 18 | 19 | (cons₁₀)-tail-<>-!value-(null₈) 20 | (cons₁₀)-head-<>-!value-(sole₉) 21 | (cons₁₀)-value!-<>-tail-(cons₁₂) 22 | 23 | (sole₉)-value!-<>-head-(cons₁₀) 24 | 25 | (null₈)-value!-<>-tail-(cons₁₀) 26 | 27 | (cons₇)-tail-<>-!value-(cons₅) 28 | (cons₇)-head-<>-!value-(sole₆) 29 | (cons₇)-value!-<>-!target-(append₁₅) 30 | 31 | (sole₆)-value!-<>-head-(cons₇) 32 | 33 | (cons₅)-tail-<>-!value-(cons₃) 34 | (cons₅)-head-<>-!value-(sole₄) 35 | (cons₅)-value!-<>-tail-(cons₇) 36 | 37 | (sole₄)-value!-<>-head-(cons₅) 38 | 39 | (cons₃)-tail-<>-!value-(null₁) 40 | (cons₃)-head-<>-!value-(sole₂) 41 | (cons₃)-value!-<>-tail-(cons₅) 42 | 43 | (sole₂)-value!-<>-head-(cons₃) 44 | 45 | (null₁)-value!-<>-tail-(cons₃) 46 | 47 | 48 | 49 | :root (cons₇) 50 | 51 | (cons₇)-tail-<>-!value-(cons₅) 52 | (cons₇)-head-<>-!value-(sole₆) 53 | 54 | (sole₆)-value!-<>-head-(cons₇) 55 | 56 | (cons₅)-tail-<>-!value-(cons₃) 57 | (cons₅)-head-<>-!value-(sole₄) 58 | (cons₅)-value!-<>-tail-(cons₇) 59 | 60 | (sole₄)-value!-<>-head-(cons₅) 61 | 62 | (cons₃)-head-<>-!value-(sole₂) 63 | (cons₃)-value!-<>-tail-(cons₅) 64 | (cons₃)-tail-<>-!value-(cons₁₄) 65 | 66 | (cons₁₄)-value!-<>-tail-(cons₃) 67 | (cons₁₄)-tail-<>-!value-(cons₁₂) 68 | (cons₁₄)-head-<>-!value-(sole₁₃) 69 | 70 | (sole₁₃)-value!-<>-head-(cons₁₄) 71 | 72 | (cons₁₂)-tail-<>-!value-(cons₁₀) 73 | (cons₁₂)-head-<>-!value-(sole₁₁) 74 | (cons₁₂)-value!-<>-tail-(cons₁₄) 75 | 76 | (sole₁₁)-value!-<>-head-(cons₁₂) 77 | 78 | (cons₁₀)-tail-<>-!value-(null₈) 79 | (cons₁₀)-head-<>-!value-(sole₉) 80 | (cons₁₀)-value!-<>-tail-(cons₁₂) 81 | 82 | (sole₉)-value!-<>-head-(cons₁₀) 83 | 84 | (null₈)-value!-<>-tail-(cons₁₀) 85 | 86 | (sole₂)-value!-<>-head-(cons₃) 87 | 88 | 89 | -------------------------------------------------------------------------------- /examples/datatypes/nat-big-mul.test.fth: -------------------------------------------------------------------------------- 1 | import zero add1 add mul nat-max "nat.fth" 2 | import one two three four "nat.fth" 3 | 4 | define sixteen four four mul end 5 | 6 | sixteen sixteen mul inspect-run 7 | -------------------------------------------------------------------------------- /examples/datatypes/nat.fth: -------------------------------------------------------------------------------- 1 | define-node zero -- value! end 2 | define-node add1 prev -- value! end 3 | define-node add target! addend -- result end 4 | 5 | define-rule zero add 6 | ( addend result ) 7 | addend result connect 8 | end 9 | 10 | define-rule add1 add 11 | ( addend result ) ( prev ) 12 | prev addend add 13 | add1 result connect 14 | end 15 | 16 | define one zero add1 end 17 | define two one one add end 18 | define three two one add end 19 | define four two two add end 20 | 21 | // to define `mul`, we first need `nat-erase` and `nat-dup` 22 | 23 | define-node nat-erase target! -- end 24 | 25 | define-rule zero nat-erase end 26 | 27 | define-rule add1 nat-erase 28 | ( prev ) 29 | prev nat-erase 30 | end 31 | 32 | define-node nat-dup target! -- first second end 33 | 34 | define-rule zero nat-dup 35 | ( first second ) 36 | zero first connect 37 | zero second connect 38 | end 39 | 40 | define-rule add1 nat-dup 41 | ( first second ) ( prev ) 42 | prev nat-dup 43 | ( prev-first prev-second ) 44 | prev-second add1 second connect 45 | prev-first add1 first connect 46 | end 47 | 48 | define-node mul target! mulend -- result end 49 | 50 | define-rule zero mul 51 | ( mulend result ) 52 | mulend nat-erase 53 | zero result connect 54 | end 55 | 56 | define-rule add1 mul 57 | ( mulend result ) ( prev ) 58 | mulend nat-dup 59 | ( mulend-first mulend-second ) 60 | prev mulend-second swap mul 61 | mulend-first add result connect 62 | end 63 | 64 | // to define `nat-max`, we need `nat-max-add1` 65 | 66 | define-node nat-max first! second -- result end 67 | define-node nat-max-add1 first second! -- result end 68 | 69 | define-rule zero nat-max 70 | ( second result ) 71 | second result connect 72 | end 73 | 74 | define-rule add1 nat-max 75 | ( second result ) ( prev ) 76 | prev second nat-max-add1 result connect 77 | end 78 | 79 | define-rule zero nat-max-add1 80 | ( first result ) 81 | first add1 result connect 82 | end 83 | 84 | define-rule add1 nat-max-add1 85 | ( first result ) ( prev ) 86 | first prev nat-max 87 | add1 result connect 88 | end 89 | -------------------------------------------------------------------------------- /examples/datatypes/nat.test.fth: -------------------------------------------------------------------------------- 1 | import zero add1 add mul nat-max "nat.fth" 2 | import one two three four "nat.fth" 3 | 4 | two two add two two add add inspect-run 5 | 6 | two two mul inspect-run 7 | 8 | one two nat-max inspect-run 9 | -------------------------------------------------------------------------------- /examples/datatypes/trivial.fth: -------------------------------------------------------------------------------- 1 | define-node sole -- value! end 2 | -------------------------------------------------------------------------------- /examples/primitives/bool.fth: -------------------------------------------------------------------------------- 1 | false false and not ok 2 | false true and not ok 3 | true false and not ok 4 | true true and ok 5 | -------------------------------------------------------------------------------- /examples/primitives/console.test.fth: -------------------------------------------------------------------------------- 1 | true print drop newline 2 | false print drop newline 3 | 4 | 1 2 iadd print drop newline 5 | -1 -2 iadd print drop newline 6 | 7 | 0.0 0.0 fadd print drop newline 8 | 0.1 0.2 fadd print drop newline 9 | 1.0 2.0 fadd print drop newline 10 | 1.1 2.2 fadd print drop newline 11 | 12 | 1. print drop newline 13 | 2. print drop newline 14 | 15 | 1 2 3 print-value-stack 16 | 17 | define hi 18 | 1 2 3 19 | print-return-stack 20 | 4 5 6 21 | end 22 | 23 | hi 24 | -------------------------------------------------------------------------------- /examples/primitives/console.test.fth.out: -------------------------------------------------------------------------------- 1 | true 2 | false 3 | 3 4 | -3 5 | 0.0 6 | 0.29999999999999982 7 | 3.0 8 | 3.2999999999999972 9 | 1.0 10 | 2.0 11 | 12 | 1 13 | 2 14 | 3 15 | 16 | 17 | 18 | 19 | (literal 1) 20 | (literal 2) 21 | (literal 3) 22 | (literal print-return-stack) 23 | (apply 0) 24 | (literal 4) <<< 25 | (literal 5) 26 | (literal 6) 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /examples/primitives/float.fth: -------------------------------------------------------------------------------- 1 | 0.1 0.1 eq ok 2 | 0.1 0.2 eq not ok 3 | 0.1 -0.1 eq not ok 4 | -0.1 -0.1 eq ok 5 | 6 | 0.1 0.1 fadd 0.2 eq ok 7 | 0.2 0.2 fadd 0.4 eq ok 8 | 0.1 -0.1 fadd 0.0 eq ok 9 | 10 | 0.1 0.1 fdiv 1.0 eq ok 11 | 0.5 0.2 fdiv 2.5 eq ok 12 | 5.0 2.0 fdiv 2.5 eq ok 13 | 14 | 1.0 float-to-int 1 eq ok 15 | -------------------------------------------------------------------------------- /examples/primitives/int.fth: -------------------------------------------------------------------------------- 1 | 1 1 eq ok 2 | 1 2 eq not ok 3 | 1 -1 eq not ok 4 | -1 -1 eq ok 5 | 6 | 1 1 iadd 2 eq ok 7 | 2 2 iadd 4 eq ok 8 | 1 -1 iadd 0 eq ok 9 | 10 | 1 1 imul 1 eq ok 11 | 2 2 imul 4 eq ok 12 | 2 -1 imul -2 eq ok 13 | 14 | 1 1 idiv 1 eq ok 15 | 5 2 idiv 2 eq ok 16 | 5 2 imod 1 eq ok 17 | 18 | 1 int-to-float 1.0 eq ok 19 | -------------------------------------------------------------------------------- /examples/primitives/value.fth: -------------------------------------------------------------------------------- 1 | true false eq not ok 2 | 3 | true dup ok ok 4 | true true false swap ok drop ok 5 | true false false rot ok not ok not ok 6 | true false tuck not ok ok not ok 7 | true false over ok not ok ok 8 | -------------------------------------------------------------------------------- /examples/readme/list.fth: -------------------------------------------------------------------------------- 1 | define-node null -- value! end 2 | define-node cons tail head -- value! end 3 | define-node append target! rest -- result end 4 | 5 | define-rule null append 6 | ( rest result ) 7 | rest result connect 8 | end 9 | 10 | define-rule cons append 11 | ( rest result ) ( tail head ) 12 | tail rest append 13 | head cons result connect 14 | end 15 | 16 | define-node sole -- value! end 17 | 18 | null sole cons sole cons sole cons 19 | null sole cons sole cons sole cons 20 | append 21 | 22 | inspect-run -------------------------------------------------------------------------------- /examples/readme/list.play.fth: -------------------------------------------------------------------------------- 1 | define-node null -- value! end 2 | define-node cons tail head -- value! end 3 | define-node append target! rest -- result end 4 | 5 | define-rule null append 6 | ( rest result ) 7 | rest result connect 8 | end 9 | 10 | define-rule cons append 11 | ( rest result ) ( tail head ) 12 | tail rest append 13 | head cons result connect 14 | end 15 | 16 | define-node sole -- value! end 17 | 18 | null sole cons sole cons sole cons 19 | null sole cons sole cons sole cons 20 | append 21 | -------------------------------------------------------------------------------- /examples/readme/nat.fth: -------------------------------------------------------------------------------- 1 | define-node zero -- value! end 2 | define-node add1 prev -- value! end 3 | define-node add target! addend -- result end 4 | 5 | define-rule zero add 6 | ( addend result ) 7 | addend result connect 8 | end 9 | 10 | define-rule add1 add 11 | ( addend result ) ( prev ) 12 | prev addend add 13 | add1 result connect 14 | end 15 | 16 | define two 17 | zero add1 add1 18 | end 19 | 20 | two two add 21 | 22 | inspect-run 23 | -------------------------------------------------------------------------------- /examples/readme/nat.play.fth: -------------------------------------------------------------------------------- 1 | define-node zero -- value! end 2 | define-node add1 prev -- value! end 3 | define-node add target! addend -- result end 4 | 5 | define-rule zero add 6 | ( addend result ) 7 | addend result connect 8 | end 9 | 10 | define-rule add1 add 11 | ( addend result ) ( prev ) 12 | prev addend add 13 | add1 result connect 14 | end 15 | 16 | zero add1 add1 17 | zero add1 add1 18 | add 19 | 20 | define two zero add1 add1 end 21 | 22 | two two add 23 | two two add 24 | add 25 | -------------------------------------------------------------------------------- /examples/tests/empty-file.test.fth: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cicada-lang/inet-forth/d11c34b36846198fa0f48c00fd5502a18705e37b/examples/tests/empty-file.test.fth -------------------------------------------------------------------------------- /examples/tests/empty-file.test.fth.out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cicada-lang/inet-forth/d11c34b36846198fa0f48c00fd5502a18705e37b/examples/tests/empty-file.test.fth.out -------------------------------------------------------------------------------- /examples/tests/line-comment.test.fth: -------------------------------------------------------------------------------- 1 | // line comment 2 | -------------------------------------------------------------------------------- /examples/tests/line-comment.test.fth.out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cicada-lang/inet-forth/d11c34b36846198fa0f48c00fd5502a18705e37b/examples/tests/line-comment.test.fth.out -------------------------------------------------------------------------------- /examples/tests/local.fth: -------------------------------------------------------------------------------- 1 | define my-drop 2 | ( x ) 3 | end 4 | 5 | 1 2 my-drop 1 eq ok 6 | 7 | define my-swap 8 | ( x y ) 9 | y x 10 | end 11 | 12 | 1 2 swap 13 | 1 eq ok 14 | 2 eq ok 15 | -------------------------------------------------------------------------------- /examples/tests/square.fth: -------------------------------------------------------------------------------- 1 | define square 2 | dup imul 3 | end 4 | 5 | 1 square 1 eq ok 6 | 2 square 4 eq ok 7 | 3 square 9 eq ok 8 | 9 | define two 2 end 10 | 11 | two square 4 eq ok 12 | -------------------------------------------------------------------------------- /examples/tests/undefined-node.error.fth: -------------------------------------------------------------------------------- 1 | define-rule zero add 2 | ( addend result ) 3 | addend result connect 4 | end 5 | 6 | define-rule add1 add 7 | ( addend result ) ( prev ) 8 | prev addend add 9 | add1 result connect 10 | end 11 | -------------------------------------------------------------------------------- /examples/tests/undefined-node.error.fth.err: -------------------------------------------------------------------------------- 1 | [check_node_name_defined] undefined node name: zero 2 | [check_node_name_defined] path: examples/tests/undefined-node.error.fth 3 | > 1|define-rule zero add 4 | 2| ( addend result ) 5 | 3| addend result connect 6 | 4|end 7 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | cc = cc 2 | ifeq ($(STATIC), true) 3 | static_ldflags = \ 4 | -static 5 | endif 6 | ifeq ($(TSAN), true) 7 | tsan_ldflags = -fsanitize=thread 8 | tsan_cflags= -fsanitize=thread 9 | endif 10 | ldflags = \ 11 | -L/usr/local/lib \ 12 | -lm \ 13 | -pthread \ 14 | $(static_ldflags) \ 15 | $(tsan_ldflags) \ 16 | $(LDFLAGS) 17 | cflags = \ 18 | -g \ 19 | -O3 \ 20 | -std=c2x \ 21 | -I/usr/local/include \ 22 | -Wall \ 23 | -Wwrite-strings \ 24 | -Wextra \ 25 | -Werror \ 26 | -Wpedantic \ 27 | -D_POSIX_C_SOURCE=200809L \ 28 | -D_TIME_BITS=64 \ 29 | -D_FILE_OFFSET_BITS=64 \ 30 | $(tsan_cflags) \ 31 | $(CFLAGS) 32 | src = $(shell find src -name '*.c') 33 | headers = $(shell find src -name '*.h') 34 | lib = $(patsubst src/%, lib/%, $(patsubst %.c, %.o, $(src))) 35 | app = inet-forth 36 | bin = bin/$(app) 37 | 38 | .PHONY: all run test-packages test-self run-examples test clean 39 | 40 | all: bin/$(app) 41 | 42 | run: bin/$(app) 43 | ./bin/$(app) 44 | 45 | test-packages: bin/$(app) 46 | ./bin/$(app) test-packages 47 | 48 | test-self: bin/$(app) 49 | ./bin/$(app) test-self 50 | 51 | run-examples: bin/$(app) 52 | bash run-examples.sh 53 | 54 | test: test-packages test-self run-examples 55 | 56 | bin/$(app): $(lib) lib/$(app).o 57 | mkdir -p $(dir $@) && $(cc) $^ $(ldflags) -o $@ 58 | 59 | lib/%.o: src/%.c $(headers) 60 | mkdir -p $(dir $@) && $(cc) -c $(cflags) $< -o $@ 61 | 62 | clean: 63 | rm -rf lib bin 64 | -------------------------------------------------------------------------------- /run-examples.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | bin=./bin/inet-forth 4 | ext=fth 5 | 6 | for example in $(find examples -name "*.${ext}" -not -name "*.test.${ext}" -not -name "*.error.${ext}" -not -name "*.play.${ext}"); do 7 | echo "[run] $example" 8 | ${bin} run $example 9 | done 10 | 11 | for example in $(find examples -name "*.test.${ext}"); do 12 | echo "[test] $example" 13 | ${bin} run $example > $example.out 14 | done 15 | 16 | for example in $(find examples -name "*.error.${ext}"); do 17 | echo "[error] $example" 18 | ${bin} run $example > $example.err || true 19 | done 20 | -------------------------------------------------------------------------------- /src/commands/deps.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../deps.h" 4 | #include "../core/index.h" 5 | #include "../prelude/index.h" 6 | -------------------------------------------------------------------------------- /src/commands/index.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "deps.h" 4 | 5 | commander_plugin_fn_t cmd_run; 6 | commander_plugin_fn_t cmd_info; 7 | commander_plugin_fn_t cmd_test_self; 8 | commander_plugin_fn_t cmd_test_packages; 9 | -------------------------------------------------------------------------------- /src/commands/info_command.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | static int run(commander_t *commander); 4 | 5 | void 6 | cmd_info(commander_t *commander) { 7 | command_t *command = command_new("info"); 8 | command->description = "print system info"; 9 | command->run = run; 10 | commander_add(commander, command); 11 | } 12 | 13 | int 14 | run(commander_t *commander) { 15 | (void) commander; 16 | 17 | printf("page size: %ld bytes\n", sysconf(_SC_PAGE_SIZE)); 18 | printf("number of processors: %ld\n", sysconf(_SC_NPROCESSORS_ONLN)); 19 | printf("size of time_t: %ld bits\n", sizeof(time_t) * 8); 20 | 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /src/commands/run_command.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | static int run(commander_t *commander); 4 | 5 | void 6 | cmd_run(commander_t *runner) { 7 | command_t *command = command_new("run"); 8 | command->description = "run files"; 9 | command->run = run; 10 | commander_add(runner, command); 11 | } 12 | 13 | int 14 | run(commander_t *commander) { 15 | char **argv = commander_rest_argv(commander); 16 | while (*argv) { 17 | char *arg = *argv++; 18 | path_t *path = path_new_cwd(); 19 | path_resolve(path, arg); 20 | load_mod(path); 21 | } 22 | 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /src/commands/test_packages_command.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | static int run(commander_t *commander); 4 | 5 | void 6 | cmd_test_packages(commander_t *commander) { 7 | command_t *command = command_new("test-packages"); 8 | command->description = "run test for packages"; 9 | command->run = run; 10 | commander_add(commander, command); 11 | } 12 | 13 | int 14 | run(commander_t *commander) { 15 | (void) commander; 16 | 17 | test_std(); 18 | 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /src/commands/test_self_command.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | static int run(commander_t *commander); 4 | 5 | void 6 | cmd_test_self(commander_t *commander) { 7 | command_t *command = command_new("test-self"); 8 | command->description = "run self test"; 9 | command->run = run; 10 | commander_add(commander, command); 11 | } 12 | 13 | int 14 | run(commander_t *commander) { 15 | (void) commander; 16 | 17 | test_node(); 18 | 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /src/config.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define INET_FORTH_VERSION "0.1.0" 4 | 5 | #define NODE_MAX_ARITY 16 6 | #define NODE_ALLOCATOR_BATCH_SIZE 1024 7 | #define NODE_ALLOCATOR_CACHE_SIZE (64 * 1024) 8 | #define WORKER_TASK_QUEUE_SIZE (1024 * 1024) 9 | 10 | // In a normal build, all debug flag should be off. 11 | 12 | // To detect `worker_handle_task` in two threads 13 | // accessing the same task. 14 | #define DEBUG_TASK_LOCK 0 15 | 16 | // To detect `worker_reconnect_node` 17 | // and `worker_disconnect_node` in two threads 18 | // accessing the same node. 19 | #define DEBUG_NODE_LOCK 0 20 | 21 | // To exclude problem with `node_allocator_t`. 22 | // - To exclude ABA problem 23 | // we do not even free the memory of node. 24 | // - When `node_allocator_t` is not used, 25 | // we can not print the net, so printing is 26 | // also disabled when this flag is on. 27 | #define DEBUG_NODE_ALLOCATOR_DISABLED 0 28 | 29 | #define DEBUG_WORK_STEALING_DISABLED 0 30 | 31 | #define DEBUG_TASK_LOG 0 32 | #define DEBUG_STEP_LOG 0 33 | -------------------------------------------------------------------------------- /src/core/connect.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | task_t *connect(value_t left, value_t right); 4 | -------------------------------------------------------------------------------- /src/core/deps.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../deps.h" 4 | #include "../value/index.h" 5 | #include "../net/index.h" 6 | -------------------------------------------------------------------------------- /src/core/frame.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | #define VARIABLE_ARRAY_SIZE 64 4 | 5 | struct frame_t { 6 | size_t cursor; 7 | const function_t *function; 8 | array_t *variable_array; 9 | }; 10 | 11 | frame_t * 12 | frame_new(const function_t *function) { 13 | frame_t *self = new(frame_t); 14 | self->cursor = 0; 15 | self->function = function; 16 | self->variable_array = array_new(VARIABLE_ARRAY_SIZE); 17 | return self; 18 | } 19 | 20 | void 21 | frame_destroy(frame_t **self_pointer) { 22 | assert(self_pointer); 23 | if (*self_pointer == NULL) return; 24 | 25 | frame_t *self = *self_pointer; 26 | // does not own function 27 | array_destroy(&self->variable_array); 28 | free(self); 29 | *self_pointer = NULL; 30 | } 31 | 32 | bool 33 | frame_is_finished(const frame_t *self) { 34 | return self->cursor == function_length(self->function); 35 | } 36 | 37 | opcode_t * 38 | frame_fetch_opcode(frame_t *self) { 39 | opcode_t *opcode = function_get_opcode(self->function, self->cursor); 40 | self->cursor++; 41 | return opcode; 42 | } 43 | 44 | void 45 | frame_print(const frame_t *self, file_t *file) { 46 | fprintf(file, "\n"); 47 | 48 | fprintf(file, "\n"); 49 | function_print_with_cursor(self->function, file, self->cursor); 50 | fprintf(file, "\n"); 51 | 52 | fprintf(file, "\n"); 53 | } 54 | 55 | value_t 56 | frame_get_variable(const frame_t *self, size_t index) { 57 | return array_get(self->variable_array, index); 58 | } 59 | 60 | void 61 | frame_set_variable(frame_t *self, size_t index, value_t value) { 62 | array_set(self->variable_array, index, value); 63 | } 64 | -------------------------------------------------------------------------------- /src/core/frame.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | frame_t *frame_new(const function_t *function); 4 | void frame_destroy(frame_t **self_pointer); 5 | 6 | bool frame_is_finished(const frame_t *self); 7 | opcode_t *frame_fetch_opcode(frame_t *self); 8 | void frame_print(const frame_t *self, file_t *file); 9 | 10 | value_t frame_get_variable(const frame_t *self, size_t index); 11 | void frame_set_variable(frame_t *self, size_t index, value_t value); 12 | -------------------------------------------------------------------------------- /src/core/function.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | extern object_spec_t function_object_spec; 4 | 5 | struct function_t { 6 | object_spec_t *spec; 7 | char *name; 8 | size_t arity; 9 | hash_t *local_index_hash; 10 | array_t *opcode_array; 11 | }; 12 | 13 | function_t *function_new(void); 14 | void function_destroy(function_t **self_pointer); 15 | 16 | bool is_function(value_t value); 17 | function_t *as_function(value_t value); 18 | 19 | size_t function_length(const function_t *self); 20 | 21 | void function_add_opcode(function_t *self, opcode_t *opcode); 22 | opcode_t *function_get_opcode(const function_t *self, size_t index); 23 | 24 | void function_print_name(const function_t *self, file_t *file); 25 | void function_print(const function_t *self, file_t *file); 26 | void function_print_with_cursor(const function_t *self, file_t *file, size_t cursor); 27 | -------------------------------------------------------------------------------- /src/core/index.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "deps.h" 4 | #include "types.h" 5 | #include "mod.h" 6 | #include "frame.h" 7 | #include "task.h" 8 | #include "worker.h" 9 | #include "scheduler.h" 10 | #include "opcode.h" 11 | #include "function.h" 12 | #include "rule.h" 13 | #include "primitive.h" 14 | #include "connect.h" 15 | -------------------------------------------------------------------------------- /src/core/mod.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | mod_t * 4 | mod_new(path_t *path, char *code) { 5 | mod_t *self = new(mod_t); 6 | self->path = path; 7 | self->code = code; 8 | self->value_hash = hash_of_string_key(); 9 | // TODO we do not have `value_destroy` for now 10 | // hash_set_destroy_fn(self->value_hash, (destroy_fn_t *) value_destroy); 11 | return self; 12 | } 13 | 14 | void 15 | mod_destroy(mod_t **self_pointer) { 16 | assert(self_pointer); 17 | if (*self_pointer == NULL) return; 18 | 19 | mod_t *self = *self_pointer; 20 | path_destroy(&self->path); 21 | string_destroy(&self->code); 22 | hash_destroy(&self->value_hash); 23 | worker_destroy(&self->loader_worker); 24 | free(self); 25 | *self_pointer = NULL; 26 | } 27 | 28 | value_t 29 | mod_find(const mod_t *self, const char *name) { 30 | return hash_get(self->value_hash, name); 31 | } 32 | 33 | void 34 | mod_define_rule( 35 | mod_t *self, 36 | const char *first_name, 37 | const char *second_name, 38 | function_t *function 39 | ) { 40 | value_t first = mod_find(self, first_name); 41 | value_t second = mod_find(self, second_name); 42 | 43 | assert(is_node_ctor(first)); 44 | assert(is_node_ctor(second)); 45 | 46 | const node_ctor_t *left_node_ctor = as_node_ctor(first); 47 | const node_ctor_t *right_node_ctor = as_node_ctor(second); 48 | 49 | rule_t *rule = rule_new(left_node_ctor, right_node_ctor, function); 50 | 51 | if (left_node_ctor == right_node_ctor) { 52 | array_push(left_node_ctor->rule_array, rule); 53 | } else { 54 | array_push(left_node_ctor->rule_array, rule); 55 | array_push(right_node_ctor->rule_array, rule); 56 | } 57 | } 58 | 59 | void 60 | mod_print(const mod_t *self, file_t *file) { 61 | fprintf(file, "\n", hash_length(self->value_hash)); 62 | 63 | value_t value = hash_first(self->value_hash); 64 | while (value) { 65 | value_print(value, file); 66 | fprintf(file, "\n"); 67 | value = hash_next(self->value_hash); 68 | } 69 | 70 | fprintf(file, "\n"); 71 | } 72 | -------------------------------------------------------------------------------- /src/core/mod.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // A mod is a compilation unit, 4 | // like the dictionary of forth. 5 | 6 | struct mod_t { 7 | path_t *path; 8 | char *code; 9 | hash_t *value_hash; 10 | // the worker that is used to load this mod, 11 | // owned by this mod. 12 | // - used by `player_start` 13 | worker_t *loader_worker; 14 | }; 15 | 16 | mod_t *mod_new(path_t *path, char *code); 17 | void mod_destroy(mod_t **self_pointer); 18 | 19 | value_t mod_find(const mod_t *self, const char *name); 20 | void mod_define_rule(mod_t *self, const char *first_name, const char *second_name, function_t *function); 21 | 22 | void mod_print(const mod_t *self, file_t *file); 23 | -------------------------------------------------------------------------------- /src/core/opcode.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | opcode_t * 4 | opcode_apply(size_t arity) { 5 | opcode_t *self = new(opcode_t); 6 | self->kind = OPCODE_APPLY; 7 | self->apply.arity = arity; 8 | return self; 9 | } 10 | 11 | opcode_t * 12 | opcode_literal(value_t value) { 13 | opcode_t *self = new(opcode_t); 14 | self->kind = OPCODE_LITERAL; 15 | self->literal.value = value; 16 | return self; 17 | } 18 | 19 | 20 | opcode_t * 21 | opcode_get_variable(size_t index) { 22 | opcode_t *self = new(opcode_t); 23 | self->kind = OPCODE_GET_VARIABLE; 24 | self->get_variable.index = index; 25 | return self; 26 | } 27 | 28 | opcode_t * 29 | opcode_set_variable(size_t index) { 30 | opcode_t *self = new(opcode_t); 31 | self->kind = OPCODE_SET_VARIABLE; 32 | self->set_variable.index = index; 33 | return self; 34 | } 35 | 36 | void 37 | opcode_destroy(opcode_t **self_pointer) { 38 | assert(self_pointer); 39 | if (*self_pointer == NULL) return; 40 | 41 | opcode_t *self = *self_pointer; 42 | switch (self->kind) { 43 | case OPCODE_APPLY: { 44 | break; 45 | } 46 | 47 | case OPCODE_LITERAL: { 48 | break; 49 | } 50 | 51 | case OPCODE_GET_VARIABLE: { 52 | break; 53 | } 54 | 55 | case OPCODE_SET_VARIABLE: { 56 | break; 57 | } 58 | } 59 | 60 | free(self); 61 | *self_pointer = NULL; 62 | return; 63 | } 64 | 65 | void 66 | opcode_print(const opcode_t *self, file_t *file) { 67 | switch (self->kind) { 68 | case OPCODE_APPLY: { 69 | fprintf(file, "(apply %lu)", self->apply.arity); 70 | return; 71 | } 72 | 73 | case OPCODE_LITERAL: { 74 | fprintf(file, "(literal "); 75 | value_print(self->literal.value, file); 76 | fprintf(file, ")"); 77 | return; 78 | } 79 | 80 | case OPCODE_GET_VARIABLE: { 81 | fprintf(file, "(get-variable %ld)", self->get_variable.index); 82 | return; 83 | } 84 | 85 | case OPCODE_SET_VARIABLE: { 86 | fprintf(file, "(set-variable %ld)", self->set_variable.index); 87 | return; 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/core/opcode.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef enum { 4 | OPCODE_APPLY, 5 | OPCODE_LITERAL, 6 | OPCODE_GET_VARIABLE, 7 | OPCODE_SET_VARIABLE, 8 | } opcode_kind_t; 9 | 10 | struct opcode_t { 11 | opcode_kind_t kind; 12 | union { 13 | struct { size_t arity; } apply; 14 | struct { value_t value; } literal; 15 | struct { size_t index; } get_variable; 16 | struct { size_t index; } set_variable; 17 | }; 18 | }; 19 | 20 | opcode_t *opcode_apply(size_t arity); 21 | opcode_t *opcode_literal(value_t value); 22 | opcode_t *opcode_get_variable(size_t index); 23 | opcode_t *opcode_set_variable(size_t index); 24 | 25 | void opcode_destroy(opcode_t **self_pointer); 26 | 27 | void opcode_print(const opcode_t *self, file_t *file); 28 | -------------------------------------------------------------------------------- /src/core/primitive.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef void (primitive_fn_t)(worker_t *worker); 4 | typedef value_t (primitive_fn_0_t)(void); 5 | typedef value_t (primitive_fn_1_t)(value_t x); 6 | typedef value_t (primitive_fn_2_t)(value_t x, value_t y); 7 | typedef value_t (primitive_fn_3_t)(value_t x, value_t y, value_t z); 8 | typedef value_t (primitive_fn_4_t)(value_t x, value_t y, value_t z, value_t w); 9 | 10 | typedef enum { 11 | PRIMITIVE_FN, 12 | PRIMITIVE_FN_0, 13 | PRIMITIVE_FN_1, 14 | PRIMITIVE_FN_2, 15 | PRIMITIVE_FN_3, 16 | PRIMITIVE_FN_4, 17 | } primitive_fn_kind_t; 18 | 19 | extern object_spec_t primitive_object_spec; 20 | 21 | struct primitive_t { 22 | object_spec_t *spec; 23 | char *name; 24 | // has an optional `node_ctor` means 25 | // this primitive is generic on wires. 26 | node_ctor_t *node_ctor; 27 | size_t input_arity; 28 | size_t output_arity; 29 | primitive_fn_kind_t fn_kind; 30 | union { 31 | primitive_fn_t *primitive_fn; 32 | primitive_fn_0_t *primitive_fn_0; 33 | primitive_fn_1_t *primitive_fn_1; 34 | primitive_fn_2_t *primitive_fn_2; 35 | primitive_fn_3_t *primitive_fn_3; 36 | primitive_fn_4_t *primitive_fn_4; 37 | }; 38 | }; 39 | 40 | primitive_t *primitive_from_fn(const char *name, size_t input_arity, size_t output_arity, primitive_fn_t *primitive_fn); 41 | primitive_t *primitive_from_fn_0(const char *name, primitive_fn_0_t *primitive_fn_0); 42 | primitive_t *primitive_from_fn_1(const char *name, primitive_fn_1_t *primitive_fn_1); 43 | primitive_t *primitive_from_fn_2(const char *name, primitive_fn_2_t *primitive_fn_2); 44 | primitive_t *primitive_from_fn_3(const char *name, primitive_fn_3_t *primitive_fn_3); 45 | primitive_t *primitive_from_fn_4(const char *name, primitive_fn_4_t *primitive_fn_4); 46 | 47 | void primitive_destroy(primitive_t **self_pointer); 48 | 49 | bool is_primitive(value_t value); 50 | primitive_t *as_primitive(value_t value); 51 | 52 | void primitive_print(primitive_t *self, file_t *file); 53 | -------------------------------------------------------------------------------- /src/core/rule.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | rule_t * 4 | rule_new( 5 | const node_ctor_t *left_node_ctor, 6 | const node_ctor_t *right_node_ctor, 7 | const function_t *function 8 | ) { 9 | rule_t *self = new(rule_t); 10 | self->left_node_ctor = left_node_ctor; 11 | self->right_node_ctor = right_node_ctor; 12 | self->function = function; 13 | return self; 14 | } 15 | 16 | void 17 | rule_destroy(rule_t **self_pointer) { 18 | assert(self_pointer); 19 | if (*self_pointer == NULL) return; 20 | 21 | rule_t *self = *self_pointer; 22 | // NOTE A rule dose not own `function`. 23 | // because they might be shared. 24 | // function_destroy(&self->function); 25 | free(self); 26 | *self_pointer = NULL; 27 | } 28 | 29 | void 30 | rule_print(const rule_t *self, file_t *file) { 31 | fprintf(file, "! (%s)-(%s) ", 32 | self->left_node_ctor->name, 33 | self->right_node_ctor->name); 34 | function_print(self->function, file); 35 | } 36 | -------------------------------------------------------------------------------- /src/core/rule.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct rule_t { 4 | const node_ctor_t *left_node_ctor; 5 | const node_ctor_t *right_node_ctor; 6 | const function_t *function; 7 | }; 8 | 9 | rule_t *rule_new( 10 | const node_ctor_t *left_node_ctor, 11 | const node_ctor_t *right_node_ctor, 12 | const function_t *function); 13 | void rule_destroy(rule_t **self_pointer); 14 | 15 | void rule_print(const rule_t *self, file_t *file); 16 | -------------------------------------------------------------------------------- /src/core/scheduler.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | scheduler_t * 4 | scheduler_new(mod_t *mod, node_allocator_t *node_allocator, size_t worker_count) { 5 | scheduler_t *self = new(scheduler_t); 6 | self->mod = mod; 7 | self->node_allocator = node_allocator; 8 | self->worker_array = array_new_auto_with((destroy_fn_t *) worker_destroy); 9 | for (size_t i = 0; i < worker_count; i++) { 10 | worker_t *worker = worker_new(mod, node_allocator); 11 | worker->scheduler = self; 12 | worker->index = i; 13 | array_push(self->worker_array, worker); 14 | } 15 | 16 | self->worker_tid_array = array_new_auto(); 17 | atomic_init(&self->atomic_task_count, 0); 18 | return self; 19 | } 20 | 21 | void 22 | scheduler_destroy(scheduler_t **self_pointer) { 23 | assert(self_pointer); 24 | if (*self_pointer == NULL) return; 25 | 26 | scheduler_t *self = *self_pointer; 27 | array_destroy(&self->worker_array); 28 | array_destroy(&self->worker_tid_array); 29 | free(self); 30 | *self_pointer = NULL; 31 | } 32 | 33 | size_t 34 | scheduler_worker_count(scheduler_t *self) { 35 | return array_length(self->worker_array); 36 | } 37 | 38 | void 39 | scheduler_start(scheduler_t *scheduler, thread_fn_t *worker_thread_fn) { 40 | for (size_t i = 0; i < array_length(scheduler->worker_array); i++) { 41 | worker_t *worker = array_get(scheduler->worker_array, i); 42 | tid_t tid = thread_start(worker_thread_fn, worker); 43 | array_set(scheduler->worker_tid_array, i, (void *) (uint64_t) tid); 44 | } 45 | } 46 | 47 | void 48 | scheduler_wait(scheduler_t *scheduler) { 49 | for (size_t i = 0; i < array_length(scheduler->worker_tid_array); i++) { 50 | tid_t tid = (tid_t) array_get(scheduler->worker_tid_array, i); 51 | thread_wait(tid); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/core/scheduler.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct scheduler_t { 4 | mod_t *mod; 5 | node_allocator_t *node_allocator; 6 | array_t *worker_array; 7 | array_t *worker_tid_array; 8 | atomic_size_t atomic_task_count; 9 | }; 10 | 11 | scheduler_t *scheduler_new(mod_t *mod, node_allocator_t *node_allocator, size_t worker_count); 12 | void scheduler_destroy(scheduler_t **self_pointer); 13 | 14 | size_t scheduler_worker_count(scheduler_t *self); 15 | 16 | void scheduler_start(scheduler_t *scheduler, thread_fn_t *worker_thread_fn); 17 | void scheduler_wait(scheduler_t *scheduler); 18 | -------------------------------------------------------------------------------- /src/core/task.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | task_t * 4 | task_new(principal_wire_t *left, principal_wire_t *right, const rule_t *rule) { 5 | task_t *self = new(task_t); 6 | self->left = left; 7 | self->right = right; 8 | self->rule = rule; 9 | #if DEBUG_TASK_LOCK 10 | self->mutex = mutex_new(); 11 | #endif 12 | return self; 13 | } 14 | 15 | void 16 | task_destroy(task_t **self_pointer) { 17 | assert(self_pointer); 18 | if (*self_pointer == NULL) return; 19 | 20 | task_t *self = *self_pointer; 21 | free(self); 22 | *self_pointer = NULL; 23 | } 24 | 25 | void 26 | task_print(const task_t *self, file_t *file) { 27 | principal_wire_print_left(self->left, file); 28 | principal_wire_print_right(self->right, file); 29 | } 30 | -------------------------------------------------------------------------------- /src/core/task.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct task_t { 4 | principal_wire_t *left; 5 | principal_wire_t *right; 6 | const rule_t *rule; 7 | #if DEBUG_TASK_LOCK 8 | mutex_t *mutex; 9 | #endif 10 | }; 11 | 12 | task_t *task_new(principal_wire_t *left, principal_wire_t *right, const rule_t *rule); 13 | void task_destroy(task_t **self_pointer); 14 | 15 | void task_print(const task_t *self, file_t *file); 16 | -------------------------------------------------------------------------------- /src/core/types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef struct mod_t mod_t; 4 | typedef struct function_t function_t; 5 | typedef struct frame_t frame_t; 6 | typedef struct task_t task_t; 7 | typedef struct worker_t worker_t; 8 | typedef struct scheduler_t scheduler_t; 9 | typedef struct rule_t rule_t; 10 | typedef struct primitive_t primitive_t; 11 | typedef struct def_t def_t; 12 | typedef struct opcode_t opcode_t; 13 | -------------------------------------------------------------------------------- /src/core/worker.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // A worker is like a little forth inner interpreter. 4 | 5 | struct worker_t { 6 | mod_t *mod; 7 | list_t *token_list; 8 | deque_t *task_deque; 9 | stack_t *value_stack; 10 | stack_t *return_stack; 11 | node_allocator_t *node_allocator; 12 | stack_t *free_node_stack; 13 | scheduler_t *scheduler; 14 | size_t index; 15 | size_t victim_cursor; 16 | }; 17 | 18 | worker_t *worker_new(mod_t *mod, node_allocator_t *node_allocator); 19 | void worker_destroy(worker_t **self_pointer); 20 | 21 | void worker_apply(worker_t *worker, value_t target, size_t arity); 22 | void worker_run_until(worker_t *worker, size_t base_length); 23 | 24 | node_t *worker_new_node(worker_t* self, const node_ctor_t *ctor); 25 | void worker_recycle_node(worker_t* self, node_t *node); 26 | 27 | void worker_add_task(worker_t *worker, task_t *task); 28 | void worker_handle_task(worker_t *worker, task_t *task); 29 | void worker_reconnect_node(worker_t *worker, node_t *node); 30 | void worker_disconnect_node(worker_t *worker, node_t *node); 31 | void worker_work_sequentially(worker_t *worker); 32 | void worker_work_parallelly(worker_t *worker); 33 | void worker_work(worker_t *worker); 34 | 35 | node_t *worker_lookup_node_by_wire(worker_t* self, wire_t *wire); 36 | 37 | void worker_print_return_stack(const worker_t *self, file_t *file); 38 | void worker_print_value_stack(const worker_t *self, file_t *file); 39 | void worker_print(const worker_t *self, file_t *file); 40 | -------------------------------------------------------------------------------- /src/core/worker_add_task.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | void 4 | worker_add_task(worker_t *worker, task_t *task) { 5 | deque_push_back(worker->task_deque, task); 6 | 7 | if (worker->scheduler) { 8 | atomic_fetch_add_explicit( 9 | &worker->scheduler->atomic_task_count, 10 | 1, 11 | memory_order_release); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/core/worker_disconnect_node.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | void 4 | worker_disconnect_node(worker_t *worker, node_t *node) { 5 | #if DEBUG_NODE_LOCK 6 | while (!mutex_try_lock(node->mutex)) { 7 | file_lock(stdout); 8 | who_printf("lock contention! "); 9 | printf("worker #%lu, ", worker->index); 10 | printf("locked by #%lu, ", ((worker_t *) node->locked_by_worker)->index); 11 | printf("node: "); node_print(node, stdout); 12 | printf("\n"); 13 | file_unlock(stdout); 14 | } 15 | #else 16 | mutex_lock(node->mutex); 17 | #endif 18 | 19 | for (size_t i = 0; i < node->ctor->arity; i++) { 20 | value_t value = node_get_value(node, i); 21 | if (is_principal_wire(value)) { 22 | principal_wire_t *principal_wire = as_principal_wire(value); 23 | principal_wire_destroy(&principal_wire); 24 | } else { 25 | stack_push(worker->value_stack, value); 26 | } 27 | } 28 | 29 | #if DEBUG_NODE_LOCK 30 | mutex_unlock(node->mutex); 31 | #else 32 | mutex_unlock(node->mutex); 33 | #endif 34 | 35 | worker_recycle_node(worker, node); 36 | } 37 | -------------------------------------------------------------------------------- /src/core/worker_handle_task.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | void 4 | worker_handle_task(worker_t *worker, task_t *task) { 5 | #if DEBUG_TASK_LOCK 6 | mutex_t *mutex = task->mutex; 7 | while (!mutex_try_lock(mutex)) { 8 | file_lock(stdout); 9 | who_printf("lock contention! "); 10 | printf("worker #%ld, ", worker->index); 11 | printf("task: "); task_print(task, stdout); 12 | printf("\n"); 13 | file_unlock(stdout); 14 | } 15 | #endif 16 | 17 | #if DEBUG_TASK_LOG 18 | file_lock(stdout); 19 | who_printf("worker #%ld, ", worker->index); 20 | printf("task: "); task_print(task, stdout); 21 | printf("\n"); 22 | file_unlock(stdout); 23 | #endif 24 | // NOTE The follow assertions can be used to verify that 25 | // the oppsite node in a task can not be synchronized by the task queue. 26 | // Thus lock on node (in `worker_disconnect_node`) is required. 27 | 28 | // { 29 | // assert(acquire_load(&task->left->node->atomic_is_ready)); 30 | // assert(acquire_load(&task->right->node->atomic_is_ready)); 31 | // } 32 | 33 | worker_disconnect_node(worker, task->left->node); 34 | worker_disconnect_node(worker, task->right->node); 35 | 36 | size_t base_length = stack_length(worker->return_stack); 37 | frame_t *frame = frame_new(task->rule->function); 38 | task_destroy(&task); 39 | stack_push(worker->return_stack, frame); 40 | worker_run_until(worker, base_length); 41 | 42 | #if DEBUG_TASK_LOCK 43 | mutex_unlock(mutex); 44 | mutex_destroy(&mutex); 45 | #endif 46 | } 47 | -------------------------------------------------------------------------------- /src/core/worker_run_until.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | inline static void 4 | worker_execute_opcode(worker_t *worker, frame_t *frame, opcode_t *opcode) { 5 | switch (opcode->kind) { 6 | case OPCODE_APPLY: { 7 | value_t target = stack_pop(worker->value_stack); 8 | worker_apply(worker, target, opcode->apply.arity); 9 | return; 10 | } 11 | 12 | case OPCODE_LITERAL: { 13 | stack_push(worker->value_stack, opcode->literal.value); 14 | return; 15 | } 16 | 17 | case OPCODE_GET_VARIABLE: { 18 | value_t value = frame_get_variable(frame, opcode->get_variable.index); 19 | stack_push(worker->value_stack, value); 20 | return; 21 | } 22 | 23 | case OPCODE_SET_VARIABLE: { 24 | value_t value = stack_pop(worker->value_stack); 25 | frame_set_variable(frame, opcode->set_variable.index, value); 26 | return; 27 | } 28 | } 29 | } 30 | 31 | inline static void 32 | worker_run_one_step(worker_t *worker) { 33 | if (stack_is_empty(worker->return_stack)) return; 34 | 35 | frame_t *frame = stack_pop(worker->return_stack); 36 | if (frame_is_finished(frame)) { 37 | frame_destroy(&frame); 38 | return; 39 | } 40 | 41 | opcode_t *op = frame_fetch_opcode(frame); 42 | 43 | // proper tail-call = do not push finished frame. 44 | bool finished = frame_is_finished(frame); 45 | if (!finished) { 46 | stack_push(worker->return_stack, frame); 47 | } 48 | 49 | worker_execute_opcode(worker, frame, op); 50 | 51 | if (finished) { 52 | frame_destroy(&frame); 53 | } 54 | 55 | #if DEBUG_STEP_LOG 56 | worker_print(worker, stdout); 57 | fprintf(stdout, "\n"); 58 | #endif 59 | } 60 | 61 | void 62 | worker_run_until(worker_t *worker, size_t base_length) { 63 | while (stack_length(worker->return_stack) > base_length) { 64 | worker_run_one_step(worker); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/core/worker_work.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | void 4 | worker_work(worker_t *worker) { 5 | if (single_threaded_flag) { 6 | worker_work_sequentially(worker); 7 | } else { 8 | worker_work_parallelly(worker); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/core/worker_work_sequentially.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | void 4 | worker_work_sequentially(worker_t *worker) { 5 | while (true) { 6 | task_t *task = deque_pop_front(worker->task_deque); 7 | if (!task) return; 8 | worker_handle_task(worker, task); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/deps.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "packages/std/index.h" 4 | 5 | #include "config.h" 6 | #include "flags.h" 7 | -------------------------------------------------------------------------------- /src/flags.c: -------------------------------------------------------------------------------- 1 | #include "deps.h" 2 | 3 | bool single_threaded_flag = false; 4 | bool print_flag = false; 5 | -------------------------------------------------------------------------------- /src/flags.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | extern bool single_threaded_flag; 4 | extern bool print_flag; 5 | -------------------------------------------------------------------------------- /src/inet-forth.c: -------------------------------------------------------------------------------- 1 | #include "deps.h" 2 | #include "commands/index.h" 3 | 4 | int 5 | main(int argc, char *argv[]) { 6 | file_disable_buffer(stdout); 7 | file_disable_buffer(stderr); 8 | 9 | commander_t *commander = commander_new("inet-forth", INET_FORTH_VERSION, argc, argv); 10 | 11 | commander_use(commander, cmd_run); 12 | commander_use(commander, cmd_info); 13 | commander_use(commander, cmd_test_self); 14 | commander_use(commander, cmd_test_packages); 15 | commander_use(commander, cmd_default_version); 16 | commander_use(commander, cmd_default_help); 17 | 18 | return commander_run(commander); 19 | } 20 | -------------------------------------------------------------------------------- /src/lang/checks.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void check_name_not_defined( 4 | const worker_t *worker, 5 | const char *name, 6 | const token_t *token); 7 | void check_name_defined( 8 | const worker_t *worker, 9 | const char *name, 10 | const token_t *token); 11 | void check_node_name_defined( 12 | const worker_t *worker, 13 | const char *name, 14 | const token_t *token); 15 | void check_port_name_defined( 16 | const worker_t *worker, 17 | const char *node_name, 18 | const char *port_name, 19 | const token_t *token); 20 | -------------------------------------------------------------------------------- /src/lang/compile.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void compile_one(worker_t *worker, function_t *function); 4 | function_t *compile_function(worker_t *worker); 5 | -------------------------------------------------------------------------------- /src/lang/compile_function.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | function_t * 4 | compile_function(worker_t *worker) { 5 | function_t *function = function_new(); 6 | while (true) { 7 | assert(list_length(worker->token_list) > 0); 8 | token_t *token = list_first(worker->token_list); 9 | if (string_equal(token->string, "end")) { 10 | (void) list_shift(worker->token_list); 11 | token_destroy(&token); 12 | return function; 13 | } 14 | 15 | compile_one(worker, function); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/lang/define.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | void 4 | define(mod_t *self, const char *name, value_t value) { 5 | assert(hash_set(self->value_hash, string_copy(name), value)); 6 | } 7 | 8 | void 9 | define_function(mod_t *mod, const char *name, function_t *function) { 10 | function->name = string_copy(name); 11 | define(mod, name, function); 12 | } 13 | 14 | void 15 | define_primitive_fn(mod_t *mod, const char *name, size_t input_arity, size_t output_arity, primitive_fn_t *primitive_fn) { 16 | define(mod, name, primitive_from_fn(name, input_arity, output_arity, primitive_fn)); 17 | } 18 | 19 | void 20 | define_primitive_fn_0(mod_t *mod, const char *name, primitive_fn_0_t *primitive_fn_0) { 21 | define(mod, name, primitive_from_fn_0(name, primitive_fn_0)); 22 | } 23 | 24 | void 25 | define_primitive_fn_1(mod_t *mod, const char *name, primitive_fn_1_t *primitive_fn_1) { 26 | define(mod, name, primitive_from_fn_1(name, primitive_fn_1)); 27 | } 28 | 29 | void 30 | define_primitive_fn_2(mod_t *mod, const char *name, primitive_fn_2_t *primitive_fn_2) { 31 | define(mod, name, primitive_from_fn_2(name, primitive_fn_2)); 32 | } 33 | 34 | void 35 | define_primitive_fn_3(mod_t *mod, const char *name, primitive_fn_3_t *primitive_fn_3) { 36 | define(mod, name, primitive_from_fn_3(name, primitive_fn_3)); 37 | } 38 | 39 | void 40 | define_primitive_fn_4(mod_t *mod, const char *name, primitive_fn_4_t *primitive_fn_4) { 41 | define(mod, name, primitive_from_fn_4(name, primitive_fn_4)); 42 | } 43 | -------------------------------------------------------------------------------- /src/lang/define.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void define(mod_t *self, const char *name, value_t value); 4 | void define_constant(mod_t *mod, const char *name, value_t value); 5 | void define_function(mod_t *mod, const char *name, function_t *function); 6 | void define_primitive_fn(mod_t *mod, const char *name, size_t input_arity, size_t output_arity, primitive_fn_t *primitive_fn); 7 | void define_primitive_fn_0(mod_t *mod, const char *name, primitive_fn_0_t *primitive_fn_0); 8 | void define_primitive_fn_1(mod_t *mod, const char *name, primitive_fn_1_t *primitive_fn_1); 9 | void define_primitive_fn_2(mod_t *mod, const char *name, primitive_fn_2_t *primitive_fn_2); 10 | void define_primitive_fn_3(mod_t *mod, const char *name, primitive_fn_3_t *primitive_fn_3); 11 | void define_primitive_fn_4(mod_t *mod, const char *name, primitive_fn_4_t *primitive_fn_4); 12 | -------------------------------------------------------------------------------- /src/lang/deps.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../deps.h" 4 | #include "../core/index.h" 5 | -------------------------------------------------------------------------------- /src/lang/execute.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | static bool 4 | execute_int(worker_t *worker) { 5 | token_t *token = list_first(worker->token_list); 6 | if (token->kind != INT_TOKEN) return false; 7 | if (!string_is_xint(token->string)) return false; 8 | (void) list_shift(worker->token_list); 9 | 10 | value_t value = xint(string_parse_xint(token->string)); 11 | stack_push(worker->value_stack, value); 12 | token_destroy(&token); 13 | return true; 14 | } 15 | 16 | static bool 17 | execute_float(worker_t *worker) { 18 | token_t *token = list_first(worker->token_list); 19 | if (token->kind != FLOAT_TOKEN) return false; 20 | if (!string_is_double(token->string)) return false; 21 | (void) list_shift(worker->token_list); 22 | 23 | value_t value = xfloat(string_parse_double(token->string)); 24 | stack_push(worker->value_stack, value); 25 | token_destroy(&token); 26 | return true; 27 | } 28 | 29 | static bool 30 | execute_generic(worker_t *worker) { 31 | token_t *token = list_first(worker->token_list); 32 | if (token->kind != GENERIC_TOKEN) return false; 33 | 34 | function_t *function = function_new(); 35 | compile_one(worker, function); 36 | 37 | size_t base_length = stack_length(worker->return_stack); 38 | frame_t *frame = frame_new(function); 39 | stack_push(worker->return_stack, frame); 40 | worker_run_until(worker, base_length); 41 | 42 | function_destroy(&function); 43 | return true; 44 | } 45 | 46 | void 47 | execute_one(worker_t *worker) { 48 | if (execute_int(worker)) return; 49 | if (execute_float(worker)) return; 50 | if (execute_generic(worker)) return; 51 | 52 | token_t *token = list_first(worker->token_list); 53 | fprintf(stderr, "[execute_one] unknown token: %s\n", token->string); 54 | } 55 | 56 | void 57 | execute_all(worker_t *worker) { 58 | while (!list_is_empty(worker->token_list)) { 59 | execute_one(worker); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/lang/execute.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void execute_one(worker_t *worker); 4 | void execute_all(worker_t *worker); 5 | -------------------------------------------------------------------------------- /src/lang/index.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "deps.h" 4 | #include "types.h" 5 | #include "execute.h" 6 | #include "checks.h" 7 | #include "define.h" 8 | #include "compile.h" 9 | #include "load.h" 10 | -------------------------------------------------------------------------------- /src/lang/load.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | hash_t *global_mod_hash = NULL; 4 | 5 | extern void import_prelude(mod_t *mod); 6 | 7 | mod_t * 8 | load_mod(path_t *path) { 9 | if (!global_mod_hash) { 10 | global_mod_hash = hash_of_string_key(); 11 | } 12 | 13 | mod_t *found_mod = hash_get(global_mod_hash, path_string(path)); 14 | if (found_mod) { 15 | path_destroy(&path); 16 | return found_mod; 17 | } 18 | 19 | file_t *file = file_open_or_fail(path_string(path), "r"); 20 | char *code = file_read_string(file); 21 | fclose(file); 22 | 23 | mod_t *mod = mod_new(path, code); 24 | import_prelude(mod); 25 | 26 | node_allocator_t *node_allocator = node_allocator_new(); 27 | worker_t *loader_worker = worker_new(mod, node_allocator); 28 | mod->loader_worker = loader_worker; 29 | 30 | execute_all(loader_worker); 31 | 32 | char *key = string_copy(path_string(path)); 33 | assert(hash_set(global_mod_hash, key, mod)); 34 | 35 | return mod; 36 | } 37 | -------------------------------------------------------------------------------- /src/lang/load.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | extern hash_t *global_mod_hash; 4 | 5 | mod_t *load_mod(path_t *path); 6 | -------------------------------------------------------------------------------- /src/lang/types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef struct function_ctx_t function_ctx_t; 4 | -------------------------------------------------------------------------------- /src/net/allocated_node_iter.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | allocated_node_iter_t * 4 | allocated_node_iter_new(node_allocator_t *node_allocator) { 5 | allocated_node_iter_t *self = new(allocated_node_iter_t); 6 | self->node_allocator = node_allocator; 7 | self->cursor = 0; 8 | return self; 9 | } 10 | 11 | void 12 | allocated_node_iter_destroy(allocated_node_iter_t **self_pointer) { 13 | assert(self_pointer); 14 | if (*self_pointer == NULL) return; 15 | 16 | allocated_node_iter_t *self = *self_pointer; 17 | free(self); 18 | *self_pointer = NULL; 19 | } 20 | 21 | node_t * 22 | allocated_node_iter_first(allocated_node_iter_t *self) { 23 | self->cursor = 0; 24 | 25 | node_t *node = array_get(self->node_allocator->node_array, self->cursor++); 26 | while (!node || (node && !node->is_allocated)) { 27 | if (self->cursor >= array_length(self->node_allocator->node_array)) 28 | return NULL; 29 | 30 | node = array_get(self->node_allocator->node_array, self->cursor++); 31 | } 32 | 33 | return node; 34 | } 35 | 36 | node_t * 37 | allocated_node_iter_next(allocated_node_iter_t *self) { 38 | node_t *node = array_get(self->node_allocator->node_array, self->cursor++); 39 | while (!node || (node && !node->is_allocated)) { 40 | if (self->cursor >= array_length(self->node_allocator->node_array)) 41 | return NULL; 42 | 43 | node = array_get(self->node_allocator->node_array, self->cursor++); 44 | } 45 | 46 | return node; 47 | } 48 | 49 | array_t * 50 | allocated_node_array(node_allocator_t *node_allocator) { 51 | mutex_lock(node_allocator->allocator->mutex); 52 | 53 | array_t *node_array = array_new_auto(); 54 | allocated_node_iter_t *allocated_node_iter = allocated_node_iter_new(node_allocator); 55 | node_t *node = allocated_node_iter_first(allocated_node_iter); 56 | while (node) { 57 | array_push(node_array, node); 58 | node = allocated_node_iter_next(allocated_node_iter); 59 | } 60 | 61 | allocated_node_iter_destroy(&allocated_node_iter); 62 | mutex_unlock(node_allocator->allocator->mutex); 63 | return node_array; 64 | } 65 | -------------------------------------------------------------------------------- /src/net/allocated_node_iter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct allocated_node_iter_t { 4 | node_allocator_t *node_allocator; 5 | size_t cursor; 6 | }; 7 | 8 | allocated_node_iter_t *allocated_node_iter_new(node_allocator_t *node_allocator); 9 | void allocated_node_iter_destroy(allocated_node_iter_t **self_pointer); 10 | 11 | node_t *allocated_node_iter_first(allocated_node_iter_t *self); 12 | node_t *allocated_node_iter_next(allocated_node_iter_t *self); 13 | 14 | array_t *allocated_node_array(node_allocator_t *node_allocator); 15 | -------------------------------------------------------------------------------- /src/net/connected_node_iter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct connected_node_iter_t { 4 | node_t *root; 5 | hash_t *node_adjacency_hash; 6 | set_t *occurred_node_set; 7 | list_t *remaining_node_list; 8 | }; 9 | 10 | connected_node_iter_t *connected_node_iter_new(node_t *root, hash_t *node_adjacency_hash); 11 | void connected_node_iter_destroy(connected_node_iter_t **self_pointer); 12 | 13 | node_t *connected_node_iter_first(connected_node_iter_t *self); 14 | node_t *connected_node_iter_next(connected_node_iter_t *self); 15 | 16 | array_t *connected_node_array(node_t *root, hash_t *node_adjacency_hash); 17 | -------------------------------------------------------------------------------- /src/net/deps.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../deps.h" 4 | #include "../value/index.h" 5 | -------------------------------------------------------------------------------- /src/net/index.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "deps.h" 4 | #include "types.h" 5 | #include "node_allocator.h" 6 | #include "node_adjacency.h" 7 | #include "allocated_node_iter.h" 8 | #include "connected_node_iter.h" 9 | #include "node.h" 10 | #include "wire.h" 11 | #include "port_info.h" 12 | #include "principal_wire.h" 13 | #include "node_ctor.h" 14 | #include "test_node.h" 15 | -------------------------------------------------------------------------------- /src/net/node.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct node_t { 4 | const node_ctor_t *ctor; 5 | mutex_t *mutex; 6 | void *locked_by_worker; 7 | size_t id; 8 | bool is_allocated; 9 | value_t *values; 10 | }; 11 | 12 | node_t *node_new(void); 13 | void node_destroy(node_t **self_pointer); 14 | void node_clean(node_t *self); 15 | 16 | void node_set_value(node_t *self, size_t index, value_t value); 17 | value_t node_get_value(const node_t *self, size_t index); 18 | port_info_t *node_get_port_info(const node_t *self, size_t index); 19 | 20 | void node_print_name(const node_t *self, file_t *file); 21 | void node_print(const node_t *self, file_t *file); 22 | void node_print_connected(node_t *self, hash_t *node_adjacency_hash, file_t *file); 23 | 24 | bool node_has_wire(node_t *node, wire_t *wire); 25 | -------------------------------------------------------------------------------- /src/net/node_adjacency.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct node_adjacency_t { 4 | node_t *start_node; 5 | size_t start_port_index; 6 | size_t end_port_index; 7 | node_t *end_node; 8 | }; 9 | 10 | node_adjacency_t *node_adjacency_new_maybe(node_t *start_node, node_t *end_node); 11 | void node_adjacency_destroy(node_adjacency_t **self_pointer); 12 | 13 | hash_t *build_node_adjacency_hash(node_allocator_t *node_allocator); 14 | void node_adjacency_print(const node_adjacency_t *self, file_t *file); 15 | 16 | void node_adjacency_array_print(array_t *node_adjacency_array, file_t *file); 17 | -------------------------------------------------------------------------------- /src/net/node_allocator.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | static void 4 | prepare_one_batch_of_nodes(node_allocator_t *self) { 5 | mutex_lock(self->allocator->mutex); 6 | 7 | for (size_t i = 0; i < self->batch_size; i++) { 8 | node_t *node = node_new(); 9 | node->id = ++self->node_count; 10 | stack_push(self->allocator->stack, node); 11 | array_push(self->node_array, node); 12 | } 13 | 14 | mutex_unlock(self->allocator->mutex); 15 | } 16 | 17 | node_allocator_t * 18 | node_allocator_new(void) { 19 | size_t cache_size = NODE_ALLOCATOR_CACHE_SIZE; 20 | size_t batch_size = NODE_ALLOCATOR_BATCH_SIZE; 21 | 22 | node_allocator_t *self = new(node_allocator_t); 23 | self->allocator = allocator_new(cache_size); 24 | self->batch_size = batch_size; 25 | self->node_array = array_new_auto_with((destroy_fn_t *) node_destroy); 26 | prepare_one_batch_of_nodes(self); 27 | return self; 28 | } 29 | 30 | void 31 | node_allocator_destroy(node_allocator_t **self_pointer) { 32 | assert(self_pointer); 33 | if (*self_pointer == NULL) return; 34 | 35 | node_allocator_t *self = *self_pointer; 36 | allocator_destroy(&self->allocator); 37 | array_destroy(&self->node_array); 38 | free(self); 39 | *self_pointer = NULL; 40 | } 41 | 42 | node_t * 43 | node_allocator_allocate(node_allocator_t *self, stack_t *stack) { 44 | node_t *node = allocator_maybe_allocate(self->allocator, stack); 45 | while (!node) { 46 | prepare_one_batch_of_nodes(self); 47 | node = allocator_maybe_allocate(self->allocator, stack); 48 | } 49 | 50 | node->is_allocated = true; 51 | return node; 52 | } 53 | 54 | void 55 | node_allocator_recycle(node_allocator_t *self, stack_t *stack, node_t **node_pointer) { 56 | node_clean(*node_pointer); 57 | allocator_recycle(self->allocator, stack, (void **) node_pointer); 58 | } 59 | -------------------------------------------------------------------------------- /src/net/node_allocator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct node_allocator_t { 4 | allocator_t *allocator; 5 | size_t node_count; 6 | size_t batch_size; 7 | array_t *node_array; 8 | }; 9 | 10 | node_allocator_t *node_allocator_new(void); 11 | void node_allocator_destroy(node_allocator_t **self_pointer); 12 | 13 | node_t *node_allocator_allocate(node_allocator_t *self, stack_t *stack); 14 | void node_allocator_recycle(node_allocator_t *self, stack_t *stack, node_t **node_pointer); 15 | -------------------------------------------------------------------------------- /src/net/node_ctor.h: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | extern object_spec_t node_ctor_object_spec; 4 | 5 | struct node_ctor_t { 6 | object_spec_t *spec; 7 | char *name; 8 | size_t input_arity; 9 | size_t output_arity; 10 | size_t arity; 11 | port_info_t **port_infos; 12 | array_t *rule_array; 13 | }; 14 | 15 | node_ctor_t *node_ctor_new( 16 | const char *name, 17 | size_t input_arity, 18 | size_t output_arity); 19 | void node_ctor_destroy(node_ctor_t **self_pointer); 20 | 21 | bool is_node_ctor(value_t value); 22 | node_ctor_t *as_node_ctor(value_t value); 23 | 24 | size_t node_ctor_find_port_index(const node_ctor_t *node_ctor, const char *port_name); 25 | 26 | void node_ctor_print(const node_ctor_t *self, file_t *file); 27 | -------------------------------------------------------------------------------- /src/net/port_info.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | port_info_t * 4 | port_info_new(char *name, bool is_principal) { 5 | port_info_t *self = new(port_info_t); 6 | self->name = name; 7 | self->is_principal = is_principal; 8 | return self; 9 | } 10 | 11 | void 12 | port_info_destroy(port_info_t **self_pointer) { 13 | assert(self_pointer); 14 | if (*self_pointer == NULL) return; 15 | 16 | port_info_t *self = *self_pointer; 17 | free(self->name); 18 | free(self); 19 | *self_pointer = NULL; 20 | } 21 | 22 | 23 | port_info_t * 24 | port_info_from_name(char *name) { 25 | if (string_ends_with(name, "!")) { 26 | char *new_name = string_slice(name, 0, strlen(name) - 1); 27 | string_destroy(&name); 28 | return port_info_new(new_name, true); 29 | } else { 30 | return port_info_new(name, false); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/net/port_info.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct port_info_t { 4 | char *name; 5 | bool is_principal; 6 | }; 7 | 8 | port_info_t *port_info_new(char *name, bool is_principal); 9 | void port_info_destroy(port_info_t **self_pointer); 10 | 11 | port_info_t *port_info_from_name(char *name); 12 | -------------------------------------------------------------------------------- /src/net/principal_wire.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | object_spec_t principal_wire_object_spec = { 4 | .name = "principal-wire", 5 | .print_fn = (print_fn_t *) principal_wire_print_left, 6 | }; 7 | 8 | principal_wire_t * 9 | principal_wire_new(node_t *node, size_t index) { 10 | principal_wire_t *self = new(principal_wire_t); 11 | self->spec = &principal_wire_object_spec; 12 | self->node = node; 13 | self->index = index; 14 | return self; 15 | } 16 | 17 | void 18 | principal_wire_destroy(principal_wire_t **self_pointer) { 19 | assert(self_pointer); 20 | if (*self_pointer == NULL) return; 21 | 22 | principal_wire_t *self = *self_pointer; 23 | free(self); 24 | *self_pointer = NULL; 25 | } 26 | 27 | 28 | bool 29 | is_principal_wire(value_t value) { 30 | if (!is_xobject(value)) return false; 31 | return as_object(value)->spec == &principal_wire_object_spec; 32 | } 33 | 34 | principal_wire_t * 35 | as_principal_wire(value_t value) { 36 | assert(is_principal_wire(value)); 37 | return (principal_wire_t *) value; 38 | } 39 | 40 | void 41 | principal_wire_print_left(const principal_wire_t *self, file_t *file) { 42 | assert(self->node); 43 | 44 | node_print(self->node, file); 45 | 46 | if (self->node->ctor) { 47 | port_info_t *port_info = self->node->ctor->port_infos[self->index]; 48 | fprintf(file, "-%s!-<", port_info->name); 49 | } else { 50 | fprintf(file, "-#%lu!-<", self->index); 51 | } 52 | } 53 | 54 | void 55 | principal_wire_print_right(const principal_wire_t *self, file_t *file) { 56 | assert(self->node); 57 | 58 | if (self->node->ctor) { 59 | port_info_t *port_info = self->node->ctor->port_infos[self->index]; 60 | fprintf(file, ">-!%s", port_info->name); 61 | } else { 62 | fprintf(file, ">-!#%lu", self->index); 63 | } 64 | 65 | node_print(self->node, file); 66 | } 67 | -------------------------------------------------------------------------------- /src/net/principal_wire.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | extern object_spec_t principal_wire_object_spec; 4 | 5 | struct principal_wire_t { 6 | object_spec_t *spec; 7 | node_t *node; 8 | size_t index; 9 | principal_wire_t *oppsite; 10 | }; 11 | 12 | principal_wire_t *principal_wire_new(node_t *node, size_t index); 13 | void principal_wire_destroy(principal_wire_t **self_pointer); 14 | 15 | bool is_principal_wire(value_t value); 16 | principal_wire_t *as_principal_wire(value_t value); 17 | 18 | void principal_wire_print_left(const principal_wire_t *self, file_t *file); 19 | void principal_wire_print_right(const principal_wire_t *self, file_t *file); 20 | -------------------------------------------------------------------------------- /src/net/test_node.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | void 4 | test_node(void) { 5 | test_start(); 6 | 7 | test_node_allocator_overhead(); 8 | test_node_allocator_throughput(); 9 | test_node_allocated_node_iter(); 10 | 11 | test_end(); 12 | } 13 | -------------------------------------------------------------------------------- /src/net/test_node.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void test_node(void); 4 | void test_node_allocator_overhead(void); 5 | void test_node_allocator_throughput(void); 6 | void test_node_allocated_node_iter(void); 7 | -------------------------------------------------------------------------------- /src/net/test_node_allocated_node_iter.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | void 4 | test_node_allocated_node_iter(void) { 5 | test_start(); 6 | 7 | node_allocator_t *node_allocator = node_allocator_new(); 8 | 9 | size_t per_thread_node_count = 10; 10 | list_t *node_list = list_new(); 11 | 12 | 13 | { 14 | stack_t *stack = stack_new(); 15 | for (size_t i = 0; i < per_thread_node_count; i++) { 16 | node_t *node = node_allocator_allocate(node_allocator, stack); 17 | list_push(node_list, node); 18 | } 19 | } 20 | 21 | { 22 | stack_t *stack = stack_new(); 23 | for (size_t i = 0; i < per_thread_node_count; i++) { 24 | node_t *node = node_allocator_allocate(node_allocator, stack); 25 | list_push(node_list, node); 26 | } 27 | } 28 | 29 | allocated_node_iter_t *allocated_node_iter = allocated_node_iter_new(node_allocator); 30 | node_t *node = allocated_node_iter_first(allocated_node_iter); 31 | size_t node_count = 0; 32 | while (node) { 33 | who_printf("#%lu node: ", node_count++); 34 | node_print(node, stdout); printf("\n"); 35 | assert(list_find(node_list, node)); 36 | node = allocated_node_iter_next(allocated_node_iter); 37 | } 38 | 39 | assert(node_count == list_length(node_list)); 40 | 41 | node_allocator_destroy(&node_allocator); 42 | 43 | test_end(); 44 | } 45 | -------------------------------------------------------------------------------- /src/net/test_node_allocator_overhead.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | void 4 | test_node_allocator_overhead(void) { 5 | test_start(); 6 | 7 | double start_second = time_second(); 8 | 9 | node_allocator_t *node_allocator = node_allocator_new(); 10 | who_printf("overhead of %d nodes: %f ms\n", 11 | NODE_ALLOCATOR_BATCH_SIZE, 12 | time_passed_second(start_second) * 1000); 13 | 14 | node_allocator_destroy(&node_allocator); 15 | 16 | test_end(); 17 | } 18 | -------------------------------------------------------------------------------- /src/net/test_node_allocator_throughput.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | #define BATCH_SIZE 1000 4 | #define REPEATION_COUNT 10000 5 | 6 | static void * 7 | thread_fn(void *arg) { 8 | node_allocator_t *node_allocator = arg; 9 | stack_t *stack = stack_new(); 10 | 11 | stack_t *allocated_stack = stack_new(); 12 | for (size_t r = 0; r < REPEATION_COUNT; r++) { 13 | for (size_t i = 0; i < BATCH_SIZE; i++) { 14 | node_t *node = node_allocator_allocate(node_allocator, stack); 15 | stack_push(allocated_stack, node); 16 | } 17 | 18 | for (size_t i = 0; i < BATCH_SIZE; i++) { 19 | node_t *node = stack_pop(allocated_stack); 20 | node_allocator_recycle(node_allocator, stack, &node); 21 | } 22 | } 23 | 24 | return NULL; 25 | } 26 | 27 | void 28 | test_node_allocator_throughput(void) { 29 | test_start(); 30 | 31 | node_allocator_t *node_allocator = node_allocator_new(); 32 | 33 | double start_second = time_second(); 34 | 35 | size_t thread_count = 3; 36 | array_t *thread_array = array_new_auto(); 37 | for (size_t i = 0; i < thread_count; i++) { 38 | tid_t tid = thread_start(thread_fn, node_allocator); 39 | array_push(thread_array, (void *) tid); 40 | } 41 | 42 | for (size_t i = 0; i < thread_count; i++) { 43 | tid_t tid = (tid_t) array_pop(thread_array); 44 | thread_wait(tid); 45 | } 46 | 47 | node_allocator_destroy(&node_allocator); 48 | 49 | who_printf("thread_count: %lu\n", thread_count); 50 | double throughput = REPEATION_COUNT * BATCH_SIZE / 1000 / time_passed_second(start_second); 51 | who_printf("throughput: %.f k/s\n", throughput); 52 | 53 | test_end(); 54 | } 55 | -------------------------------------------------------------------------------- /src/net/types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef struct node_allocator_t node_allocator_t; 4 | typedef struct allocated_node_iter_t allocated_node_iter_t; 5 | typedef struct connected_node_iter_t connected_node_iter_t; 6 | typedef struct node_adjacency_t node_adjacency_t; 7 | typedef struct node_t node_t; 8 | typedef struct wire_t wire_t; 9 | typedef struct node_ctor_t node_ctor_t; 10 | typedef struct port_info_t port_info_t; 11 | typedef struct principal_wire_t principal_wire_t; 12 | -------------------------------------------------------------------------------- /src/net/wire.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | object_spec_t wire_object_spec = { 4 | .name = "wire", 5 | }; 6 | 7 | wire_t * 8 | wire_new(void) { 9 | wire_t *self = new(wire_t); 10 | self->spec = &wire_object_spec; 11 | atomic_init(&self->atomic_fuzed_value, NULL); 12 | return self; 13 | } 14 | 15 | void 16 | wire_destroy(wire_t **self_pointer) { 17 | assert(self_pointer); 18 | if (*self_pointer == NULL) return; 19 | 20 | wire_t *self = *self_pointer; 21 | free(self); 22 | *self_pointer = NULL; 23 | } 24 | 25 | bool 26 | is_wire(value_t value) { 27 | if (!is_xobject(value)) return false; 28 | return as_object(value)->spec == &wire_object_spec; 29 | } 30 | 31 | wire_t * 32 | as_wire(value_t value) { 33 | assert(is_wire(value)); 34 | return (wire_t *) value; 35 | } 36 | 37 | static value_t 38 | walk(value_t value) { 39 | while (is_wire(value)) { 40 | wire_t *wire = as_wire(value); 41 | value_t fuzed_value = atomic_load(&wire->atomic_fuzed_value); 42 | if (!fuzed_value) break; 43 | 44 | value = fuzed_value; 45 | } 46 | 47 | return value; 48 | } 49 | 50 | bool 51 | is_fuzed(value_t x, value_t y) { 52 | x = walk(x); 53 | y = walk(y); 54 | return x == y; 55 | } 56 | 57 | bool 58 | is_connected(value_t x, value_t y) { 59 | x = walk(x); 60 | y = walk(y); 61 | 62 | if (is_principal_wire(x) && is_principal_wire(y)) { 63 | return (x == y || 64 | (as_principal_wire(x)->oppsite == y && 65 | as_principal_wire(y)->oppsite == x)); 66 | } else { 67 | return x == y; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/net/wire.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | extern object_spec_t wire_object_spec; 4 | 5 | struct wire_t { 6 | object_spec_t *spec; 7 | // might be `wire_t` or `principal_wire_t` 8 | atomic_value_t atomic_fuzed_value; 9 | }; 10 | 11 | wire_t *wire_new(void); 12 | void wire_destroy(wire_t **self_pointer); 13 | 14 | bool is_wire(value_t value); 15 | wire_t *as_wire(value_t value); 16 | 17 | bool is_fuzed(value_t x, value_t y); 18 | bool is_connected(value_t x, value_t y); 19 | -------------------------------------------------------------------------------- /src/packages/std/allocator/allocator.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | allocator_t * 4 | allocator_new(size_t cache_size) { 5 | allocator_t *self = new_page_aligned(allocator_t); 6 | self->mutex = mutex_new(); 7 | self->stack = stack_new(); 8 | self->cache_size = cache_size; 9 | return self; 10 | } 11 | 12 | void 13 | allocator_destroy(allocator_t **self_pointer) { 14 | assert(self_pointer); 15 | if (*self_pointer == NULL) return; 16 | 17 | allocator_t *self = *self_pointer; 18 | mutex_destroy(&self->mutex); 19 | stack_destroy(&self->stack); 20 | free(self); 21 | *self_pointer = NULL; 22 | } 23 | 24 | void * 25 | allocator_maybe_allocate(allocator_t *self, stack_t *stack) { 26 | if (stack_is_empty(stack)) { 27 | mutex_lock(self->mutex); 28 | 29 | for (size_t i = 0; i < self->cache_size; i++) { 30 | if (stack_is_empty(self->stack)) break; 31 | stack_push(stack, stack_pop(self->stack)); 32 | } 33 | 34 | mutex_unlock(self->mutex); 35 | } 36 | 37 | if (stack_is_empty(stack)) { 38 | return NULL; 39 | } 40 | 41 | return stack_pop(stack); 42 | } 43 | 44 | void * 45 | allocator_allocate(allocator_t *self, stack_t *stack) { 46 | void *value = allocator_maybe_allocate(self, stack); 47 | 48 | if (!value) { 49 | who_printf("not enough value\n"); 50 | exit(1); 51 | } 52 | 53 | return value; 54 | } 55 | 56 | static void 57 | allocator_free(allocator_t *self, stack_t *stack, void *value) { 58 | if (stack_length(stack) >= 2 * self->cache_size) { 59 | mutex_lock(self->mutex); 60 | 61 | for (size_t i = 0; i < self->cache_size; i++) { 62 | stack_push(self->stack, stack_pop(stack)); 63 | } 64 | 65 | mutex_unlock(self->mutex); 66 | } 67 | 68 | stack_push(stack, value); 69 | } 70 | 71 | void 72 | allocator_recycle(allocator_t *self, stack_t *stack, void **value_pointer) { 73 | assert(value_pointer); 74 | if (*value_pointer == NULL) return; 75 | 76 | void *value = *value_pointer; 77 | allocator_free(self, stack, value); 78 | *value_pointer = NULL; 79 | } 80 | -------------------------------------------------------------------------------- /src/packages/std/allocator/allocator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Can be use to allocate value value in parallel, 4 | // learned from section "6.4.3 Resource Allocator Caches" 5 | // of the book "Is Parallel Programming Hard?". 6 | 7 | // - allocate := pop per-thread stack -- return value to caller 8 | // - free := push per-thread stack -- recycle value from caller 9 | 10 | struct allocator_t { 11 | mutex_t *mutex; 12 | stack_t *stack; 13 | size_t cache_size; 14 | }; 15 | 16 | allocator_t *allocator_new(size_t cache_size); 17 | void allocator_destroy(allocator_t **self_pointer); 18 | 19 | void *allocator_maybe_allocate(allocator_t *self, stack_t *stack); 20 | void *allocator_allocate(allocator_t *self, stack_t *stack); 21 | 22 | void allocator_recycle(allocator_t *self, stack_t *stack, void **value_pointer); 23 | -------------------------------------------------------------------------------- /src/packages/std/allocator/deps.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../memory/index.h" 4 | #include "../thread/index.h" 5 | #include "../string/index.h" 6 | #include "../stack/index.h" 7 | #include "../time/index.h" 8 | -------------------------------------------------------------------------------- /src/packages/std/allocator/index.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "deps.h" 4 | #include "types.h" 5 | #include "allocator.h" 6 | #include "test_allocator.h" 7 | -------------------------------------------------------------------------------- /src/packages/std/allocator/test_allocator.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | void 4 | test_allocator(void) { 5 | test_start(); 6 | 7 | test_allocator_throughput(); 8 | test_allocator_thread_safe(); 9 | 10 | test_end(); 11 | } 12 | -------------------------------------------------------------------------------- /src/packages/std/allocator/test_allocator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void test_allocator(void); 4 | void test_allocator_throughput(void); 5 | void test_allocator_thread_safe(void); 6 | -------------------------------------------------------------------------------- /src/packages/std/allocator/test_allocator_throughput.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | #define CACHE_SIZE 1000 4 | #define BATCH_SIZE 1000 5 | #define REPEATION_COUNT 5000 6 | 7 | static void * 8 | thread_fn(void *arg) { 9 | allocator_t *allocator = arg; 10 | stack_t *stack = stack_new(); 11 | 12 | stack_t *allocated_stack = stack_new(); 13 | for (size_t r = 0; r < REPEATION_COUNT; r++) { 14 | for (size_t i = 0; i < BATCH_SIZE; i++) { 15 | void *value = allocator_allocate(allocator, stack); 16 | stack_push(allocated_stack, value); 17 | } 18 | 19 | for (size_t i = 0; i < BATCH_SIZE; i++) { 20 | void *value = stack_pop(allocated_stack); 21 | allocator_recycle(allocator, stack, &value); 22 | } 23 | } 24 | 25 | return NULL; 26 | } 27 | 28 | void 29 | test_allocator_throughput(void) { 30 | test_start(); 31 | 32 | allocator_t *allocator = allocator_new(CACHE_SIZE); 33 | size_t ENOUGH_ALLOCATION_COUNT = CACHE_SIZE * 100; 34 | for (size_t i = 0; i < ENOUGH_ALLOCATION_COUNT; i++) { 35 | stack_push(allocator->stack, string_copy("abc")); 36 | } 37 | 38 | double start_second = time_second(); 39 | 40 | size_t thread_count = 10; 41 | array_t *thread_array = array_new_auto(); 42 | for (size_t i = 0; i < thread_count; i++) { 43 | tid_t tid = thread_start(thread_fn, allocator); 44 | array_push(thread_array, (void *) tid); 45 | } 46 | 47 | for (size_t i = 0; i < thread_count; i++) { 48 | tid_t tid = (tid_t) array_pop(thread_array); 49 | thread_wait(tid); 50 | } 51 | 52 | who_printf("thread_count: %lu\n", thread_count); 53 | double throughput = REPEATION_COUNT * BATCH_SIZE / 1000 / time_passed_second(start_second); 54 | who_printf("throughput: %.f k/s\n", throughput); 55 | 56 | allocator_destroy(&allocator); 57 | 58 | test_end(); 59 | } 60 | -------------------------------------------------------------------------------- /src/packages/std/allocator/types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef struct allocator_t allocator_t; 4 | -------------------------------------------------------------------------------- /src/packages/std/array/array.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // growable array 4 | 5 | array_t *array_new(size_t size); 6 | void array_purge(array_t *self); 7 | void array_destroy(array_t **self_pointer); 8 | 9 | void array_set_destroy_fn(array_t *self, destroy_fn_t *destroy_fn); 10 | array_t *array_new_with(size_t size, destroy_fn_t *destroy_fn); 11 | 12 | #define ARRAY_AUTO_SIZE 64 13 | 14 | array_t *array_new_auto(void); 15 | array_t *array_new_auto_with(destroy_fn_t *destroy_fn); 16 | 17 | size_t array_size(const array_t *self); 18 | size_t array_grow_step(const array_t *self); 19 | void array_set_grow_step(array_t *self, size_t grow_step); 20 | size_t array_length(const array_t *self); 21 | bool array_is_empty(const array_t *self); 22 | bool array_is_full(const array_t *self); 23 | 24 | void array_resize(array_t *self, size_t larger_size); 25 | 26 | void *array_top(array_t *self); 27 | void *array_pop(array_t *self); 28 | void array_push(array_t *self, void *value); 29 | 30 | void *array_get(const array_t *self, size_t index); 31 | void *array_pick(const array_t *self, size_t back_index); 32 | 33 | void array_set(array_t *self, size_t index, void *value); 34 | -------------------------------------------------------------------------------- /src/packages/std/array/deps.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "../memory/index.h" 6 | #include "../string/index.h" 7 | #include "../file/index.h" 8 | -------------------------------------------------------------------------------- /src/packages/std/array/index.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "deps.h" 4 | #include "types.h" 5 | #include "array.h" 6 | #include "string_array.h" 7 | #include "test_array.h" 8 | -------------------------------------------------------------------------------- /src/packages/std/array/string_array.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | array_t * 4 | string_array_new_auto(void) { 5 | return array_new_auto_with((destroy_fn_t *) string_destroy); 6 | } 7 | 8 | void 9 | string_array_print(array_t *array, const char *delimiter, file_t *file) { 10 | for (size_t i = 0; i < array_length(array); i++) { 11 | void *value = array_get(array, i); 12 | if (i + 1 == array_length(array)) { 13 | fprintf(file, "%s", (char *) value); 14 | } else { 15 | fprintf(file, "%s%s", (char *) value, delimiter); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/packages/std/array/string_array.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | array_t *string_array_new_auto(void); 4 | 5 | void string_array_print(array_t *array, const char *delimiter, file_t *file); 6 | -------------------------------------------------------------------------------- /src/packages/std/array/test_array.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void test_array(void); 4 | -------------------------------------------------------------------------------- /src/packages/std/array/types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef struct array_t array_t; 4 | -------------------------------------------------------------------------------- /src/packages/std/blob/blob.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | // with an extra ending '\0' to be viewed as string. 4 | 5 | struct blob_t { 6 | size_t size; 7 | uint8_t *bytes; 8 | }; 9 | 10 | blob_t * 11 | blob_new(size_t size) { 12 | blob_t *self = new(blob_t); 13 | self->size = size; 14 | self->bytes = allocate(size + 1); 15 | return self; 16 | } 17 | 18 | void 19 | blob_destroy(blob_t **self_pointer) { 20 | assert(self_pointer); 21 | if (*self_pointer == NULL) return; 22 | 23 | blob_t *self = *self_pointer; 24 | free(self->bytes); 25 | free(self); 26 | *self_pointer = NULL; 27 | } 28 | 29 | size_t 30 | blob_size(const blob_t *self) { 31 | return self->size; 32 | } 33 | 34 | uint8_t * 35 | blob_bytes(const blob_t *self) { 36 | return self->bytes; 37 | } 38 | 39 | char * 40 | blob_string(const blob_t *self) { 41 | return (char *) self->bytes; 42 | } 43 | 44 | void 45 | blob_copy_from(blob_t *self, const uint8_t *bytes) { 46 | memcpy(self->bytes, bytes, self->size); 47 | } 48 | 49 | void 50 | blob_copy_into(const blob_t *self, uint8_t *bytes) { 51 | memcpy(bytes, self->bytes, self->size); 52 | } 53 | 54 | bool 55 | blob_equal(blob_t *left, blob_t *right) { 56 | if (left == right) 57 | return true; 58 | 59 | if (left->size != right->size) 60 | return false; 61 | 62 | return memcmp( 63 | left->bytes, 64 | right->bytes, 65 | left->size) == 0; 66 | } 67 | 68 | blob_t * 69 | blob_copy(blob_t *self) { 70 | blob_t *blob = blob_new(self->size); 71 | memcpy(blob->bytes, self->bytes, self->size); 72 | return blob; 73 | } 74 | -------------------------------------------------------------------------------- /src/packages/std/blob/blob.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | blob_t *blob_new(size_t size); 4 | void blob_destroy(blob_t **self_pointer); 5 | 6 | size_t blob_size(const blob_t *self); 7 | uint8_t *blob_bytes(const blob_t *self); 8 | char *blob_string(const blob_t *self); 9 | 10 | void blob_copy_from(blob_t *self, const uint8_t *bytes); 11 | void blob_copy_into(const blob_t *self, uint8_t *bytes); 12 | 13 | bool blob_equal(blob_t *left, blob_t *right); 14 | blob_t *blob_copy(blob_t *self); 15 | -------------------------------------------------------------------------------- /src/packages/std/blob/deps.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "../memory/index.h" 12 | #include "../string/index.h" 13 | -------------------------------------------------------------------------------- /src/packages/std/blob/index.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "deps.h" 4 | #include "types.h" 5 | #include "blob.h" 6 | #include "test_blob.h" 7 | -------------------------------------------------------------------------------- /src/packages/std/blob/test_blob.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | void 4 | test_blob(void) { 5 | test_start(); 6 | 7 | { 8 | blob_t *blob = blob_new(3); 9 | blob_bytes(blob)[0] = 'a'; 10 | blob_bytes(blob)[1] = 'b'; 11 | blob_bytes(blob)[2] = 'c'; 12 | 13 | assert(blob_size(blob) == 3); 14 | assert(string_equal(blob_string(blob), "abc")); 15 | 16 | blob_destroy(&blob); 17 | } 18 | 19 | { 20 | blob_t *blob_1 = blob_new(3); 21 | blob_bytes(blob_1)[0] = 'a'; 22 | blob_bytes(blob_1)[1] = 'b'; 23 | blob_bytes(blob_1)[2] = 'c'; 24 | 25 | blob_t *blob_2 = blob_new(3); 26 | blob_bytes(blob_2)[0] = 'a'; 27 | blob_bytes(blob_2)[1] = 'b'; 28 | blob_bytes(blob_2)[2] = 'c'; 29 | 30 | assert(blob_1 != blob_2); 31 | assert(blob_equal(blob_1, blob_2)); 32 | 33 | blob_bytes(blob_2)[1] = 'B'; 34 | 35 | assert(!blob_equal(blob_1, blob_2)); 36 | 37 | blob_destroy(&blob_1); 38 | blob_destroy(&blob_2); 39 | } 40 | 41 | { 42 | blob_t *blob_1 = blob_new(3); 43 | blob_bytes(blob_1)[0] = 'a'; 44 | blob_bytes(blob_1)[1] = 'b'; 45 | blob_bytes(blob_1)[2] = 'c'; 46 | 47 | blob_t *blob_2 = blob_copy(blob_1); 48 | 49 | assert(blob_1 != blob_2); 50 | assert(blob_equal(blob_1, blob_2)); 51 | 52 | blob_bytes(blob_2)[1] = 'B'; 53 | 54 | assert(!blob_equal(blob_1, blob_2)); 55 | 56 | blob_destroy(&blob_1); 57 | blob_destroy(&blob_2); 58 | } 59 | 60 | test_end(); 61 | } 62 | -------------------------------------------------------------------------------- /src/packages/std/blob/test_blob.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void test_blob(void); 4 | -------------------------------------------------------------------------------- /src/packages/std/blob/types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef struct blob_t blob_t; 4 | -------------------------------------------------------------------------------- /src/packages/std/char/char.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | // https://en.wikipedia.org/wiki/ASCII 4 | 5 | uint8_t 6 | char_to_hex(char c) { 7 | if ('0' <= c && c <= '9') return c - '0'; 8 | if ('a' <= c && c <= 'f') return c - 'a' + 10; 9 | if ('A' <= c && c <= 'F') return c - 'A' + 10; 10 | 11 | who_printf("unknown char: %c\n", c); 12 | exit(1); 13 | } 14 | 15 | bool 16 | char_is_digit(char c) { 17 | return ('0' <= c && c <= '9'); 18 | } 19 | -------------------------------------------------------------------------------- /src/packages/std/char/char.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | uint8_t char_to_hex(char c); 4 | bool char_is_digit(char c); 5 | -------------------------------------------------------------------------------- /src/packages/std/char/deps.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "../test/index.h" 12 | -------------------------------------------------------------------------------- /src/packages/std/char/index.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "deps.h" 4 | #include "types.h" 5 | #include "char.h" 6 | #include "test_char.h" 7 | -------------------------------------------------------------------------------- /src/packages/std/char/test_char.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | void 4 | test_char(void) { 5 | test_start(); 6 | 7 | assert(char_to_hex('0') == 0); 8 | assert(char_to_hex('1') == 1); 9 | assert(char_to_hex('2') == 2); 10 | assert(char_to_hex('3') == 3); 11 | assert(char_to_hex('4') == 4); 12 | assert(char_to_hex('5') == 5); 13 | assert(char_to_hex('6') == 6); 14 | assert(char_to_hex('7') == 7); 15 | assert(char_to_hex('8') == 8); 16 | assert(char_to_hex('9') == 9); 17 | 18 | assert(char_to_hex('a') == 0xa); 19 | assert(char_to_hex('b') == 0xb); 20 | assert(char_to_hex('c') == 0xc); 21 | assert(char_to_hex('d') == 0xd); 22 | assert(char_to_hex('e') == 0xe); 23 | assert(char_to_hex('f') == 0xf); 24 | 25 | assert(char_to_hex('A') == 0xA); 26 | assert(char_to_hex('B') == 0xB); 27 | assert(char_to_hex('C') == 0xC); 28 | assert(char_to_hex('D') == 0xD); 29 | assert(char_to_hex('E') == 0xE); 30 | assert(char_to_hex('F') == 0xF); 31 | 32 | assert(char_is_digit('0')); 33 | assert(char_is_digit('1')); 34 | assert(char_is_digit('2')); 35 | assert(char_is_digit('3')); 36 | assert(char_is_digit('4')); 37 | assert(char_is_digit('5')); 38 | assert(char_is_digit('6')); 39 | assert(char_is_digit('7')); 40 | assert(char_is_digit('8')); 41 | assert(char_is_digit('9')); 42 | 43 | assert(!char_is_digit('a')); 44 | assert(!char_is_digit('A')); 45 | 46 | test_end(); 47 | } 48 | -------------------------------------------------------------------------------- /src/packages/std/char/test_char.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void test_char(void); 4 | -------------------------------------------------------------------------------- /src/packages/std/char/types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | -------------------------------------------------------------------------------- /src/packages/std/code/code.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | size_t 4 | code_max_lineno(const char *string) { 5 | size_t lineno = 1; 6 | size_t length = strlen(string); 7 | for (size_t i = 0; i < length; i++) { 8 | if (string[i] == '\n') lineno++; 9 | } 10 | 11 | return lineno; 12 | } 13 | 14 | size_t 15 | code_lineno_of_index(const char *string, size_t index) { 16 | // just count the number of '\n'. 17 | // the consting starts from 1. 18 | size_t lineno = 1; 19 | size_t length = strlen(string); 20 | for (size_t i = 0; i < length; i++) { 21 | if (i >= index) break; 22 | else if (string[i] == '\n') lineno++; 23 | } 24 | 25 | return lineno; 26 | } 27 | 28 | void 29 | code_print_context( 30 | file_t* file, 31 | const char *string, 32 | size_t start, 33 | size_t end 34 | ) { 35 | size_t offset = 3; 36 | 37 | size_t start_lineno = code_lineno_of_index(string, start); 38 | size_t end_lineno = code_lineno_of_index(string, end); 39 | size_t max_lineno = end_lineno + offset; 40 | 41 | size_t padding_left = uint_decimal_length(max_lineno); 42 | size_t length = strlen(string); 43 | 44 | size_t current_lineno = 1; 45 | 46 | for (size_t i = 0; i < length; i++) { 47 | char c = string[i]; 48 | // Do NOT use minus on unsigned int! 49 | if (start_lineno <= current_lineno + offset && 50 | current_lineno <= end_lineno + offset) { 51 | if (i == 0 || string[i-1] == '\n') { 52 | if (start_lineno <= current_lineno && 53 | current_lineno <= end_lineno) { 54 | fprintf(file, "> %*lu|", (int) padding_left, current_lineno); 55 | } else { 56 | fprintf(file, " %*lu|", (int) padding_left, current_lineno); 57 | } 58 | } 59 | 60 | fprintf(file, "%c", c); 61 | } 62 | 63 | if (c == '\n') current_lineno++; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/packages/std/code/code.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | size_t code_max_lineno(const char *string); 4 | size_t code_lineno_of_index(const char *string, size_t index); 5 | void code_print_context(file_t* file, const char *string, size_t start, size_t end); 6 | -------------------------------------------------------------------------------- /src/packages/std/code/deps.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "../int/index.h" 6 | #include "../string/index.h" 7 | #include "../file/index.h" 8 | -------------------------------------------------------------------------------- /src/packages/std/code/index.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "deps.h" 4 | #include "code.h" 5 | #include "test_code.h" 6 | -------------------------------------------------------------------------------- /src/packages/std/code/test_code.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | void 4 | test_code(void) { 5 | test_start(); 6 | 7 | { 8 | const char *string = "" 9 | ".\n" 10 | "12345\n" 11 | "."; 12 | 13 | assert(code_max_lineno(string) == 3); 14 | } 15 | 16 | { 17 | const char *string = "" 18 | ".\n" 19 | "12345\n" 20 | ".\n"; 21 | 22 | assert(code_max_lineno(string) == 4); 23 | } 24 | 25 | { 26 | const char *string = "" 27 | ".\n" 28 | "12345\n" 29 | ".\n"; 30 | 31 | assert(code_lineno_of_index(string, 0) == 1); 32 | assert(code_lineno_of_index(string, 1) == 1); 33 | assert(code_lineno_of_index(string, 100) == 4); 34 | } 35 | 36 | test_end(); 37 | } 38 | -------------------------------------------------------------------------------- /src/packages/std/code/test_code.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void test_code(void); 4 | -------------------------------------------------------------------------------- /src/packages/std/commander/cmd_default.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | commander_plugin_fn_t cmd_default_help; 4 | commander_plugin_fn_t cmd_default_version; 5 | -------------------------------------------------------------------------------- /src/packages/std/commander/cmd_default_help.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | static int run(commander_t *commander); 4 | 5 | void 6 | cmd_default_help(commander_t *commander) { 7 | command_t *command = command_new("help"); 8 | command->description = "print help message"; 9 | command->run = run; 10 | commander_add(commander, command); 11 | } 12 | 13 | int 14 | run(commander_t *commander) { 15 | commander_help(commander); 16 | 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /src/packages/std/commander/cmd_default_version.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | static int run(commander_t *commander); 4 | 5 | void 6 | cmd_default_version(commander_t *commander) { 7 | command_t *command = command_new("version"); 8 | command->description = "print version"; 9 | command->run = run; 10 | commander_add(commander, command); 11 | } 12 | 13 | int 14 | run(commander_t *commander) { 15 | printf("%s\n", commander->version); 16 | 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /src/packages/std/commander/command.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | command_t * 4 | command_new(const char *name) { 5 | command_t *self = new(command_t); 6 | self->name = name; 7 | self->description = NULL; 8 | self->help = NULL; 9 | self->run = NULL; 10 | return self; 11 | } 12 | 13 | void 14 | command_destroy(command_t **self_pointer) { 15 | assert(self_pointer); 16 | if (*self_pointer == NULL) return; 17 | 18 | command_t *self = *self_pointer; 19 | free(self); 20 | *self_pointer = NULL; 21 | } 22 | -------------------------------------------------------------------------------- /src/packages/std/commander/command.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef int (command_run_t)(commander_t *commander); 4 | 5 | struct command_t { 6 | const char *name; 7 | const char *description; 8 | const char *help; 9 | command_run_t *run; 10 | }; 11 | 12 | command_t *command_new(const char *name); 13 | void command_destroy(command_t **self_pointer); 14 | -------------------------------------------------------------------------------- /src/packages/std/commander/commander.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef void (commander_plugin_fn_t)(commander_t *commander); 4 | 5 | struct commander_t { 6 | const char *name; 7 | const char *version; 8 | const char *description; 9 | int argc; 10 | char **argv; 11 | list_t *command_list; 12 | }; 13 | 14 | commander_t *commander_new( 15 | const char *name, 16 | const char *version, 17 | int argc, 18 | char **argv); 19 | void commander_destroy(commander_t **self_pointer); 20 | 21 | const char *commander_command_name(const commander_t *self); 22 | char **commander_rest_argv(const commander_t *self); 23 | size_t commander_rest_argc(const commander_t *self); 24 | 25 | void commander_add(commander_t *self, command_t *command); 26 | void commander_use(commander_t *self, commander_plugin_fn_t *plugin); 27 | void commander_help(const commander_t *self); 28 | int commander_run(commander_t *self); 29 | -------------------------------------------------------------------------------- /src/packages/std/commander/deps.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../list/index.h" 4 | #include "../file/index.h" 5 | -------------------------------------------------------------------------------- /src/packages/std/commander/index.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "deps.h" 4 | #include "types.h" 5 | #include "command.h" 6 | #include "commander.h" 7 | #include "cmd_default.h" 8 | -------------------------------------------------------------------------------- /src/packages/std/commander/types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef struct command_t command_t; 4 | typedef struct commander_t commander_t; 5 | -------------------------------------------------------------------------------- /src/packages/std/deque/deps.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "../memory/index.h" 7 | #include "../string/index.h" 8 | #include "../int/index.h" 9 | #include "../thread/index.h" 10 | #include "../time/index.h" 11 | -------------------------------------------------------------------------------- /src/packages/std/deque/deque.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // a multiple producer multiple consumer 4 | // thread safe double ended queue. 5 | 6 | deque_t *deque_new(void); 7 | void deque_destroy(deque_t **self_pointer); 8 | 9 | size_t deque_length(deque_t *self); 10 | bool deque_is_empty(deque_t *self); 11 | 12 | void deque_push_front(deque_t *self, void *value); 13 | void *deque_pop_front(deque_t *self); 14 | 15 | void deque_push_back(deque_t *self, void *value); 16 | void *deque_pop_back(deque_t *self); 17 | 18 | // NOT thread safe 19 | void *deque_get(const deque_t *self, size_t index); 20 | -------------------------------------------------------------------------------- /src/packages/std/deque/index.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "deps.h" 4 | #include "types.h" 5 | #include "deque.h" 6 | #include "test_deque.h" 7 | -------------------------------------------------------------------------------- /src/packages/std/deque/test_deque.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | void 4 | test_deque(void) { 5 | test_start(); 6 | 7 | test_deque_throughput(); 8 | 9 | test_end(); 10 | } 11 | -------------------------------------------------------------------------------- /src/packages/std/deque/test_deque.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void test_deque(void); 4 | void test_deque_throughput(void); 5 | -------------------------------------------------------------------------------- /src/packages/std/deque/test_deque_throughput.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | #define LENGTH 10000000 4 | 5 | static void * 6 | uint_producer(deque_t *deque) { 7 | size_t count = 0; 8 | while (true) { 9 | if (count == LENGTH) return NULL; 10 | 11 | deque_push_back(deque, (void *) count); 12 | count++; 13 | } 14 | } 15 | 16 | static void * 17 | uint_consumer(deque_t *deque) { 18 | size_t count = 0; 19 | while (true) { 20 | if (count == LENGTH) return NULL; 21 | 22 | while (deque_is_empty(deque)) {} 23 | 24 | assert(((size_t) deque_pop_front(deque)) == count); 25 | count++; 26 | } 27 | } 28 | 29 | void 30 | test_deque_throughput(void) { 31 | test_start(); 32 | 33 | deque_t *deque = deque_new(); 34 | 35 | double start_second = time_second(); 36 | 37 | tid_t producer_id = 38 | thread_start((thread_fn_t *) uint_producer, deque); 39 | tid_t consumer_id = 40 | thread_start((thread_fn_t *) uint_consumer, deque); 41 | 42 | thread_wait(producer_id); 43 | thread_wait(consumer_id); 44 | 45 | double throughput = LENGTH / 1000 / time_passed_second(start_second); 46 | who_printf("throughput: %.f k/s\n", throughput); 47 | 48 | deque_destroy(&deque); 49 | 50 | test_end(); 51 | } 52 | -------------------------------------------------------------------------------- /src/packages/std/deque/types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef struct deque_t deque_t; 4 | -------------------------------------------------------------------------------- /src/packages/std/file/abc.txt: -------------------------------------------------------------------------------- 1 | abc 2 | abc 3 | abc 4 | -------------------------------------------------------------------------------- /src/packages/std/file/deps.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "../memory/index.h" 12 | #include "../string/index.h" 13 | #include "../blob/index.h" 14 | -------------------------------------------------------------------------------- /src/packages/std/file/file.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | bool 4 | file_exists(const char *file_name) { 5 | return access(file_name, F_OK) != -1; 6 | } 7 | 8 | file_t * 9 | file_open_or_fail( 10 | const char *file_name, 11 | const char *mode 12 | ) { 13 | file_t *file = fopen(file_name, mode); 14 | if (!file) { 15 | who_printf("file name: %s\n", file_name); 16 | who_printf("mode: %s\n", mode); 17 | exit(1); 18 | } 19 | 20 | setbuf(file, NULL); 21 | return file; 22 | } 23 | 24 | off_t 25 | file_size(file_t *file) { 26 | struct stat st; 27 | fstat(fileno(file), &st); 28 | return st.st_size; 29 | } 30 | 31 | char * 32 | file_read_string(file_t *file) { 33 | off_t size = file_size(file); 34 | char *string = allocate(size + 1); // +1 for the ending '\0'. 35 | size_t nbytes = fread(string, 1, size, file); 36 | assert(nbytes == (size_t) size); 37 | return string; 38 | } 39 | 40 | uint8_t * 41 | file_read_bytes(file_t *file) { 42 | off_t size = file_size(file); 43 | uint8_t *bytes = allocate(size); 44 | size_t nbytes = fread(bytes, 1, size, file); 45 | assert(nbytes == (size_t) size); 46 | return bytes; 47 | } 48 | 49 | void 50 | file_write_bytes(file_t *file, uint8_t *bytes, size_t size) { 51 | fwrite(bytes, 1, size, file); 52 | } 53 | 54 | blob_t * 55 | file_read_blob(file_t *file) { 56 | off_t size = file_size(file); 57 | blob_t *blob = blob_new(size); 58 | uint8_t *bytes = blob_bytes(blob); 59 | size_t nbytes = fread(bytes, 1, size, file); 60 | assert(nbytes == (size_t) size); 61 | return blob; 62 | } 63 | 64 | void 65 | file_write_blob(file_t *file, blob_t *blob) { 66 | fwrite(blob_bytes(blob), 1, blob_size(blob), file); 67 | } 68 | 69 | void 70 | file_lock(file_t *file) { 71 | flockfile(file); 72 | } 73 | 74 | void 75 | file_unlock(file_t *file) { 76 | funlockfile(file); 77 | } 78 | 79 | void 80 | file_disable_buffer(file_t *file) { 81 | setbuf(file, NULL); 82 | } 83 | -------------------------------------------------------------------------------- /src/packages/std/file/file.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | bool file_exists(const char *file_name); 4 | file_t *file_open_or_fail(const char *file_name, const char *mode); 5 | off_t file_size(file_t *file); 6 | 7 | char *file_read_string(file_t *file); 8 | 9 | uint8_t *file_read_bytes(file_t *file); 10 | void file_write_bytes(file_t *file, uint8_t *bytes, size_t size); 11 | 12 | blob_t *file_read_blob(file_t *file); 13 | void file_write_blob(file_t *file, blob_t *blob); 14 | 15 | void file_lock(file_t *file); 16 | void file_unlock(file_t *file); 17 | 18 | void file_disable_buffer(file_t *file); 19 | -------------------------------------------------------------------------------- /src/packages/std/file/index.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "deps.h" 4 | #include "types.h" 5 | #include "file.h" 6 | #include "test_file.h" 7 | -------------------------------------------------------------------------------- /src/packages/std/file/test_file.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | void 4 | test_file(void) { 5 | test_start(); 6 | 7 | char *base = dirname(string_copy(__FILE__)); 8 | char *file_name = string_append(base, "/abc.txt"); 9 | 10 | 11 | { 12 | file_t *file = file_open_or_fail(file_name, "r"); 13 | char *string = file_read_string(file); 14 | assert( 15 | string_equal( 16 | string, 17 | "abc\n" 18 | "abc\n" 19 | "abc\n")); 20 | } 21 | 22 | { 23 | file_t *file = file_open_or_fail(file_name, "r"); 24 | blob_t *blob = file_read_blob(file); 25 | assert( 26 | string_equal( 27 | blob_string(blob), 28 | "abc\n" 29 | "abc\n" 30 | "abc\n")); 31 | } 32 | 33 | test_end(); 34 | } 35 | -------------------------------------------------------------------------------- /src/packages/std/file/test_file.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void test_file(void); 4 | -------------------------------------------------------------------------------- /src/packages/std/file/types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef FILE file_t; 4 | -------------------------------------------------------------------------------- /src/packages/std/hash/deps.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "../memory/index.h" 6 | #include "../string/index.h" 7 | #include "../list/index.h" 8 | #include "../int/index.h" 9 | -------------------------------------------------------------------------------- /src/packages/std/hash/hash.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | hash_t *hash_new(void); 4 | void hash_purge(hash_t *self); 5 | void hash_destroy(hash_t **self_pointer); 6 | 7 | void hash_set_hash_fn(hash_t *self, hash_fn_t *hash_fn); 8 | void hash_set_destroy_fn(hash_t *self, destroy_fn_t *destroy_fn); 9 | void hash_set_key_destroy_fn(hash_t *self, destroy_fn_t *key_destroy_fn); 10 | void hash_set_key_equal_fn(hash_t *self, equal_fn_t *key_equal_fn); 11 | 12 | hash_t *hash_of_string_key(void); 13 | 14 | size_t hash_length(const hash_t *self); 15 | 16 | bool hash_has(hash_t *self, const void *key); 17 | void *hash_get(hash_t *self, const void *key); 18 | 19 | // set and put will own the key, 20 | // which only has effect when there is `key_destroy_fn`. 21 | bool hash_set(hash_t *self, void *key, void *value); 22 | // put auto destroy old value if there is destroy_fn. 23 | // put will not update the key if the entry exists. 24 | void hash_put(hash_t *self, void *key, void *value); 25 | 26 | bool hash_delete(hash_t *self, const void *key); 27 | 28 | void *hash_first(hash_t *self); 29 | void *hash_next(hash_t *self); 30 | void *hash_cursor(hash_t *self); 31 | 32 | list_t *hash_value_list(hash_t *self); 33 | 34 | void hash_report(const hash_t *self); 35 | -------------------------------------------------------------------------------- /src/packages/std/hash/hash_primes.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // largest primes less than 2^n for n = 4...63 4 | 5 | size_t hash_primes[] = { 6 | 13, // 2^4 7 | 31, // 2^5 8 | 61, // 2^6 9 | 127, // 2^7 10 | 251, // 2^8 11 | 509, // 2^9 12 | 1021, // 2^10 13 | 2039, // 2^11 14 | 4093, // 2^12 15 | 8191, // 2^13 16 | 16381, // 2^14 17 | 32749, // 2^15 18 | 65521, // 2^16 19 | 131071, // 2^17 20 | 262139, // 2^18 21 | 524287, // 2^19 22 | 1048573, // 2^20 23 | 2097143, // 2^21 24 | 4194301, // 2^22 25 | 8388593, // 2^23 26 | 16777213, // 2^24 27 | 33554393, // 2^25 28 | 67108859, // 2^26 29 | 134217689, // 2^27 30 | 268435399, // 2^28 31 | 536870909, // 2^29 32 | 1073741789, // 2^30 33 | 2147483647, // 2^31 34 | 4294967295, // 2^32 35 | 8589934591, // 2^33 36 | 17179869183, // 2^34 37 | 34359738367, // 2^35 38 | 68719476735, // 2^36 39 | 137438953471, // 2^37 40 | 274877906943, // 2^38 41 | 549755813887, // 2^39 42 | 1099511627775, // 2^40 43 | 2199023255551, // 2^41 44 | 4398046511103, // 2^42 45 | 8796093022207, // 2^43 46 | 17592186044415, // 2^44 47 | 35184372088831, // 2^45 48 | 70368744177663, // 2^46 49 | 140737488355327, // 2^47 50 | 281474976710655, // 2^48 51 | 562949953421311, // 2^49 52 | 1125899906842623, // 2^50 53 | 2251799813685247, // 2^51 54 | 4503599627370495, // 2^52 55 | 9007199254740991, // 2^53 56 | 18014398509481983, // 2^54 57 | 36028797018963967, // 2^55 58 | 72057594037927935, // 2^56 59 | 144115188075855871, // 2^57 60 | 288230376151711743, // 2^58 61 | 576460752303423487, // 2^59 62 | 1152921504606846975, // 2^60 63 | 2305843009213693949, // 2^61 64 | 4611686018427387903, // 2^62 65 | 9223372036854775807, // 2^63 66 | }; 67 | -------------------------------------------------------------------------------- /src/packages/std/hash/index.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "deps.h" 4 | #include "types.h" 5 | #include "hash.h" 6 | #include "test_hash.h" 7 | -------------------------------------------------------------------------------- /src/packages/std/hash/test_hash.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void test_hash(void); 4 | -------------------------------------------------------------------------------- /src/packages/std/hash/types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef size_t (hash_fn_t)(const void *key); 4 | 5 | typedef struct hash_t hash_t; 6 | -------------------------------------------------------------------------------- /src/packages/std/index.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "test/index.h" 4 | #include "memory/index.h" 5 | #include "char/index.h" 6 | #include "string/index.h" 7 | #include "list/index.h" 8 | #include "hash/index.h" 9 | #include "set/index.h" 10 | #include "vec/index.h" 11 | #include "blob/index.h" 12 | #include "file/index.h" 13 | #include "path/index.h" 14 | #include "array/index.h" 15 | #include "stack/index.h" 16 | #include "int/index.h" 17 | #include "code/index.h" 18 | #include "utf8/index.h" 19 | #include "text/index.h" 20 | #include "lexer/index.h" 21 | #include "sexp/index.h" 22 | #include "commander/index.h" 23 | #include "time/index.h" 24 | #include "thread/index.h" 25 | #include "queue/index.h" 26 | #include "deque/index.h" 27 | #include "allocator/index.h" 28 | 29 | #include "test_std.h" 30 | -------------------------------------------------------------------------------- /src/packages/std/int/deps.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "../memory/index.h" 6 | #include "../string/index.h" 7 | -------------------------------------------------------------------------------- /src/packages/std/int/index.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "deps.h" 4 | #include "int.h" 5 | #include "test_int.h" 6 | -------------------------------------------------------------------------------- /src/packages/std/int/int.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | uint64_t uint_max(uint64_t x, uint64_t y); 4 | uint64_t uint_min(uint64_t x, uint64_t y); 5 | 6 | char *uint_to_string(uint64_t self); 7 | char *uint_to_subscript(uint64_t self); 8 | char *uint_to_superscript(uint64_t self); 9 | 10 | size_t uint_decimal_length(uint64_t self); 11 | 12 | uint64_t int_relu(int64_t self); 13 | -------------------------------------------------------------------------------- /src/packages/std/int/test_int.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | void 4 | test_int(void) { 5 | test_start(); 6 | 7 | assert(uint_max(1, 2) == 2); 8 | assert(uint_min(1, 2) == 1); 9 | 10 | assert(string_equal(uint_to_string(123), "123")); 11 | assert(string_equal(uint_to_subscript(123), "₁₂₃")); 12 | assert(string_equal(uint_to_superscript(123), "¹²³")); 13 | 14 | assert(uint_decimal_length(1) == 1); 15 | assert(uint_decimal_length(12) == 2); 16 | assert(uint_decimal_length(123) == 3); 17 | assert(uint_decimal_length(1234) == 4); 18 | 19 | { 20 | assert(int_relu(1) == 1); 21 | assert(int_relu(-1) == 0); 22 | 23 | int x = -1; 24 | assert(int_relu(x) == 0); 25 | } 26 | 27 | test_end(); 28 | } 29 | -------------------------------------------------------------------------------- /src/packages/std/int/test_int.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void test_int(void); 4 | -------------------------------------------------------------------------------- /src/packages/std/lexer/deps.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "../memory/index.h" 7 | #include "../string/index.h" 8 | #include "../list/index.h" 9 | -------------------------------------------------------------------------------- /src/packages/std/lexer/index.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "deps.h" 4 | #include "types.h" 5 | #include "token.h" 6 | #include "lexer.h" 7 | #include "test_lexer.h" 8 | -------------------------------------------------------------------------------- /src/packages/std/lexer/lexer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define MAX_TOKEN_LENGTH 1024 4 | 5 | struct lexer_t { 6 | const char *string; 7 | size_t length; 8 | 9 | size_t cursor; 10 | size_t lineno; // index from 1 11 | size_t column; // index from 1 12 | 13 | char *buffer; 14 | size_t buffer_length; 15 | list_t *token_list; 16 | const char *line_comment; 17 | list_t *delimiter_list; 18 | 19 | bool enable_int; 20 | bool enable_float; 21 | bool enable_string; 22 | }; 23 | 24 | lexer_t *lexer_new(void); 25 | void lexer_destroy(lexer_t **self_pointer); 26 | 27 | void lexer_add_delimiter(lexer_t *self, const char *delimiter); 28 | 29 | void lexer_run(lexer_t *self); 30 | -------------------------------------------------------------------------------- /src/packages/std/lexer/test_lexer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void test_lexer(void); 4 | -------------------------------------------------------------------------------- /src/packages/std/lexer/token.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | token_t * 4 | token_new(char *string, token_kind_t kind, size_t start, size_t end, size_t lineno, size_t column) { 5 | token_t *self = new(token_t); 6 | self->string = string; 7 | self->kind = kind; 8 | self->start = start; 9 | self->end = end; 10 | self->lineno = lineno; 11 | self->column = column; 12 | return self; 13 | } 14 | 15 | void 16 | token_destroy(token_t **self_pointer) { 17 | assert(self_pointer); 18 | if (*self_pointer == NULL) return; 19 | 20 | token_t *self = *self_pointer; 21 | free(self->string); 22 | free(self); 23 | *self_pointer = NULL; 24 | } 25 | -------------------------------------------------------------------------------- /src/packages/std/lexer/token.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef enum { 4 | GENERIC_TOKEN, 5 | DELIMITER_TOKEN, 6 | INT_TOKEN, 7 | FLOAT_TOKEN, 8 | STRING_TOKEN, 9 | } token_kind_t; 10 | 11 | struct token_t { 12 | char *string; 13 | token_kind_t kind; 14 | size_t start, end; 15 | size_t lineno; // index from 1 16 | size_t column; // index from 1, end of token 17 | union { 18 | int64_t int_value; 19 | double float_value; 20 | }; 21 | }; 22 | 23 | token_t *token_new(char *string, token_kind_t kind, size_t start, size_t end, size_t lineno, size_t column); 24 | void token_destroy(token_t **self_pointer); 25 | -------------------------------------------------------------------------------- /src/packages/std/lexer/types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef struct token_t token_t; 4 | typedef struct lexer_t lexer_t; 5 | -------------------------------------------------------------------------------- /src/packages/std/list/deps.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "../array/index.h" 6 | #include "../memory/index.h" 7 | #include "../string/index.h" 8 | #include "../file/index.h" 9 | -------------------------------------------------------------------------------- /src/packages/std/list/index.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "deps.h" 4 | #include "types.h" 5 | #include "list.h" 6 | #include "string_list.h" 7 | #include "test_list.h" 8 | -------------------------------------------------------------------------------- /src/packages/std/list/list.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // double linked list, with a private cursor. 4 | 5 | list_t *list_new(void); 6 | void list_destroy(list_t **self_pointer); 7 | void list_purge(list_t *self); 8 | 9 | void list_set_destroy_fn(list_t *self, destroy_fn_t *destroy_fn); 10 | void list_set_equal_fn(list_t *self, equal_fn_t *equal_fn); 11 | void list_set_copy_fn(list_t *self, copy_fn_t *copy_fn); 12 | 13 | list_t *list_new_with(destroy_fn_t *destroy_fn); 14 | 15 | // Make a copy of the list; values are copyed if you set a copy_fn for 16 | // the list, otherwise not. Copying a null reference returns a null 17 | // reference. 18 | // - `list_copy` should not copy callbacks, 19 | // specially not `destroy_fn`, 20 | // to avoid double free. 21 | list_t *list_copy(list_t *self); 22 | list_t *list_copy_reversed(list_t *self); 23 | 24 | size_t list_length(const list_t *self); 25 | bool list_is_empty(const list_t *self); 26 | bool list_has(const list_t *self, const void *value); 27 | bool list_remove(list_t *self, const void *value); 28 | 29 | // Find an value in the list, searching from the start. 30 | // Uses the injected `equal`, if any, else compares value values directly. 31 | // Returns the value handle found, or NULL. 32 | // Sets the cursor to the found value, if any. 33 | void *list_find(list_t *self, const void *value); 34 | 35 | bool list_cursor_is_end(const list_t *self); 36 | 37 | // move the cursor. 38 | 39 | void *list_first(list_t *self); 40 | void *list_next(list_t *self); 41 | void *list_prev(list_t *self); 42 | void *list_last(list_t *self); 43 | 44 | // at the end of the list. 45 | 46 | void list_push(list_t *self, void *value); 47 | void *list_pop(list_t *self); 48 | 49 | // at the start of the list. 50 | 51 | void list_unshift(list_t *self, void *value); 52 | void *list_shift(list_t *self); 53 | 54 | // at the index of the list. 55 | 56 | void *list_get(const list_t *self, size_t index); 57 | 58 | list_t *list_from_array(const array_t *array); 59 | -------------------------------------------------------------------------------- /src/packages/std/list/string_list.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | list_t * 4 | string_list_new(void) { 5 | return list_new_with((destroy_fn_t *) string_destroy); 6 | } 7 | 8 | list_t * 9 | string_list_copy(list_t *list) { 10 | list_set_copy_fn(list, (copy_fn_t *) string_copy); 11 | return list_copy(list); 12 | } 13 | 14 | void 15 | string_list_print(list_t *list, const char *delimiter, file_t *file) { 16 | void *value = list_first(list); 17 | while (value) { 18 | if (list_cursor_is_end(list)) { 19 | fprintf(file, "%s", (char *) value); 20 | } else { 21 | fprintf(file, "%s%s", (char *) value, delimiter); 22 | } 23 | 24 | value = list_next(list); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/packages/std/list/string_list.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | list_t *string_list_new(void); 4 | list_t *string_list_copy(list_t *list); 5 | 6 | void string_list_print(list_t *list, const char *delimiter, file_t *file); 7 | -------------------------------------------------------------------------------- /src/packages/std/list/test_list.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void test_list(void); 4 | -------------------------------------------------------------------------------- /src/packages/std/list/types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef struct list_t list_t; 4 | -------------------------------------------------------------------------------- /src/packages/std/memory/deps.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "../test/index.h" 13 | -------------------------------------------------------------------------------- /src/packages/std/memory/destroy.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | void 4 | destroy(void **value_pointer) { 5 | assert(value_pointer); 6 | if (*value_pointer) { 7 | void *value = *value_pointer; 8 | free(value); 9 | *value_pointer = NULL; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/packages/std/memory/destroy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void destroy(void **value_pointer); 4 | -------------------------------------------------------------------------------- /src/packages/std/memory/index.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "deps.h" 4 | #include "types.h" 5 | #include "memory.h" 6 | #include "destroy.h" 7 | #include "test_memory.h" 8 | #include "new.h" 9 | -------------------------------------------------------------------------------- /src/packages/std/memory/memory.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | // The address of a block returned by malloc or realloc in GNU systems 4 | // is always a multiple of eight (or sixteen on 64-bit systems). 5 | // -- https://www.gnu.org/software/libc/manual/html_node/Aligned-Memory-Blocks.html 6 | 7 | bool 8 | pointer_is_8_bytes_aligned(void *pointer) { 9 | return (((uintptr_t) pointer) & ((uintptr_t) 0x7)) == 0; 10 | } 11 | 12 | void * 13 | allocate(size_t size) { 14 | void *pointer = calloc(1, size); 15 | assert(pointer); 16 | assert(pointer_is_8_bytes_aligned(pointer)); 17 | return pointer; 18 | } 19 | 20 | void * 21 | allocate_pointers(size_t size) { 22 | return allocate(size * sizeof(void *)); 23 | } 24 | 25 | void * 26 | reallocate(void *pointer, size_t old_size, size_t new_size) { 27 | void *new_pointer = realloc(pointer, new_size); 28 | assert(new_pointer); 29 | assert(pointer_is_8_bytes_aligned(new_pointer)); 30 | memory_clear((((char *) new_pointer) + old_size), new_size - old_size); 31 | return new_pointer; 32 | } 33 | 34 | void * 35 | reallocate_pointers(void *pointer, size_t old_size, size_t new_size) { 36 | size_t unit_size = sizeof(void *); 37 | void *new_pointer = realloc(pointer, new_size * unit_size); 38 | assert(new_pointer); 39 | assert(pointer_is_8_bytes_aligned(new_pointer)); 40 | memory_clear((((char *) new_pointer) + old_size * unit_size), 41 | (new_size - old_size) * unit_size); 42 | return new_pointer; 43 | } 44 | 45 | bool 46 | pointer_is_page_aligned(void *pointer) { 47 | size_t page_size = sysconf(_SC_PAGE_SIZE); 48 | return (((uintptr_t) pointer) % page_size) == 0; 49 | } 50 | 51 | void * 52 | allocate_page_aligned(size_t size) { 53 | size_t page_size = sysconf(_SC_PAGE_SIZE); 54 | assert(page_size > 0); 55 | size_t real_size = ((size / page_size) + 1) * page_size; 56 | void *pointer = aligned_alloc(page_size, real_size); 57 | memory_clear(pointer, real_size); 58 | assert(pointer); 59 | assert(pointer_is_8_bytes_aligned(pointer)); 60 | assert(pointer_is_page_aligned(pointer)); 61 | return pointer; 62 | } 63 | 64 | void 65 | memory_clear(void *pointer, size_t size) { 66 | memset(pointer, 0, size); 67 | } 68 | -------------------------------------------------------------------------------- /src/packages/std/memory/memory.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | bool pointer_is_8_bytes_aligned(void *pointer); 4 | 5 | // clear memory to zero 6 | void *allocate(size_t size); 7 | void *allocate_pointers(size_t size); 8 | 9 | // clear new memory to zero 10 | void *reallocate(void *pointer, size_t old_size, size_t new_size); 11 | void *reallocate_pointers(void *pointer, size_t old_size, size_t new_size); 12 | 13 | bool pointer_is_page_aligned(void *pointer); 14 | 15 | // aligned to page to avoid false sharing 16 | void *allocate_page_aligned(size_t size); 17 | 18 | void memory_clear(void *pointer, size_t size); 19 | -------------------------------------------------------------------------------- /src/packages/std/memory/new.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define new(type) allocate(sizeof(type)) 4 | #define new_page_aligned(type) allocate_page_aligned(sizeof(type)) 5 | -------------------------------------------------------------------------------- /src/packages/std/memory/test_memory.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void test_memory(void); 4 | -------------------------------------------------------------------------------- /src/packages/std/memory/types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef void (destroy_fn_t)(void **value_pointer); 4 | typedef bool (equal_fn_t)(const void *value1, const void *value2); 5 | typedef void *(copy_fn_t)(void *value); 6 | 7 | -------------------------------------------------------------------------------- /src/packages/std/path/deps.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../memory/index.h" 4 | #include "../string/index.h" 5 | #include "../stack/index.h" 6 | -------------------------------------------------------------------------------- /src/packages/std/path/index.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "deps.h" 4 | #include "types.h" 5 | #include "path.h" 6 | #include "test_path.h" 7 | -------------------------------------------------------------------------------- /src/packages/std/path/path.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | path_t *path_new(const char *string); 4 | void path_destroy(path_t **self_pointer); 5 | 6 | path_t *path_new_cwd(void); 7 | 8 | bool path_is_relative(const path_t *self); 9 | bool path_is_absolute(const path_t *self); 10 | 11 | path_t *path_copy(path_t *self); 12 | bool path_equal(path_t *x, path_t *y); 13 | 14 | void path_join(path_t *self, const char *string); 15 | void path_resolve(path_t *self, const char *string); 16 | const char *path_string(path_t *self); 17 | 18 | path_t *path_relative(path_t *from, path_t *to); 19 | void path_relative_print(path_t *from, path_t *to, file_t *file); 20 | void path_relative_cwd_print(path_t *to, file_t *file); 21 | -------------------------------------------------------------------------------- /src/packages/std/path/test_path.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void test_path(void); 4 | -------------------------------------------------------------------------------- /src/packages/std/path/types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef struct path_t path_t; 4 | -------------------------------------------------------------------------------- /src/packages/std/queue/deps.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "../memory/index.h" 7 | #include "../string/index.h" 8 | #include "../int/index.h" 9 | #include "../thread/index.h" 10 | #include "../time/index.h" 11 | -------------------------------------------------------------------------------- /src/packages/std/queue/index.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "deps.h" 4 | #include "types.h" 5 | #include "queue.h" 6 | #include "test_queue.h" 7 | -------------------------------------------------------------------------------- /src/packages/std/queue/queue.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | queue_t *queue_new(size_t size); 4 | void queue_purge(queue_t *self); 5 | void queue_destroy(queue_t **self_pointer); 6 | 7 | void queue_set_destroy_fn(queue_t *self, destroy_fn_t *destroy_fn); 8 | queue_t *queue_new_with(size_t size, destroy_fn_t *destroy_fn); 9 | 10 | size_t queue_size(const queue_t *self); 11 | size_t queue_length(const queue_t *self); 12 | bool queue_is_full(const queue_t *self); 13 | bool queue_is_empty(const queue_t *self); 14 | 15 | // return successful or not 16 | bool queue_push_back(queue_t *self, void *value); 17 | void *queue_pop_front(queue_t *self); 18 | 19 | // NOT thread safe 20 | void *queue_get(const queue_t *self, size_t index); 21 | -------------------------------------------------------------------------------- /src/packages/std/queue/test_queue.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | void 4 | test_queue(void) { 5 | test_start(); 6 | 7 | test_queue_single_thread(); 8 | test_queue_multi_thread(); 9 | test_queue_throughput(); 10 | 11 | test_end(); 12 | } 13 | -------------------------------------------------------------------------------- /src/packages/std/queue/test_queue.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void test_queue(void); 4 | void test_queue_single_thread(void); 5 | void test_queue_multi_thread(void); 6 | void test_queue_throughput(void); 7 | -------------------------------------------------------------------------------- /src/packages/std/queue/test_queue_single_thread.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | void 4 | test_queue_single_thread(void) { 5 | test_start(); 6 | 7 | queue_t *queue = queue_new(4); 8 | assert(queue_size(queue) == 4); 9 | assert(queue_length(queue) == 0); 10 | 11 | assert(queue_push_back(queue, (void *) 1)); 12 | assert(queue_push_back(queue, (void *) 2)); 13 | assert(queue_push_back(queue, (void *) 3)); 14 | assert(queue_push_back(queue, (void *) 4)); 15 | 16 | assert(((uint64_t) queue_get(queue, 0)) == 1); 17 | assert(((uint64_t) queue_get(queue, 1)) == 2); 18 | assert(((uint64_t) queue_get(queue, 2)) == 3); 19 | assert(((uint64_t) queue_get(queue, 3)) == 4); 20 | 21 | assert(queue_length(queue) == 4); 22 | assert(queue_is_full(queue)); 23 | 24 | assert(((uint64_t) queue_pop_front(queue)) == 1); 25 | assert(((uint64_t) queue_pop_front(queue)) == 2); 26 | assert(((uint64_t) queue_pop_front(queue)) == 3); 27 | assert(((uint64_t) queue_pop_front(queue)) == 4); 28 | assert(queue_pop_front(queue) == NULL); 29 | 30 | assert(queue_length(queue) == 0); 31 | 32 | queue_destroy(&queue); 33 | 34 | test_end(); 35 | } 36 | -------------------------------------------------------------------------------- /src/packages/std/queue/test_queue_throughput.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | #define QUEUE_SIZE 1024 4 | #define LENGTH 10000000 5 | 6 | static void * 7 | uint_producer(queue_t *queue) { 8 | size_t count = 0; 9 | while (true) { 10 | if (count == LENGTH) return NULL; 11 | 12 | while (queue_is_full(queue)) {} 13 | 14 | assert(queue_push_back(queue, (void *) count)); 15 | count++; 16 | } 17 | } 18 | 19 | static void * 20 | uint_consumer(queue_t *queue) { 21 | size_t count = 0; 22 | while (true) { 23 | if (count == LENGTH) return NULL; 24 | 25 | while (queue_is_empty(queue)) {} 26 | 27 | assert(((size_t) queue_pop_front(queue)) == count); 28 | count++; 29 | } 30 | } 31 | 32 | void 33 | test_queue_throughput(void) { 34 | test_start(); 35 | 36 | queue_t *queue = queue_new(QUEUE_SIZE); 37 | 38 | double start_second = time_second(); 39 | 40 | tid_t producer_id = 41 | thread_start((thread_fn_t *) uint_producer, queue); 42 | tid_t consumer_id = 43 | thread_start((thread_fn_t *) uint_consumer, queue); 44 | 45 | thread_wait(producer_id); 46 | thread_wait(consumer_id); 47 | 48 | double throughput = LENGTH / 1000 / time_passed_second(start_second); 49 | who_printf("throughput: %.f k/s\n", throughput); 50 | 51 | queue_destroy(&queue); 52 | 53 | test_end(); 54 | } 55 | -------------------------------------------------------------------------------- /src/packages/std/queue/types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef struct queue_t queue_t; 4 | -------------------------------------------------------------------------------- /src/packages/std/set/deps.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "../memory/index.h" 6 | #include "../string/index.h" 7 | #include "../array/index.h" 8 | #include "../list/index.h" 9 | #include "../hash/index.h" 10 | #include "../int/index.h" 11 | -------------------------------------------------------------------------------- /src/packages/std/set/index.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "deps.h" 4 | #include "types.h" 5 | #include "set.h" 6 | #include "test_set.h" 7 | -------------------------------------------------------------------------------- /src/packages/std/set/set.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | set_t *set_new(void); 4 | void set_destroy(set_t **self_pointer); 5 | 6 | void set_set_hash_fn(set_t *self, hash_fn_t *hash_fn); 7 | void set_set_destroy_fn(set_t *self, destroy_fn_t *destroy_fn); 8 | void set_set_equal_fn(set_t *self, equal_fn_t *equal_fn); 9 | 10 | set_t *set_new_with(destroy_fn_t *destroy_fn); 11 | set_t *string_set_new(void); 12 | 13 | size_t set_length(const set_t *self); 14 | 15 | // add successes if the value is not already exist. 16 | bool set_add(set_t *self, void *value); 17 | 18 | // put auto destroy old value if there is destroy_fn 19 | void set_put(set_t *self, void *value); 20 | 21 | bool set_has(set_t *self, void *value); 22 | 23 | // return successful deleted or not. 24 | bool set_delete(set_t *self, void *value); 25 | 26 | void *set_first(set_t *self); 27 | void *set_next(set_t *self); 28 | 29 | list_t *set_to_list(set_t *self); 30 | array_t *set_to_array(set_t *self); 31 | -------------------------------------------------------------------------------- /src/packages/std/set/test_set.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | void 4 | test_set(void) { 5 | test_start(); 6 | 7 | { 8 | set_t *set = set_new(); 9 | assert(set_length(set) == 0); 10 | 11 | assert(set_add(set, (void *) 1)); 12 | assert(set_add(set, (void *) 2)); 13 | assert(set_add(set, (void *) 3)); 14 | 15 | assert(set_length(set) == 3); 16 | 17 | assert(!set_add(set, (void *) 1)); 18 | assert(!set_add(set, (void *) 2)); 19 | assert(!set_add(set, (void *) 3)); 20 | 21 | assert(set_length(set) == 3); 22 | 23 | assert(set_has(set, (void *) 1)); 24 | assert(set_has(set, (void *) 2)); 25 | assert(set_has(set, (void *) 3)); 26 | 27 | assert(!set_has(set, (void *) 0)); 28 | assert(!set_has(set, (void *) 4)); 29 | 30 | assert(set_delete(set, (void *) 2)); 31 | assert(set_delete(set, (void *) 3)); 32 | 33 | assert(!set_delete(set, (void *) 2)); 34 | assert(!set_delete(set, (void *) 3)); 35 | 36 | assert(set_length(set) == 1); 37 | 38 | assert(set_has(set, (void *) 1)); 39 | assert(!set_has(set, (void *) 2)); 40 | assert(!set_has(set, (void *) 3)); 41 | 42 | set_destroy(&set); 43 | } 44 | 45 | test_end(); 46 | } 47 | -------------------------------------------------------------------------------- /src/packages/std/set/test_set.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void test_set(void); 4 | -------------------------------------------------------------------------------- /src/packages/std/set/types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef struct set_t set_t; 4 | -------------------------------------------------------------------------------- /src/packages/std/sexp/deps.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "../memory/index.h" 7 | #include "../string/index.h" 8 | #include "../list/index.h" 9 | #include "../lexer/index.h" 10 | #include "../file/index.h" 11 | -------------------------------------------------------------------------------- /src/packages/std/sexp/index.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "deps.h" 4 | #include "types.h" 5 | #include "sexp.h" 6 | #include "test_sexp.h" 7 | -------------------------------------------------------------------------------- /src/packages/std/sexp/sexp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // we do not handle (car . cdr) 4 | // because it is only one way of 5 | // interpreting a list of symbols. 6 | 7 | typedef enum { 8 | ATOM_SEXP, 9 | LIST_SEXP, 10 | } sexp_kind_t; 11 | 12 | struct sexp_t { sexp_kind_t kind; }; 13 | 14 | struct atom_sexp_t { 15 | sexp_kind_t kind; 16 | const token_t *token; 17 | }; 18 | 19 | struct list_sexp_t { 20 | sexp_kind_t kind; 21 | const token_t *start_token; 22 | const token_t *end_token; 23 | list_t *sexp_list; 24 | }; 25 | 26 | atom_sexp_t *atom_sexp_new(const token_t *token); 27 | void atom_sexp_destroy(atom_sexp_t **self_pointer); 28 | 29 | list_sexp_t *list_sexp_new(const token_t *start_token, const token_t *end_token, list_t *sexp_list); 30 | void list_sexp_destroy(list_sexp_t **self_pointer); 31 | 32 | void sexp_destroy(sexp_t **self_pointer); 33 | 34 | list_t *sexp_parse_list(const char *string); 35 | sexp_t *sexp_parse(const char *string); 36 | 37 | void sexp_print(const sexp_t *self, file_t *file); 38 | 39 | bool is_atom_sexp(const sexp_t *self); 40 | bool is_list_sexp(const sexp_t *self); 41 | 42 | atom_sexp_t *as_atom_sexp(sexp_t *self); 43 | list_sexp_t *as_list_sexp(sexp_t *self); 44 | 45 | const token_t *sexp_token(sexp_t *self); 46 | const char *sexp_string(sexp_t *self); 47 | list_t *sexp_sexp_list(sexp_t *self); 48 | 49 | bool sexp_starts_with(sexp_t *self, const char *string); 50 | -------------------------------------------------------------------------------- /src/packages/std/sexp/test_sexp.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | void 4 | test_sexp(void) { 5 | test_start(); 6 | 7 | { 8 | const char *code = "(a b c)"; 9 | who_printf("code: %s\n", code); 10 | who_printf("echo: "); 11 | sexp_print(sexp_parse(code), stdout); printf("\n"); 12 | } 13 | 14 | { 15 | const char *code = "((a \"b\" c) (a . c) (1 1.2))"; 16 | who_printf("code: %s\n", code); 17 | who_printf("echo: "); 18 | sexp_print(sexp_parse(code), stdout); printf("\n"); 19 | } 20 | 21 | test_end(); 22 | } 23 | -------------------------------------------------------------------------------- /src/packages/std/sexp/test_sexp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void test_sexp(void); 4 | -------------------------------------------------------------------------------- /src/packages/std/sexp/types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef struct sexp_t sexp_t; 4 | typedef struct atom_sexp_t atom_sexp_t; 5 | typedef struct list_sexp_t list_sexp_t; 6 | -------------------------------------------------------------------------------- /src/packages/std/stack/deps.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "../memory/index.h" 6 | #include "../string/index.h" 7 | #include "../array/index.h" 8 | #include "../list/index.h" 9 | -------------------------------------------------------------------------------- /src/packages/std/stack/index.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "deps.h" 4 | #include "types.h" 5 | #include "stack.h" 6 | #include "string_stack.h" 7 | #include "test_stack.h" 8 | -------------------------------------------------------------------------------- /src/packages/std/stack/stack.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // stack implemented by growable array 4 | 5 | stack_t *stack_new(void); 6 | void stack_purge(stack_t *self); 7 | void stack_destroy(stack_t **self_pointer); 8 | 9 | void stack_set_destroy_fn(stack_t *self, destroy_fn_t *destroy_fn); 10 | stack_t *stack_new_with(destroy_fn_t *destroy_fn); 11 | 12 | size_t stack_length(const stack_t *self); 13 | bool stack_is_empty(const stack_t *self); 14 | 15 | void *stack_top(stack_t *self); 16 | void *stack_pop(stack_t *self); 17 | void stack_push(stack_t *self, void *value); 18 | 19 | void *stack_get(const stack_t *self, size_t index); 20 | void *stack_pick(const stack_t *self, size_t index); 21 | 22 | void stack_tuck_n(stack_t *self, void *target, size_t n); 23 | -------------------------------------------------------------------------------- /src/packages/std/stack/string_stack.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | stack_t * 4 | string_stack_new(void) { 5 | stack_t *self = stack_new_with((destroy_fn_t *) string_destroy); 6 | return self; 7 | } 8 | -------------------------------------------------------------------------------- /src/packages/std/stack/string_stack.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | stack_t *string_stack_new(void); 4 | -------------------------------------------------------------------------------- /src/packages/std/stack/test_stack.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | void 4 | test_stack(void) { 5 | test_start(); 6 | 7 | stack_t *stack = stack_new_with((destroy_fn_t *) string_destroy); 8 | 9 | assert(stack); 10 | 11 | assert(stack_length(stack) == 0); 12 | assert(stack_is_empty(stack)); 13 | 14 | char *cheese = string_copy("boursin"); 15 | char *bread = string_copy("baguette"); 16 | char *wine = string_copy("bordeaux"); 17 | 18 | stack_push(stack, cheese); 19 | assert(stack_top(stack) == cheese); 20 | assert(stack_length(stack) == 1); 21 | assert(!stack_is_empty(stack)); 22 | 23 | stack_push(stack, bread); 24 | assert(stack_top(stack) == bread); 25 | assert(stack_length(stack) == 2); 26 | assert(!stack_is_empty(stack)); 27 | 28 | stack_push(stack, wine); 29 | assert(stack_top(stack) == wine); 30 | assert(stack_length(stack) == 3); 31 | assert(!stack_is_empty(stack)); 32 | 33 | assert(stack_pick(stack, 0) == wine); 34 | assert(stack_pick(stack, 1) == bread); 35 | assert(stack_pick(stack, 2) == cheese); 36 | 37 | assert(stack_get(stack, 2) == wine); 38 | assert(stack_get(stack, 1) == bread); 39 | assert(stack_get(stack, 0) == cheese); 40 | 41 | assert(stack_pop(stack) == wine); 42 | assert(stack_pop(stack) == bread); 43 | assert(stack_pop(stack) == cheese); 44 | 45 | assert(stack_length(stack) == 0); 46 | assert(stack_is_empty(stack)); 47 | 48 | stack_push(stack, cheese); 49 | stack_push(stack, bread); 50 | stack_push(stack, wine); 51 | assert(stack_length(stack) == 3); 52 | 53 | stack_purge(stack); 54 | assert(stack_length(stack) == 0); 55 | assert(stack_is_empty(stack)); 56 | 57 | stack_destroy(&stack); 58 | assert(stack == NULL); 59 | 60 | test_end(); 61 | } 62 | -------------------------------------------------------------------------------- /src/packages/std/stack/test_stack.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void test_stack(void); 4 | -------------------------------------------------------------------------------- /src/packages/std/stack/types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef struct stack_t stack_t; 4 | -------------------------------------------------------------------------------- /src/packages/std/string/deps.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "../test/index.h" 12 | -------------------------------------------------------------------------------- /src/packages/std/string/index.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "deps.h" 4 | #include "string.h" 5 | #include "test_string.h" 6 | -------------------------------------------------------------------------------- /src/packages/std/string/string.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void string_destroy(char **self_pointer); 4 | char *string_copy(const char *self); 5 | size_t string_length(const char *self); 6 | char *string_empty(void); 7 | bool string_equal(const char *left, const char *right); 8 | bool string_is_empty(const char *self); 9 | size_t string_bernstein_hash(const char *self); 10 | 11 | bool string_is_int_of_base(const char *self, size_t base); 12 | bool string_is_int(const char *self); 13 | int64_t string_parse_int(const char *self, size_t base); 14 | uint64_t string_parse_uint(const char *self, size_t base); 15 | 16 | bool string_is_double(const char *self); 17 | double string_parse_double(const char *self); 18 | 19 | bool string_starts_with(const char *self, const char *prefix); 20 | bool string_ends_with(const char *self, const char *postfix); 21 | 22 | char *string_append(const char *left, const char *right); 23 | char *string_slice(const char *self, size_t start, size_t end); 24 | int string_find_index(const char *self, char ch); 25 | size_t string_count_char(const char *self, char ch); 26 | bool string_has_char(const char *self, char ch); 27 | size_t string_count_substring(const char *self, const char* substring); 28 | char *string_to_lower_case(const char *self); 29 | char *string_to_upper_case(const char *self); 30 | bool string_equal_mod_case(const char *left, const char *right); 31 | const char *string_next_line(const char *self); 32 | 33 | // xint -- support 0o prefix (but not 0b). 34 | bool string_is_xint(const char *self); 35 | int64_t string_parse_xint(const char *self); 36 | -------------------------------------------------------------------------------- /src/packages/std/string/test_string.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void test_string(void); 4 | -------------------------------------------------------------------------------- /src/packages/std/test/deps.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | -------------------------------------------------------------------------------- /src/packages/std/test/index.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "deps.h" 4 | #include "types.h" 5 | #include "test.h" 6 | #include "test_test.h" 7 | -------------------------------------------------------------------------------- /src/packages/std/test/test.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | double 4 | test_time_millisecond(void) { 5 | struct timespec ts; 6 | clock_gettime(CLOCK_REALTIME, &ts); 7 | double millisecond = ts.tv_sec * 1000 + ts.tv_nsec * 1e-6; 8 | return millisecond; 9 | } 10 | 11 | double 12 | test_time_passed_millisecond(double start_millisecond) { 13 | double end_millisecond = test_time_millisecond(); 14 | return end_millisecond - start_millisecond; 15 | } 16 | -------------------------------------------------------------------------------- /src/packages/std/test/test.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | double test_time_millisecond(void); 4 | double test_time_passed_millisecond(double start_millisecond); 5 | 6 | #define test_start(...) \ 7 | double test_start_millisecond = test_time_millisecond(); \ 8 | printf("[%s] start\n", __func__) 9 | 10 | #define test_end(...) printf("[%s] end: %.3f ms\n", __func__, test_time_passed_millisecond(test_start_millisecond)) 11 | 12 | #define who_printf(...) printf("[%s] ", __func__); printf(__VA_ARGS__) 13 | -------------------------------------------------------------------------------- /src/packages/std/test/test_test.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | void 4 | test_test(void) { 5 | test_start(); 6 | test_end(); 7 | } 8 | -------------------------------------------------------------------------------- /src/packages/std/test/test_test.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void test_test(void); 4 | -------------------------------------------------------------------------------- /src/packages/std/test/types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | -------------------------------------------------------------------------------- /src/packages/std/test_std.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | void 4 | test_std(void) { 5 | test_test(); 6 | test_memory(); 7 | test_char(); 8 | test_string(); 9 | test_list(); 10 | test_hash(); 11 | test_set(); 12 | test_vec(); 13 | test_blob(); 14 | test_file(); 15 | test_array(); 16 | test_stack(); 17 | test_path(); 18 | test_int(); 19 | test_code(); 20 | test_utf8(); 21 | test_text(); 22 | test_lexer(); 23 | test_sexp(); 24 | test_time(); 25 | test_thread(); 26 | test_queue(); 27 | test_deque(); 28 | test_allocator(); 29 | } 30 | -------------------------------------------------------------------------------- /src/packages/std/test_std.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void test_std(void); 4 | -------------------------------------------------------------------------------- /src/packages/std/text/deps.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "../int/index.h" 6 | #include "../string/index.h" 7 | #include "../utf8/index.h" 8 | -------------------------------------------------------------------------------- /src/packages/std/text/index.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "deps.h" 4 | #include "types.h" 5 | #include "text.h" 6 | #include "test_text.h" 7 | -------------------------------------------------------------------------------- /src/packages/std/text/test_text.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void test_text(void); 4 | -------------------------------------------------------------------------------- /src/packages/std/text/text.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | text_t *text_new(size_t length); 4 | void text_destroy(text_t **self_pointer); 5 | 6 | text_t *text_from_string(const char *string); 7 | 8 | size_t text_length(const text_t *self); 9 | code_point_t text_get(const text_t *self, size_t index); 10 | bool text_equal(const text_t *left, const text_t *right); 11 | text_t *text_copy(const text_t *self); 12 | text_t *text_append(text_t *left, text_t *right); 13 | text_t *text_slice(text_t *self, size_t start, size_t end); 14 | 15 | char *text_to_string(text_t *self); 16 | -------------------------------------------------------------------------------- /src/packages/std/text/types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef struct text_t text_t; 4 | -------------------------------------------------------------------------------- /src/packages/std/thread/atomics.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define relaxed_load(pointer) \ 4 | atomic_load_explicit(pointer, memory_order_relaxed) 5 | #define relaxed_store(pointer, value) \ 6 | atomic_store_explicit(pointer, value, memory_order_relaxed) 7 | 8 | #define acquire_load(pointer) \ 9 | atomic_load_explicit(pointer, memory_order_acquire) 10 | 11 | #define release_store(pointer, value) \ 12 | atomic_store_explicit(pointer, value, memory_order_release) 13 | -------------------------------------------------------------------------------- /src/packages/std/thread/deps.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "../memory/index.h" 8 | #include "../string/index.h" 9 | #include "../list/index.h" 10 | #include "../time/index.h" 11 | -------------------------------------------------------------------------------- /src/packages/std/thread/fast_spinlock.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | struct fast_spinlock_t { 4 | atomic_bool atomic_is_locked; 5 | }; 6 | 7 | fast_spinlock_t * 8 | fast_spinlock_new(void) { 9 | fast_spinlock_t *self = new(fast_spinlock_t); 10 | atomic_init(&self->atomic_is_locked, false); 11 | return self; 12 | } 13 | 14 | void 15 | fast_spinlock_destroy(fast_spinlock_t **self_pointer) { 16 | assert(self_pointer); 17 | if (*self_pointer == NULL) return; 18 | 19 | fast_spinlock_t *self = *self_pointer; 20 | free(self); 21 | *self_pointer = NULL; 22 | } 23 | 24 | void 25 | fast_spinlock_lock(fast_spinlock_t *self) { 26 | while (atomic_load_explicit( 27 | &self->atomic_is_locked, 28 | memory_order_relaxed) || 29 | atomic_exchange_explicit( 30 | &self->atomic_is_locked, 31 | true, 32 | memory_order_acquire)) 33 | { 34 | time_sleep_nanosecond(1); 35 | } 36 | } 37 | 38 | bool 39 | fast_spinlock_try_lock(fast_spinlock_t *self) { 40 | return !(atomic_load_explicit( 41 | &self->atomic_is_locked, 42 | memory_order_relaxed) || 43 | atomic_exchange_explicit( 44 | &self->atomic_is_locked, 45 | true, 46 | memory_order_acquire)); 47 | } 48 | 49 | void 50 | fast_spinlock_unlock(fast_spinlock_t *self) { 51 | atomic_store_explicit( 52 | &self->atomic_is_locked, 53 | false, 54 | memory_order_release); 55 | } 56 | -------------------------------------------------------------------------------- /src/packages/std/thread/fast_spinlock.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | fast_spinlock_t *fast_spinlock_new(void); 4 | void fast_spinlock_destroy(fast_spinlock_t **self_pointer); 5 | 6 | void fast_spinlock_lock(fast_spinlock_t *self); 7 | bool fast_spinlock_try_lock(fast_spinlock_t *self); 8 | void fast_spinlock_unlock(fast_spinlock_t *self); 9 | -------------------------------------------------------------------------------- /src/packages/std/thread/index.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "deps.h" 4 | #include "types.h" 5 | #include "thread.h" 6 | #include "mutex.h" 7 | #include "spinlock.h" 8 | #include "fast_spinlock.h" 9 | #include "atomics.h" 10 | #include "test_thread.h" 11 | -------------------------------------------------------------------------------- /src/packages/std/thread/mutex.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | mutex_t * 4 | mutex_new(void) { 5 | mutex_t *self = new(mutex_t); 6 | pthread_mutexattr_t mutex_attr; 7 | pthread_mutexattr_init(&mutex_attr); 8 | pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_ERRORCHECK); 9 | int errno = pthread_mutex_init(self, &mutex_attr); 10 | assert(errno == 0); 11 | pthread_mutexattr_destroy(&mutex_attr); 12 | return self; 13 | } 14 | 15 | void 16 | mutex_destroy(mutex_t **self_pointer) { 17 | assert(self_pointer); 18 | if (*self_pointer == NULL) return; 19 | 20 | mutex_t *self = *self_pointer; 21 | int errno = pthread_mutex_destroy(self); 22 | assert(errno == 0); 23 | free(self); 24 | *self_pointer = NULL; 25 | } 26 | 27 | void 28 | mutex_lock(mutex_t *self) { 29 | int errno = pthread_mutex_lock(self); 30 | assert(errno == 0); 31 | } 32 | 33 | bool 34 | mutex_try_lock(mutex_t *self) { 35 | int errno = pthread_mutex_trylock(self); 36 | return errno == 0; 37 | } 38 | 39 | void mutex_unlock(mutex_t *self) { 40 | int errno = pthread_mutex_unlock(self); 41 | assert(errno == 0); 42 | } 43 | -------------------------------------------------------------------------------- /src/packages/std/thread/mutex.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | mutex_t *mutex_new(void); 4 | void mutex_destroy(mutex_t **self_pointer); 5 | 6 | void mutex_lock(mutex_t *self); 7 | bool mutex_try_lock(mutex_t *self); 8 | void mutex_unlock(mutex_t *self); 9 | -------------------------------------------------------------------------------- /src/packages/std/thread/spinlock.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | spinlock_t * 4 | spinlock_new(void) { 5 | spinlock_t *self = new(spinlock_t); 6 | int errno = pthread_spin_init(self, PTHREAD_PROCESS_PRIVATE); 7 | assert(errno == 0); 8 | return self; 9 | } 10 | 11 | void 12 | spinlock_destroy(spinlock_t **self_pointer) { 13 | assert(self_pointer); 14 | if (*self_pointer == NULL) return; 15 | 16 | spinlock_t *self = *self_pointer; 17 | int errno = pthread_spin_destroy(self); 18 | assert(errno == 0); 19 | // We need to cast pointer to volatile data to normal pointer. 20 | free((void *) self); 21 | *self_pointer = NULL; 22 | } 23 | 24 | void 25 | spinlock_lock(spinlock_t *self) { 26 | int errno = pthread_spin_lock(self); 27 | assert(errno == 0); 28 | } 29 | 30 | bool 31 | spinlock_try_lock(spinlock_t *self) { 32 | int errno = pthread_spin_trylock(self); 33 | return errno == 0; 34 | } 35 | 36 | void spinlock_unlock(spinlock_t *self) { 37 | int errno = pthread_spin_unlock(self); 38 | assert(errno == 0); 39 | } 40 | -------------------------------------------------------------------------------- /src/packages/std/thread/spinlock.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | spinlock_t *spinlock_new(void); 4 | void spinlock_destroy(spinlock_t **self_pointer); 5 | 6 | void spinlock_lock(spinlock_t *self); 7 | bool spinlock_try_lock(spinlock_t *self); 8 | void spinlock_unlock(spinlock_t *self); 9 | -------------------------------------------------------------------------------- /src/packages/std/thread/test_thread.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | void 4 | test_thread(void) { 5 | test_start(); 6 | 7 | test_thread_start(); 8 | test_thread_mutex(); 9 | test_thread_counter_non_atomic(); 10 | test_thread_counter_atomic(); 11 | test_thread_counter_stat(); 12 | test_thread_counter_stat_eventual(); 13 | test_thread_count_to_big(); 14 | test_thread_weak_memory_dekker(); 15 | test_thread_weak_memory_dekker_relaxed(); 16 | test_thread_weak_memory_dekker_atomic(); 17 | 18 | test_end(); 19 | } 20 | -------------------------------------------------------------------------------- /src/packages/std/thread/test_thread.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void test_thread(void); 4 | void test_thread_start(void); 5 | void test_thread_mutex(void); 6 | void test_thread_counter_non_atomic(void); 7 | void test_thread_counter_atomic(void); 8 | void test_thread_counter_stat(void); 9 | void test_thread_counter_stat_eventual(void); 10 | void test_thread_count_to_big(void); 11 | void test_thread_weak_memory_dekker(void); 12 | void test_thread_weak_memory_dekker_relaxed(void); 13 | void test_thread_weak_memory_dekker_atomic(void); 14 | -------------------------------------------------------------------------------- /src/packages/std/thread/test_thread_count_to_big.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | #define BIG 100000 4 | 5 | static _Atomic uint64_t count = 0; 6 | 7 | static void * 8 | count_to_big(void *arg) { 9 | (void) arg; 10 | 11 | for (size_t i = 0; i < BIG; i++) { 12 | relaxed_store(&count, relaxed_load(&count) + 1); 13 | // count++; 14 | } 15 | 16 | return NULL; 17 | } 18 | 19 | void 20 | test_thread_count_to_big(void) { 21 | test_start(); 22 | 23 | tid_t T1 = thread_start(count_to_big, NULL); 24 | tid_t T2 = thread_start(count_to_big, NULL); 25 | 26 | thread_wait(T1); 27 | thread_wait(T2); 28 | 29 | who_printf("count: %lu\n", count); 30 | 31 | test_end(); 32 | } 33 | -------------------------------------------------------------------------------- /src/packages/std/thread/test_thread_counter_atomic.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | static atomic_size_t global_count = 0; 4 | 5 | static void * 6 | counter_add1(void *arg) { 7 | (void) arg; 8 | atomic_fetch_add(&global_count, 1); 9 | sleep(0); // let other threads run 10 | return NULL; 11 | } 12 | 13 | static size_t 14 | counter_read(void) { 15 | return atomic_load(&global_count); 16 | } 17 | 18 | void 19 | test_thread_counter_atomic(void) { 20 | test_start(); 21 | double start_second = time_second(); 22 | 23 | list_t *list = list_new(); 24 | 25 | thread_fn_t *thread_fn = (thread_fn_t *) counter_add1; 26 | for (size_t i = 0; i < 1000; i++) { 27 | tid_t tid = thread_start(thread_fn, NULL); 28 | list_push(list, (void *) tid); 29 | } 30 | 31 | while (!list_is_empty(list)) { 32 | tid_t tid = (tid_t) list_pop(list); 33 | thread_wait(tid); 34 | } 35 | 36 | list_destroy(&list); 37 | 38 | who_printf("final count: %lu\n", counter_read()); 39 | who_printf("elapsed seconds: %fs\n", time_passed_second(start_second)); 40 | test_end(); 41 | } 42 | -------------------------------------------------------------------------------- /src/packages/std/thread/test_thread_counter_non_atomic.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | static atomic_size_t global_count = 0; 4 | 5 | static void * 6 | counter_add1(void *arg) { 7 | (void) arg; 8 | size_t count = relaxed_load(&global_count); 9 | sleep(0); // let other threads run 10 | relaxed_store(&global_count, count + 1); 11 | return NULL; 12 | } 13 | 14 | static size_t 15 | counter_read(void) { 16 | return relaxed_load(&global_count); 17 | } 18 | 19 | void 20 | test_thread_counter_non_atomic(void) { 21 | test_start(); 22 | double start_second = time_second(); 23 | 24 | list_t *list = list_new(); 25 | 26 | thread_fn_t *thread_fn = (thread_fn_t *) counter_add1; 27 | for (size_t i = 0; i < 1000; i++) { 28 | tid_t tid = thread_start(thread_fn, NULL); 29 | list_push(list, (void *) tid); 30 | } 31 | 32 | while (!list_is_empty(list)) { 33 | tid_t tid = (tid_t) list_pop(list); 34 | thread_wait(tid); 35 | } 36 | 37 | list_destroy(&list); 38 | 39 | who_printf("final count: %lu\n", counter_read()); 40 | who_printf("elapsed seconds: %fs\n", time_passed_second(start_second)); 41 | test_end(); 42 | } 43 | -------------------------------------------------------------------------------- /src/packages/std/thread/test_thread_counter_stat.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | static void * 4 | counter_add1(atomic_size_t *count_pointer) { 5 | size_t count = relaxed_load(count_pointer); 6 | sleep(0); // let other threads run 7 | relaxed_store(count_pointer, count + 1); 8 | return NULL; 9 | } 10 | 11 | #define THREAD_NUMBER 1000 12 | 13 | static atomic_size_t counts[THREAD_NUMBER]; 14 | 15 | static size_t 16 | counter_read(void) { 17 | size_t total_count = 0; 18 | for (size_t i = 0; i < THREAD_NUMBER; i++) { 19 | total_count += relaxed_load(&counts[i]); 20 | } 21 | 22 | return total_count; 23 | } 24 | 25 | void 26 | test_thread_counter_stat(void) { 27 | test_start(); 28 | double start_second = time_second(); 29 | 30 | list_t *list = list_new(); 31 | 32 | thread_fn_t *thread_fn = (thread_fn_t *) counter_add1; 33 | for (size_t i = 0; i < THREAD_NUMBER; i++) { 34 | tid_t tid = thread_start(thread_fn, &counts[i]); 35 | list_push(list, (void *) tid); 36 | } 37 | 38 | while (!list_is_empty(list)) { 39 | tid_t tid = (tid_t) list_pop(list); 40 | thread_wait(tid); 41 | } 42 | 43 | list_destroy(&list); 44 | 45 | who_printf("final count: %lu\n", counter_read()); 46 | who_printf("elapsed seconds: %fs\n", time_passed_second(start_second)); 47 | test_end(); 48 | } 49 | -------------------------------------------------------------------------------- /src/packages/std/thread/test_thread_mutex.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | static size_t loop_count = 10000; 4 | static uint64_t global_count = 0; 5 | 6 | static void * 7 | thread_fn(void *arg) { 8 | mutex_t *mutex = arg; 9 | size_t count = 0; 10 | while (count < loop_count) { 11 | { 12 | mutex_lock(mutex); 13 | 14 | global_count++; 15 | sleep(0); 16 | 17 | mutex_unlock(mutex); 18 | } 19 | 20 | sleep(0); 21 | count++; 22 | } 23 | 24 | return NULL; 25 | } 26 | 27 | void 28 | test_thread_mutex(void) { 29 | test_start(); 30 | 31 | mutex_t *mutex = mutex_new(); 32 | 33 | tid_t T1 = thread_start(thread_fn, mutex); 34 | tid_t T2 = thread_start(thread_fn, mutex); 35 | 36 | thread_wait(T1); 37 | thread_wait(T2); 38 | 39 | assert(global_count == loop_count * 2); 40 | 41 | test_end(); 42 | } 43 | -------------------------------------------------------------------------------- /src/packages/std/thread/test_thread_start.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | static void * 4 | thread_fn(void *arg) { 5 | char *message = arg; 6 | printf("[thread_fn] %s\n", message); 7 | return (void *) strlen(message); 8 | } 9 | 10 | void 11 | test_thread_start(void) { 12 | test_start(); 13 | 14 | char *message = string_copy("hello thread"); 15 | tid_t tid = thread_start(thread_fn, message); 16 | 17 | who_printf("thread created: %lu\n", (uint64_t) tid); 18 | size_t length = (size_t) thread_wait(tid); 19 | who_printf("thread returned: %lu\n", length); 20 | 21 | test_end(); 22 | } 23 | -------------------------------------------------------------------------------- /src/packages/std/thread/test_thread_weak_memory_dekker.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | static int x, y; 4 | static int a, b; 5 | 6 | static void * 7 | thread_fn_1(void *arg) { 8 | (void) arg; 9 | 10 | x = 1; 11 | a = y; 12 | 13 | return NULL; 14 | } 15 | 16 | static void * 17 | thread_fn_2(void *arg) { 18 | (void) arg; 19 | 20 | y = 1; 21 | b = x; 22 | 23 | return NULL; 24 | } 25 | 26 | void 27 | test_thread_weak_memory_dekker(void) { 28 | test_start(); 29 | 30 | // comment the follow early `return` to run this test. 31 | // due to weak memory model, the program exit the follow loop, 32 | // and report after how many loops an unintuitive behavior occurred. 33 | 34 | return; 35 | 36 | size_t count = 0; 37 | 38 | do { 39 | x = 0; 40 | y = 0; 41 | 42 | tid_t T1 = thread_start(thread_fn_1, NULL); 43 | tid_t T2 = thread_start(thread_fn_2, NULL); 44 | 45 | thread_wait(T1); 46 | thread_wait(T2); 47 | 48 | count++; 49 | } while (a != 0 || b != 0); 50 | 51 | who_printf("count: %lu\n", count); 52 | 53 | test_end(); 54 | } 55 | -------------------------------------------------------------------------------- /src/packages/std/thread/test_thread_weak_memory_dekker_atomic.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | static atomic_int x, y; 4 | static atomic_int a, b; 5 | 6 | static void * 7 | thread_fn_1(void *arg) { 8 | (void) arg; 9 | 10 | atomic_store(&x, 1); 11 | atomic_store(&a, atomic_load(&y)); 12 | 13 | return NULL; 14 | } 15 | 16 | static void * 17 | thread_fn_2(void *arg) { 18 | (void) arg; 19 | 20 | atomic_store(&y, 1); 21 | atomic_store(&b, atomic_load(&x)); 22 | 23 | return NULL; 24 | } 25 | 26 | void 27 | test_thread_weak_memory_dekker_atomic(void) { 28 | test_start(); 29 | 30 | // comment the follow early `return` to run this test. 31 | // unlike the relaxed version, this program should loop forever. 32 | 33 | return; 34 | 35 | size_t count = 0; 36 | 37 | do { 38 | atomic_store(&x, 0); 39 | atomic_store(&y, 0); 40 | 41 | tid_t T1 = thread_start(thread_fn_1, NULL); 42 | tid_t T2 = thread_start(thread_fn_2, NULL); 43 | 44 | thread_wait(T1); 45 | thread_wait(T2); 46 | 47 | count++; 48 | } while (atomic_load(&a) != 0 || atomic_load(&b) != 0); 49 | 50 | who_printf("count: %lu\n", count); 51 | 52 | test_end(); 53 | } 54 | -------------------------------------------------------------------------------- /src/packages/std/thread/test_thread_weak_memory_dekker_relaxed.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | static atomic_int x, y; 4 | static atomic_int a, b; 5 | 6 | static void * 7 | thread_fn_1(void *arg) { 8 | (void) arg; 9 | 10 | relaxed_store(&x, 1); 11 | relaxed_store(&a, relaxed_load(&y)); 12 | 13 | return NULL; 14 | } 15 | 16 | static void * 17 | thread_fn_2(void *arg) { 18 | (void) arg; 19 | 20 | relaxed_store(&y, 1); 21 | relaxed_store(&b, relaxed_load(&x)); 22 | 23 | return NULL; 24 | } 25 | 26 | void 27 | test_thread_weak_memory_dekker_relaxed(void) { 28 | test_start(); 29 | 30 | // comment the follow early `return` to run this test. 31 | // due to weak memory model, the program exit the follow loop, 32 | // and report after how many loops an unintuitive behavior occurred. 33 | 34 | return; 35 | 36 | size_t count = 0; 37 | 38 | do { 39 | relaxed_store(&x, 0); 40 | relaxed_store(&y, 0); 41 | 42 | tid_t T1 = thread_start(thread_fn_1, NULL); 43 | tid_t T2 = thread_start(thread_fn_2, NULL); 44 | 45 | thread_wait(T1); 46 | thread_wait(T2); 47 | 48 | count++; 49 | } while (relaxed_load(&a) != 0 || relaxed_load(&b) != 0); 50 | 51 | who_printf("count: %lu\n", count); 52 | 53 | test_end(); 54 | } 55 | -------------------------------------------------------------------------------- /src/packages/std/thread/thread.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | tid_t 4 | thread_start(thread_fn_t *thread_fn, void *arg) { 5 | tid_t tid; 6 | int ok = pthread_create(&tid, NULL, thread_fn, arg); 7 | assert(ok == 0); 8 | return tid; 9 | } 10 | 11 | tid_t 12 | thread_tid(void) { 13 | return pthread_self(); 14 | } 15 | 16 | void * 17 | thread_wait(tid_t tid) { 18 | void *result; 19 | int ok = pthread_join(tid, &result); 20 | assert(ok == 0); 21 | return result; 22 | } 23 | 24 | bool 25 | tid_equal(tid_t T1, tid_t T2) { 26 | return pthread_equal(T1, T2); 27 | } 28 | 29 | void 30 | tid_print(tid_t tid) { 31 | printf("%lu", (uint64_t) tid); 32 | } 33 | -------------------------------------------------------------------------------- /src/packages/std/thread/thread.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | tid_t thread_start(thread_fn_t *thread_fn, void *arg); 4 | tid_t thread_tid(void); 5 | void *thread_wait(tid_t tid); 6 | 7 | bool tid_equal(tid_t T1, tid_t T2); 8 | void tid_print(tid_t tid); 9 | -------------------------------------------------------------------------------- /src/packages/std/thread/types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef void *(thread_fn_t)(void *arg); 4 | 5 | typedef pthread_t tid_t; 6 | typedef pthread_mutex_t mutex_t; 7 | typedef pthread_spinlock_t spinlock_t; 8 | typedef struct fast_spinlock_t fast_spinlock_t; 9 | -------------------------------------------------------------------------------- /src/packages/std/time/deps.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "../memory/index.h" 7 | #include "../string/index.h" 8 | -------------------------------------------------------------------------------- /src/packages/std/time/index.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "deps.h" 4 | #include "types.h" 5 | #include "time.h" 6 | #include "test_time.h" 7 | -------------------------------------------------------------------------------- /src/packages/std/time/test_time.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | void 4 | test_time(void) { 5 | test_start(); 6 | 7 | who_printf("time_second(): %f\n", time_second()); 8 | who_printf("time_second(): %f\n", time_second()); 9 | who_printf("time_second(): %f\n", time_second()); 10 | 11 | who_printf("time_nanosecond(): %lu\n", time_nanosecond()); 12 | who_printf("time_nanosecond(): %lu\n", time_nanosecond()); 13 | who_printf("time_nanosecond(): %lu\n", time_nanosecond()); 14 | 15 | test_end(); 16 | } 17 | -------------------------------------------------------------------------------- /src/packages/std/time/test_time.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void test_time(void); 4 | -------------------------------------------------------------------------------- /src/packages/std/time/time.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | double 4 | time_second(void) { 5 | struct timespec ts; 6 | clock_gettime(CLOCK_REALTIME, &ts); 7 | double second = ts.tv_sec + ts.tv_nsec * 1e-9; 8 | return second; 9 | } 10 | 11 | double 12 | time_passed_second(double start_second) { 13 | double end_second = time_second(); 14 | return end_second - start_second; 15 | } 16 | 17 | uint64_t 18 | time_nanosecond(void) { 19 | struct timespec ts; 20 | clock_gettime(CLOCK_REALTIME, &ts); 21 | uint64_t nanosecond = ts.tv_sec * 1e+9 + ts.tv_nsec; 22 | return nanosecond; 23 | } 24 | 25 | bool 26 | time_sleep_nanosecond(long nanosecond) { 27 | struct timespec ts = { 28 | .tv_sec = 0, 29 | .tv_nsec = nanosecond, 30 | }; 31 | int ok = nanosleep(&ts, NULL); 32 | return ok == 0; 33 | } 34 | -------------------------------------------------------------------------------- /src/packages/std/time/time.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | double time_second(void); 4 | double time_passed_second(double start_second); 5 | 6 | uint64_t time_nanosecond(void); 7 | bool time_sleep_nanosecond(long nanosecond); 8 | -------------------------------------------------------------------------------- /src/packages/std/time/types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | -------------------------------------------------------------------------------- /src/packages/std/utf8/deps.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "../memory/index.h" 12 | #include "../string/index.h" 13 | -------------------------------------------------------------------------------- /src/packages/std/utf8/index.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "deps.h" 4 | #include "types.h" 5 | #include "utf8.h" 6 | #include "utf8_iter.h" 7 | #include "test_utf8.h" 8 | -------------------------------------------------------------------------------- /src/packages/std/utf8/test_utf8.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void test_utf8(void); 4 | -------------------------------------------------------------------------------- /src/packages/std/utf8/types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef uint32_t code_point_t; 4 | 5 | typedef struct utf8_iter_t utf8_iter_t; 6 | -------------------------------------------------------------------------------- /src/packages/std/utf8/utf8.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | uint8_t utf8_char_length(char c); 4 | code_point_t utf8_decode(const char *string); 5 | size_t utf8_string_length(const char *string); 6 | void utf8_encode_into(code_point_t code_point, char *dest); 7 | char *utf8_encode(code_point_t code_point); 8 | -------------------------------------------------------------------------------- /src/packages/std/utf8/utf8_iter.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | utf8_iter_t * 4 | utf8_iter_new(const char *string) { 5 | utf8_iter_t *self = new(utf8_iter_t); 6 | self->cursor = 0; 7 | self->string = string; 8 | return self; 9 | } 10 | 11 | void 12 | utf8_iter_destroy(utf8_iter_t **self_pointer) { 13 | assert(self_pointer); 14 | if (*self_pointer == NULL) return; 15 | 16 | utf8_iter_t *self = *self_pointer; 17 | free(self); 18 | *self_pointer = NULL; 19 | } 20 | 21 | code_point_t 22 | utf8_iter_current(utf8_iter_t *self) { 23 | if (self->string[self->cursor] == '\0') 24 | return '\0'; 25 | 26 | return utf8_decode(self->string + self->cursor); 27 | } 28 | 29 | code_point_t 30 | utf8_iter_first(utf8_iter_t *self) { 31 | self->cursor = 0; 32 | 33 | if (self->string[self->cursor] == '\0') 34 | return '\0'; 35 | 36 | return utf8_decode(self->string + self->cursor); 37 | } 38 | 39 | code_point_t 40 | utf8_iter_next(utf8_iter_t *self) { 41 | self->cursor += utf8_char_length(self->string[self->cursor]); 42 | 43 | if (self->string[self->cursor] == '\0') 44 | return '\0'; 45 | 46 | return utf8_decode(self->string + self->cursor); 47 | } 48 | -------------------------------------------------------------------------------- /src/packages/std/utf8/utf8_iter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct utf8_iter_t { 4 | size_t cursor; 5 | const char *string; 6 | }; 7 | 8 | utf8_iter_t *utf8_iter_new(const char *string); 9 | void utf8_iter_destroy(utf8_iter_t **self_pointer); 10 | 11 | // We view code point 0 as the ending point like in c string. 12 | code_point_t utf8_iter_current(utf8_iter_t *self); 13 | code_point_t utf8_iter_first(utf8_iter_t *self); 14 | code_point_t utf8_iter_next(utf8_iter_t *self); 15 | -------------------------------------------------------------------------------- /src/packages/std/vec/deps.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "../memory/index.h" 7 | #include "../string/index.h" 8 | -------------------------------------------------------------------------------- /src/packages/std/vec/index.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "deps.h" 4 | #include "types.h" 5 | #include "vec2.h" 6 | #include "test_vec2.h" 7 | #include "test_vec.h" 8 | -------------------------------------------------------------------------------- /src/packages/std/vec/test_vec.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | void 4 | test_vec(void) { 5 | test_start(); 6 | 7 | test_vec2(); 8 | 9 | test_end(); 10 | } 11 | -------------------------------------------------------------------------------- /src/packages/std/vec/test_vec.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void test_vec(void); 4 | -------------------------------------------------------------------------------- /src/packages/std/vec/test_vec2.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | static double add1(double x) { return x + 1; } 4 | 5 | void 6 | test_vec2(void) { 7 | test_start(); 8 | 9 | assert( 10 | vec2_equal( 11 | vec2_map(vec2_zeros(), add1), 12 | vec2_ones())); 13 | 14 | test_end(); 15 | } 16 | -------------------------------------------------------------------------------- /src/packages/std/vec/test_vec2.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void test_vec2(void); 4 | -------------------------------------------------------------------------------- /src/packages/std/vec/types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef double (double_unary_fn_t)(double x); 4 | 5 | typedef struct vec2_t vec2_t; 6 | -------------------------------------------------------------------------------- /src/packages/std/vec/vec2.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | vec2_t 4 | vec2_zeros(void) { 5 | return (vec2_t) { .x = 0, .y = 0 }; 6 | } 7 | 8 | vec2_t 9 | vec2_ones(void) { 10 | return (vec2_t) { .x = 1, .y = 1 }; 11 | } 12 | 13 | bool 14 | vec2_equal(vec2_t v1, vec2_t v2) { 15 | return v1.x == v2.x && v1.y == v2.y; 16 | } 17 | 18 | vec2_t 19 | vec2_add(vec2_t v1, vec2_t v2) { 20 | return (vec2_t) { 21 | .x = v1.x + v2.x, 22 | .y = v1.y + v2.y, 23 | }; 24 | } 25 | 26 | vec2_t 27 | vec2_sub(vec2_t v1, vec2_t v2) { 28 | return (vec2_t) { 29 | .x = v1.x - v2.x, 30 | .y = v1.y - v2.y, 31 | }; 32 | } 33 | 34 | vec2_t 35 | vec2_neg(vec2_t v) { 36 | return (vec2_t) { 37 | .x = - v.x, 38 | .y = - v.y, 39 | }; 40 | } 41 | 42 | vec2_t 43 | vec2_mul(vec2_t v1, vec2_t v2) { 44 | return (vec2_t) { 45 | .x = v1.x * v2.x, 46 | .y = v1.y * v2.y, 47 | }; 48 | } 49 | 50 | double 51 | vec2_dot(vec2_t v1, vec2_t v2) { 52 | return v1.x * v2.x + v1.y * v2.y; 53 | } 54 | 55 | double 56 | vec2_square(vec2_t v) { 57 | return vec2_dot(v, v); 58 | } 59 | 60 | double 61 | vec2_length(vec2_t v) { 62 | return sqrt(vec2_square(v)); 63 | } 64 | 65 | bool 66 | vec2_is_nan(vec2_t v) { 67 | return isnan(v.x) || isnan(v.y); 68 | } 69 | 70 | vec2_t 71 | vec2_add_scalar(vec2_t v, double s) { 72 | return (vec2_t) { 73 | .x = v.x + s, 74 | .y = v.y + s, 75 | }; 76 | } 77 | 78 | vec2_t 79 | vec2_sub_scalar(vec2_t v, double s) { 80 | return (vec2_t) { 81 | .x = v.x - s, 82 | .y = v.y - s, 83 | }; 84 | } 85 | 86 | vec2_t 87 | vec2_mul_scalar(vec2_t v, double s) { 88 | return (vec2_t) { 89 | .x = v.x * s, 90 | .y = v.y * s, 91 | }; 92 | } 93 | 94 | vec2_t 95 | vec2_div_scalar(vec2_t v, double s) { 96 | return (vec2_t) { 97 | .x = v.x / s, 98 | .y = v.y / s, 99 | }; 100 | } 101 | 102 | vec2_t 103 | vec2_map(vec2_t v, double_unary_fn_t* fn) { 104 | return (vec2_t) { 105 | .x = fn(v.x), 106 | .y = fn(v.y), 107 | }; 108 | } 109 | -------------------------------------------------------------------------------- /src/packages/std/vec/vec2.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct vec2_t { double x, y; }; 4 | 5 | vec2_t vec2_zeros(void); 6 | vec2_t vec2_ones(void); 7 | 8 | bool vec2_equal(vec2_t v1, vec2_t v2); 9 | 10 | vec2_t vec2_add(vec2_t v1, vec2_t v2); 11 | vec2_t vec2_sub(vec2_t v1, vec2_t v2); 12 | vec2_t vec2_neg(vec2_t v); 13 | vec2_t vec2_mul(vec2_t v1, vec2_t v2); 14 | 15 | double vec2_dot(vec2_t v1, vec2_t v2); 16 | double vec2_square(vec2_t v); 17 | double vec2_length(vec2_t v); 18 | 19 | bool vec2_is_nan(vec2_t v); 20 | 21 | vec2_t vec2_add_scalar(vec2_t v, double s); 22 | vec2_t vec2_sub_scalar(vec2_t v, double s); 23 | vec2_t vec2_mul_scalar(vec2_t v, double s); 24 | vec2_t vec2_div_scalar(vec2_t v, double s); 25 | 26 | vec2_t vec2_map(vec2_t v, double_unary_fn_t* fn); 27 | -------------------------------------------------------------------------------- /src/prelude/console.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | value_t x_print(value_t x) { 4 | value_print(x, stdout); 5 | return x; 6 | } 7 | 8 | value_t x_newline(void) { 9 | printf("\n"); 10 | return NULL; 11 | } 12 | -------------------------------------------------------------------------------- /src/prelude/console.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | primitive_fn_1_t x_print; 4 | primitive_fn_0_t x_newline; 5 | -------------------------------------------------------------------------------- /src/prelude/deps.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../deps.h" 4 | #include "../lang/index.h" 5 | -------------------------------------------------------------------------------- /src/prelude/function.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | void x_define_function(worker_t *worker) { 4 | token_t *token = list_shift(worker->token_list); 5 | function_t *function = compile_function(worker); 6 | define_function(worker->mod, token->string, function); 7 | token_destroy(&token); 8 | } 9 | 10 | static void 11 | import(worker_t *worker, list_t *name_list, path_t *target_path) { 12 | path_t *path = path_copy(worker->mod->path); 13 | path_join(path, ".."); 14 | path_join(path, path_string(target_path)); 15 | mod_t *imported_mod = load_mod(path); 16 | char *name = list_first(name_list); 17 | while (name) { 18 | value_t value = mod_find(imported_mod, name); 19 | if (value == NULL) { 20 | who_printf("unknown name: %s", name); 21 | exit(1); 22 | } 23 | 24 | define(worker->mod, name, value); 25 | name = list_next(name_list); 26 | } 27 | 28 | return; 29 | } 30 | 31 | void x_import(worker_t *worker) { 32 | token_t *token = list_shift(worker->token_list); 33 | list_t *name_list = string_list_new(); 34 | while (true) { 35 | if (!token) { 36 | who_printf("expect a path to be the end of import\n"); 37 | exit(1); 38 | } else if (token->kind == GENERIC_TOKEN) { 39 | list_push(name_list, string_copy(token->string)); 40 | token_destroy(&token); 41 | } else if (token->kind == STRING_TOKEN) { 42 | path_t *path = path_new(token->string); 43 | token_destroy(&token); 44 | import(worker, name_list, path); 45 | list_destroy(&name_list); 46 | path_destroy(&path); 47 | return; 48 | } else { 49 | who_printf("can not handle token: %s\n", token->string); 50 | exit(1); 51 | } 52 | 53 | token = list_shift(worker->token_list); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/prelude/function.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | primitive_fn_t x_define_function; 4 | primitive_fn_t x_import; 5 | -------------------------------------------------------------------------------- /src/prelude/import_prelude.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void import_prelude(mod_t *mod); 4 | -------------------------------------------------------------------------------- /src/prelude/index.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "deps.h" 4 | #include "types.h" 5 | #include "value.h" 6 | #include "testing.h" 7 | #include "net.h" 8 | #include "worker.h" 9 | #include "console.h" 10 | #include "function.h" 11 | #include "import_prelude.h" 12 | -------------------------------------------------------------------------------- /src/prelude/net.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | primitive_fn_t x_connect; 4 | primitive_fn_t x_link; 5 | primitive_fn_t x_run; 6 | primitive_fn_t x_inspect_run; 7 | primitive_fn_t x_define_node; 8 | primitive_fn_t x_define_rule; 9 | -------------------------------------------------------------------------------- /src/prelude/testing.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | void x_ok(worker_t *worker) { 4 | bool ok = to_bool(stack_pop(worker->value_stack)); 5 | if (!ok) { 6 | fprintf(stderr, "[assertion-failed]\n"); 7 | worker_print(worker, stderr); 8 | exit(1); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/prelude/testing.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | primitive_fn_t x_ok; 4 | -------------------------------------------------------------------------------- /src/prelude/types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | -------------------------------------------------------------------------------- /src/prelude/value.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | value_t x_eq(value_t x, value_t y) { 4 | return xbool(x == y); 5 | } 6 | 7 | void x_dup(worker_t *worker) { 8 | value_t x = stack_pop(worker->value_stack); 9 | stack_push(worker->value_stack, x); 10 | stack_push(worker->value_stack, x); 11 | } 12 | 13 | void x_swap(worker_t *worker) { 14 | value_t y = stack_pop(worker->value_stack); 15 | value_t x = stack_pop(worker->value_stack); 16 | stack_push(worker->value_stack, y); 17 | stack_push(worker->value_stack, x); 18 | } 19 | 20 | void x_drop(worker_t *worker) { 21 | (void) stack_pop(worker->value_stack); 22 | } 23 | 24 | void x_rot(worker_t *worker) { 25 | value_t z = stack_pop(worker->value_stack); 26 | value_t y = stack_pop(worker->value_stack); 27 | value_t x = stack_pop(worker->value_stack); 28 | stack_push(worker->value_stack, y); 29 | stack_push(worker->value_stack, z); 30 | stack_push(worker->value_stack, x); 31 | } 32 | 33 | void x_over(worker_t *worker) { 34 | value_t y = stack_pop(worker->value_stack); 35 | value_t x = stack_pop(worker->value_stack); 36 | stack_push(worker->value_stack, x); 37 | stack_push(worker->value_stack, y); 38 | stack_push(worker->value_stack, x); 39 | } 40 | 41 | void x_tuck(worker_t *worker) { 42 | value_t y = stack_pop(worker->value_stack); 43 | value_t x = stack_pop(worker->value_stack); 44 | stack_push(worker->value_stack, y); 45 | stack_push(worker->value_stack, x); 46 | stack_push(worker->value_stack, y); 47 | } 48 | -------------------------------------------------------------------------------- /src/prelude/value.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | primitive_fn_2_t x_eq; 4 | primitive_fn_t x_dup; 5 | primitive_fn_t x_swap; 6 | primitive_fn_t x_drop; 7 | primitive_fn_t x_rot; 8 | primitive_fn_t x_over; 9 | primitive_fn_t x_tuck; 10 | -------------------------------------------------------------------------------- /src/prelude/worker.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | void 4 | x_print_worker(worker_t *worker) { 5 | worker_print(worker, stdout); 6 | fprintf(stdout, "\n"); 7 | } 8 | 9 | void 10 | x_print_value_stack(worker_t *worker) { 11 | worker_print_value_stack(worker, stdout); 12 | } 13 | 14 | void 15 | x_print_return_stack(worker_t *worker) { 16 | worker_print_return_stack(worker, stdout); 17 | } 18 | -------------------------------------------------------------------------------- /src/prelude/worker.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | primitive_fn_t x_print_worker; 4 | primitive_fn_t x_print_value_stack; 5 | primitive_fn_t x_print_return_stack; 6 | -------------------------------------------------------------------------------- /src/value/constant_table.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | constant_table_entry_t constant_table[] = { 4 | { "true", xtrue }, 5 | { "false", xfalse }, 6 | }; 7 | 8 | bool 9 | string_is_constant_value(const char *string) { 10 | size_t length = sizeof(constant_table) / sizeof(constant_table_entry_t); 11 | for (size_t i = 0; i < length; i++) { 12 | if (string_equal(string, constant_table[i].name)) { 13 | return true; 14 | } 15 | } 16 | 17 | return false; 18 | } 19 | 20 | value_t 21 | string_to_constant_value(const char *string) { 22 | size_t length = sizeof(constant_table) / sizeof(constant_table_entry_t); 23 | for (size_t i = 0; i < length; i++) { 24 | if (string_equal(string, constant_table[i].name)) { 25 | return constant_table[i].value; 26 | } 27 | } 28 | 29 | assert(false); 30 | } 31 | -------------------------------------------------------------------------------- /src/value/constant_table.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct constant_table_entry_t { 4 | const char *name; 5 | value_t value; 6 | }; 7 | 8 | typedef struct constant_table_entry_t constant_table_entry_t; 9 | 10 | extern constant_table_entry_t constant_table[]; 11 | 12 | bool string_is_constant_value(const char *string); 13 | value_t string_to_constant_value(const char *string); 14 | -------------------------------------------------------------------------------- /src/value/deps.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../deps.h" 4 | -------------------------------------------------------------------------------- /src/value/index.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "deps.h" 4 | #include "types.h" 5 | #include "value.h" 6 | 7 | #include "xbool.h" 8 | #include "xint.h" 9 | #include "xfloat.h" 10 | #include "xobject.h" 11 | 12 | #include "constant_table.h" 13 | -------------------------------------------------------------------------------- /src/value/types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef void *value_t; 4 | typedef _Atomic value_t atomic_value_t; 5 | 6 | // value = higher 61 bits data + lower 3 bits tag. 7 | // thus we have 8 tags. 8 | 9 | #define DATA_MASK ((uint64_t) 0xfffffffffffffff8) 10 | #define TAG_MASK ((uint64_t) 0x07) 11 | 12 | // xobject is 8 bytes aligned pointer. 13 | 14 | typedef enum { 15 | XOBJECT = 0, // 0b000 16 | XSTATIC = 1, // 0b001 17 | XINT = 2, // 0b010 18 | XFLOAT = 3, // 0b011 19 | // TODO = 4, // 0b100 20 | // TODO = 5, // 0b101 21 | // TODO = 6, // 0b110 22 | XEXTENDED = 7, // 0b111 23 | } tag_t; 24 | 25 | typedef struct object_spec_t object_spec_t; 26 | typedef struct object_t object_t; 27 | -------------------------------------------------------------------------------- /src/value/value.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | tag_t 4 | value_tag(value_t value) { 5 | return (size_t) value & TAG_MASK; 6 | } 7 | 8 | void 9 | value_print(value_t value, file_t *file) { 10 | if (value == xtrue) { 11 | fprintf(file, "true"); 12 | return; 13 | } 14 | 15 | if (value == xfalse) { 16 | fprintf(file, "false"); 17 | return; 18 | } 19 | 20 | if (is_xint(value)) { 21 | fprintf(file, "%ld", to_int64(value)); 22 | return; 23 | } 24 | 25 | if (is_xfloat(value)) { 26 | char buffer[64]; 27 | sprintf(buffer, "%.17g", to_double(value)); 28 | if (!string_has_char(buffer, '.')) { 29 | size_t end = string_length(buffer); 30 | buffer[end] = '.'; 31 | buffer[end + 1] = '0'; 32 | buffer[end + 2] = '\0'; 33 | } 34 | 35 | fprintf(stdout, "%s", buffer); 36 | return; 37 | } 38 | 39 | if (is_xobject(value)) { 40 | object_t *object = as_object(value); 41 | if (object->spec->print_fn) { 42 | object->spec->print_fn(object, file); 43 | return; 44 | } 45 | 46 | // fprintf(file, "#", value); 47 | fprintf(file, "#<%s 0x%p>", object->spec->name, value); 48 | return; 49 | } 50 | 51 | fprintf(file, "#", value); 52 | return; 53 | } 54 | -------------------------------------------------------------------------------- /src/value/value.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | tag_t value_tag(value_t value); 4 | 5 | void value_print(value_t value, file_t *file); 6 | -------------------------------------------------------------------------------- /src/value/xbool.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | value_t 4 | xbool(bool target) { 5 | return target ? xtrue : xfalse; 6 | } 7 | 8 | bool 9 | is_xbool(value_t value) { 10 | return value == xtrue || value == xfalse; 11 | } 12 | 13 | bool 14 | to_bool(value_t value) { 15 | assert(is_xbool(value)); 16 | return value == xtrue; 17 | } 18 | 19 | value_t 20 | xbool_and(value_t x, value_t y) { 21 | return xbool(to_bool(x) && to_bool(y)); 22 | } 23 | 24 | value_t 25 | xbool_or(value_t x, value_t y) { 26 | return xbool(to_bool(x) || to_bool(y)); 27 | } 28 | 29 | value_t xbool_not(value_t x) { 30 | return xbool(!to_bool(x)); 31 | } 32 | -------------------------------------------------------------------------------- /src/value/xbool.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define xtrue ((value_t) 0x00ffffffffffffff) 4 | #define xfalse ((value_t) 0x01ffffffffffffff) 5 | 6 | value_t xbool(bool target); 7 | bool is_xbool(value_t value); 8 | bool to_bool(value_t value); 9 | 10 | value_t xbool_and(value_t x, value_t y); 11 | value_t xbool_or(value_t x, value_t y); 12 | value_t xbool_not(value_t x); 13 | -------------------------------------------------------------------------------- /src/value/xfloat.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | // double-precision floating-point but truncate the lower 3 bits 4 | 5 | typedef union { double as_double; uint64_t as_uint64; } double_or_uint64_t; 6 | 7 | value_t 8 | xfloat(double target) { 9 | double_or_uint64_t the_union = (double_or_uint64_t) { 10 | .as_double = target 11 | }; 12 | 13 | return (value_t) ((the_union.as_uint64 & DATA_MASK) | XFLOAT); 14 | } 15 | 16 | bool 17 | is_xfloat(value_t value) { 18 | return value_tag(value) == XFLOAT; 19 | } 20 | 21 | double 22 | to_double(value_t value) { 23 | assert(is_xfloat(value)); 24 | 25 | double_or_uint64_t the_union = (double_or_uint64_t) { 26 | .as_uint64 = ((uint64_t) value) & DATA_MASK 27 | }; 28 | 29 | return the_union.as_double; 30 | } 31 | 32 | value_t 33 | xfloat_add(value_t x, value_t y) { 34 | return xfloat(to_double(x) + to_double(y)); 35 | } 36 | 37 | value_t 38 | xfloat_sub(value_t x, value_t y) { 39 | return xfloat(to_double(x) - to_double(y)); 40 | } 41 | 42 | value_t 43 | xfloat_mul(value_t x, value_t y) { 44 | return xfloat(to_double(x) * to_double(y)); 45 | } 46 | 47 | value_t 48 | xfloat_div(value_t x, value_t y) { 49 | return xfloat(to_double(x) / to_double(y)); 50 | } 51 | 52 | value_t 53 | xfloat_mod(value_t x, value_t y) { 54 | return xfloat(fmod(to_double(x), to_double(y))); 55 | } 56 | 57 | value_t 58 | xfloat_to_xint(value_t x) { 59 | if (!is_xfloat(x)) { 60 | fprintf(stderr, "[xfloat_to_xint] type mismatch\n"); 61 | exit(1); 62 | } 63 | 64 | return xint((uint64_t) to_double(x)); 65 | } 66 | -------------------------------------------------------------------------------- /src/value/xfloat.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | value_t xfloat(double target); 4 | bool is_xfloat(value_t value); 5 | double to_double(value_t value); 6 | 7 | value_t xfloat_add(value_t x, value_t y); 8 | value_t xfloat_sub(value_t x, value_t y); 9 | value_t xfloat_mul(value_t x, value_t y); 10 | value_t xfloat_div(value_t x, value_t y); 11 | value_t xfloat_mod(value_t x, value_t y); 12 | value_t xfloat_to_xint(value_t x); 13 | -------------------------------------------------------------------------------- /src/value/xint.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | // int64_t but truncate the lower 3 bits 4 | 5 | value_t 6 | xint(int64_t target) { 7 | return (value_t) ((target << 3) | XINT); 8 | } 9 | 10 | bool 11 | is_xint(value_t value) { 12 | return value_tag(value) == XINT; 13 | } 14 | 15 | int64_t 16 | to_int64(value_t value) { 17 | assert(is_xint(value)); 18 | return ((int64_t) value) >> 3; 19 | } 20 | 21 | value_t 22 | xint_add(value_t x, value_t y) { 23 | return xint(to_int64(x) + to_int64(y)); 24 | } 25 | 26 | value_t 27 | xint_sub(value_t x, value_t y) { 28 | return xint(to_int64(x) - to_int64(y)); 29 | } 30 | 31 | value_t 32 | xint_mul(value_t x, value_t y) { 33 | return xint(to_int64(x) * to_int64(y)); 34 | } 35 | 36 | value_t 37 | xint_div(value_t x, value_t y) { 38 | return xint(to_int64(x) / to_int64(y)); 39 | } 40 | 41 | value_t 42 | xint_mod(value_t x, value_t y) { 43 | return xint(to_int64(x) % to_int64(y)); 44 | } 45 | 46 | value_t 47 | xint_to_xfloat(value_t x) { 48 | if (!is_xint(x)) { 49 | fprintf(stderr, "[xint_to_xfloat] type mismatch\n"); 50 | exit(1); 51 | } 52 | 53 | return xfloat((double) to_int64(x)); 54 | } 55 | -------------------------------------------------------------------------------- /src/value/xint.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | value_t xint(int64_t target); 4 | bool is_xint(value_t value); 5 | int64_t to_int64(value_t value); 6 | 7 | value_t xint_add(value_t x, value_t y); 8 | value_t xint_sub(value_t x, value_t y); 9 | value_t xint_mul(value_t x, value_t y); 10 | value_t xint_div(value_t x, value_t y); 11 | value_t xint_mod(value_t x, value_t y); 12 | value_t xint_to_xfloat(value_t x); 13 | -------------------------------------------------------------------------------- /src/value/xobject.c: -------------------------------------------------------------------------------- 1 | #include "index.h" 2 | 3 | value_t 4 | xobject(object_t *target) { 5 | return target; 6 | } 7 | 8 | bool 9 | is_xobject(value_t value) { 10 | return value != NULL && value_tag(value) == XOBJECT; 11 | } 12 | 13 | object_t * 14 | as_object(value_t value) { 15 | assert(is_xobject(value)); 16 | return value; 17 | } 18 | -------------------------------------------------------------------------------- /src/value/xobject.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef void (print_fn_t)(const void *value, file_t *file); 4 | 5 | struct object_spec_t { 6 | const char *name; 7 | print_fn_t *print_fn; 8 | }; 9 | 10 | struct object_t { 11 | const object_spec_t *spec; 12 | }; 13 | 14 | value_t xobject(object_t *target); 15 | bool is_xobject(value_t value); 16 | object_t *as_object(value_t value); 17 | --------------------------------------------------------------------------------