├── .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 |
--------------------------------------------------------------------------------