From 86934f189598076786307db92ed9f33c91efac7c Mon Sep 17 00:00:00 2001 From: Zander Thannhauser Date: Mon, 13 Jan 2025 20:36:07 -0600 Subject: [PATCH] . --- .gitignore | 7 + booleans/free.c | 27 + booleans/free.h | 6 + booleans/new.c | 82 + booleans/new.h | 3 + booleans/struct.h | 8 + build-all.py | 59 + buildtypes/debug-valgrind.txt | 31 + buildtypes/debug.txt | 32 + buildtypes/release.txt | 30 + buildtypes/test-asan.txt | 35 + buildtypes/test-ubsan.txt | 33 + buildtypes/test.txt | 31 + builtin/compare/eq.c | 73 + builtin/compare/eq.h | 10 + builtin/compare/gt.c | 73 + builtin/compare/gt.h | 8 + builtin/compare/gte.c | 73 + builtin/compare/gte.h | 8 + builtin/compare/lt.c | 73 + builtin/compare/lt.h | 8 + builtin/compare/lte.c | 80 + builtin/compare/lte.h | 8 + builtin/compare/neq.c | 73 + builtin/compare/neq.h | 8 + builtin/numeric/add.c | 71 + builtin/numeric/add.h | 8 + builtin/numeric/divide.c | 15 + builtin/numeric/divide.h | 9 + builtin/numeric/multiply.c | 59 + builtin/numeric/multiply.h | 8 + builtin/numeric/subtract.c | 59 + builtin/numeric/subtract.h | 8 + cmdln/free.c | 16 + cmdln/free.h | 7 + cmdln/new.c | 168 + cmdln/new.h | 7 + cmdln/struct.h | 30 + color_factory/free.c | 44 + color_factory/free.h | 7 + color_factory/new.c | 108 + color_factory/new.h | 3 + color_factory/struct.h | 16 + debug.c | 91 + debug.h | 282 ++ defines/N.h | 5 + defines/argv0.h | 4 + dep-snipe.sh | 2 + environment/declare.c | 31 + environment/declare.h | 11 + environment/declare_builtins.c | 98 + environment/declare_builtins.h | 9 + environment/free.c | 27 + environment/free.h | 7 + environment/inc.c | 15 + environment/inc.h | 5 + environment/lookup.c | 53 + environment/lookup.h | 8 + environment/new.c | 33 + environment/new.h | 5 + environment/struct.h | 11 + environment/variable/compare.c | 18 + environment/variable/compare.h | 6 + environment/variable/free.c | 25 + environment/variable/free.h | 5 + environment/variable/new.c | 29 + environment/variable/new.h | 9 + environment/variable/struct.h | 12 + examples/init.txt | 11 + examples/sandbox.txt | 63 + expression/application/evaluate.c | 117 + expression/application/evaluate.h | 7 + expression/application/free.c | 23 + expression/application/free.h | 6 + expression/application/inheritance.c | 20 + expression/application/inheritance.h | 2 + expression/application/new.c | 29 + expression/application/new.h | 6 + expression/application/prettyprint.c | 72 + expression/application/prettyprint.h | 15 + expression/application/prettyprint_errors.c | 34 + expression/application/prettyprint_errors.h | 4 + expression/application/struct.h | 10 + expression/evaluate.c | 25 + expression/evaluate.h | 11 + expression/free.c | 29 + expression/free.h | 6 + expression/inc.c | 15 + expression/inc.h | 4 + expression/inheritance.h | 28 + expression/lambda/evaluate.c | 25 + expression/lambda/evaluate.h | 11 + expression/lambda/free.c | 23 + expression/lambda/free.h | 6 + expression/lambda/inheritance.c | 20 + expression/lambda/inheritance.h | 2 + expression/lambda/new.c | 34 + expression/lambda/new.h | 8 + expression/lambda/prettyprint.c | 75 + expression/lambda/prettyprint.h | 15 + expression/lambda/prettyprint_errors.c | 21 + expression/lambda/prettyprint_errors.h | 4 + expression/lambda/struct.h | 12 + expression/literal/evaluate.c | 22 + expression/literal/evaluate.h | 11 + expression/literal/free.c | 19 + expression/literal/free.h | 6 + expression/literal/inheritance.c | 20 + expression/literal/inheritance.h | 2 + expression/literal/new.c | 30 + expression/literal/new.h | 7 + expression/literal/prettyprint.c | 38 + expression/literal/prettyprint.h | 13 + expression/literal/prettyprint_errors.c | 17 + expression/literal/prettyprint_errors.h | 4 + expression/literal/struct.h | 10 + expression/new.c | 24 + expression/new.h | 10 + expression/parenthesis/evaluate.c | 23 + expression/parenthesis/evaluate.h | 7 + expression/parenthesis/free.c | 19 + expression/parenthesis/free.h | 6 + expression/parenthesis/inheritance.c | 20 + expression/parenthesis/inheritance.h | 2 + expression/parenthesis/new.c | 25 + expression/parenthesis/new.h | 8 + expression/parenthesis/prettyprint.c | 73 + expression/parenthesis/prettyprint.h | 15 + expression/parenthesis/prettyprint_errors.c | 22 + expression/parenthesis/prettyprint_errors.h | 4 + expression/parenthesis/struct.h | 10 + expression/prettyprint.c | 29 + expression/prettyprint.h | 12 + expression/prettyprint_errors.c | 23 + expression/prettyprint_errors.h | 6 + expression/print.c | 0 expression/print.h | 0 expression/struct.h | 10 + expression/variable/evaluate.c | 22 + expression/variable/evaluate.h | 11 + expression/variable/free.c | 19 + expression/variable/free.h | 6 + expression/variable/inheritance.c | 20 + expression/variable/inheritance.h | 2 + expression/variable/new.c | 30 + expression/variable/new.h | 8 + expression/variable/prettyprint.c | 54 + expression/variable/prettyprint.h | 13 + expression/variable/prettyprint_errors.c | 17 + expression/variable/prettyprint_errors.h | 4 + expression/variable/struct.h | 10 + extern/avl/avl.c | 650 +++ extern/avl/avl.h | 208 + extern/gmp/mini-gmp.c | 4635 ++++++++++++++++++ extern/gmp/mini-gmp.h | 313 ++ extern/gmp/mini-mpq.c | 562 +++ extern/gmp/mini-mpq.h | 114 + handle_file.c | 0 handle_file.h | 0 handle_init_file.c | 132 + handle_init_file.h | 9 + handle_interactive.c | 0 handle_interactive.h | 0 handle_string.c | 0 handle_string.h | 0 main.c | 364 ++ makefile | 77 + memory/smalloc.c | 25 + memory/smalloc.h | 4 + memory/srealloc.c | 25 + memory/srealloc.h | 6 + misc/wcindex.c | 18 + misc/wcindex.h | 8 + notes.md | 86 + number/add.c | 23 + number/add.h | 6 + number/compare.c | 13 + number/compare.h | 8 + number/free.c | 22 + number/free.h | 7 + number/inc.c | 15 + number/inc.h | 6 + number/multiply.c | 23 + number/multiply.h | 8 + number/new.c | 25 + number/new.h | 5 + number/prettyprint.c | 154 + number/prettyprint.h | 6 + number/set_int.c | 13 + number/set_int.h | 8 + number/set_str.c | 142 + number/set_str.h | 9 + number/struct.h | 11 + number/subtract.c | 23 + number/subtract.h | 5 + ostream/file/free.c | 23 + ostream/file/free.h | 7 + ostream/file/inheritance.c | 14 + ostream/file/inheritance.h | 6 + ostream/file/new.c | 24 + ostream/file/new.h | 4 + ostream/file/struct.h | 10 + ostream/file/write.c | 31 + ostream/file/write.h | 12 + ostream/free.c | 29 + ostream/free.h | 6 + ostream/inc.c | 15 + ostream/inc.h | 7 + ostream/inheritance.h | 16 + ostream/new.c | 24 + ostream/new.h | 10 + ostream/struct.h | 12 + ostream/write.c | 25 + ostream/write.h | 11 + parse/istream/file/free.c | 20 + parse/istream/file/free.h | 3 + parse/istream/file/inheritance.c | 16 + parse/istream/file/inheritance.h | 6 + parse/istream/file/new.c | 40 + parse/istream/file/new.h | 3 + parse/istream/file/read.c | 49 + parse/istream/file/read.h | 3 + parse/istream/file/struct.h | 18 + parse/istream/free.c | 29 + parse/istream/free.h | 5 + parse/istream/inc.c | 15 + parse/istream/inc.h | 3 + parse/istream/inheritance.h | 16 + parse/istream/new.c | 26 + parse/istream/new.h | 9 + parse/istream/read.c | 23 + parse/istream/read.h | 3 + parse/istream/string/free.c | 21 + parse/istream/string/free.h | 3 + parse/istream/string/inheritance.c | 16 + parse/istream/string/inheritance.h | 6 + parse/istream/string/new.c | 34 + parse/istream/string/new.h | 3 + parse/istream/string/read.c | 25 + parse/istream/string/read.h | 3 + parse/istream/string/struct.h | 14 + parse/istream/struct.h | 14 + parse/parse.c | 606 +++ parse/parse.h | 6 + parse/position/assign.c | 19 + parse/position/assign.h | 6 + parse/position/clone.c | 29 + parse/position/clone.h | 6 + parse/position/free.c | 25 + parse/position/free.h | 7 + parse/position/inc.c | 15 + parse/position/inc.h | 6 + parse/position/new.c | 31 + parse/position/new.h | 10 + parse/position/print.c | 0 parse/position/print.h | 0 parse/position/struct.h | 12 + parse/token/free.c | 31 + parse/token/free.h | 7 + parse/token/inc.c | 15 + parse/token/inc.h | 5 + parse/token/kind.h | 34 + parse/token/new.c | 37 + parse/token/new.h | 12 + parse/token/struct.h | 19 + parse/tokenizer/free.c | 37 + parse/tokenizer/free.h | 5 + parse/tokenizer/inc.c | 0 parse/tokenizer/inc.h | 0 parse/tokenizer/new.c | 53 + parse/tokenizer/new.h | 10 + parse/tokenizer/next.c | 432 ++ parse/tokenizer/next.h | 3 + parse/tokenizer/put_back.c | 26 + parse/tokenizer/put_back.h | 9 + parse/tokenizer/struct.h | 36 + parse/wcistream/file/free.c | 20 + parse/wcistream/file/free.h | 3 + parse/wcistream/file/inheritance.c | 16 + parse/wcistream/file/inheritance.h | 6 + parse/wcistream/file/new.c | 40 + parse/wcistream/file/new.h | 3 + parse/wcistream/file/read.c | 52 + parse/wcistream/file/read.h | 3 + parse/wcistream/file/struct.h | 18 + parse/wcistream/free.c | 29 + parse/wcistream/free.h | 5 + parse/wcistream/inc.c | 15 + parse/wcistream/inc.h | 3 + parse/wcistream/inheritance.h | 16 + parse/wcistream/istream/free.c | 22 + parse/wcistream/istream/free.h | 3 + parse/wcistream/istream/inheritance.c | 16 + parse/wcistream/istream/inheritance.h | 6 + parse/wcistream/istream/new.c | 34 + parse/wcistream/istream/new.h | 3 + parse/wcistream/istream/read.c | 136 + parse/wcistream/istream/read.h | 3 + parse/wcistream/istream/struct.h | 14 + parse/wcistream/new.c | 26 + parse/wcistream/new.h | 9 + parse/wcistream/read.c | 23 + parse/wcistream/read.h | 3 + parse/wcistream/string/free.c | 18 + parse/wcistream/string/free.h | 3 + parse/wcistream/string/inheritance.c | 16 + parse/wcistream/string/inheritance.h | 6 + parse/wcistream/string/new.c | 34 + parse/wcistream/string/new.h | 3 + parse/wcistream/string/read.c | 25 + parse/wcistream/string/read.h | 3 + parse/wcistream/string/struct.h | 14 + parse/wcistream/struct.h | 15 + srclist.mk | 208 + statement/assignment/execute.c | 80 + statement/assignment/execute.h | 13 + statement/assignment/free.c | 24 + statement/assignment/free.h | 5 + statement/assignment/inheritance.c | 21 + statement/assignment/inheritance.h | 3 + statement/assignment/new.c | 31 + statement/assignment/new.h | 6 + statement/assignment/prettyprint.c | 66 + statement/assignment/prettyprint.h | 11 + statement/assignment/prettyprint_errors.c | 20 + statement/assignment/prettyprint_errors.h | 4 + statement/assignment/struct.h | 12 + statement/execute.c | 30 + statement/execute.h | 19 + statement/expression/execute.c | 68 + statement/expression/execute.h | 13 + statement/expression/free.c | 20 + statement/expression/free.h | 5 + statement/expression/inheritance.c | 21 + statement/expression/inheritance.h | 3 + statement/expression/new.c | 26 + statement/expression/new.h | 6 + statement/expression/prettyprint.c | 26 + statement/expression/prettyprint.h | 11 + statement/expression/prettyprint_errors.c | 20 + statement/expression/prettyprint_errors.h | 4 + statement/expression/struct.h | 10 + statement/free.c | 29 + statement/free.h | 7 + statement/inc.c | 15 + statement/inc.h | 7 + statement/inheritance.h | 33 + statement/new.c | 25 + statement/new.h | 10 + statement/prettyprint.c | 31 + statement/prettyprint.h | 11 + statement/prettyprint_errors.c | 24 + statement/prettyprint_errors.h | 5 + statement/print.c | 0 statement/print.h | 0 statement/struct.h | 10 + statement/substatements/execute.c | 28 + statement/substatements/execute.h | 11 + statement/substatements/free.c | 22 + statement/substatements/free.h | 5 + statement/substatements/inheritance.c | 21 + statement/substatements/inheritance.h | 3 + statement/substatements/new.c | 29 + statement/substatements/new.h | 6 + statement/substatements/prettyprint.c | 86 + statement/substatements/prettyprint.h | 12 + statement/substatements/prettyprint_errors.c | 34 + statement/substatements/prettyprint_errors.h | 7 + statement/substatements/struct.h | 11 + string/compare.c | 17 + string/compare.h | 6 + string/free.c | 21 + string/free.h | 5 + string/inc.c | 18 + string/inc.h | 3 + string/new.c | 140 + string/new.h | 16 + string/print.c | 22 + string/print.h | 8 + string/println.c | 0 string/println.h | 0 string/struct.h | 12 + stringtree/append.c | 158 + stringtree/append.h | 21 + stringtree/free.c | 61 + stringtree/free.h | 6 + stringtree/inc.c | 18 + stringtree/inc.h | 3 + stringtree/new.c | 23 + stringtree/new.h | 2 + stringtree/prepend.c | 156 + stringtree/prepend.h | 21 + stringtree/print.c | 48 + stringtree/print.h | 9 + stringtree/println.c | 21 + stringtree/println.h | 8 + stringtree/struct.h | 27 + value/builtin_lambda/free.c | 26 + value/builtin_lambda/free.h | 6 + value/builtin_lambda/inheritance.c | 15 + value/builtin_lambda/inheritance.h | 7 + value/builtin_lambda/new.c | 53 + value/builtin_lambda/new.h | 14 + value/builtin_lambda/prettyprint.c | 127 + value/builtin_lambda/prettyprint.h | 7 + value/builtin_lambda/struct.h | 27 + value/free.c | 25 + value/free.h | 7 + value/inc.c | 15 + value/inc.h | 5 + value/inheritance.h | 23 + value/kind.h | 16 + value/lambda/free.c | 28 + value/lambda/free.h | 6 + value/lambda/inheritance.c | 15 + value/lambda/inheritance.h | 7 + value/lambda/new.c | 37 + value/lambda/new.h | 11 + value/lambda/prettyprint.c | 75 + value/lambda/prettyprint.h | 7 + value/lambda/struct.h | 14 + value/lazy/free.c | 28 + value/lazy/free.h | 6 + value/lazy/inheritance.c | 15 + value/lazy/inheritance.h | 7 + value/lazy/new.c | 34 + value/lazy/new.h | 6 + value/lazy/prettyprint.c | 48 + value/lazy/prettyprint.h | 7 + value/lazy/struct.h | 14 + value/lazy/unlazy.c | 58 + value/lazy/unlazy.h | 8 + value/new.c | 27 + value/new.h | 13 + value/number/free.c | 20 + value/number/free.h | 6 + value/number/inheritance.c | 15 + value/number/inheritance.h | 7 + value/number/new.c | 27 + value/number/new.h | 5 + value/number/prettyprint.c | 51 + value/number/prettyprint.h | 7 + value/number/struct.h | 10 + value/prettyprint.c | 28 + value/prettyprint.h | 13 + value/struct.h | 18 + wcostream/file/free.c | 0 wcostream/file/free.h | 0 wcostream/file/new.c | 0 wcostream/file/new.h | 0 wcostream/file/struct.h | 0 wcostream/file/write.c | 0 wcostream/file/write.h | 0 wcostream/free.c | 30 + wcostream/free.h | 7 + wcostream/inc.c | 0 wcostream/inc.h | 0 wcostream/inheritance.h | 20 + wcostream/new.c | 24 + wcostream/new.h | 10 + wcostream/ostream/free.c | 21 + wcostream/ostream/free.h | 7 + wcostream/ostream/inheritance.c | 15 + wcostream/ostream/inheritance.h | 6 + wcostream/ostream/new.c | 26 + wcostream/ostream/new.h | 7 + wcostream/ostream/struct.h | 12 + wcostream/ostream/write.c | 122 + wcostream/ostream/write.h | 9 + wcostream/string/free.c | 0 wcostream/string/free.h | 0 wcostream/string/new.c | 0 wcostream/string/new.h | 0 wcostream/string/struct.h | 0 wcostream/string/write.c | 0 wcostream/string/write.h | 0 wcostream/struct.h | 10 + wcostream/write.c | 25 + wcostream/write.h | 11 + 479 files changed, 18103 insertions(+) create mode 100644 .gitignore create mode 100644 booleans/free.c create mode 100644 booleans/free.h create mode 100644 booleans/new.c create mode 100644 booleans/new.h create mode 100644 booleans/struct.h create mode 100755 build-all.py create mode 100644 buildtypes/debug-valgrind.txt create mode 100644 buildtypes/debug.txt create mode 100644 buildtypes/release.txt create mode 100644 buildtypes/test-asan.txt create mode 100644 buildtypes/test-ubsan.txt create mode 100644 buildtypes/test.txt create mode 100644 builtin/compare/eq.c create mode 100644 builtin/compare/eq.h create mode 100644 builtin/compare/gt.c create mode 100644 builtin/compare/gt.h create mode 100644 builtin/compare/gte.c create mode 100644 builtin/compare/gte.h create mode 100644 builtin/compare/lt.c create mode 100644 builtin/compare/lt.h create mode 100644 builtin/compare/lte.c create mode 100644 builtin/compare/lte.h create mode 100644 builtin/compare/neq.c create mode 100644 builtin/compare/neq.h create mode 100644 builtin/numeric/add.c create mode 100644 builtin/numeric/add.h create mode 100644 builtin/numeric/divide.c create mode 100644 builtin/numeric/divide.h create mode 100644 builtin/numeric/multiply.c create mode 100644 builtin/numeric/multiply.h create mode 100644 builtin/numeric/subtract.c create mode 100644 builtin/numeric/subtract.h create mode 100644 cmdln/free.c create mode 100644 cmdln/free.h create mode 100644 cmdln/new.c create mode 100644 cmdln/new.h create mode 100644 cmdln/struct.h create mode 100644 color_factory/free.c create mode 100644 color_factory/free.h create mode 100644 color_factory/new.c create mode 100644 color_factory/new.h create mode 100644 color_factory/struct.h create mode 100644 debug.c create mode 100644 debug.h create mode 100644 defines/N.h create mode 100644 defines/argv0.h create mode 100755 dep-snipe.sh create mode 100644 environment/declare.c create mode 100644 environment/declare.h create mode 100644 environment/declare_builtins.c create mode 100644 environment/declare_builtins.h create mode 100644 environment/free.c create mode 100644 environment/free.h create mode 100644 environment/inc.c create mode 100644 environment/inc.h create mode 100644 environment/lookup.c create mode 100644 environment/lookup.h create mode 100644 environment/new.c create mode 100644 environment/new.h create mode 100644 environment/struct.h create mode 100644 environment/variable/compare.c create mode 100644 environment/variable/compare.h create mode 100644 environment/variable/free.c create mode 100644 environment/variable/free.h create mode 100644 environment/variable/new.c create mode 100644 environment/variable/new.h create mode 100644 environment/variable/struct.h create mode 100644 examples/init.txt create mode 100644 examples/sandbox.txt create mode 100644 expression/application/evaluate.c create mode 100644 expression/application/evaluate.h create mode 100644 expression/application/free.c create mode 100644 expression/application/free.h create mode 100644 expression/application/inheritance.c create mode 100644 expression/application/inheritance.h create mode 100644 expression/application/new.c create mode 100644 expression/application/new.h create mode 100644 expression/application/prettyprint.c create mode 100644 expression/application/prettyprint.h create mode 100644 expression/application/prettyprint_errors.c create mode 100644 expression/application/prettyprint_errors.h create mode 100644 expression/application/struct.h create mode 100644 expression/evaluate.c create mode 100644 expression/evaluate.h create mode 100644 expression/free.c create mode 100644 expression/free.h create mode 100644 expression/inc.c create mode 100644 expression/inc.h create mode 100644 expression/inheritance.h create mode 100644 expression/lambda/evaluate.c create mode 100644 expression/lambda/evaluate.h create mode 100644 expression/lambda/free.c create mode 100644 expression/lambda/free.h create mode 100644 expression/lambda/inheritance.c create mode 100644 expression/lambda/inheritance.h create mode 100644 expression/lambda/new.c create mode 100644 expression/lambda/new.h create mode 100644 expression/lambda/prettyprint.c create mode 100644 expression/lambda/prettyprint.h create mode 100644 expression/lambda/prettyprint_errors.c create mode 100644 expression/lambda/prettyprint_errors.h create mode 100644 expression/lambda/struct.h create mode 100644 expression/literal/evaluate.c create mode 100644 expression/literal/evaluate.h create mode 100644 expression/literal/free.c create mode 100644 expression/literal/free.h create mode 100644 expression/literal/inheritance.c create mode 100644 expression/literal/inheritance.h create mode 100644 expression/literal/new.c create mode 100644 expression/literal/new.h create mode 100644 expression/literal/prettyprint.c create mode 100644 expression/literal/prettyprint.h create mode 100644 expression/literal/prettyprint_errors.c create mode 100644 expression/literal/prettyprint_errors.h create mode 100644 expression/literal/struct.h create mode 100644 expression/new.c create mode 100644 expression/new.h create mode 100644 expression/parenthesis/evaluate.c create mode 100644 expression/parenthesis/evaluate.h create mode 100644 expression/parenthesis/free.c create mode 100644 expression/parenthesis/free.h create mode 100644 expression/parenthesis/inheritance.c create mode 100644 expression/parenthesis/inheritance.h create mode 100644 expression/parenthesis/new.c create mode 100644 expression/parenthesis/new.h create mode 100644 expression/parenthesis/prettyprint.c create mode 100644 expression/parenthesis/prettyprint.h create mode 100644 expression/parenthesis/prettyprint_errors.c create mode 100644 expression/parenthesis/prettyprint_errors.h create mode 100644 expression/parenthesis/struct.h create mode 100644 expression/prettyprint.c create mode 100644 expression/prettyprint.h create mode 100644 expression/prettyprint_errors.c create mode 100644 expression/prettyprint_errors.h create mode 100644 expression/print.c create mode 100644 expression/print.h create mode 100644 expression/struct.h create mode 100644 expression/variable/evaluate.c create mode 100644 expression/variable/evaluate.h create mode 100644 expression/variable/free.c create mode 100644 expression/variable/free.h create mode 100644 expression/variable/inheritance.c create mode 100644 expression/variable/inheritance.h create mode 100644 expression/variable/new.c create mode 100644 expression/variable/new.h create mode 100644 expression/variable/prettyprint.c create mode 100644 expression/variable/prettyprint.h create mode 100644 expression/variable/prettyprint_errors.c create mode 100644 expression/variable/prettyprint_errors.h create mode 100644 expression/variable/struct.h create mode 100644 extern/avl/avl.c create mode 100644 extern/avl/avl.h create mode 100644 extern/gmp/mini-gmp.c create mode 100644 extern/gmp/mini-gmp.h create mode 100644 extern/gmp/mini-mpq.c create mode 100644 extern/gmp/mini-mpq.h create mode 100644 handle_file.c create mode 100644 handle_file.h create mode 100644 handle_init_file.c create mode 100644 handle_init_file.h create mode 100644 handle_interactive.c create mode 100644 handle_interactive.h create mode 100644 handle_string.c create mode 100644 handle_string.h create mode 100644 main.c create mode 100644 makefile create mode 100644 memory/smalloc.c create mode 100644 memory/smalloc.h create mode 100644 memory/srealloc.c create mode 100644 memory/srealloc.h create mode 100644 misc/wcindex.c create mode 100644 misc/wcindex.h create mode 100644 notes.md create mode 100644 number/add.c create mode 100644 number/add.h create mode 100644 number/compare.c create mode 100644 number/compare.h create mode 100644 number/free.c create mode 100644 number/free.h create mode 100644 number/inc.c create mode 100644 number/inc.h create mode 100644 number/multiply.c create mode 100644 number/multiply.h create mode 100644 number/new.c create mode 100644 number/new.h create mode 100644 number/prettyprint.c create mode 100644 number/prettyprint.h create mode 100644 number/set_int.c create mode 100644 number/set_int.h create mode 100644 number/set_str.c create mode 100644 number/set_str.h create mode 100644 number/struct.h create mode 100644 number/subtract.c create mode 100644 number/subtract.h create mode 100644 ostream/file/free.c create mode 100644 ostream/file/free.h create mode 100644 ostream/file/inheritance.c create mode 100644 ostream/file/inheritance.h create mode 100644 ostream/file/new.c create mode 100644 ostream/file/new.h create mode 100644 ostream/file/struct.h create mode 100644 ostream/file/write.c create mode 100644 ostream/file/write.h create mode 100644 ostream/free.c create mode 100644 ostream/free.h create mode 100644 ostream/inc.c create mode 100644 ostream/inc.h create mode 100644 ostream/inheritance.h create mode 100644 ostream/new.c create mode 100644 ostream/new.h create mode 100644 ostream/struct.h create mode 100644 ostream/write.c create mode 100644 ostream/write.h create mode 100644 parse/istream/file/free.c create mode 100644 parse/istream/file/free.h create mode 100644 parse/istream/file/inheritance.c create mode 100644 parse/istream/file/inheritance.h create mode 100644 parse/istream/file/new.c create mode 100644 parse/istream/file/new.h create mode 100644 parse/istream/file/read.c create mode 100644 parse/istream/file/read.h create mode 100644 parse/istream/file/struct.h create mode 100644 parse/istream/free.c create mode 100644 parse/istream/free.h create mode 100644 parse/istream/inc.c create mode 100644 parse/istream/inc.h create mode 100644 parse/istream/inheritance.h create mode 100644 parse/istream/new.c create mode 100644 parse/istream/new.h create mode 100644 parse/istream/read.c create mode 100644 parse/istream/read.h create mode 100644 parse/istream/string/free.c create mode 100644 parse/istream/string/free.h create mode 100644 parse/istream/string/inheritance.c create mode 100644 parse/istream/string/inheritance.h create mode 100644 parse/istream/string/new.c create mode 100644 parse/istream/string/new.h create mode 100644 parse/istream/string/read.c create mode 100644 parse/istream/string/read.h create mode 100644 parse/istream/string/struct.h create mode 100644 parse/istream/struct.h create mode 100644 parse/parse.c create mode 100644 parse/parse.h create mode 100644 parse/position/assign.c create mode 100644 parse/position/assign.h create mode 100644 parse/position/clone.c create mode 100644 parse/position/clone.h create mode 100644 parse/position/free.c create mode 100644 parse/position/free.h create mode 100644 parse/position/inc.c create mode 100644 parse/position/inc.h create mode 100644 parse/position/new.c create mode 100644 parse/position/new.h create mode 100644 parse/position/print.c create mode 100644 parse/position/print.h create mode 100644 parse/position/struct.h create mode 100644 parse/token/free.c create mode 100644 parse/token/free.h create mode 100644 parse/token/inc.c create mode 100644 parse/token/inc.h create mode 100644 parse/token/kind.h create mode 100644 parse/token/new.c create mode 100644 parse/token/new.h create mode 100644 parse/token/struct.h create mode 100644 parse/tokenizer/free.c create mode 100644 parse/tokenizer/free.h create mode 100644 parse/tokenizer/inc.c create mode 100644 parse/tokenizer/inc.h create mode 100644 parse/tokenizer/new.c create mode 100644 parse/tokenizer/new.h create mode 100644 parse/tokenizer/next.c create mode 100644 parse/tokenizer/next.h create mode 100644 parse/tokenizer/put_back.c create mode 100644 parse/tokenizer/put_back.h create mode 100644 parse/tokenizer/struct.h create mode 100644 parse/wcistream/file/free.c create mode 100644 parse/wcistream/file/free.h create mode 100644 parse/wcistream/file/inheritance.c create mode 100644 parse/wcistream/file/inheritance.h create mode 100644 parse/wcistream/file/new.c create mode 100644 parse/wcistream/file/new.h create mode 100644 parse/wcistream/file/read.c create mode 100644 parse/wcistream/file/read.h create mode 100644 parse/wcistream/file/struct.h create mode 100644 parse/wcistream/free.c create mode 100644 parse/wcistream/free.h create mode 100644 parse/wcistream/inc.c create mode 100644 parse/wcistream/inc.h create mode 100644 parse/wcistream/inheritance.h create mode 100644 parse/wcistream/istream/free.c create mode 100644 parse/wcistream/istream/free.h create mode 100644 parse/wcistream/istream/inheritance.c create mode 100644 parse/wcistream/istream/inheritance.h create mode 100644 parse/wcistream/istream/new.c create mode 100644 parse/wcistream/istream/new.h create mode 100644 parse/wcistream/istream/read.c create mode 100644 parse/wcistream/istream/read.h create mode 100644 parse/wcistream/istream/struct.h create mode 100644 parse/wcistream/new.c create mode 100644 parse/wcistream/new.h create mode 100644 parse/wcistream/read.c create mode 100644 parse/wcistream/read.h create mode 100644 parse/wcistream/string/free.c create mode 100644 parse/wcistream/string/free.h create mode 100644 parse/wcistream/string/inheritance.c create mode 100644 parse/wcistream/string/inheritance.h create mode 100644 parse/wcistream/string/new.c create mode 100644 parse/wcistream/string/new.h create mode 100644 parse/wcistream/string/read.c create mode 100644 parse/wcistream/string/read.h create mode 100644 parse/wcistream/string/struct.h create mode 100644 parse/wcistream/struct.h create mode 100644 srclist.mk create mode 100644 statement/assignment/execute.c create mode 100644 statement/assignment/execute.h create mode 100644 statement/assignment/free.c create mode 100644 statement/assignment/free.h create mode 100644 statement/assignment/inheritance.c create mode 100644 statement/assignment/inheritance.h create mode 100644 statement/assignment/new.c create mode 100644 statement/assignment/new.h create mode 100644 statement/assignment/prettyprint.c create mode 100644 statement/assignment/prettyprint.h create mode 100644 statement/assignment/prettyprint_errors.c create mode 100644 statement/assignment/prettyprint_errors.h create mode 100644 statement/assignment/struct.h create mode 100644 statement/execute.c create mode 100644 statement/execute.h create mode 100644 statement/expression/execute.c create mode 100644 statement/expression/execute.h create mode 100644 statement/expression/free.c create mode 100644 statement/expression/free.h create mode 100644 statement/expression/inheritance.c create mode 100644 statement/expression/inheritance.h create mode 100644 statement/expression/new.c create mode 100644 statement/expression/new.h create mode 100644 statement/expression/prettyprint.c create mode 100644 statement/expression/prettyprint.h create mode 100644 statement/expression/prettyprint_errors.c create mode 100644 statement/expression/prettyprint_errors.h create mode 100644 statement/expression/struct.h create mode 100644 statement/free.c create mode 100644 statement/free.h create mode 100644 statement/inc.c create mode 100644 statement/inc.h create mode 100644 statement/inheritance.h create mode 100644 statement/new.c create mode 100644 statement/new.h create mode 100644 statement/prettyprint.c create mode 100644 statement/prettyprint.h create mode 100644 statement/prettyprint_errors.c create mode 100644 statement/prettyprint_errors.h create mode 100644 statement/print.c create mode 100644 statement/print.h create mode 100644 statement/struct.h create mode 100644 statement/substatements/execute.c create mode 100644 statement/substatements/execute.h create mode 100644 statement/substatements/free.c create mode 100644 statement/substatements/free.h create mode 100644 statement/substatements/inheritance.c create mode 100644 statement/substatements/inheritance.h create mode 100644 statement/substatements/new.c create mode 100644 statement/substatements/new.h create mode 100644 statement/substatements/prettyprint.c create mode 100644 statement/substatements/prettyprint.h create mode 100644 statement/substatements/prettyprint_errors.c create mode 100644 statement/substatements/prettyprint_errors.h create mode 100644 statement/substatements/struct.h create mode 100644 string/compare.c create mode 100644 string/compare.h create mode 100644 string/free.c create mode 100644 string/free.h create mode 100644 string/inc.c create mode 100644 string/inc.h create mode 100644 string/new.c create mode 100644 string/new.h create mode 100644 string/print.c create mode 100644 string/print.h create mode 100644 string/println.c create mode 100644 string/println.h create mode 100644 string/struct.h create mode 100644 stringtree/append.c create mode 100644 stringtree/append.h create mode 100644 stringtree/free.c create mode 100644 stringtree/free.h create mode 100644 stringtree/inc.c create mode 100644 stringtree/inc.h create mode 100644 stringtree/new.c create mode 100644 stringtree/new.h create mode 100644 stringtree/prepend.c create mode 100644 stringtree/prepend.h create mode 100644 stringtree/print.c create mode 100644 stringtree/print.h create mode 100644 stringtree/println.c create mode 100644 stringtree/println.h create mode 100644 stringtree/struct.h create mode 100644 value/builtin_lambda/free.c create mode 100644 value/builtin_lambda/free.h create mode 100644 value/builtin_lambda/inheritance.c create mode 100644 value/builtin_lambda/inheritance.h create mode 100644 value/builtin_lambda/new.c create mode 100644 value/builtin_lambda/new.h create mode 100644 value/builtin_lambda/prettyprint.c create mode 100644 value/builtin_lambda/prettyprint.h create mode 100644 value/builtin_lambda/struct.h create mode 100644 value/free.c create mode 100644 value/free.h create mode 100644 value/inc.c create mode 100644 value/inc.h create mode 100644 value/inheritance.h create mode 100644 value/kind.h create mode 100644 value/lambda/free.c create mode 100644 value/lambda/free.h create mode 100644 value/lambda/inheritance.c create mode 100644 value/lambda/inheritance.h create mode 100644 value/lambda/new.c create mode 100644 value/lambda/new.h create mode 100644 value/lambda/prettyprint.c create mode 100644 value/lambda/prettyprint.h create mode 100644 value/lambda/struct.h create mode 100644 value/lazy/free.c create mode 100644 value/lazy/free.h create mode 100644 value/lazy/inheritance.c create mode 100644 value/lazy/inheritance.h create mode 100644 value/lazy/new.c create mode 100644 value/lazy/new.h create mode 100644 value/lazy/prettyprint.c create mode 100644 value/lazy/prettyprint.h create mode 100644 value/lazy/struct.h create mode 100644 value/lazy/unlazy.c create mode 100644 value/lazy/unlazy.h create mode 100644 value/new.c create mode 100644 value/new.h create mode 100644 value/number/free.c create mode 100644 value/number/free.h create mode 100644 value/number/inheritance.c create mode 100644 value/number/inheritance.h create mode 100644 value/number/new.c create mode 100644 value/number/new.h create mode 100644 value/number/prettyprint.c create mode 100644 value/number/prettyprint.h create mode 100644 value/number/struct.h create mode 100644 value/prettyprint.c create mode 100644 value/prettyprint.h create mode 100644 value/struct.h create mode 100644 wcostream/file/free.c create mode 100644 wcostream/file/free.h create mode 100644 wcostream/file/new.c create mode 100644 wcostream/file/new.h create mode 100644 wcostream/file/struct.h create mode 100644 wcostream/file/write.c create mode 100644 wcostream/file/write.h create mode 100644 wcostream/free.c create mode 100644 wcostream/free.h create mode 100644 wcostream/inc.c create mode 100644 wcostream/inc.h create mode 100644 wcostream/inheritance.h create mode 100644 wcostream/new.c create mode 100644 wcostream/new.h create mode 100644 wcostream/ostream/free.c create mode 100644 wcostream/ostream/free.h create mode 100644 wcostream/ostream/inheritance.c create mode 100644 wcostream/ostream/inheritance.h create mode 100644 wcostream/ostream/new.c create mode 100644 wcostream/ostream/new.h create mode 100644 wcostream/ostream/struct.h create mode 100644 wcostream/ostream/write.c create mode 100644 wcostream/ostream/write.h create mode 100644 wcostream/string/free.c create mode 100644 wcostream/string/free.h create mode 100644 wcostream/string/new.c create mode 100644 wcostream/string/new.h create mode 100644 wcostream/string/struct.h create mode 100644 wcostream/string/write.c create mode 100644 wcostream/string/write.h create mode 100644 wcostream/struct.h create mode 100644 wcostream/write.c create mode 100644 wcostream/write.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f761d9f --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ + +bin/ + +.build-all.db + +junk + diff --git a/booleans/free.c b/booleans/free.c new file mode 100644 index 0000000..08607fd --- /dev/null +++ b/booleans/free.c @@ -0,0 +1,27 @@ + +#include + +#include + +#include + +#include "struct.h" +#include "free.h" + +void free_booleans( + struct booleans* this) +{ + ENTER; + + if (this) + { + free_value(this->true_value); + + free_value(this->false_value); + + free(this); + } + + EXIT; +} + diff --git a/booleans/free.h b/booleans/free.h new file mode 100644 index 0000000..d6d9f1c --- /dev/null +++ b/booleans/free.h @@ -0,0 +1,6 @@ + +struct booleans; + +void free_booleans( + struct booleans* this); + diff --git a/booleans/new.c b/booleans/new.c new file mode 100644 index 0000000..f9040d7 --- /dev/null +++ b/booleans/new.c @@ -0,0 +1,82 @@ + +#include + +#include + +#include +#include + +#include + +#include + +#include + +#include + +#include "struct.h" +#include "new.h" + +struct booleans* new_booleans(void) +{ + ENTER; + + struct booleans* this = smalloc(sizeof(*this)); + + struct string* x = new_string(L"x", 1); + + struct string* y = new_string(L"y", 1); + + { + struct expression* body = new_variable_expression(x); + + struct expression* lambda_y = new_lambda_expression(y, body); + + struct value* lambda_xy = new_lambda_value(NULL, x, lambda_y); + + this->true_value = lambda_xy; + + free_expression(lambda_y); + + free_expression(body); + } + + { + struct expression* body = new_variable_expression(y); + + struct expression* lambda_y = new_lambda_expression(y, body); + + struct value* lambda_xy = new_lambda_value(NULL, x, lambda_y); + + this->false_value = lambda_xy; + + free_expression(lambda_y); + + free_expression(body); + } + + free_string(x); + + free_string(y); + + EXIT; + return this; +} + + + + + + + + + + + + + + + + + + diff --git a/booleans/new.h b/booleans/new.h new file mode 100644 index 0000000..90010a1 --- /dev/null +++ b/booleans/new.h @@ -0,0 +1,3 @@ + +struct booleans* new_booleans(void); + diff --git a/booleans/struct.h b/booleans/struct.h new file mode 100644 index 0000000..5dc0f5a --- /dev/null +++ b/booleans/struct.h @@ -0,0 +1,8 @@ + +struct booleans +{ + struct value* true_value; + + struct value* false_value; +}; + diff --git a/build-all.py b/build-all.py new file mode 100755 index 0000000..9193288 --- /dev/null +++ b/build-all.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python3 + +import subprocess; +import time; +import atexit; +import os; +import pickle; + +PICKLEFILE = ".build-all.db" + +try: + with open(PICKLEFILE, "rb") as stream: + ftimes = pickle.load(stream); +except: + ftimes = dict(); + +def dumpftimes(): + with open(PICKLEFILE, "wb") as stream: + pickle.dump(ftimes, stream); + +atexit.register(dumpftimes); + +buildtypes = set(); + +for x in os.listdir("buildtypes"): + buildtype = x[:-4]; + + if buildtype not in ftimes: + ftimes[buildtype] = time.time(); + + buildtypes.add(buildtype); + +for buildtype in sorted(buildtypes, key = lambda x: -ftimes[x]): + print("\033[32m" f"$ make buildtype={buildtype}" "\033[0m"); + + result = subprocess.run(["make", f"buildtype={buildtype}"]); + + if result.returncode: + ftimes[buildtype] = time.time(); + print("subcommand failed!"); + exit(1); + + + + + + + + + + + + + + + + + + diff --git a/buildtypes/debug-valgrind.txt b/buildtypes/debug-valgrind.txt new file mode 100644 index 0000000..86c49cd --- /dev/null +++ b/buildtypes/debug-valgrind.txt @@ -0,0 +1,31 @@ + +-g + +-I . + +-D _GNU_SOURCE + +-D DEBUG_BUILD +-D VALGRIND_BUILD + +-Wall +-Werror +-Wfatal-errors +-Wstrict-prototypes +-Wextra +-Wdouble-promotion +-Wformat=2 +-Wformat-truncation=2 +-Wimplicit-fallthrough +-Wconversion +-Wshadow +-Wcast-align=strict +-Wformat-security +-Wnested-externs +-Wuninitialized +-Wmaybe-uninitialized +-Wswitch-default + +-Wno-comment +-Wno-unused +-Wno-override-init diff --git a/buildtypes/debug.txt b/buildtypes/debug.txt new file mode 100644 index 0000000..6ec9166 --- /dev/null +++ b/buildtypes/debug.txt @@ -0,0 +1,32 @@ + +-g + +-I . + +-D _GNU_SOURCE + +-D DEBUG_BUILD +-D VALGRIND_BUILD + +-Wall +-Werror +-Wfatal-errors +-Wstrict-prototypes +-Wextra +-Wdouble-promotion +-Wformat=2 +-Wformat-truncation=2 +-Wimplicit-fallthrough +-Wconversion +-Wshadow +-Wcast-align=strict +-Wformat-security +-Wnested-externs +-Wuninitialized +-Wmaybe-uninitialized +-Wswitch-default + +-Wno-comment +-Wno-unused +-Wno-override-init + diff --git a/buildtypes/release.txt b/buildtypes/release.txt new file mode 100644 index 0000000..3360c51 --- /dev/null +++ b/buildtypes/release.txt @@ -0,0 +1,30 @@ + +-I . + +-D _GNU_SOURCE + +-D RELEASE_BUILD + +-O3 + +-Wall +-Werror +-Wfatal-errors +-Wstrict-prototypes +-Wextra +-Wdouble-promotion +-Wformat=2 +-Wformat-truncation=2 +-Wimplicit-fallthrough +-Wconversion +-Wshadow +-Wcast-align=strict +-Wformat-security +-Wnested-externs +-Wuninitialized +-Wmaybe-uninitialized +-Wswitch-default + +-Wno-comment +-Wno-override-init +-Wno-unused-parameter diff --git a/buildtypes/test-asan.txt b/buildtypes/test-asan.txt new file mode 100644 index 0000000..59ec0f0 --- /dev/null +++ b/buildtypes/test-asan.txt @@ -0,0 +1,35 @@ + +-g + +-I . + +-D _GNU_SOURCE + +-D TEST_BUILD + +-fsanitize=address + +-static-libasan + +-Wall +-Werror +-Wfatal-errors +-Wstrict-prototypes +-Wextra +-Wdouble-promotion +-Wformat=2 +-Wformat-truncation=2 +-Wimplicit-fallthrough +-Wconversion +-Wshadow +-Wcast-align=strict +-Wformat-security +-Wnested-externs +-Wuninitialized +-Wmaybe-uninitialized +-Wswitch +-Wswitch-default + +-Wno-comment +-Wno-unused +-Wno-override-init diff --git a/buildtypes/test-ubsan.txt b/buildtypes/test-ubsan.txt new file mode 100644 index 0000000..b7266ec --- /dev/null +++ b/buildtypes/test-ubsan.txt @@ -0,0 +1,33 @@ + +-g + +-I . + +-D _GNU_SOURCE + +-D TEST_BUILD + +-fsanitize=undefined + +-Wall +-Werror +-Wfatal-errors +-Wstrict-prototypes +-Wextra +-Wdouble-promotion +-Wformat=2 +-Wformat-truncation=2 +-Wimplicit-fallthrough +-Wconversion +-Wshadow +-Wcast-align=strict +-Wformat-security +-Wnested-externs +-Wuninitialized +-Wmaybe-uninitialized +-Wswitch +-Wswitch-default + +-Wno-comment +-Wno-unused +-Wno-override-init diff --git a/buildtypes/test.txt b/buildtypes/test.txt new file mode 100644 index 0000000..dda3d12 --- /dev/null +++ b/buildtypes/test.txt @@ -0,0 +1,31 @@ + +-g + +-I . + +-D _GNU_SOURCE + +-D TEST_BUILD + +-Wall +-Werror +-Wfatal-errors +-Wstrict-prototypes +-Wextra +-Wdouble-promotion +-Wformat=2 +-Wformat-truncation=2 +-Wimplicit-fallthrough +-Wconversion +-Wshadow +-Wcast-align=strict +-Wformat-security +-Wnested-externs +-Wuninitialized +-Wmaybe-uninitialized +-Wswitch +-Wswitch-default + +-Wno-comment +-Wno-unused +-Wno-override-init diff --git a/builtin/compare/eq.c b/builtin/compare/eq.c new file mode 100644 index 0000000..bb02eec --- /dev/null +++ b/builtin/compare/eq.c @@ -0,0 +1,73 @@ + +#include + +#include + +/*#include */ +/*#include */ + +/*#include */ +/*#include */ + +#include + +#include + +#include + +#include "eq.h" + +struct value* builtin_compare_eq( + struct booleans* booleans, + struct builtin_lambda_value* prev, + struct value* tail) +{ + ENTER; + + struct value* left = lazy_value_unlazy(prev->value, booleans); + + struct value* right = lazy_value_unlazy(tail, booleans); + + dpvp(left); + dpvp(right); + + assert(left); + assert(right); + + TODO; + #if 0 + if (left->kind != vk_number || right->kind != vk_number) + { + TODO; + exit(1); + } + + struct number* sum = number_add( + /* left: */ ((struct number_value*) left)->value, + /* right: */ ((struct number_value*) right)->value); + + struct value* result = new_number_value(sum); + + free_number(sum); + + free_value(left); + + free_value(right); + + EXIT; + return result; + #endif +} + + + + + + + + + + + + + diff --git a/builtin/compare/eq.h b/builtin/compare/eq.h new file mode 100644 index 0000000..170a0c0 --- /dev/null +++ b/builtin/compare/eq.h @@ -0,0 +1,10 @@ + +struct builtin_lambda_value; +struct value; + +struct value* builtin_compare_eq( + struct booleans* booleans, + struct builtin_lambda_value* prev, + struct value* tail); + + diff --git a/builtin/compare/gt.c b/builtin/compare/gt.c new file mode 100644 index 0000000..a3e2e47 --- /dev/null +++ b/builtin/compare/gt.c @@ -0,0 +1,73 @@ + +#include + +#include + +/*#include */ +/*#include */ + +/*#include */ +/*#include */ + +#include + +#include + +#include + +#include "gt.h" + +struct value* builtin_compare_gt( + struct booleans* booleans, + struct builtin_lambda_value* prev, + struct value* tail) +{ + ENTER; + + struct value* left = lazy_value_unlazy(prev->value, booleans); + + struct value* right = lazy_value_unlazy(tail, booleans); + + dpvp(left); + dpvp(right); + + assert(left); + assert(right); + + TODO; + #if 0 + if (left->kind != vk_number || right->kind != vk_number) + { + TODO; + exit(1); + } + + struct number* sum = number_add( + /* left: */ ((struct number_value*) left)->value, + /* right: */ ((struct number_value*) right)->value); + + struct value* result = new_number_value(sum); + + free_number(sum); + + free_value(left); + + free_value(right); + + EXIT; + return result; + #endif +} + + + + + + + + + + + + + diff --git a/builtin/compare/gt.h b/builtin/compare/gt.h new file mode 100644 index 0000000..68f0c90 --- /dev/null +++ b/builtin/compare/gt.h @@ -0,0 +1,8 @@ + +struct builtin_lambda_value; +struct value; + +struct value* builtin_compare_gt( + struct booleans* booleans, + struct builtin_lambda_value* prev, + struct value* tail); diff --git a/builtin/compare/gte.c b/builtin/compare/gte.c new file mode 100644 index 0000000..c09f011 --- /dev/null +++ b/builtin/compare/gte.c @@ -0,0 +1,73 @@ + +#include + +#include + +/*#include */ +/*#include */ + +/*#include */ +/*#include */ + +#include + +#include + +#include + +#include "gte.h" + +struct value* builtin_compare_gte( + struct booleans* booleans, + struct builtin_lambda_value* prev, + struct value* tail) +{ + ENTER; + + struct value* left = lazy_value_unlazy(prev->value, booleans); + + struct value* right = lazy_value_unlazy(tail, booleans); + + dpvp(left); + dpvp(right); + + assert(left); + assert(right); + + TODO; + #if 0 + if (left->kind != vk_number || right->kind != vk_number) + { + TODO; + exit(1); + } + + struct number* sum = number_add( + /* left: */ ((struct number_value*) left)->value, + /* right: */ ((struct number_value*) right)->value); + + struct value* result = new_number_value(sum); + + free_number(sum); + + free_value(left); + + free_value(right); + + EXIT; + return result; + #endif +} + + + + + + + + + + + + + diff --git a/builtin/compare/gte.h b/builtin/compare/gte.h new file mode 100644 index 0000000..8a60aa4 --- /dev/null +++ b/builtin/compare/gte.h @@ -0,0 +1,8 @@ + +struct builtin_lambda_value; +struct value; + +struct value* builtin_compare_gte( + struct booleans* booleans, + struct builtin_lambda_value* prev, + struct value* tail); diff --git a/builtin/compare/lt.c b/builtin/compare/lt.c new file mode 100644 index 0000000..4f56fdb --- /dev/null +++ b/builtin/compare/lt.c @@ -0,0 +1,73 @@ + +#include + +#include + +/*#include */ +/*#include */ + +/*#include */ +/*#include */ + +#include + +#include + +#include + +#include "lt.h" + +struct value* builtin_compare_lt( + struct booleans* booleans, + struct builtin_lambda_value* prev, + struct value* tail) +{ + ENTER; + + struct value* left = lazy_value_unlazy(prev->value, booleans); + + struct value* right = lazy_value_unlazy(tail, booleans); + + dpvp(left); + dpvp(right); + + assert(left); + assert(right); + + TODO; + #if 0 + if (left->kind != vk_number || right->kind != vk_number) + { + TODO; + exit(1); + } + + struct number* sum = number_add( + /* left: */ ((struct number_value*) left)->value, + /* right: */ ((struct number_value*) right)->value); + + struct value* result = new_number_value(sum); + + free_number(sum); + + free_value(left); + + free_value(right); + + EXIT; + return result; + #endif +} + + + + + + + + + + + + + diff --git a/builtin/compare/lt.h b/builtin/compare/lt.h new file mode 100644 index 0000000..7751bd4 --- /dev/null +++ b/builtin/compare/lt.h @@ -0,0 +1,8 @@ + +struct builtin_lambda_value; +struct value; + +struct value* builtin_compare_lt( + struct booleans* booleans, + struct builtin_lambda_value* prev, + struct value* tail); diff --git a/builtin/compare/lte.c b/builtin/compare/lte.c new file mode 100644 index 0000000..87fbb34 --- /dev/null +++ b/builtin/compare/lte.c @@ -0,0 +1,80 @@ + +#include + +#include + +#include + +#include + +#include + +/*#include */ +#include +/*#include */ +/*#include */ + +#include +/*#include */ + +#include + +#include +#include + +#include + +#include "lte.h" + +struct value* builtin_compare_lte( + struct booleans* booleans, + struct builtin_lambda_value* prev, + struct value* tail) +{ + ENTER; + + struct value* left = lazy_value_unlazy(prev->value, booleans); + + struct value* right = lazy_value_unlazy(tail, booleans); + + dpvp(left); + dpvp(right); + + assert(left); + assert(right); + + if (left->kind != vk_number || right->kind != vk_number) + { + TODO; + exit(1); + } + + int cmp = compare_number( + /* left: */ ((struct number_value*) left)->value, + /* right: */ ((struct number_value*) right)->value); + + struct value* result = inc_value( + cmp <= 0 + ? booleans->true_value + : booleans->false_value); + + free_value(left); + + free_value(right); + + EXIT; + return result; +} + + + + + + + + + + + + + diff --git a/builtin/compare/lte.h b/builtin/compare/lte.h new file mode 100644 index 0000000..aacae07 --- /dev/null +++ b/builtin/compare/lte.h @@ -0,0 +1,8 @@ + +struct builtin_lambda_value; +struct value; + +struct value* builtin_compare_lte( + struct booleans* booleans, + struct builtin_lambda_value* prev, + struct value* tail); diff --git a/builtin/compare/neq.c b/builtin/compare/neq.c new file mode 100644 index 0000000..45c5554 --- /dev/null +++ b/builtin/compare/neq.c @@ -0,0 +1,73 @@ + +#include + +#include + +/*#include */ +/*#include */ + +/*#include */ +/*#include */ + +#include + +/*#include */ + +#include + +#include "neq.h" + +struct value* builtin_compare_neq( + struct booleans* booleans, + struct builtin_lambda_value* prev, + struct value* tail) +{ + ENTER; + + struct value* left = lazy_value_unlazy(prev->value, booleans); + + struct value* right = lazy_value_unlazy(tail, booleans); + + dpvp(left); + dpvp(right); + + assert(left); + assert(right); + + TODO; + #if 0 + if (left->kind != vk_number || right->kind != vk_number) + { + TODO; + exit(1); + } + + struct number* sum = number_add( + /* left: */ ((struct number_value*) left)->value, + /* right: */ ((struct number_value*) right)->value); + + struct value* result = new_number_value(sum); + + free_number(sum); + + free_value(left); + + free_value(right); + + EXIT; + return result; + #endif +} + + + + + + + + + + + + + diff --git a/builtin/compare/neq.h b/builtin/compare/neq.h new file mode 100644 index 0000000..2b476ef --- /dev/null +++ b/builtin/compare/neq.h @@ -0,0 +1,8 @@ + +struct builtin_lambda_value; +struct value; + +struct value* builtin_compare_neq( + struct booleans* booleans, + struct builtin_lambda_value* prev, + struct value* tail); diff --git a/builtin/numeric/add.c b/builtin/numeric/add.c new file mode 100644 index 0000000..0410272 --- /dev/null +++ b/builtin/numeric/add.c @@ -0,0 +1,71 @@ + +#include +#include + +#include + +#include +#include + +#include +#include + +#include + +#include + +#include + +#include "add.h" + +struct value* builtin_numeric_add( + struct booleans* booleans, + struct builtin_lambda_value* prev, + struct value* tail) +{ + ENTER; + + struct value* left = lazy_value_unlazy(prev->value, booleans); + + struct value* right = lazy_value_unlazy(tail, booleans); + + dpvp(left); + dpvp(right); + + assert(left); + assert(right); + + if (left->kind != vk_number || right->kind != vk_number) + { + TODO; + exit(1); + } + + struct number* sum = number_add( + /* left: */ ((struct number_value*) left)->value, + /* right: */ ((struct number_value*) right)->value); + + struct value* result = new_number_value(sum); + + free_number(sum); + + free_value(left); + + free_value(right); + + EXIT; + return result; +} + + + + + + + + + + + + + diff --git a/builtin/numeric/add.h b/builtin/numeric/add.h new file mode 100644 index 0000000..ca9f259 --- /dev/null +++ b/builtin/numeric/add.h @@ -0,0 +1,8 @@ + +struct value; +struct builtin_lambda_value; + +struct value* builtin_numeric_add( + struct booleans* booleans, + struct builtin_lambda_value* prev, + struct value* tail); diff --git a/builtin/numeric/divide.c b/builtin/numeric/divide.c new file mode 100644 index 0000000..01a1993 --- /dev/null +++ b/builtin/numeric/divide.c @@ -0,0 +1,15 @@ + +#include + +#include + +#include "divide.h" + +struct value* builtin_numeric_divide( + struct booleans* booleans, + struct builtin_lambda_value* prev, + struct value* tail) +{ + TODO; +} + diff --git a/builtin/numeric/divide.h b/builtin/numeric/divide.h new file mode 100644 index 0000000..d33af9c --- /dev/null +++ b/builtin/numeric/divide.h @@ -0,0 +1,9 @@ + +struct booleans; +struct value; +struct builtin_lambda_value; + +struct value* builtin_numeric_divide( + struct booleans* booleans, + struct builtin_lambda_value* prev, + struct value* tail); diff --git a/builtin/numeric/multiply.c b/builtin/numeric/multiply.c new file mode 100644 index 0000000..7c7ecd4 --- /dev/null +++ b/builtin/numeric/multiply.c @@ -0,0 +1,59 @@ + +#include +#include + +#include + +#include +#include + +#include +#include + +#include + +#include + +#include + +#include "multiply.h" + +struct value* builtin_numeric_multiply( + struct booleans* booleans, + struct builtin_lambda_value* prev, + struct value* tail) +{ + ENTER; + + struct value* left = lazy_value_unlazy(prev->value, booleans); + + struct value* right = lazy_value_unlazy(tail, booleans); + + dpvp(left); + dpvp(right); + + assert(left); + assert(right); + + if (left->kind != vk_number || right->kind != vk_number) + { + TODO; + exit(1); + } + + struct number* sum = number_multiply( + /* left: */ ((struct number_value*) left)->value, + /* right: */ ((struct number_value*) right)->value); + + struct value* result = new_number_value(sum); + + free_number(sum); + + free_value(left); + + free_value(right); + + EXIT; + return result; +} + diff --git a/builtin/numeric/multiply.h b/builtin/numeric/multiply.h new file mode 100644 index 0000000..fa7db13 --- /dev/null +++ b/builtin/numeric/multiply.h @@ -0,0 +1,8 @@ + +struct value; +struct builtin_lambda_value; + +struct value* builtin_numeric_multiply( + struct booleans* booleans, + struct builtin_lambda_value* prev, + struct value* tail); diff --git a/builtin/numeric/subtract.c b/builtin/numeric/subtract.c new file mode 100644 index 0000000..0e140ad --- /dev/null +++ b/builtin/numeric/subtract.c @@ -0,0 +1,59 @@ + +#include +#include + +#include + +#include +#include + +#include +#include + +#include + +#include + +#include + +#include "subtract.h" + +struct value* builtin_numeric_subtract( + struct booleans* booleans, + struct builtin_lambda_value* prev, + struct value* tail) +{ + ENTER; + + struct value* left = lazy_value_unlazy(prev->value, booleans); + + struct value* right = lazy_value_unlazy(tail, booleans); + + dpvp(left); + dpvp(right); + + assert(left); + assert(right); + + if (left->kind != vk_number || right->kind != vk_number) + { + TODO; + exit(1); + } + + struct number* difference = number_subtract( + /* left: */ ((struct number_value*) left)->value, + /* right: */ ((struct number_value*) right)->value); + + struct value* result = new_number_value(difference); + + free_number(difference); + + free_value(left); + + free_value(right); + + EXIT; + return result; +} + diff --git a/builtin/numeric/subtract.h b/builtin/numeric/subtract.h new file mode 100644 index 0000000..f42fe0d --- /dev/null +++ b/builtin/numeric/subtract.h @@ -0,0 +1,8 @@ + +struct value; +struct builtin_lambda_value; + +struct value* builtin_numeric_subtract( + struct booleans* booleans, + struct builtin_lambda_value* prev, + struct value* tail); diff --git a/cmdln/free.c b/cmdln/free.c new file mode 100644 index 0000000..6fa3380 --- /dev/null +++ b/cmdln/free.c @@ -0,0 +1,16 @@ + +#include +#include + +#include "free.h" + +void free_cmdln_flags( + struct cmdln_flags* flags) +{ + ENTER; + + free(flags); + + EXIT; +} + diff --git a/cmdln/free.h b/cmdln/free.h new file mode 100644 index 0000000..6e2d71a --- /dev/null +++ b/cmdln/free.h @@ -0,0 +1,7 @@ + +struct cmdln_flags; + +void free_cmdln_flags( + struct cmdln_flags* flags); + + diff --git a/cmdln/new.c b/cmdln/new.c new file mode 100644 index 0000000..f0d537f --- /dev/null +++ b/cmdln/new.c @@ -0,0 +1,168 @@ + +#include +#include +#include + +#include + +#include + +#include "struct.h" +#include "new.h" + +struct cmdln_flags* new_cmdln_flags( + int argc, char* const* argv) +{ + ENTER; + + bool echo = false; + + bool rainbow = false; + + bool read_init_file = true; + + const char* custom_init_path = "~/.13rc"; + + const char* input_string = NULL; + + enum input_kind input_kind = ik_interactive; + + static const struct option long_options[] = { + {"echo", no_argument, 0, 1}, + + {"echo-rainbow", no_argument, 0, 2}, + + {"no-init", no_argument, 0, 3}, + + {"custom-init-path", required_argument, 0, 4}, + + {"command", required_argument, 0, 'c'}, + + {0, 0, 0, 0} + }; + + for (int c; (c = getopt_long(argc, argv, "" + "\1\2\3\4c:\5\6" + "", long_options, NULL)) >= 0; ) + { + switch (c) + { + case 1: // --echo + { + echo = true; + + break; + } + + case 2: // --echo-rainbow + { + echo = true; + + rainbow = true; + + break; + } + + case 3: // --no-init + { + read_init_file = false; + + break; + } + + case 4: // --custom-init-path + { + custom_init_path = optarg; + + break; + } + + case 'c': // --command + { + switch (input_kind) + { + case ik_interactive: + { + input_kind = ik_string; + + input_string = optarg; + + dpvp(input_string); + + break; + } + + default: + TODO; + break; + } + + break; + } + + default: + TODO; + exit(1); + break; + } + } + + struct cmdln_flags* flags = smalloc(sizeof(*flags)); + + switch (input_kind) + { + case ik_interactive: + { + if (argv[optind]) + { + flags->input_file = argv[optind++]; + + flags->argv = &argv[optind++]; + + input_kind = ik_file; + } + + break; + } + + case ik_string: + { + flags->argv = &argv[optind]; + + break; + } + + default: + TODO; + break; + } + + flags->echo = echo; + + flags->rainbow = rainbow; + + flags->read_init_file = read_init_file; + + flags->custom_init_path = custom_init_path; + + flags->input_kind = input_kind; + + flags->input_string = input_string; + + EXIT; + return flags; +} + + + + + + + + + + + + + + diff --git a/cmdln/new.h b/cmdln/new.h new file mode 100644 index 0000000..6b59708 --- /dev/null +++ b/cmdln/new.h @@ -0,0 +1,7 @@ + + +struct cmdln_flags* new_cmdln_flags( + int argc, char* const* argv); + + + diff --git a/cmdln/struct.h b/cmdln/struct.h new file mode 100644 index 0000000..8104550 --- /dev/null +++ b/cmdln/struct.h @@ -0,0 +1,30 @@ + +#include + +enum input_kind +{ + ik_string, + ik_file, + ik_interactive, +}; + +struct cmdln_flags +{ + bool echo; + + bool rainbow; + + enum input_kind input_kind; + + bool read_init_file; + + const char* custom_init_path; + + const char* input_string; + + const char* input_file; + + char* const* argv; +}; + + diff --git a/color_factory/free.c b/color_factory/free.c new file mode 100644 index 0000000..248e495 --- /dev/null +++ b/color_factory/free.c @@ -0,0 +1,44 @@ + +#include + +#include + +#include + +#include + +#include "struct.h" +#include "free.h" + +void free_color_factory( + struct color_factory* this) +{ + ENTER; + + if (this) + { + for (unsigned i = 0; i < N(this->colors); i++) + { + free_string(this->colors[i]); + } + + free_string(this->numeric); + + free_string(this->string); + + free_string(this->variable); + + free_string(this->builtin); + + free_string(this->reset); + + free(this); + } + + EXIT; +} + + + + + diff --git a/color_factory/free.h b/color_factory/free.h new file mode 100644 index 0000000..7082ac0 --- /dev/null +++ b/color_factory/free.h @@ -0,0 +1,7 @@ + +struct color_factory; + +void free_color_factory( + struct color_factory* this); + + diff --git a/color_factory/new.c b/color_factory/new.c new file mode 100644 index 0000000..3af547d --- /dev/null +++ b/color_factory/new.c @@ -0,0 +1,108 @@ + +#include + +#include + +#include + +#include + +#include + +#include + +#include "struct.h" +#include "new.h" + +struct rgb +{ + uint8_t r, g, b; +}; + +static struct rgb hsv_to_rgb(double hue, double sat, double val) +{ + double c = val * sat; + double x = c * (1 - fabs(fmod(hue / (M_PI / 3), 2) - 1)); + double m = val - c; + + double r, g, b; + + if (hue < 1 * M_PI / 3) r = c, g = x, b = 0; + else if (hue < 2 * M_PI / 3) r = x, g = c, b = 0; + else if (hue < 3 * M_PI / 3) r = 0, g = c, b = x; + else if (hue < 4 * M_PI / 3) r = 0, g = x, b = c; + else if (hue < 5 * M_PI / 3) r = x, g = 0, b = c; + else r = c, g = 0, b = x; + + return (struct rgb) { + (uint8_t) ((r + m) * 255), + (uint8_t) ((g + m) * 255), + (uint8_t) ((b + m) * 255)}; +} + + +static struct string* new_color_from_hue( + double hue, + double sat, + double val) +{ + ENTER; + + dpvlf(hue); + dpvlf(sat); + dpvlf(val); + + struct rgb rgb = hsv_to_rgb(hue, sat, val); + + struct string* string = new_string_from_ascii_format( + "\e[38;2;%hhu;%hhu;%hhum", rgb.r, rgb.g, rgb.b); + + EXIT; + return string; +} + +struct color_factory* new_color_factory(void) +{ + ENTER; + + struct color_factory* this = smalloc(sizeof(*this)); + + for (unsigned i = 0, n = N(this->colors); i < n; i++) + { + this->colors[i] = new_color_from_hue( + /* hue: */ (double) i / N(this->colors) * 2 * M_PI, + /* sat: */ 0.9, + /* val: */ 1.0); + } + + this->numeric = new_color_from_hue(31.0 / 180 * M_PI, 0.80, 1.0); + + this->string = new_color_from_hue(300.0 / 180 * M_PI, 0.80, 1.0); + + this->variable = new_color_from_hue(263.0 / 180 * M_PI, 0.80, 1.0); + + this->builtin = new_color_from_hue(0.0, 0.0, 0.52); + + this->reset = new_string(L"\e[0m", ULONG_MAX); + + EXIT; + return this; +} + + + + + + + + + + + + + + + + + + diff --git a/color_factory/new.h b/color_factory/new.h new file mode 100644 index 0000000..044433b --- /dev/null +++ b/color_factory/new.h @@ -0,0 +1,3 @@ + +struct color_factory* new_color_factory(void); + diff --git a/color_factory/struct.h b/color_factory/struct.h new file mode 100644 index 0000000..461aa65 --- /dev/null +++ b/color_factory/struct.h @@ -0,0 +1,16 @@ + +struct color_factory +{ + struct string* colors[20]; + + struct string* numeric; + + struct string* string; + + struct string* variable; + + struct string* builtin; + + struct string* reset; +}; + diff --git a/debug.c b/debug.c new file mode 100644 index 0000000..148d63d --- /dev/null +++ b/debug.c @@ -0,0 +1,91 @@ + +#include + +int debug_depth; + +void dpvs_implementation( + const char* expression, + char quote, + const unsigned char* string_value, + size_t len) +{ + printf("%*s", debug_depth, ""); + + printf("%s = %c", expression, quote); + + for (const unsigned char* m = string_value; len && *m; m++, len--) + { + switch (*m) + { + case ' ': + case '~': + case '@': + case '$': + case ',': + case '%': + case '^': + case '&': + case '\'': + case '*': + case '#': + case '`': + case ';': + case '.': + case '=': + case '/': + case '+': + case '-': + case '_': + case '!': + case ':': + case '<': case '>': + case '(': case ')': + case '[': case ']': + case '{': case '}': + case '0' ... '9': + case 'a' ... 'z': + case 'A' ... 'Z': + putchar(*m); + break; + + case '\\': + printf("\\\\"); + break; + + case '\"': + printf("\\\""); + break; + + case '\e': + printf("\\e"); + break; + + case '\n': + printf("\\n"); + break; + + default: + printf("\\x%02X", *m); + break; + } + } + + + printf("%c\n", quote); +} + + + + + + + + + + + + + + + + diff --git a/debug.h b/debug.h new file mode 100644 index 0000000..7af367e --- /dev/null +++ b/debug.h @@ -0,0 +1,282 @@ + +#if (defined(DEBUG_BUILD) || defined(TEST_BUILD)) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +struct statement; +struct tokenizer; +struct istream; +struct cmdln_flags; +struct istream_inheritance; +struct token; +struct position; +struct environment; +struct number; +struct mpq; +struct booleans; + +#include +/*#include */ + +/*#include */ + +/*#include */ +/*#include */ + +/*#include */ +/*#include */ +/*#include */ +/*#include */ + +/*#include */ +/*#include */ +/*#include */ + +/*#include */ +/*#include */ + +/*#include */ + +/*#include */ + +#endif + +#ifdef DEBUG_BUILD + +extern int debug_depth; + +#define HERE \ + printf("%*s" "HERE at %s:%i\n", debug_depth, "", __PRETTY_FUNCTION__, __LINE__); + +#define ENTER \ + printf("%*s" "%s\n", debug_depth++, "", __PRETTY_FUNCTION__); + +#define EXIT \ + assert(debug_depth), printf("%*s" "return; // from %s\n", debug_depth--, "", __FUNCTION__); + +#define TODO \ + { \ + printf("TODO hit at %s:%i!\n", __FILE__, __LINE__); \ + \ + pid_t __child = fork(); \ + \ + if (__child < 0) \ + {\ + perror("fork");\ + }\ + else if (__child)\ + {\ + int wstatus = 0;\ + \ + if (waitpid(__child, &wstatus, 0) < 0)\ + perror("waitpid");\ + else if (wstatus)\ + fprintf(stderr, "child failed!");\ + }\ + else\ + {\ + char __buffer[100]; \ + snprintf(__buffer, 100, "+%u", __LINE__); \ + execlp("gedit", "gedit", __FILE__, __buffer, NULL); \ + }\ + \ + exit(1); \ + } + +#define CHECK \ + { \ + printf("CHECK hit at %s:%i!\n", __FILE__, __LINE__); \ + \ + pid_t child = fork(); \ + \ + if (child < 0) \ + {\ + perror("fork");\ + }\ + else if (child)\ + {\ + int wstatus = 0;\ + \ + if (waitpid(child, &wstatus, 0) < 0)\ + perror("waitpid");\ + else if (wstatus)\ + fprintf(stderr, "child failed!");\ + }\ + else\ + {\ + char __buffer[100]; \ + snprintf(__buffer, 100, "+%u", __LINE__); \ + execlp("gedit", "gedit", __FILE__, __buffer, NULL); \ + }\ + \ + exit(1); \ + } + +#define NOPE \ + { \ + printf("NOPE hit at %s:%i!\n", __FILE__, __LINE__); \ + \ + pid_t child = fork(); \ + \ + if (child < 0) \ + {\ + perror("fork");\ + }\ + else if (child)\ + {\ + int wstatus = 0;\ + \ + if (waitpid(child, &wstatus, 0) < 0)\ + perror("waitpid");\ + else if (wstatus)\ + fprintf(stderr, "child failed!");\ + }\ + else\ + {\ + char buffer[100]; \ + snprintf(buffer, 100, "+%u", __LINE__); \ + execlp("gedit", "gedit", __FILE__, buffer, NULL); \ + }\ + \ + exit(1); \ + } + +extern void dpvs_implementation( + const char*, + char quote, + const unsigned char*, + size_t); + +#define dpvs(str) \ + dpvs_implementation(#str, '\"', (const unsigned char*) str, (size_t) -1); + +#define dpvsn(str, len) \ + dpvs_implementation(#str, '\"', (const unsigned char*) str, (size_t) (len)); + +#define dpvss(str) \ + dpvs_implementation(#str, str->data, str->len); + +#define dpvb(b) \ + printf("%*s" "%s = %s\n", debug_depth, "", #b, (b) ? "true" : "false"); + +#define dputs(s) \ + printf("%*s" "%s\n", debug_depth, "", s); + +#define dpvc(c) \ + dpvs_implementation(#c, '\'', (const unsigned char[1]) {(unsigned char) (c)}, (size_t) 1); + +#define dpvwc(c) \ + printf("%*s" "%s = '%lc'\n", debug_depth, "", #c, c); + +#define dpvws(s) \ + printf("%*s" "%s = \"%ls\"\n", debug_depth, "", #s, s); + +#define dpvp(p) \ + printf("%*s" "%s = %p\n", debug_depth, "", #p, p); + +#define dpvf(f) \ + printf("%*s" "%s = %f\n", debug_depth, "", #f, f); + +#define dpvlf(f) \ + printf("%*s" "%s = %lf\n", debug_depth, "", #f, f); + +#define dpvi(x) \ + printf("%*s" "%s = %i\n", debug_depth, "", #x, (x)); + +#define dpvhhu(x) \ + printf("%*s" "%s = %hhu\n", debug_depth, "", #x, (x)); + +#define dpvhhx(x) \ + printf("%*s" "%s = 0x%hhX\n", debug_depth, "", #x, (x)); + +#define dpvu(x) \ + printf("%*s" "%s = %u\n", debug_depth, "", #x, (x)); + +#define dpvlu(x) \ + printf("%*s" "%s = %lu\n", debug_depth, "", #x, (x)); + +#else + +#define ENTER ; + +#define EXIT ; + +#define HERE ; + +#define TODO assert(!"TODO"); + +#define CHECK assert(!"CHECK"); + +#define NOPE assert(!"NOPE"); + +#define dpvp(_) ; + +#define dpvs(_) ; + +#define dpvss(_) ; + +#define dpvsn(str, len) ; + +#define dpvb(_) ; + +#define dputs(_) ; + +#define dpvc(_) ; + +#define dpvi(_) ; + +#define dpvf(_) ; + +#define dpvlf(_) ; + +#define dpvhhu(_) ; + +#define dpvhhx(_) ; + +#define dpvws(_) ; + +#define dpvwc(_) ; + +#define dpvlu(_) ; + +#define dpvu(_) ; + +#endif + + + + + + + + + + + + + + + + + diff --git a/defines/N.h b/defines/N.h new file mode 100644 index 0000000..5bea10b --- /dev/null +++ b/defines/N.h @@ -0,0 +1,5 @@ + +#define N(a) \ + (sizeof(a) / sizeof(*a)) + + diff --git a/defines/argv0.h b/defines/argv0.h new file mode 100644 index 0000000..5cad7a4 --- /dev/null +++ b/defines/argv0.h @@ -0,0 +1,4 @@ + +#define argv0 \ + (program_invocation_name) + diff --git a/dep-snipe.sh b/dep-snipe.sh new file mode 100755 index 0000000..3bb08fb --- /dev/null +++ b/dep-snipe.sh @@ -0,0 +1,2 @@ +#!/bin/sh +find bin -name '*.d' | xargs grep -F "${1}" -l | xargs rm -vf diff --git a/environment/declare.c b/environment/declare.c new file mode 100644 index 0000000..11abe02 --- /dev/null +++ b/environment/declare.c @@ -0,0 +1,31 @@ + +#include + +#include + +#include + +#include "variable/new.h" + +#include "struct.h" +#include "declare.h" + +void environment_declare( + struct environment* this, + struct string* name, + struct value* value) +{ + ENTER; + + struct variable* variable = new_variable(name, value); + + void* node = avl_insert(this->tree, variable); + + if (!node) + { + TODO; + } + + EXIT; +} + diff --git a/environment/declare.h b/environment/declare.h new file mode 100644 index 0000000..5e132dd --- /dev/null +++ b/environment/declare.h @@ -0,0 +1,11 @@ + +struct environment; +struct string; +struct value; + +void environment_declare( + struct environment* this, + struct string* name, + struct value* value); + + diff --git a/environment/declare_builtins.c b/environment/declare_builtins.c new file mode 100644 index 0000000..76c0ab7 --- /dev/null +++ b/environment/declare_builtins.c @@ -0,0 +1,98 @@ + +#include + +#include + +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "struct.h" +#include "declare.h" +#include "declare_builtins.h" + +void environment_declare_builtins( + struct environment* this, + struct booleans* booleans) +{ + ENTER; + + #define DECLARE_BOOLEAN(name, value) \ + { \ + struct string* string = new_string(name, UINT_MAX); \ + \ + environment_declare(this, string, value); \ + \ + free_string(string); \ + } + + DECLARE_BOOLEAN(L"true", booleans->true_value); + DECLARE_BOOLEAN(L"false", booleans->false_value); + + #define DECLARE_BUILTIN(name, funcptr, num_of_param) \ + { \ + struct string* string = new_string(name, UINT_MAX); \ + \ + struct value* value = new_builtin_lambda_value( \ + /* name: */ string, \ + /* function pointer: */ funcptr, \ + /* number of parameters: */ num_of_param, \ + /* value: */ NULL, \ + /* prev: */ NULL); \ + \ + environment_declare(this, string, value); \ + \ + free_value(value); \ + \ + free_string(string); \ + } + + DECLARE_BUILTIN(L"+", builtin_numeric_add, 2); + DECLARE_BUILTIN(L"-", builtin_numeric_subtract, 2); + DECLARE_BUILTIN(L"−", builtin_numeric_subtract, 2); + DECLARE_BUILTIN(L"×", builtin_numeric_multiply, 2); + DECLARE_BUILTIN(L"÷", builtin_numeric_divide, 2); + + DECLARE_BUILTIN(L"=", builtin_compare_eq, 2); + DECLARE_BUILTIN(L"≥", builtin_compare_gte, 2); + DECLARE_BUILTIN(L"≤", builtin_compare_lte, 2); + DECLARE_BUILTIN(L">", builtin_compare_gt, 2); + DECLARE_BUILTIN(L"<", builtin_compare_lt, 2); + DECLARE_BUILTIN(L"≠", builtin_compare_neq, 2); + + // declare = + // declare ≥ + // declare ≤ + // declare ≮ + // declare ≯ + // declare ≰ + // declare ≱ + // declare ≠ + + EXIT; +} + + + + + + + + + diff --git a/environment/declare_builtins.h b/environment/declare_builtins.h new file mode 100644 index 0000000..0a2ee95 --- /dev/null +++ b/environment/declare_builtins.h @@ -0,0 +1,9 @@ + +struct environment; +struct booleans; + +void environment_declare_builtins( + struct environment* this, + struct booleans* booleans); + + diff --git a/environment/free.c b/environment/free.c new file mode 100644 index 0000000..b32f9d6 --- /dev/null +++ b/environment/free.c @@ -0,0 +1,27 @@ + +#include + +#include + +#include + +#include "struct.h" +#include "free.h" + +void free_environment( + struct environment* this) +{ + ENTER; + + if (this && !--this->refcount) + { + free_environment(this->fallback); + + avl_free_tree(this->tree); + + free(this); + } + + EXIT; +} + diff --git a/environment/free.h b/environment/free.h new file mode 100644 index 0000000..1170c64 --- /dev/null +++ b/environment/free.h @@ -0,0 +1,7 @@ + +struct environment; + +void free_environment( + struct environment* this); + + diff --git a/environment/inc.c b/environment/inc.c new file mode 100644 index 0000000..f315fe9 --- /dev/null +++ b/environment/inc.c @@ -0,0 +1,15 @@ + +#include + +#include "struct.h" +#include "inc.h" + +struct environment* inc_environment( + struct environment* this) +{ + if (this) + this->refcount++; + + return this; +} + diff --git a/environment/inc.h b/environment/inc.h new file mode 100644 index 0000000..3e73e64 --- /dev/null +++ b/environment/inc.h @@ -0,0 +1,5 @@ + +struct environment* inc_environment( + struct environment* this); + + diff --git a/environment/lookup.c b/environment/lookup.c new file mode 100644 index 0000000..72ed2ac --- /dev/null +++ b/environment/lookup.c @@ -0,0 +1,53 @@ + +#include + +#include + +#include + +#include + +#include + +#include + +#include "variable/struct.h" + +#include "struct.h" +#include "lookup.h" + +struct value* environment_lookup( + struct environment* this, + struct string* name) +{ + ENTER; + + struct value* result = NULL; + + for (struct environment* moving = this; + !result && moving; + moving = moving->fallback) + { + struct avl_node_t* node = avl_search(moving->tree, &name); + + if (node) + { + struct variable* variable = node->item; + + result = inc_value(variable->value); + } + } + + if (!result) + { + dpvu(*name->data); + + TODO; + + exit(1); + } + + EXIT; + return result; +} + diff --git a/environment/lookup.h b/environment/lookup.h new file mode 100644 index 0000000..a018341 --- /dev/null +++ b/environment/lookup.h @@ -0,0 +1,8 @@ + +struct environment; +struct string; + +struct value* environment_lookup( + struct environment* this, + struct string* name); + diff --git a/environment/new.c b/environment/new.c new file mode 100644 index 0000000..9e48e90 --- /dev/null +++ b/environment/new.c @@ -0,0 +1,33 @@ + +#include + +#include + +#include + +#include "variable/compare.h" +#include "variable/free.h" + +#include "inc.h" +#include "struct.h" +#include "new.h" + +struct environment* new_environment( + struct environment* fallback) +{ + ENTER; + + struct environment* this = smalloc(sizeof(*this)); + + this->fallback = inc_environment(fallback); + + this->tree = avl_alloc_tree( + compare_variables, + free_variable); + + this->refcount = 1; + + EXIT; + return this; +} + diff --git a/environment/new.h b/environment/new.h new file mode 100644 index 0000000..c5f3bc8 --- /dev/null +++ b/environment/new.h @@ -0,0 +1,5 @@ + +struct environment* new_environment( + struct environment* fallback); + + diff --git a/environment/struct.h b/environment/struct.h new file mode 100644 index 0000000..e77e130 --- /dev/null +++ b/environment/struct.h @@ -0,0 +1,11 @@ + +struct environment +{ + struct environment* fallback; + + struct avl_tree_t* tree; + + unsigned refcount; +}; + + diff --git a/environment/variable/compare.c b/environment/variable/compare.c new file mode 100644 index 0000000..0234e2e --- /dev/null +++ b/environment/variable/compare.c @@ -0,0 +1,18 @@ + +#include + +#include + +#include "struct.h" +#include "compare.h" + +int compare_variables( + const void* a, + const void* b) +{ + const struct variable *A = a, *B = b; + + return compare_strings(A->name, B->name); +} + +// wcscmp(A->name->data, B->name->data); diff --git a/environment/variable/compare.h b/environment/variable/compare.h new file mode 100644 index 0000000..e611fd1 --- /dev/null +++ b/environment/variable/compare.h @@ -0,0 +1,6 @@ + +int compare_variables( + const void* a, + const void* b); + + diff --git a/environment/variable/free.c b/environment/variable/free.c new file mode 100644 index 0000000..5c5f270 --- /dev/null +++ b/environment/variable/free.c @@ -0,0 +1,25 @@ + +#include + +#include + +#include + +#include + +#include "struct.h" +#include "free.h" + +void free_variable( + void* ptr) +{ + struct variable* this = ptr; + + free_string(this->name); + + free_value(this->value); + + free(this); +} + + diff --git a/environment/variable/free.h b/environment/variable/free.h new file mode 100644 index 0000000..5d4a0d1 --- /dev/null +++ b/environment/variable/free.h @@ -0,0 +1,5 @@ + +void free_variable( + void* ptr); + + diff --git a/environment/variable/new.c b/environment/variable/new.c new file mode 100644 index 0000000..782bc10 --- /dev/null +++ b/environment/variable/new.c @@ -0,0 +1,29 @@ + +#include + +#include + +#include + +#include + +#include "struct.h" +#include "new.h" + +struct variable* new_variable( + struct string* name, + struct value* value) +{ + ENTER; + + struct variable* this = smalloc(sizeof(*this)); + + this->name = inc_string(name); + + this->value = inc_value(value); + + EXIT; + return this; +} + + diff --git a/environment/variable/new.h b/environment/variable/new.h new file mode 100644 index 0000000..35ad478 --- /dev/null +++ b/environment/variable/new.h @@ -0,0 +1,9 @@ + +struct string; +struct value; + +struct variable* new_variable( + struct string* name, + struct value* value); + + diff --git a/environment/variable/struct.h b/environment/variable/struct.h new file mode 100644 index 0000000..8a4872c --- /dev/null +++ b/environment/variable/struct.h @@ -0,0 +1,12 @@ + +struct string; + +struct value; + +struct variable +{ + struct string* name; + + struct value* value; +}; + diff --git a/examples/init.txt b/examples/init.txt new file mode 100644 index 0000000..70e06a9 --- /dev/null +++ b/examples/init.txt @@ -0,0 +1,11 @@ + +# these are built in to the language +# true <- λ x, y: x +# false <- λ x, y: y + +𝐼 <- λ x: x + +𝑌 <- λ f: (λ x: f (x x)) (λ x: f (x x)) + + + diff --git a/examples/sandbox.txt b/examples/sandbox.txt new file mode 100644 index 0000000..7c9d60f --- /dev/null +++ b/examples/sandbox.txt @@ -0,0 +1,63 @@ + +# comments + +0 +1 +3.14159 + +# booleans are lambdas or values? + # well, if they're lambdas, then they're read by the init file? + # if they're user-defined, then what should comparisions return? + # maybe they just return what 'true' or 'false' would return in the \ + given envronment? + # also keep in mind that if they're values, we'll need a builtin \ + conditional switch function in addition to them. + # it's probably best if they're builtin lambdas, like '+' or '×'. +true +false + +# an expression doesn't end until it could validly end: +λ + x: + x + # ends before the 2 + 2 + +(λ x: x)(2) + +f <- λ x: x; f 2 + +# numerical operators exist and can curry ...somehow: ++ +- +× +÷ + ++ 1 +× 2 + ++ 1 1 +× 2 2 + +× (+ 1 2) 3 + +fib <- 𝑌 λ f x: (≤ x 1) x (+ (f (- x 1)) (f (- x 2))) + +fib 8 + +(𝑌 λ f x: (≤ x 1) x (+ (f (- x 1)) (f (- x 2)))) 10 + + + + + + + + + + + + + + + diff --git a/expression/application/evaluate.c b/expression/application/evaluate.c new file mode 100644 index 0000000..48ea8c7 --- /dev/null +++ b/expression/application/evaluate.c @@ -0,0 +1,117 @@ + +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "../evaluate.h" + +#include "struct.h" +#include "evaluate.h" + +struct value* application_expression_evaluate( + struct expression* super, + struct environment* outer_environment, + struct booleans* booleans) +{ + ENTER; + + struct value* result; + + struct application_expression* this = (void*) super; + + struct value* left = expression_evaluate(this->left, outer_environment, booleans); + + struct value* lleft = lazy_value_unlazy(left, booleans); + + struct value* right = new_lazy_value( + /* capture environment: */ outer_environment, + /* expression: */ this->right); + + switch (lleft->kind) + { + case vk_lambda: + { + struct lambda_value* lambda = (void*) lleft; + + struct environment* environment = new_environment(lambda->environment); + + environment_declare(environment, lambda->variable_name, right); + + result = expression_evaluate(lambda->body, environment, booleans); + + free_environment(environment); + + break; + } + + case vk_builtin_lambda: + { + struct builtin_lambda_value* lambda = (void*) lleft; + + assert(lambda->number_of_parameters > 0); + + if (lambda->number_of_parameters == 1) + { + result = (lambda->funcptr)(booleans, lambda, right); + } + else + { + result = new_builtin_lambda_value( + /* name: */ lambda->name, + /* funcptr: */ lambda->funcptr, + /* number_of_parameters: */ lambda->number_of_parameters - 1, + /* value: */ right, + /* prev: */ lambda); + } + + break; + } + + case vk_lazy: + { + TODO; + break; + } + + default: + { + dpvu(lleft->kind); + + TODO; + exit(1); + break; + } + } + + free_value(left); + + free_value(lleft); + + free_value(right); + + EXIT; + return result; +} + + + + + + + + + + diff --git a/expression/application/evaluate.h b/expression/application/evaluate.h new file mode 100644 index 0000000..e34f5e4 --- /dev/null +++ b/expression/application/evaluate.h @@ -0,0 +1,7 @@ + +struct value* application_expression_evaluate( + struct expression* this, + struct environment* environment, + struct booleans* booleans); + + diff --git a/expression/application/free.c b/expression/application/free.c new file mode 100644 index 0000000..53bf46c --- /dev/null +++ b/expression/application/free.c @@ -0,0 +1,23 @@ + +#include + +#include + +#include "../free.h" + +#include "struct.h" +#include "free.h" + +void free_application_expression( + struct expression* super) +{ + ENTER; + + struct application_expression* this = (void*) super; + + free_expression(this->left); + + free_expression(this->right); + + EXIT; +} diff --git a/expression/application/free.h b/expression/application/free.h new file mode 100644 index 0000000..2db3c2f --- /dev/null +++ b/expression/application/free.h @@ -0,0 +1,6 @@ + +struct expression; + +void free_application_expression( + struct expression* super); + diff --git a/expression/application/inheritance.c b/expression/application/inheritance.c new file mode 100644 index 0000000..d7feaf5 --- /dev/null +++ b/expression/application/inheritance.c @@ -0,0 +1,20 @@ + +#include + +#include "../inheritance.h" + +#include "prettyprint_errors.h" +#include "prettyprint.h" +#include "evaluate.h" +#include "free.h" +#include "inheritance.h" + +struct expression_inheritance application_expression_inheritance = { + .prettyprint_errors = application_expression_prettyprint_errors, + + .prettyprint = application_expression_prettyprint, + + .evaluate = application_expression_evaluate, + + .free = free_application_expression +}; diff --git a/expression/application/inheritance.h b/expression/application/inheritance.h new file mode 100644 index 0000000..99be99e --- /dev/null +++ b/expression/application/inheritance.h @@ -0,0 +1,2 @@ + +extern struct expression_inheritance application_expression_inheritance; diff --git a/expression/application/new.c b/expression/application/new.c new file mode 100644 index 0000000..e31c1f4 --- /dev/null +++ b/expression/application/new.c @@ -0,0 +1,29 @@ + +#include + +#include + +#include "../new.h" + +#include "inheritance.h" +#include "struct.h" +#include "new.h" + +struct expression* new_application_expression( + struct expression* left, + struct expression* right) +{ + ENTER; + + struct application_expression* this = (void*) new_expression( + /* inheritance: */ &application_expression_inheritance, + /* alloc size: */ sizeof(*this)); + + this->left = inc_expression(left); + + this->right = inc_expression(right); + + EXIT; + return (void*) this; +} + diff --git a/expression/application/new.h b/expression/application/new.h new file mode 100644 index 0000000..2e01ff8 --- /dev/null +++ b/expression/application/new.h @@ -0,0 +1,6 @@ + +struct expression; + +struct expression* new_application_expression( + struct expression* left, + struct expression* right); diff --git a/expression/application/prettyprint.c b/expression/application/prettyprint.c new file mode 100644 index 0000000..694dd39 --- /dev/null +++ b/expression/application/prettyprint.c @@ -0,0 +1,72 @@ + +#include + +#include + +/*#include */ + +#include +#include +#include +#include + +#include + +#include "struct.h" +#include "prettyprint.h" + +struct stringtree* application_expression_prettyprint( + int *out_chosen_color, + struct expression* super, + struct color_factory* cfactory, + bool with_color) +{ + ENTER; + + struct application_expression* const this = (void*) super; + + int left_color, right_color; + + struct stringtree* left = expression_prettyprint( + &left_color, + this->left, + cfactory, + with_color); + + struct stringtree* right = expression_prettyprint( + &right_color, + this->right, + cfactory, + with_color); + + if (with_color && out_chosen_color) + { + *out_chosen_color = MAX(left_color, right_color); + } + + struct stringtree* tree = new_stringtree(); + + stringtree_append_stringtree(tree, left); + stringtree_append_cstr(tree, L" "); + stringtree_append_stringtree(tree, right); + + free_stringtree(left); + + free_stringtree(right); + + EXIT; + return tree; +} + + + + + + + + + + + + + diff --git a/expression/application/prettyprint.h b/expression/application/prettyprint.h new file mode 100644 index 0000000..399f4d1 --- /dev/null +++ b/expression/application/prettyprint.h @@ -0,0 +1,15 @@ + +#include + +struct expression; + +struct color_factory; + +struct stringtree* application_expression_prettyprint( + int *out_chosen_color, + struct expression* this, + struct color_factory* cfactory, + bool with_color); + + + diff --git a/expression/application/prettyprint_errors.c b/expression/application/prettyprint_errors.c new file mode 100644 index 0000000..c95dee9 --- /dev/null +++ b/expression/application/prettyprint_errors.c @@ -0,0 +1,34 @@ + +#include + +#include + +#include + +#include "../prettyprint_errors.h" + +#include "struct.h" +#include "prettyprint_errors.h" + +struct stringtree* application_expression_prettyprint_errors( + struct expression* super) +{ + ENTER; + + struct application_expression* const this = (void*) super; + + struct stringtree* tree = expression_prettyprint_errors(this->left); + + if (tree) + { + TODO; + } + else + { + tree = expression_prettyprint_errors(this->right); + } + + EXIT; + return NULL; +} + diff --git a/expression/application/prettyprint_errors.h b/expression/application/prettyprint_errors.h new file mode 100644 index 0000000..0ddc472 --- /dev/null +++ b/expression/application/prettyprint_errors.h @@ -0,0 +1,4 @@ + +struct stringtree* application_expression_prettyprint_errors( + struct expression* super); + diff --git a/expression/application/struct.h b/expression/application/struct.h new file mode 100644 index 0000000..489841b --- /dev/null +++ b/expression/application/struct.h @@ -0,0 +1,10 @@ + +#include "../struct.h" + +struct application_expression +{ + struct expression super; + + struct expression *left, *right; +}; + diff --git a/expression/evaluate.c b/expression/evaluate.c new file mode 100644 index 0000000..a0860d2 --- /dev/null +++ b/expression/evaluate.c @@ -0,0 +1,25 @@ + +#include +#include + +#include "struct.h" +#include "inheritance.h" +#include "evaluate.h" + +struct value* expression_evaluate( + struct expression* this, + struct environment* environment, + struct booleans* booleans) +{ + ENTER; + + assert(this); + assert(this->inheritance); + assert(this->inheritance->evaluate); + + struct value* value = (this->inheritance->evaluate)( + this, environment, booleans); + + EXIT; + return value; +} diff --git a/expression/evaluate.h b/expression/evaluate.h new file mode 100644 index 0000000..0c9eee1 --- /dev/null +++ b/expression/evaluate.h @@ -0,0 +1,11 @@ + +struct expression; +struct environment; +struct booleans; + +struct value* expression_evaluate( + struct expression*, + struct environment*, + struct booleans* booleans); + + diff --git a/expression/free.c b/expression/free.c new file mode 100644 index 0000000..96b521d --- /dev/null +++ b/expression/free.c @@ -0,0 +1,29 @@ + +#include +#include + +#include + +#include "inheritance.h" +#include "struct.h" +#include "free.h" + +void free_expression( + struct expression* this) +{ + ENTER; + + if (this && !--this->refcount) + { + assert(this); + assert(this->inheritance); + assert(this->inheritance->free); + + (this->inheritance->free)(this); + + free(this); + } + + EXIT; +} + diff --git a/expression/free.h b/expression/free.h new file mode 100644 index 0000000..eb024e9 --- /dev/null +++ b/expression/free.h @@ -0,0 +1,6 @@ + +struct expression; + +void free_expression( + struct expression* this); + diff --git a/expression/inc.c b/expression/inc.c new file mode 100644 index 0000000..5486e78 --- /dev/null +++ b/expression/inc.c @@ -0,0 +1,15 @@ + +#include + +#include "struct.h" +#include "inc.h" + +struct expression* inc_expression( + struct expression* this) +{ + if (this) + this->refcount++; + + return this; +} + diff --git a/expression/inc.h b/expression/inc.h new file mode 100644 index 0000000..666f7ec --- /dev/null +++ b/expression/inc.h @@ -0,0 +1,4 @@ + +struct expression* inc_expression( + struct expression* this); + diff --git a/expression/inheritance.h b/expression/inheritance.h new file mode 100644 index 0000000..7601c9b --- /dev/null +++ b/expression/inheritance.h @@ -0,0 +1,28 @@ + +#include + +struct booleans; +struct color_factory; +struct expression; +struct environment; + +struct expression_inheritance +{ + struct stringtree* (*prettyprint)( + int *out_chosen_color, + struct expression* this, + struct color_factory* cfactory, + bool with_color); + + struct stringtree* (*prettyprint_errors)( + struct expression* this); + + struct value* (*evaluate)( + struct expression*, + struct environment*, + struct booleans* booleans); + + void (*free)( + struct expression*); +}; + diff --git a/expression/lambda/evaluate.c b/expression/lambda/evaluate.c new file mode 100644 index 0000000..942e35d --- /dev/null +++ b/expression/lambda/evaluate.c @@ -0,0 +1,25 @@ + +#include + +#include + +#include "struct.h" +#include "evaluate.h" + +struct value* lambda_expression_evaluate( + struct expression* super, + struct environment* environment, + struct booleans* booleans) +{ + ENTER; + + struct lambda_expression* this = (void*) super; + + struct value* result = new_lambda_value( + /* captured environment: */ environment, + /* variable name: */ this->variable_name, + /* body: */ this->body); + + EXIT; + return result; +} diff --git a/expression/lambda/evaluate.h b/expression/lambda/evaluate.h new file mode 100644 index 0000000..6d0b9a9 --- /dev/null +++ b/expression/lambda/evaluate.h @@ -0,0 +1,11 @@ + +struct expression; +struct environment; +struct booleans; + +struct value* lambda_expression_evaluate( + struct expression* this, + struct environment* environment, + struct booleans* booleans); + + diff --git a/expression/lambda/free.c b/expression/lambda/free.c new file mode 100644 index 0000000..ffebf26 --- /dev/null +++ b/expression/lambda/free.c @@ -0,0 +1,23 @@ + +#include + +#include + +#include + +#include "struct.h" +#include "free.h" + +void free_lambda_expression( + struct expression* super) +{ + ENTER; + + struct lambda_expression* this = (void*) super; + + free_string(this->variable_name); + + free_expression(this->body); + + EXIT; +} diff --git a/expression/lambda/free.h b/expression/lambda/free.h new file mode 100644 index 0000000..230bde9 --- /dev/null +++ b/expression/lambda/free.h @@ -0,0 +1,6 @@ + +struct expression; + +void free_lambda_expression( + struct expression* super); + diff --git a/expression/lambda/inheritance.c b/expression/lambda/inheritance.c new file mode 100644 index 0000000..057d67f --- /dev/null +++ b/expression/lambda/inheritance.c @@ -0,0 +1,20 @@ + +#include + +#include "../inheritance.h" + +#include "prettyprint_errors.h" +#include "prettyprint.h" +#include "evaluate.h" +#include "free.h" +#include "inheritance.h" + +struct expression_inheritance lambda_expression_inheritance = { + .prettyprint_errors = lambda_expression_prettyprint_errors, + + .prettyprint = lambda_expression_prettyprint, + + .evaluate = lambda_expression_evaluate, + + .free = free_lambda_expression +}; diff --git a/expression/lambda/inheritance.h b/expression/lambda/inheritance.h new file mode 100644 index 0000000..729466f --- /dev/null +++ b/expression/lambda/inheritance.h @@ -0,0 +1,2 @@ + +extern struct expression_inheritance lambda_expression_inheritance; diff --git a/expression/lambda/new.c b/expression/lambda/new.c new file mode 100644 index 0000000..64da596 --- /dev/null +++ b/expression/lambda/new.c @@ -0,0 +1,34 @@ + +#include + +/*#include */ + +/*#include */ + +#include + +#include "../new.h" +#include "../inc.h" + +#include "inheritance.h" +#include "struct.h" +#include "new.h" + +struct expression* new_lambda_expression( + struct string *variable_name, + struct expression* body) +{ + ENTER; + + struct lambda_expression* this = (void*) new_expression( + /* inheritance: */ &lambda_expression_inheritance, + /* alloc size: */ sizeof(*this)); + + this->variable_name = inc_string(variable_name); + + this->body = inc_expression(body); + + EXIT; + return (void*) this; +} + diff --git a/expression/lambda/new.h b/expression/lambda/new.h new file mode 100644 index 0000000..73cb582 --- /dev/null +++ b/expression/lambda/new.h @@ -0,0 +1,8 @@ + +struct value; +struct string; + +struct expression* new_lambda_expression( + struct string *parameter_name, + struct expression* body); + diff --git a/expression/lambda/prettyprint.c b/expression/lambda/prettyprint.c new file mode 100644 index 0000000..e4ea54c --- /dev/null +++ b/expression/lambda/prettyprint.c @@ -0,0 +1,75 @@ + +#include + +#include + +#include + +#include +#include +#include +#include + +#include "../prettyprint.h" + +#include "struct.h" +#include "prettyprint.h" + +struct stringtree* lambda_expression_prettyprint( + int *out_chosen_color, + struct expression* super, + struct color_factory* cfactory, + bool with_color) +{ + ENTER; + + struct lambda_expression* const this = (void*) super; + + int chosen_color; + + struct stringtree* tree = new_stringtree(); + + stringtree_append_cstr(tree, L"λ"); + + stringtree_append_string(tree, this->variable_name); + + stringtree_append_cstr(tree, L": "); + + struct stringtree* subtree = expression_prettyprint( + &chosen_color, + this->body, + cfactory, + with_color); + + if (with_color) + { + int my_color = (chosen_color + 1) % (int) N(cfactory->colors); + + stringtree_prepend_string(tree, cfactory->colors[my_color]); + + stringtree_append_string(tree, cfactory->reset); + + if (out_chosen_color) + *out_chosen_color = my_color; + } + + stringtree_append_stringtree(tree, subtree); + + free_stringtree(subtree); + + EXIT; + return tree; +} + + + + + + + + + + + + + diff --git a/expression/lambda/prettyprint.h b/expression/lambda/prettyprint.h new file mode 100644 index 0000000..4c12a73 --- /dev/null +++ b/expression/lambda/prettyprint.h @@ -0,0 +1,15 @@ + +#include + +struct expression; + +struct color_factory; + +struct stringtree* lambda_expression_prettyprint( + int *out_chosen_color, + struct expression* this, + struct color_factory* cfactory, + bool with_color); + + + diff --git a/expression/lambda/prettyprint_errors.c b/expression/lambda/prettyprint_errors.c new file mode 100644 index 0000000..15847c8 --- /dev/null +++ b/expression/lambda/prettyprint_errors.c @@ -0,0 +1,21 @@ + +#include + +#include "../prettyprint_errors.h" + +#include "struct.h" +#include "prettyprint_errors.h" + +struct stringtree* lambda_expression_prettyprint_errors( + struct expression* super) +{ + ENTER; + + struct lambda_expression* const this = (void*) super; + + struct stringtree* tree = expression_prettyprint_errors(this->body); + + EXIT; + return tree; +} + diff --git a/expression/lambda/prettyprint_errors.h b/expression/lambda/prettyprint_errors.h new file mode 100644 index 0000000..1ca8e1e --- /dev/null +++ b/expression/lambda/prettyprint_errors.h @@ -0,0 +1,4 @@ + +struct stringtree* lambda_expression_prettyprint_errors( + struct expression* super); + diff --git a/expression/lambda/struct.h b/expression/lambda/struct.h new file mode 100644 index 0000000..94008cd --- /dev/null +++ b/expression/lambda/struct.h @@ -0,0 +1,12 @@ + +#include "../struct.h" + +struct lambda_expression +{ + struct expression super; + + struct string *variable_name; + + struct expression* body; +}; + diff --git a/expression/literal/evaluate.c b/expression/literal/evaluate.c new file mode 100644 index 0000000..721238f --- /dev/null +++ b/expression/literal/evaluate.c @@ -0,0 +1,22 @@ + +#include + +#include + +#include "struct.h" +#include "evaluate.h" + +struct value* literal_expression_evaluate( + struct expression* super, + struct environment* environment, + struct booleans* booleans) +{ + ENTER; + + struct literal_expression* this = (void*) super; + + struct value* result = inc_value(this->value); + + EXIT; + return result; +} diff --git a/expression/literal/evaluate.h b/expression/literal/evaluate.h new file mode 100644 index 0000000..2319b9e --- /dev/null +++ b/expression/literal/evaluate.h @@ -0,0 +1,11 @@ + +struct expression; +struct environment; +struct booleans; + +struct value* literal_expression_evaluate( + struct expression* this, + struct environment* environment, + struct booleans* booleans); + + diff --git a/expression/literal/free.c b/expression/literal/free.c new file mode 100644 index 0000000..15528a5 --- /dev/null +++ b/expression/literal/free.c @@ -0,0 +1,19 @@ + +#include + +#include + +#include "struct.h" +#include "free.h" + +void free_literal_expression( + struct expression* super) +{ + ENTER; + + struct literal_expression* this = (void*) super; + + free_value(this->value); + + EXIT; +} diff --git a/expression/literal/free.h b/expression/literal/free.h new file mode 100644 index 0000000..ca967cb --- /dev/null +++ b/expression/literal/free.h @@ -0,0 +1,6 @@ + +struct expression; + +void free_literal_expression( + struct expression* super); + diff --git a/expression/literal/inheritance.c b/expression/literal/inheritance.c new file mode 100644 index 0000000..87ca6dc --- /dev/null +++ b/expression/literal/inheritance.c @@ -0,0 +1,20 @@ + +#include + +#include "../inheritance.h" + +#include "prettyprint_errors.h" +#include "prettyprint.h" +#include "evaluate.h" +#include "free.h" +#include "inheritance.h" + +struct expression_inheritance literal_expression_inheritance = { + .prettyprint_errors = literal_expression_prettyprint_errors, + + .prettyprint = literal_expression_prettyprint, + + .evaluate = literal_expression_evaluate, + + .free = free_literal_expression +}; diff --git a/expression/literal/inheritance.h b/expression/literal/inheritance.h new file mode 100644 index 0000000..8b0b5fb --- /dev/null +++ b/expression/literal/inheritance.h @@ -0,0 +1,2 @@ + +extern struct expression_inheritance literal_expression_inheritance; diff --git a/expression/literal/new.c b/expression/literal/new.c new file mode 100644 index 0000000..60a3931 --- /dev/null +++ b/expression/literal/new.c @@ -0,0 +1,30 @@ + +#include + +/*#include */ + +/*#include */ + +#include + +#include "../new.h" + +#include "inheritance.h" +#include "struct.h" +#include "new.h" + +struct expression* new_literal_expression( + struct value* value) +{ + ENTER; + + struct literal_expression* this = (void*) new_expression( + /* inheritance: */ &literal_expression_inheritance, + /* alloc size: */ sizeof(*this)); + + this->value = inc_value(value); + + EXIT; + return (void*) this; +} + diff --git a/expression/literal/new.h b/expression/literal/new.h new file mode 100644 index 0000000..409f10c --- /dev/null +++ b/expression/literal/new.h @@ -0,0 +1,7 @@ + +struct value; + +struct expression* new_literal_expression( + struct value* value); + + diff --git a/expression/literal/prettyprint.c b/expression/literal/prettyprint.c new file mode 100644 index 0000000..f73dfb3 --- /dev/null +++ b/expression/literal/prettyprint.c @@ -0,0 +1,38 @@ + +#include + +#include + +#include "struct.h" +#include "prettyprint.h" + +struct stringtree* literal_expression_prettyprint( + int *out_chosen_color, + struct expression* super, + struct color_factory* cfactory, + bool with_color) +{ + ENTER; + + struct literal_expression* const this = (void*) super; + + struct stringtree* tree = value_prettyprint( + out_chosen_color, + this->value, cfactory, with_color); + + EXIT; + return tree; +} + + + + + + + + + + + + + diff --git a/expression/literal/prettyprint.h b/expression/literal/prettyprint.h new file mode 100644 index 0000000..46272de --- /dev/null +++ b/expression/literal/prettyprint.h @@ -0,0 +1,13 @@ + +struct expression; + +struct color_factory; + +struct stringtree* literal_expression_prettyprint( + int *out_chosen_color, + struct expression* this, + struct color_factory* cfactory, + bool with_color); + + + diff --git a/expression/literal/prettyprint_errors.c b/expression/literal/prettyprint_errors.c new file mode 100644 index 0000000..0ee5fe6 --- /dev/null +++ b/expression/literal/prettyprint_errors.c @@ -0,0 +1,17 @@ + +#include + +#include + +#include "struct.h" +#include "prettyprint_errors.h" + +struct stringtree* literal_expression_prettyprint_errors( + struct expression* super) +{ + ENTER; + + EXIT; + return NULL; +} + diff --git a/expression/literal/prettyprint_errors.h b/expression/literal/prettyprint_errors.h new file mode 100644 index 0000000..d93447a --- /dev/null +++ b/expression/literal/prettyprint_errors.h @@ -0,0 +1,4 @@ + +struct stringtree* literal_expression_prettyprint_errors( + struct expression* super); + diff --git a/expression/literal/struct.h b/expression/literal/struct.h new file mode 100644 index 0000000..434c8e8 --- /dev/null +++ b/expression/literal/struct.h @@ -0,0 +1,10 @@ + +#include "../struct.h" + +struct literal_expression +{ + struct expression super; + + struct value* value; +}; + diff --git a/expression/new.c b/expression/new.c new file mode 100644 index 0000000..f1cb0ef --- /dev/null +++ b/expression/new.c @@ -0,0 +1,24 @@ + +#include + +#include + +#include "struct.h" +#include "new.h" + +struct expression* new_expression( + const struct expression_inheritance* inheritance, + size_t alloc_size) +{ + ENTER; + + struct expression* this = smalloc(alloc_size); + + this->inheritance = inheritance; + + this->refcount = 1; + + EXIT; + return this; +} + diff --git a/expression/new.h b/expression/new.h new file mode 100644 index 0000000..b67f206 --- /dev/null +++ b/expression/new.h @@ -0,0 +1,10 @@ + +#include + +struct expression_inheritance; + +struct expression* new_expression( + const struct expression_inheritance* inheritance, + size_t alloc_size); + + diff --git a/expression/parenthesis/evaluate.c b/expression/parenthesis/evaluate.c new file mode 100644 index 0000000..d11c1e6 --- /dev/null +++ b/expression/parenthesis/evaluate.c @@ -0,0 +1,23 @@ + +#include + +#include "../evaluate.h" + +#include "struct.h" +#include "evaluate.h" + +struct value* parenthesis_expression_evaluate( + struct expression* super, + struct environment* environment, + struct booleans* booleans) +{ + ENTER; + + struct parenthesis_expression* this = (void*) super; + + struct value* result = expression_evaluate( + this->subexpression, environment, booleans); + + EXIT; + return result; +} diff --git a/expression/parenthesis/evaluate.h b/expression/parenthesis/evaluate.h new file mode 100644 index 0000000..0edde40 --- /dev/null +++ b/expression/parenthesis/evaluate.h @@ -0,0 +1,7 @@ + +struct value* parenthesis_expression_evaluate( + struct expression* this, + struct environment* environment, + struct booleans* booleans); + + diff --git a/expression/parenthesis/free.c b/expression/parenthesis/free.c new file mode 100644 index 0000000..1b05831 --- /dev/null +++ b/expression/parenthesis/free.c @@ -0,0 +1,19 @@ + +#include + +#include "../free.h" + +#include "struct.h" +#include "free.h" + +void free_parenthesis_expression( + struct expression* super) +{ + ENTER; + + struct parenthesis_expression* this = (void*) super; + + free_expression(this->subexpression); + + EXIT; +} diff --git a/expression/parenthesis/free.h b/expression/parenthesis/free.h new file mode 100644 index 0000000..5c24e37 --- /dev/null +++ b/expression/parenthesis/free.h @@ -0,0 +1,6 @@ + +struct expression; + +void free_parenthesis_expression( + struct expression* super); + diff --git a/expression/parenthesis/inheritance.c b/expression/parenthesis/inheritance.c new file mode 100644 index 0000000..551aac9 --- /dev/null +++ b/expression/parenthesis/inheritance.c @@ -0,0 +1,20 @@ + +#include + +#include "../inheritance.h" + +#include "prettyprint_errors.h" +#include "prettyprint.h" +#include "evaluate.h" +#include "free.h" +#include "inheritance.h" + +struct expression_inheritance parenthesis_expression_inheritance = { + .prettyprint_errors = parenthesis_expression_prettyprint_errors, + + .prettyprint = parenthesis_expression_prettyprint, + + .evaluate = parenthesis_expression_evaluate, + + .free = free_parenthesis_expression +}; diff --git a/expression/parenthesis/inheritance.h b/expression/parenthesis/inheritance.h new file mode 100644 index 0000000..00a1f4a --- /dev/null +++ b/expression/parenthesis/inheritance.h @@ -0,0 +1,2 @@ + +extern struct expression_inheritance parenthesis_expression_inheritance; diff --git a/expression/parenthesis/new.c b/expression/parenthesis/new.c new file mode 100644 index 0000000..926d2f0 --- /dev/null +++ b/expression/parenthesis/new.c @@ -0,0 +1,25 @@ + +#include + +#include "../new.h" +#include "../inc.h" + +#include "inheritance.h" +#include "struct.h" +#include "new.h" + +struct expression* new_parenthesis_expression( + struct expression* subexpression) +{ + ENTER; + + struct parenthesis_expression* this = (void*) new_expression( + /* inheritance: */ &parenthesis_expression_inheritance, + /* alloc size: */ sizeof(*this)); + + this->subexpression = inc_expression(subexpression); + + EXIT; + return (void*) this; +} + diff --git a/expression/parenthesis/new.h b/expression/parenthesis/new.h new file mode 100644 index 0000000..77781ff --- /dev/null +++ b/expression/parenthesis/new.h @@ -0,0 +1,8 @@ + +struct value; +struct string; + +struct expression* new_parenthesis_expression( + struct expression* subexpression); + + diff --git a/expression/parenthesis/prettyprint.c b/expression/parenthesis/prettyprint.c new file mode 100644 index 0000000..e0c7eed --- /dev/null +++ b/expression/parenthesis/prettyprint.c @@ -0,0 +1,73 @@ + +#include + +#include + +#include + +#include +#include +#include + +/*#include */ + +#include "../prettyprint.h" + +#include "struct.h" +#include "prettyprint.h" + +struct stringtree* parenthesis_expression_prettyprint( + int *out_chosen_color, + struct expression* super, + struct color_factory* cfactory, + bool with_color) +{ + ENTER; + + struct parenthesis_expression* const this = (void*) super; + + int inner_color; + + struct stringtree* tree = expression_prettyprint( + &inner_color, + this->subexpression, + cfactory, + with_color); + + if (with_color) + { + int my_color = (inner_color + 1) % (int) N(cfactory->colors); + + stringtree_prepend_string(tree, cfactory->reset); + stringtree_prepend_cstr(tree, L"("); + stringtree_prepend_string(tree, cfactory->colors[my_color]); + + stringtree_append_string(tree, cfactory->colors[my_color]); + stringtree_append_cstr(tree, L")"); + stringtree_append_string(tree, cfactory->reset); + + if (out_chosen_color) + *out_chosen_color = my_color; + } + else + { + stringtree_prepend_cstr(tree, L"("); + stringtree_append_cstr(tree, L")"); + } + + EXIT; + return tree; +} + + + + + + + + + + + + + diff --git a/expression/parenthesis/prettyprint.h b/expression/parenthesis/prettyprint.h new file mode 100644 index 0000000..21381e0 --- /dev/null +++ b/expression/parenthesis/prettyprint.h @@ -0,0 +1,15 @@ + +#include + +struct expression; + +struct color_factory; + +struct stringtree* parenthesis_expression_prettyprint( + int *out_chosen_color, + struct expression* this, + struct color_factory* cfactory, + bool with_color); + + + diff --git a/expression/parenthesis/prettyprint_errors.c b/expression/parenthesis/prettyprint_errors.c new file mode 100644 index 0000000..e9afd47 --- /dev/null +++ b/expression/parenthesis/prettyprint_errors.c @@ -0,0 +1,22 @@ + +#include + +#include "../prettyprint_errors.h" + +#include "struct.h" +#include "prettyprint_errors.h" + +struct stringtree* parenthesis_expression_prettyprint_errors( + struct expression* super) +{ + ENTER; + + struct parenthesis_expression* const this = (void*) super; + + struct stringtree* tree = expression_prettyprint_errors( + this->subexpression); + + EXIT; + return tree; +} + diff --git a/expression/parenthesis/prettyprint_errors.h b/expression/parenthesis/prettyprint_errors.h new file mode 100644 index 0000000..2b174b2 --- /dev/null +++ b/expression/parenthesis/prettyprint_errors.h @@ -0,0 +1,4 @@ + +struct stringtree* parenthesis_expression_prettyprint_errors( + struct expression* super); + diff --git a/expression/parenthesis/struct.h b/expression/parenthesis/struct.h new file mode 100644 index 0000000..738392f --- /dev/null +++ b/expression/parenthesis/struct.h @@ -0,0 +1,10 @@ + +#include "../struct.h" + +struct parenthesis_expression +{ + struct expression super; + + struct expression* subexpression; +}; + diff --git a/expression/prettyprint.c b/expression/prettyprint.c new file mode 100644 index 0000000..a716e2b --- /dev/null +++ b/expression/prettyprint.c @@ -0,0 +1,29 @@ + +#include + +#include + +#include "struct.h" +#include "inheritance.h" +#include "prettyprint.h" + +struct stringtree* expression_prettyprint( + int *out_chosen_color, + struct expression* this, + struct color_factory* cfactory, + unsigned precedence_level) +{ + ENTER; + + assert(this); + assert(this->inheritance); + assert(this->inheritance->prettyprint); + + struct stringtree* tree = (this->inheritance->prettyprint)( + out_chosen_color, + this, cfactory, precedence_level); + + EXIT; + return tree; +} + diff --git a/expression/prettyprint.h b/expression/prettyprint.h new file mode 100644 index 0000000..5af151e --- /dev/null +++ b/expression/prettyprint.h @@ -0,0 +1,12 @@ + +struct expression; + +struct color_factory; + +struct stringtree* expression_prettyprint( + int *out_chosen_color, + struct expression* this, + struct color_factory* cfactory, + unsigned precedence_level); + + diff --git a/expression/prettyprint_errors.c b/expression/prettyprint_errors.c new file mode 100644 index 0000000..6b02429 --- /dev/null +++ b/expression/prettyprint_errors.c @@ -0,0 +1,23 @@ + +#include + +#include + +#include "struct.h" +#include "inheritance.h" +#include "prettyprint_errors.h" + +struct stringtree* expression_prettyprint_errors( + struct expression* this) +{ + ENTER; + + assert(this); + assert(this->inheritance); + assert(this->inheritance->prettyprint_errors); + + struct stringtree* tree = (this->inheritance->prettyprint_errors)(this); + + EXIT; + return tree; +} diff --git a/expression/prettyprint_errors.h b/expression/prettyprint_errors.h new file mode 100644 index 0000000..1307dc4 --- /dev/null +++ b/expression/prettyprint_errors.h @@ -0,0 +1,6 @@ + +struct expression; + +struct stringtree* expression_prettyprint_errors( + struct expression* super); + diff --git a/expression/print.c b/expression/print.c new file mode 100644 index 0000000..e69de29 diff --git a/expression/print.h b/expression/print.h new file mode 100644 index 0000000..e69de29 diff --git a/expression/struct.h b/expression/struct.h new file mode 100644 index 0000000..f34fc1b --- /dev/null +++ b/expression/struct.h @@ -0,0 +1,10 @@ + +struct expression_inheritance; + +struct expression +{ + const struct expression_inheritance* inheritance; + + unsigned refcount; +}; + diff --git a/expression/variable/evaluate.c b/expression/variable/evaluate.c new file mode 100644 index 0000000..ad1e6f3 --- /dev/null +++ b/expression/variable/evaluate.c @@ -0,0 +1,22 @@ + +#include + +#include + +#include "struct.h" +#include "evaluate.h" + +struct value* variable_expression_evaluate( + struct expression* super, + struct environment* environment, + struct booleans* booleans) +{ + ENTER; + + struct variable_expression* this = (void*) super; + + struct value* result = environment_lookup(environment, this->name); + + EXIT; + return result; +} diff --git a/expression/variable/evaluate.h b/expression/variable/evaluate.h new file mode 100644 index 0000000..d46b418 --- /dev/null +++ b/expression/variable/evaluate.h @@ -0,0 +1,11 @@ + +struct expression; +struct environment; +struct booleans; + +struct value* variable_expression_evaluate( + struct expression* this, + struct environment* environment, + struct booleans* booleans); + + diff --git a/expression/variable/free.c b/expression/variable/free.c new file mode 100644 index 0000000..7075014 --- /dev/null +++ b/expression/variable/free.c @@ -0,0 +1,19 @@ + +#include + +#include + +#include "struct.h" +#include "free.h" + +void free_variable_expression( + struct expression* super) +{ + ENTER; + + struct variable_expression* this = (void*) super; + + free_string(this->name); + + EXIT; +} diff --git a/expression/variable/free.h b/expression/variable/free.h new file mode 100644 index 0000000..f6fdfcb --- /dev/null +++ b/expression/variable/free.h @@ -0,0 +1,6 @@ + +struct expression; + +void free_variable_expression( + struct expression* super); + diff --git a/expression/variable/inheritance.c b/expression/variable/inheritance.c new file mode 100644 index 0000000..d44e795 --- /dev/null +++ b/expression/variable/inheritance.c @@ -0,0 +1,20 @@ + +#include + +#include "../inheritance.h" + +#include "prettyprint_errors.h" +#include "prettyprint.h" +#include "evaluate.h" +#include "free.h" +#include "inheritance.h" + +struct expression_inheritance variable_expression_inheritance = { + .prettyprint_errors = variable_expression_prettyprint_errors, + + .prettyprint = variable_expression_prettyprint, + + .evaluate = variable_expression_evaluate, + + .free = free_variable_expression +}; diff --git a/expression/variable/inheritance.h b/expression/variable/inheritance.h new file mode 100644 index 0000000..7a8de00 --- /dev/null +++ b/expression/variable/inheritance.h @@ -0,0 +1,2 @@ + +extern struct expression_inheritance variable_expression_inheritance; diff --git a/expression/variable/new.c b/expression/variable/new.c new file mode 100644 index 0000000..a0760df --- /dev/null +++ b/expression/variable/new.c @@ -0,0 +1,30 @@ + +#include + +/*#include */ + +/*#include */ + +#include + +#include "../new.h" + +#include "inheritance.h" +#include "struct.h" +#include "new.h" + +struct expression* new_variable_expression( + struct string *name) +{ + ENTER; + + struct variable_expression* this = (void*) new_expression( + /* inheritance: */ &variable_expression_inheritance, + /* alloc size: */ sizeof(*this)); + + this->name = inc_string(name); + + EXIT; + return (void*) this; +} + diff --git a/expression/variable/new.h b/expression/variable/new.h new file mode 100644 index 0000000..f0a694d --- /dev/null +++ b/expression/variable/new.h @@ -0,0 +1,8 @@ + +struct value; +struct string; + +struct expression* new_variable_expression( + struct string* name); + + diff --git a/expression/variable/prettyprint.c b/expression/variable/prettyprint.c new file mode 100644 index 0000000..1f24609 --- /dev/null +++ b/expression/variable/prettyprint.c @@ -0,0 +1,54 @@ + +#include + +#include + +#include +#include +#include + +#include + +#include "struct.h" +#include "prettyprint.h" + +struct stringtree* variable_expression_prettyprint( + int *out_chosen_color, + struct expression* super, + struct color_factory* cfactory, + bool with_color) +{ + ENTER; + + struct variable_expression* const this = (void*) super; + + struct stringtree* tree = new_stringtree(); + + stringtree_append_string(tree, this->name); + + if (with_color) + { + stringtree_prepend_string(tree, cfactory->variable); + + stringtree_append_string(tree, cfactory->reset); + + if (out_chosen_color) + *out_chosen_color = -1; + } + + EXIT; + return tree; +} + + + + + + + + + + + + + diff --git a/expression/variable/prettyprint.h b/expression/variable/prettyprint.h new file mode 100644 index 0000000..1bfc8eb --- /dev/null +++ b/expression/variable/prettyprint.h @@ -0,0 +1,13 @@ + +struct expression; + +struct color_factory; + +struct stringtree* variable_expression_prettyprint( + int *out_chosen_color, + struct expression* this, + struct color_factory* cfactory, + bool with_color); + + + diff --git a/expression/variable/prettyprint_errors.c b/expression/variable/prettyprint_errors.c new file mode 100644 index 0000000..f21dacf --- /dev/null +++ b/expression/variable/prettyprint_errors.c @@ -0,0 +1,17 @@ + +#include + +#include + +#include "struct.h" +#include "prettyprint_errors.h" + +struct stringtree* variable_expression_prettyprint_errors( + struct expression* super) +{ + ENTER; + + EXIT; + return NULL; +} + diff --git a/expression/variable/prettyprint_errors.h b/expression/variable/prettyprint_errors.h new file mode 100644 index 0000000..c5541bd --- /dev/null +++ b/expression/variable/prettyprint_errors.h @@ -0,0 +1,4 @@ + +struct stringtree* variable_expression_prettyprint_errors( + struct expression* super); + diff --git a/expression/variable/struct.h b/expression/variable/struct.h new file mode 100644 index 0000000..4e55956 --- /dev/null +++ b/expression/variable/struct.h @@ -0,0 +1,10 @@ + +#include "../struct.h" + +struct variable_expression +{ + struct expression super; + + struct string *name; +}; + diff --git a/extern/avl/avl.c b/extern/avl/avl.c new file mode 100644 index 0000000..f8e1e3c --- /dev/null +++ b/extern/avl/avl.c @@ -0,0 +1,650 @@ +/***************************************************************************** + + avl.c - Source code for the AVL-tree library. + + Copyright (C) 1998 Michael H. Buselli + Copyright (C) 2000-2002 Wessel Dankers + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Augmented AVL-tree. Original by Michael H. Buselli . + + Modified by Wessel Dankers to add a bunch of bloat to + the sourcecode, change the interface and squash a few bugs. + Mail him if you find new bugs. + +*****************************************************************************/ + +#include +#include +#include +#include "avl.h" + +static void avl_rebalance(avl_tree_t *, avl_node_t *); + +#ifdef AVL_COUNT +#define NODE_COUNT(n) ((n) ? (n)->count : 0) +#define L_COUNT(n) (NODE_COUNT((n)->left)) +#define R_COUNT(n) (NODE_COUNT((n)->right)) +#define CALC_COUNT(n) (L_COUNT(n) + R_COUNT(n) + 1) +#endif + +#ifdef AVL_DEPTH +#define NODE_DEPTH(n) ((n) ? (n)->depth : 0) +#define L_DEPTH(n) (NODE_DEPTH((n)->left)) +#define R_DEPTH(n) (NODE_DEPTH((n)->right)) +#define CALC_DEPTH(n) ((L_DEPTH(n) > R_DEPTH(n) ? L_DEPTH(n) : R_DEPTH(n)) + 1) +#endif + +#ifndef AVL_DEPTH +/* Also known as ffs() (from BSD) */ +static int lg(unsigned int u) { + int r = 1; + if(!u) return 0; + if(u & 0xffff0000) { u >>= 16; r += 16; } + if(u & 0x0000ff00) { u >>= 8; r += 8; } + if(u & 0x000000f0) { u >>= 4; r += 4; } + if(u & 0x0000000c) { u >>= 2; r += 2; } + if(u & 0x00000002) r++; + return r; +} +#endif + +static int avl_check_balance(avl_node_t *avlnode) { +#ifdef AVL_DEPTH + int d; + d = R_DEPTH(avlnode) - L_DEPTH(avlnode); + return d<-1?-1:d>1?1:0; +#else +/* int d; + * d = lg(R_COUNT(avlnode)) - lg(L_COUNT(avlnode)); + * d = d<-1?-1:d>1?1:0; + */ +#ifdef AVL_COUNT + int pl, r; + + pl = lg(L_COUNT(avlnode)); + r = R_COUNT(avlnode); + + if(r>>pl+1) + return 1; + if(pl<2 || r>>pl-2) + return 0; + return -1; +#else +#error No balancing possible. +#endif +#endif +} + +#ifdef AVL_COUNT +unsigned int avl_count(const avl_tree_t *avltree) { + return NODE_COUNT(avltree->top); +} + +avl_node_t *avl_at(const avl_tree_t *avltree, unsigned int index) { + avl_node_t *avlnode; + unsigned int c; + + avlnode = avltree->top; + + while(avlnode) { + c = L_COUNT(avlnode); + + if(index < c) { + avlnode = avlnode->left; + } else if(index > c) { + avlnode = avlnode->right; + index -= c+1; + } else { + return avlnode; + } + } + return NULL; +} + +unsigned int avl_index(const avl_node_t *avlnode) { + avl_node_t *next; + unsigned int c; + + c = L_COUNT(avlnode); + + while((next = avlnode->parent)) { + if(avlnode == next->right) + c += L_COUNT(next) + 1; + avlnode = next; + } + + return c; +} +#endif + +int avl_search_closest(const avl_tree_t *avltree, const void *item, avl_compare_t cmp, avl_node_t **avlnode) { + avl_node_t *node; + int c; + + if (!avlnode) + avlnode = &node; + + if (!cmp) + { + cmp = avltree->cmp; + } + + node = avltree->top; + + if (!node) + return *avlnode = NULL, 0; + + for (;;) { + c = cmp(item, node->item); + + if(c < 0) { + if(node->left) + node = node->left; + else + return *avlnode = node, -1; + } else if(c > 0) { + if(node->right) + node = node->right; + else + return *avlnode = node, 1; + } else { + return *avlnode = node, 0; + } + } +} + +/* + * avl_search: + * Return a pointer to a node with the given item in the tree. + * If no such item is in the tree, then NULL is returned. + */ +avl_node_t *avl_search(const avl_tree_t *avltree, const void *item) { + avl_node_t *node; + return avl_search_closest(avltree, item, NULL, &node) ? NULL : node; +} + +avl_node_t *avl_search2(const avl_tree_t *avltree, const void *item, avl_compare_t cmp) { + avl_node_t *node; + return avl_search_closest(avltree, item, cmp, &node) ? NULL : node; +} + +avl_tree_t *avl_init_tree(avl_tree_t *rc, avl_compare_t cmp, avl_freeitem_t freeitem) { + if(rc) { + rc->head = NULL; + rc->tail = NULL; + rc->top = NULL; + rc->cmp = cmp; + rc->freeitem = freeitem; + } + return rc; +} + +avl_tree_t *avl_alloc_tree(avl_compare_t cmp, avl_freeitem_t freeitem) { + return avl_init_tree(malloc(sizeof(avl_tree_t)), cmp, freeitem); +} + +void avl_clear_tree(avl_tree_t *avltree) { + avltree->top = avltree->head = avltree->tail = NULL; +} + +void avl_free_nodes(avl_tree_t *avltree) { + avl_node_t *node, *next; + avl_freeitem_t freeitem; + + freeitem = avltree->freeitem; + + for(node = avltree->head; node; node = next) { + next = node->next; + if(freeitem) + freeitem(node->item); + free(node); + } + + avl_clear_tree(avltree); +} + +/* + * avl_free_tree: + * Free all memory used by this tree. If freeitem is not NULL, then + * it is assumed to be a destructor for the items referenced in the avl_ + * tree, and they are deleted as well. + */ +void avl_free_tree(avl_tree_t *avltree) { + if (avltree) { + avl_free_nodes(avltree); + free(avltree); + } +} + +static void avl_clear_node(avl_node_t *newnode) { + newnode->left = newnode->right = NULL; + #ifdef AVL_COUNT + newnode->count = 1; + #endif + #ifdef AVL_DEPTH + newnode->depth = 1; + #endif +} + +avl_node_t *avl_init_node(avl_node_t *newnode, void *item) { + if(newnode) { +/* avl_clear_node(newnode); */ + newnode->item = item; + } + return newnode; +} + +avl_node_t *avl_insert_top(avl_tree_t *avltree, avl_node_t *newnode) { + avl_clear_node(newnode); + newnode->prev = newnode->next = newnode->parent = NULL; + avltree->head = avltree->tail = avltree->top = newnode; + return newnode; +} + +avl_node_t *avl_insert_before(avl_tree_t *avltree, avl_node_t *node, avl_node_t *newnode) { + if(!node) + return avltree->tail + ? avl_insert_after(avltree, avltree->tail, newnode) + : avl_insert_top(avltree, newnode); + + if(node->left) + return avl_insert_after(avltree, node->prev, newnode); + + avl_clear_node(newnode); + + newnode->next = node; + newnode->parent = node; + + newnode->prev = node->prev; + if(node->prev) + node->prev->next = newnode; + else + avltree->head = newnode; + node->prev = newnode; + + node->left = newnode; + avl_rebalance(avltree, node); + return newnode; +} + +avl_node_t *avl_insert_after(avl_tree_t *avltree, avl_node_t *node, avl_node_t *newnode) { + if(!node) + return avltree->head + ? avl_insert_before(avltree, avltree->head, newnode) + : avl_insert_top(avltree, newnode); + + if(node->right) + return avl_insert_before(avltree, node->next, newnode); + + avl_clear_node(newnode); + + newnode->prev = node; + newnode->parent = node; + + newnode->next = node->next; + if(node->next) + node->next->prev = newnode; + else + avltree->tail = newnode; + node->next = newnode; + + node->right = newnode; + avl_rebalance(avltree, node); + return newnode; +} + +avl_node_t *avl_insert_node(avl_tree_t *avltree, avl_node_t *newnode) { + avl_node_t *node; + + if(!avltree->top) + return avl_insert_top(avltree, newnode); + + switch (avl_search_closest(avltree, newnode->item, avltree->cmp, &node)) + { + case -1: + return avl_insert_before(avltree, node, newnode); + + case 1: + return avl_insert_after(avltree, node, newnode); + + case 0: + break; + + default: + abort(); + break; + } + + return NULL; +} + +/* + * avl_insert: + * Create a new node and insert an item there. + * Returns the new node on success or NULL if no memory could be allocated. + */ +avl_node_t *avl_insert(avl_tree_t *avltree, void *item) { + avl_node_t *newnode; + + newnode = avl_init_node(malloc(sizeof(avl_node_t)), item); + if(newnode) { + if(avl_insert_node(avltree, newnode)) + return newnode; + free(newnode); + errno = EEXIST; + } + return NULL; +} + +/* + * avl_unlink_node: + * Removes the given node. Does not delete the item at that node. + * The item of the node may be freed before calling avl_unlink_node. + * (In other words, it is not referenced by this function.) + */ +void avl_unlink_node(avl_tree_t *avltree, avl_node_t *avlnode) { + avl_node_t *parent; + avl_node_t **superparent; + avl_node_t *subst, *left, *right; + avl_node_t *balnode; + + if(avlnode->prev) + avlnode->prev->next = avlnode->next; + else + avltree->head = avlnode->next; + + if(avlnode->next) + avlnode->next->prev = avlnode->prev; + else + avltree->tail = avlnode->prev; + + parent = avlnode->parent; + + superparent = parent + ? avlnode == parent->left ? &parent->left : &parent->right + : &avltree->top; + + left = avlnode->left; + right = avlnode->right; + if(!left) { + *superparent = right; + if(right) + right->parent = parent; + balnode = parent; + } else if(!right) { + *superparent = left; + left->parent = parent; + balnode = parent; + } else { + subst = avlnode->prev; + if(subst == left) { + balnode = subst; + } else { + balnode = subst->parent; + balnode->right = subst->left; + if(balnode->right) + balnode->right->parent = balnode; + subst->left = left; + left->parent = subst; + } + subst->right = right; + subst->parent = parent; + right->parent = subst; + *superparent = subst; + } + + avl_rebalance(avltree, balnode); +} + +void *avl_delete_node(avl_tree_t *avltree, avl_node_t *avlnode) { + void *item = NULL; + if(avlnode) { + item = avlnode->item; + avl_unlink_node(avltree, avlnode); + if(avltree->freeitem) + avltree->freeitem(item); + free(avlnode); + } + return item; +} + +void *avl_delete(avl_tree_t *avltree, const void *item) { + return avl_delete_node(avltree, avl_search(avltree, item)); +} + +avl_node_t *avl_fixup_node(avl_tree_t *avltree, avl_node_t *newnode) { + avl_node_t *oldnode = NULL, *node; + + if(!avltree || !newnode) + return NULL; + + node = newnode->prev; + if(node) { + oldnode = node->next; + node->next = newnode; + } else { + avltree->head = newnode; + } + + node = newnode->next; + if(node) { + oldnode = node->prev; + node->prev = newnode; + } else { + avltree->tail = newnode; + } + + node = newnode->parent; + if(node) { + if(node->left == oldnode) + node->left = newnode; + else + node->right = newnode; + } else { + oldnode = avltree->top; + avltree->top = newnode; + } + + return oldnode; +} + +/* + * avl_rebalance: + * Rebalances the tree if one side becomes too heavy. This function + * assumes that both subtrees are AVL-trees with consistant data. The + * function has the additional side effect of recalculating the count of + * the tree at this node. It should be noted that at the return of this + * function, if a rebalance takes place, the top of this subtree is no + * longer going to be the same node. + */ +void avl_rebalance(avl_tree_t *avltree, avl_node_t *avlnode) { + avl_node_t *child; + avl_node_t *gchild; + avl_node_t *parent; + avl_node_t **superparent; + + parent = avlnode; + + while(avlnode) { + parent = avlnode->parent; + + superparent = parent + ? avlnode == parent->left ? &parent->left : &parent->right + : &avltree->top; + + switch(avl_check_balance(avlnode)) { + case -1: + child = avlnode->left; + #ifdef AVL_DEPTH + if(L_DEPTH(child) >= R_DEPTH(child)) { + #else + #ifdef AVL_COUNT + if(L_COUNT(child) >= R_COUNT(child)) { + #else + #error No balancing possible. + #endif + #endif + avlnode->left = child->right; + if(avlnode->left) + avlnode->left->parent = avlnode; + child->right = avlnode; + avlnode->parent = child; + *superparent = child; + child->parent = parent; + #ifdef AVL_COUNT + avlnode->count = CALC_COUNT(avlnode); + child->count = CALC_COUNT(child); + #endif + #ifdef AVL_DEPTH + avlnode->depth = CALC_DEPTH(avlnode); + child->depth = CALC_DEPTH(child); + #endif + } else { + gchild = child->right; + avlnode->left = gchild->right; + if(avlnode->left) + avlnode->left->parent = avlnode; + child->right = gchild->left; + if(child->right) + child->right->parent = child; + gchild->right = avlnode; + if(gchild->right) + gchild->right->parent = gchild; + gchild->left = child; + if(gchild->left) + gchild->left->parent = gchild; + *superparent = gchild; + gchild->parent = parent; + #ifdef AVL_COUNT + avlnode->count = CALC_COUNT(avlnode); + child->count = CALC_COUNT(child); + gchild->count = CALC_COUNT(gchild); + #endif + #ifdef AVL_DEPTH + avlnode->depth = CALC_DEPTH(avlnode); + child->depth = CALC_DEPTH(child); + gchild->depth = CALC_DEPTH(gchild); + #endif + } + break; + case 1: + child = avlnode->right; + #ifdef AVL_DEPTH + if(R_DEPTH(child) >= L_DEPTH(child)) { + #else + #ifdef AVL_COUNT + if(R_COUNT(child) >= L_COUNT(child)) { + #else + #error No balancing possible. + #endif + #endif + avlnode->right = child->left; + if(avlnode->right) + avlnode->right->parent = avlnode; + child->left = avlnode; + avlnode->parent = child; + *superparent = child; + child->parent = parent; + #ifdef AVL_COUNT + avlnode->count = CALC_COUNT(avlnode); + child->count = CALC_COUNT(child); + #endif + #ifdef AVL_DEPTH + avlnode->depth = CALC_DEPTH(avlnode); + child->depth = CALC_DEPTH(child); + #endif + } else { + gchild = child->left; + avlnode->right = gchild->left; + if(avlnode->right) + avlnode->right->parent = avlnode; + child->left = gchild->right; + if(child->left) + child->left->parent = child; + gchild->left = avlnode; + if(gchild->left) + gchild->left->parent = gchild; + gchild->right = child; + if(gchild->right) + gchild->right->parent = gchild; + *superparent = gchild; + gchild->parent = parent; + #ifdef AVL_COUNT + avlnode->count = CALC_COUNT(avlnode); + child->count = CALC_COUNT(child); + gchild->count = CALC_COUNT(gchild); + #endif + #ifdef AVL_DEPTH + avlnode->depth = CALC_DEPTH(avlnode); + child->depth = CALC_DEPTH(child); + gchild->depth = CALC_DEPTH(gchild); + #endif + } + break; + default: + #ifdef AVL_COUNT + avlnode->count = CALC_COUNT(avlnode); + #endif + #ifdef AVL_DEPTH + avlnode->depth = CALC_DEPTH(avlnode); + #endif + } + avlnode = parent; + } +} + +void avl_foreach(avl_tree_t* tree, void (*callback)(void*)) +{ + for (avl_node_t* node = tree->head; node; node = node->next) + { + callback(node->item); + } +}; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/extern/avl/avl.h b/extern/avl/avl.h new file mode 100644 index 0000000..851d8d3 --- /dev/null +++ b/extern/avl/avl.h @@ -0,0 +1,208 @@ +/***************************************************************************** + + avl.h - Source code for the AVL-tree library. + + Copyright (C) 1998 Michael H. Buselli + Copyright (C) 2000-2002 Wessel Dankers + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Augmented AVL-tree. Original by Michael H. Buselli . + + Modified by Wessel Dankers to add a bunch of bloat to + the sourcecode, change the interface and squash a few bugs. + Mail him if you find new bugs. + +*****************************************************************************/ + +#ifndef _AVL_H +#define _AVL_H + +/* We need either depths, counts or both (the latter being the default) */ +#if !defined(AVL_DEPTH) && !defined(AVL_COUNT) +#define AVL_DEPTH +#define AVL_COUNT +#endif + +/* User supplied function to compare two items like strcmp() does. + * For example: cmp(a,b) will return: + * -1 if a < b + * 0 if a = b + * 1 if a > b + */ +typedef int (*avl_compare_t)(const void *, const void *); + +/* User supplied function to delete an item when a node is free()d. + * If NULL, the item is not free()d. + */ +typedef void (*avl_freeitem_t)(void *); + +typedef struct avl_node_t { + struct avl_node_t *next; + struct avl_node_t *prev; + struct avl_node_t *parent; + struct avl_node_t *left; + struct avl_node_t *right; + void *item; +#ifdef AVL_COUNT + unsigned int count; +#endif +#ifdef AVL_DEPTH + int depth; +#endif +} avl_node_t; + +typedef struct avl_tree_t { + avl_node_t *head; + avl_node_t *tail; + avl_node_t *top; + avl_compare_t cmp; + avl_freeitem_t freeitem; +} avl_tree_t; + +/* Initializes a new tree for elements that will be ordered using + * the supplied strcmp()-like function. + * Returns the value of avltree (even if it's NULL). + * O(1) */ +extern avl_tree_t *avl_init_tree(avl_tree_t *avltree, avl_compare_t, avl_freeitem_t); + +/* Allocates and initializes a new tree for elements that will be + * ordered using the supplied strcmp()-like function. + * Returns NULL if memory could not be allocated. + * O(1) */ +extern avl_tree_t *avl_alloc_tree(avl_compare_t, avl_freeitem_t); + +/* Frees the entire tree efficiently. Nodes will be free()d. + * If the tree's freeitem is not NULL it will be invoked on every item. + * O(n) */ +extern void avl_free_tree(avl_tree_t *); + +/* Reinitializes the tree structure for reuse. Nothing is free()d. + * Compare and freeitem functions are left alone. + * O(1) */ +extern void avl_clear_tree(avl_tree_t *); + +/* Free()s all nodes in the tree but leaves the tree itself. + * If the tree's freeitem is not NULL it will be invoked on every item. + * O(n) */ +extern void avl_free_nodes(avl_tree_t *); + +/* Initializes memory for use as a node. Returns NULL if avlnode is NULL. + * O(1) */ +extern avl_node_t *avl_init_node(avl_node_t *avlnode, void *item); + +/* Insert an item into the tree and return the new node. + * Returns NULL and sets errno if memory for the new node could not be + * allocated or if the node is already in the tree (EEXIST). + * O(lg n) */ +extern avl_node_t *avl_insert(avl_tree_t *, void *item); + +/* Insert a node into the tree and return it. + * Returns NULL if the node is already in the tree. + * O(lg n) */ +extern avl_node_t *avl_insert_node(avl_tree_t *, avl_node_t *); + +/* Insert a node in an empty tree. If avlnode is NULL, the tree will be + * cleared and ready for re-use. + * If the tree is not empty, the old nodes are left dangling. + * O(1) */ +extern avl_node_t *avl_insert_top(avl_tree_t *, avl_node_t *avlnode); + +/* Insert a node before another node. Returns the new node. + * If old is NULL, the item is appended to the tree. + * O(lg n) */ +extern avl_node_t *avl_insert_before(avl_tree_t *, avl_node_t *old, avl_node_t *new); + +/* Insert a node after another node. Returns the new node. + * If old is NULL, the item is prepended to the tree. + * O(lg n) */ +extern avl_node_t *avl_insert_after(avl_tree_t *, avl_node_t *old, avl_node_t *new); + +/* Deletes a node from the tree. Returns immediately if the node is NULL. + * The item will not be free()d regardless of the tree's freeitem handler. + * This function comes in handy if you need to update the search key. + * O(lg n) */ +extern void avl_unlink_node(avl_tree_t *, avl_node_t *); + +/* Deletes a node from the tree. Returns immediately if the node is NULL. + * If the tree's freeitem is not NULL, it is invoked on the item. + * If it is, returns the item. + * O(lg n) */ +extern void *avl_delete_node(avl_tree_t *, avl_node_t *); + +/* Searches for an item in the tree and deletes it if found. + * If the tree's freeitem is not NULL, it is invoked on the item. + * If it is, returns the item. + * O(lg n) */ +extern void *avl_delete(avl_tree_t *, const void *item); + +/* If exactly one node is moved in memory, this will fix the pointers + * in the tree that refer to it. It must be an exact shallow copy. + * Returns the pointer to the old position. + * O(1) */ +extern avl_node_t *avl_fixup_node(avl_tree_t *, avl_node_t *new); + +/* Searches for a node with the key closest (or equal) to the given item. + * If avlnode is not NULL, *avlnode will be set to the node found or NULL + * if the tree is empty. Return values: + * -1 if the returned node is smaller + * 0 if the returned node is equal or if the tree is empty + * 1 if the returned node is greater + * O(lg n) */ +int avl_search_closest(const avl_tree_t *avltree, const void *item, avl_compare_t cmp, avl_node_t **avlnode); + +/* Searches for the item in the tree and returns a matching node if found + * or NULL if not. + * O(lg n) */ +extern avl_node_t *avl_search(const avl_tree_t *, const void *item); + +avl_node_t *avl_search2(const avl_tree_t *avltree, const void *item, avl_compare_t cmp); + +void avl_foreach(avl_tree_t* tree, void (*callback)(void*)); + +#ifdef AVL_COUNT +/* Returns the number of nodes in the tree. + * O(1) */ +extern unsigned int avl_count(const avl_tree_t *); + +/* Searches a node by its rank in the list. Counting starts at 0. + * Returns NULL if the index exceeds the number of nodes in the tree. + * O(lg n) */ +extern avl_node_t *avl_at(const avl_tree_t *, unsigned int); + +/* Returns the rank of a node in the list. Counting starts at 0. + * O(lg n) */ +extern unsigned int avl_index(const avl_node_t *); +#endif + +#endif + + + + + + + + + + + + + + + + + + diff --git a/extern/gmp/mini-gmp.c b/extern/gmp/mini-gmp.c new file mode 100644 index 0000000..e37206e --- /dev/null +++ b/extern/gmp/mini-gmp.c @@ -0,0 +1,4635 @@ +/* mini-gmp, a minimalistic implementation of a GNU GMP subset. + + Contributed to the GNU project by Niels Möller + Additional functionalities and improvements by Marco Bodrato. + +Copyright 1991-1997, 1999-2022 Free Software Foundation, Inc. + +This file is part of the GNU MP Library. + +The GNU MP Library is free software; you can redistribute it and/or modify +it under the terms of either: + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at your + option) any later version. + +or + + * the GNU General Public License as published by the Free Software + Foundation; either version 2 of the License, or (at your option) any + later version. + +or both in parallel, as here. + +The GNU MP Library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received copies of the GNU General Public License and the +GNU Lesser General Public License along with the GNU MP Library. If not, +see https://www.gnu.org/licenses/. */ + +/* NOTE: All functions in this file which are not declared in + mini-gmp.h are internal, and are not intended to be compatible + with GMP or with future versions of mini-gmp. */ + +/* Much of the material copied from GMP files, including: gmp-impl.h, + longlong.h, mpn/generic/add_n.c, mpn/generic/addmul_1.c, + mpn/generic/lshift.c, mpn/generic/mul_1.c, + mpn/generic/mul_basecase.c, mpn/generic/rshift.c, + mpn/generic/sbpi1_div_qr.c, mpn/generic/sub_n.c, + mpn/generic/submul_1.c. */ + +#include +#include +#include +#include +#include +#include + +#include "mini-gmp.h" + +#if !defined(MINI_GMP_DONT_USE_FLOAT_H) +#include +#endif + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#pragma GCC diagnostic ignored "-Wsign-conversion" +#pragma GCC diagnostic ignored "-Wsign-compare" +#pragma GCC diagnostic ignored "-Wswitch-default" + + +/* Macros */ +#define GMP_LIMB_BITS (sizeof(mp_limb_t) * CHAR_BIT) + +#define GMP_LIMB_MAX ((mp_limb_t) ~ (mp_limb_t) 0) +#define GMP_LIMB_HIGHBIT ((mp_limb_t) 1 << (GMP_LIMB_BITS - 1)) + +#define GMP_HLIMB_BIT ((mp_limb_t) 1 << (GMP_LIMB_BITS / 2)) +#define GMP_LLIMB_MASK (GMP_HLIMB_BIT - 1) + +#define GMP_ULONG_BITS (sizeof(unsigned long) * CHAR_BIT) +#define GMP_ULONG_HIGHBIT ((unsigned long) 1 << (GMP_ULONG_BITS - 1)) + +#define GMP_ABS(x) ((x) >= 0 ? (x) : -(x)) +#define GMP_NEG_CAST(T,x) (-((T)((x) + 1) - 1)) + +#define GMP_MIN(a, b) ((a) < (b) ? (a) : (b)) +#define GMP_MAX(a, b) ((a) > (b) ? (a) : (b)) + +#define GMP_CMP(a,b) (((a) > (b)) - ((a) < (b))) + +#if defined(DBL_MANT_DIG) && FLT_RADIX == 2 +#define GMP_DBL_MANT_BITS DBL_MANT_DIG +#else +#define GMP_DBL_MANT_BITS (53) +#endif + +/* Return non-zero if xp,xsize and yp,ysize overlap. + If xp+xsize<=yp there's no overlap, or if yp+ysize<=xp there's no + overlap. If both these are false, there's an overlap. */ +#define GMP_MPN_OVERLAP_P(xp, xsize, yp, ysize) \ + ((xp) + (xsize) > (yp) && (yp) + (ysize) > (xp)) + +#define gmp_assert_nocarry(x) do { \ + mp_limb_t __cy = (x); \ + assert (__cy == 0); \ + (void) (__cy); \ + } while (0) + +#define gmp_clz(count, x) do { \ + mp_limb_t __clz_x = (x); \ + unsigned __clz_c = 0; \ + int LOCAL_SHIFT_BITS = 8; \ + if (GMP_LIMB_BITS > LOCAL_SHIFT_BITS) \ + for (; \ + (__clz_x & ((mp_limb_t) 0xff << (GMP_LIMB_BITS - 8))) == 0; \ + __clz_c += 8) \ + { __clz_x <<= LOCAL_SHIFT_BITS; } \ + for (; (__clz_x & GMP_LIMB_HIGHBIT) == 0; __clz_c++) \ + __clz_x <<= 1; \ + (count) = __clz_c; \ + } while (0) + +#define gmp_ctz(count, x) do { \ + mp_limb_t __ctz_x = (x); \ + unsigned __ctz_c = 0; \ + gmp_clz (__ctz_c, __ctz_x & - __ctz_x); \ + (count) = GMP_LIMB_BITS - 1 - __ctz_c; \ + } while (0) + +#define gmp_add_ssaaaa(sh, sl, ah, al, bh, bl) \ + do { \ + mp_limb_t __x; \ + __x = (al) + (bl); \ + (sh) = (ah) + (bh) + (__x < (al)); \ + (sl) = __x; \ + } while (0) + +#define gmp_sub_ddmmss(sh, sl, ah, al, bh, bl) \ + do { \ + mp_limb_t __x; \ + __x = (al) - (bl); \ + (sh) = (ah) - (bh) - ((al) < (bl)); \ + (sl) = __x; \ + } while (0) + +#define gmp_umul_ppmm(w1, w0, u, v) \ + do { \ + int LOCAL_GMP_LIMB_BITS = GMP_LIMB_BITS; \ + if (sizeof(unsigned int) * CHAR_BIT >= 2 * GMP_LIMB_BITS) \ + { \ + unsigned int __ww = (unsigned int) (u) * (v); \ + w0 = (mp_limb_t) __ww; \ + w1 = (mp_limb_t) (__ww >> LOCAL_GMP_LIMB_BITS); \ + } \ + else if (GMP_ULONG_BITS >= 2 * GMP_LIMB_BITS) \ + { \ + unsigned long int __ww = (unsigned long int) (u) * (v); \ + w0 = (mp_limb_t) __ww; \ + w1 = (mp_limb_t) (__ww >> LOCAL_GMP_LIMB_BITS); \ + } \ + else { \ + mp_limb_t __x0, __x1, __x2, __x3; \ + unsigned __ul, __vl, __uh, __vh; \ + mp_limb_t __u = (u), __v = (v); \ + assert (sizeof (unsigned) * 2 >= sizeof (mp_limb_t)); \ + \ + __ul = __u & GMP_LLIMB_MASK; \ + __uh = __u >> (GMP_LIMB_BITS / 2); \ + __vl = __v & GMP_LLIMB_MASK; \ + __vh = __v >> (GMP_LIMB_BITS / 2); \ + \ + __x0 = (mp_limb_t) __ul * __vl; \ + __x1 = (mp_limb_t) __ul * __vh; \ + __x2 = (mp_limb_t) __uh * __vl; \ + __x3 = (mp_limb_t) __uh * __vh; \ + \ + __x1 += __x0 >> (GMP_LIMB_BITS / 2);/* this can't give carry */ \ + __x1 += __x2; /* but this indeed can */ \ + if (__x1 < __x2) /* did we get it? */ \ + __x3 += GMP_HLIMB_BIT; /* yes, add it in the proper pos. */ \ + \ + (w1) = __x3 + (__x1 >> (GMP_LIMB_BITS / 2)); \ + (w0) = (__x1 << (GMP_LIMB_BITS / 2)) + (__x0 & GMP_LLIMB_MASK); \ + } \ + } while (0) + +/* If mp_limb_t is of size smaller than int, plain u*v implies + automatic promotion to *signed* int, and then multiply may overflow + and cause undefined behavior. Explicitly cast to unsigned int for + that case. */ +#define gmp_umullo_limb(u, v) \ + ((sizeof(mp_limb_t) >= sizeof(int)) ? (u)*(v) : (unsigned int)(u) * (v)) + +#define gmp_udiv_qrnnd_preinv(q, r, nh, nl, d, di) \ + do { \ + mp_limb_t _qh, _ql, _r, _mask; \ + gmp_umul_ppmm (_qh, _ql, (nh), (di)); \ + gmp_add_ssaaaa (_qh, _ql, _qh, _ql, (nh) + 1, (nl)); \ + _r = (nl) - gmp_umullo_limb (_qh, (d)); \ + _mask = -(mp_limb_t) (_r > _ql); /* both > and >= are OK */ \ + _qh += _mask; \ + _r += _mask & (d); \ + if (_r >= (d)) \ + { \ + _r -= (d); \ + _qh++; \ + } \ + \ + (r) = _r; \ + (q) = _qh; \ + } while (0) + +#define gmp_udiv_qr_3by2(q, r1, r0, n2, n1, n0, d1, d0, dinv) \ + do { \ + mp_limb_t _q0, _t1, _t0, _mask; \ + gmp_umul_ppmm ((q), _q0, (n2), (dinv)); \ + gmp_add_ssaaaa ((q), _q0, (q), _q0, (n2), (n1)); \ + \ + /* Compute the two most significant limbs of n - q'd */ \ + (r1) = (n1) - gmp_umullo_limb ((d1), (q)); \ + gmp_sub_ddmmss ((r1), (r0), (r1), (n0), (d1), (d0)); \ + gmp_umul_ppmm (_t1, _t0, (d0), (q)); \ + gmp_sub_ddmmss ((r1), (r0), (r1), (r0), _t1, _t0); \ + (q)++; \ + \ + /* Conditionally adjust q and the remainders */ \ + _mask = - (mp_limb_t) ((r1) >= _q0); \ + (q) += _mask; \ + gmp_add_ssaaaa ((r1), (r0), (r1), (r0), _mask & (d1), _mask & (d0)); \ + if ((r1) >= (d1)) \ + { \ + if ((r1) > (d1) || (r0) >= (d0)) \ + { \ + (q)++; \ + gmp_sub_ddmmss ((r1), (r0), (r1), (r0), (d1), (d0)); \ + } \ + } \ + } while (0) + +/* Swap macros. */ +#define MP_LIMB_T_SWAP(x, y) \ + do { \ + mp_limb_t __mp_limb_t_swap__tmp = (x); \ + (x) = (y); \ + (y) = __mp_limb_t_swap__tmp; \ + } while (0) +#define MP_SIZE_T_SWAP(x, y) \ + do { \ + mp_size_t __mp_size_t_swap__tmp = (x); \ + (x) = (y); \ + (y) = __mp_size_t_swap__tmp; \ + } while (0) +#define MP_BITCNT_T_SWAP(x,y) \ + do { \ + mp_bitcnt_t __mp_bitcnt_t_swap__tmp = (x); \ + (x) = (y); \ + (y) = __mp_bitcnt_t_swap__tmp; \ + } while (0) +#define MP_PTR_SWAP(x, y) \ + do { \ + mp_ptr __mp_ptr_swap__tmp = (x); \ + (x) = (y); \ + (y) = __mp_ptr_swap__tmp; \ + } while (0) +#define MP_SRCPTR_SWAP(x, y) \ + do { \ + mp_srcptr __mp_srcptr_swap__tmp = (x); \ + (x) = (y); \ + (y) = __mp_srcptr_swap__tmp; \ + } while (0) + +#define MPN_PTR_SWAP(xp,xs, yp,ys) \ + do { \ + MP_PTR_SWAP (xp, yp); \ + MP_SIZE_T_SWAP (xs, ys); \ + } while(0) +#define MPN_SRCPTR_SWAP(xp,xs, yp,ys) \ + do { \ + MP_SRCPTR_SWAP (xp, yp); \ + MP_SIZE_T_SWAP (xs, ys); \ + } while(0) + +#define MPZ_PTR_SWAP(x, y) \ + do { \ + mpz_ptr __mpz_ptr_swap__tmp = (x); \ + (x) = (y); \ + (y) = __mpz_ptr_swap__tmp; \ + } while (0) +#define MPZ_SRCPTR_SWAP(x, y) \ + do { \ + mpz_srcptr __mpz_srcptr_swap__tmp = (x); \ + (x) = (y); \ + (y) = __mpz_srcptr_swap__tmp; \ + } while (0) + +const int mp_bits_per_limb = GMP_LIMB_BITS; + + +/* Memory allocation and other helper functions. */ +static void +gmp_die (const char *msg) +{ + fprintf (stderr, "%s\n", msg); + abort(); +} + +static void * +gmp_default_alloc (size_t size) +{ + void *p; + + assert (size > 0); + + p = malloc (size); + if (!p) + gmp_die("gmp_default_alloc: Virtual memory exhausted."); + + return p; +} + +static void * +gmp_default_realloc (void *old, size_t unused_old_size, size_t new_size) +{ + void * p; + + p = realloc (old, new_size); + + if (!p) + gmp_die("gmp_default_realloc: Virtual memory exhausted."); + + return p; +} + +static void +gmp_default_free (void *p, size_t unused_size) +{ + free (p); +} + +static void * (*gmp_allocate_func) (size_t) = gmp_default_alloc; +static void * (*gmp_reallocate_func) (void *, size_t, size_t) = gmp_default_realloc; +static void (*gmp_free_func) (void *, size_t) = gmp_default_free; + +void +mp_get_memory_functions (void *(**alloc_func) (size_t), + void *(**realloc_func) (void *, size_t, size_t), + void (**free_func) (void *, size_t)) +{ + if (alloc_func) + *alloc_func = gmp_allocate_func; + + if (realloc_func) + *realloc_func = gmp_reallocate_func; + + if (free_func) + *free_func = gmp_free_func; +} + +void +mp_set_memory_functions (void *(*alloc_func) (size_t), + void *(*realloc_func) (void *, size_t, size_t), + void (*free_func) (void *, size_t)) +{ + if (!alloc_func) + alloc_func = gmp_default_alloc; + if (!realloc_func) + realloc_func = gmp_default_realloc; + if (!free_func) + free_func = gmp_default_free; + + gmp_allocate_func = alloc_func; + gmp_reallocate_func = realloc_func; + gmp_free_func = free_func; +} + +#define gmp_alloc(size) ((*gmp_allocate_func)((size))) +#define gmp_free(p, size) ((*gmp_free_func) ((p), (size))) +#define gmp_realloc(ptr, old_size, size) ((*gmp_reallocate_func)(ptr, old_size, size)) + +static mp_ptr +gmp_alloc_limbs (mp_size_t size) +{ + return (mp_ptr) gmp_alloc (size * sizeof (mp_limb_t)); +} + +static mp_ptr +gmp_realloc_limbs (mp_ptr old, mp_size_t old_size, mp_size_t size) +{ + assert (size > 0); + return (mp_ptr) gmp_realloc (old, old_size * sizeof (mp_limb_t), size * sizeof (mp_limb_t)); +} + +static void +gmp_free_limbs (mp_ptr old, mp_size_t size) +{ + gmp_free (old, size * sizeof (mp_limb_t)); +} + + +/* MPN interface */ + +void +mpn_copyi (mp_ptr d, mp_srcptr s, mp_size_t n) +{ + mp_size_t i; + for (i = 0; i < n; i++) + d[i] = s[i]; +} + +void +mpn_copyd (mp_ptr d, mp_srcptr s, mp_size_t n) +{ + while (--n >= 0) + d[n] = s[n]; +} + +int +mpn_cmp (mp_srcptr ap, mp_srcptr bp, mp_size_t n) +{ + while (--n >= 0) + { + if (ap[n] != bp[n]) + return ap[n] > bp[n] ? 1 : -1; + } + return 0; +} + +static int +mpn_cmp4 (mp_srcptr ap, mp_size_t an, mp_srcptr bp, mp_size_t bn) +{ + if (an != bn) + return an < bn ? -1 : 1; + else + return mpn_cmp (ap, bp, an); +} + +static mp_size_t +mpn_normalized_size (mp_srcptr xp, mp_size_t n) +{ + while (n > 0 && xp[n-1] == 0) + --n; + return n; +} + +int +mpn_zero_p(mp_srcptr rp, mp_size_t n) +{ + return mpn_normalized_size (rp, n) == 0; +} + +void +mpn_zero (mp_ptr rp, mp_size_t n) +{ + while (--n >= 0) + rp[n] = 0; +} + +mp_limb_t +mpn_add_1 (mp_ptr rp, mp_srcptr ap, mp_size_t n, mp_limb_t b) +{ + mp_size_t i; + + assert (n > 0); + i = 0; + do + { + mp_limb_t r = ap[i] + b; + /* Carry out */ + b = (r < b); + rp[i] = r; + } + while (++i < n); + + return b; +} + +mp_limb_t +mpn_add_n (mp_ptr rp, mp_srcptr ap, mp_srcptr bp, mp_size_t n) +{ + mp_size_t i; + mp_limb_t cy; + + for (i = 0, cy = 0; i < n; i++) + { + mp_limb_t a, b, r; + a = ap[i]; b = bp[i]; + r = a + cy; + cy = (r < cy); + r += b; + cy += (r < b); + rp[i] = r; + } + return cy; +} + +mp_limb_t +mpn_add (mp_ptr rp, mp_srcptr ap, mp_size_t an, mp_srcptr bp, mp_size_t bn) +{ + mp_limb_t cy; + + assert (an >= bn); + + cy = mpn_add_n (rp, ap, bp, bn); + if (an > bn) + cy = mpn_add_1 (rp + bn, ap + bn, an - bn, cy); + return cy; +} + +mp_limb_t +mpn_sub_1 (mp_ptr rp, mp_srcptr ap, mp_size_t n, mp_limb_t b) +{ + mp_size_t i; + + assert (n > 0); + + i = 0; + do + { + mp_limb_t a = ap[i]; + /* Carry out */ + mp_limb_t cy = a < b; + rp[i] = a - b; + b = cy; + } + while (++i < n); + + return b; +} + +mp_limb_t +mpn_sub_n (mp_ptr rp, mp_srcptr ap, mp_srcptr bp, mp_size_t n) +{ + mp_size_t i; + mp_limb_t cy; + + for (i = 0, cy = 0; i < n; i++) + { + mp_limb_t a, b; + a = ap[i]; b = bp[i]; + b += cy; + cy = (b < cy); + cy += (a < b); + rp[i] = a - b; + } + return cy; +} + +mp_limb_t +mpn_sub (mp_ptr rp, mp_srcptr ap, mp_size_t an, mp_srcptr bp, mp_size_t bn) +{ + mp_limb_t cy; + + assert (an >= bn); + + cy = mpn_sub_n (rp, ap, bp, bn); + if (an > bn) + cy = mpn_sub_1 (rp + bn, ap + bn, an - bn, cy); + return cy; +} + +mp_limb_t +mpn_mul_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t vl) +{ + mp_limb_t ul, cl, hpl, lpl; + + assert (n >= 1); + + cl = 0; + do + { + ul = *up++; + gmp_umul_ppmm (hpl, lpl, ul, vl); + + lpl += cl; + cl = (lpl < cl) + hpl; + + *rp++ = lpl; + } + while (--n != 0); + + return cl; +} + +mp_limb_t +mpn_addmul_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t vl) +{ + mp_limb_t ul, cl, hpl, lpl, rl; + + assert (n >= 1); + + cl = 0; + do + { + ul = *up++; + gmp_umul_ppmm (hpl, lpl, ul, vl); + + lpl += cl; + cl = (lpl < cl) + hpl; + + rl = *rp; + lpl = rl + lpl; + cl += lpl < rl; + *rp++ = lpl; + } + while (--n != 0); + + return cl; +} + +mp_limb_t +mpn_submul_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t vl) +{ + mp_limb_t ul, cl, hpl, lpl, rl; + + assert (n >= 1); + + cl = 0; + do + { + ul = *up++; + gmp_umul_ppmm (hpl, lpl, ul, vl); + + lpl += cl; + cl = (lpl < cl) + hpl; + + rl = *rp; + lpl = rl - lpl; + cl += lpl > rl; + *rp++ = lpl; + } + while (--n != 0); + + return cl; +} + +mp_limb_t +mpn_mul (mp_ptr rp, mp_srcptr up, mp_size_t un, mp_srcptr vp, mp_size_t vn) +{ + assert (un >= vn); + assert (vn >= 1); + assert (!GMP_MPN_OVERLAP_P(rp, un + vn, up, un)); + assert (!GMP_MPN_OVERLAP_P(rp, un + vn, vp, vn)); + + /* We first multiply by the low order limb. This result can be + stored, not added, to rp. We also avoid a loop for zeroing this + way. */ + + rp[un] = mpn_mul_1 (rp, up, un, vp[0]); + + /* Now accumulate the product of up[] and the next higher limb from + vp[]. */ + + while (--vn >= 1) + { + rp += 1, vp += 1; + rp[un] = mpn_addmul_1 (rp, up, un, vp[0]); + } + return rp[un]; +} + +void +mpn_mul_n (mp_ptr rp, mp_srcptr ap, mp_srcptr bp, mp_size_t n) +{ + mpn_mul (rp, ap, n, bp, n); +} + +void +mpn_sqr (mp_ptr rp, mp_srcptr ap, mp_size_t n) +{ + mpn_mul (rp, ap, n, ap, n); +} + +mp_limb_t +mpn_lshift (mp_ptr rp, mp_srcptr up, mp_size_t n, unsigned int cnt) +{ + mp_limb_t high_limb, low_limb; + unsigned int tnc; + mp_limb_t retval; + + assert (n >= 1); + assert (cnt >= 1); + assert (cnt < GMP_LIMB_BITS); + + up += n; + rp += n; + + tnc = GMP_LIMB_BITS - cnt; + low_limb = *--up; + retval = low_limb >> tnc; + high_limb = (low_limb << cnt); + + while (--n != 0) + { + low_limb = *--up; + *--rp = high_limb | (low_limb >> tnc); + high_limb = (low_limb << cnt); + } + *--rp = high_limb; + + return retval; +} + +mp_limb_t +mpn_rshift (mp_ptr rp, mp_srcptr up, mp_size_t n, unsigned int cnt) +{ + mp_limb_t high_limb, low_limb; + unsigned int tnc; + mp_limb_t retval; + + assert (n >= 1); + assert (cnt >= 1); + assert (cnt < GMP_LIMB_BITS); + + tnc = GMP_LIMB_BITS - cnt; + high_limb = *up++; + retval = (high_limb << tnc); + low_limb = high_limb >> cnt; + + while (--n != 0) + { + high_limb = *up++; + *rp++ = low_limb | (high_limb << tnc); + low_limb = high_limb >> cnt; + } + *rp = low_limb; + + return retval; +} + +static mp_bitcnt_t +mpn_common_scan (mp_limb_t limb, mp_size_t i, mp_srcptr up, mp_size_t un, + mp_limb_t ux) +{ + unsigned cnt; + + assert (ux == 0 || ux == GMP_LIMB_MAX); + assert (0 <= i && i <= un ); + + while (limb == 0) + { + i++; + if (i == un) + return (ux == 0 ? ~(mp_bitcnt_t) 0 : un * GMP_LIMB_BITS); + limb = ux ^ up[i]; + } + gmp_ctz (cnt, limb); + return (mp_bitcnt_t) i * GMP_LIMB_BITS + cnt; +} + +mp_bitcnt_t +mpn_scan1 (mp_srcptr ptr, mp_bitcnt_t bit) +{ + mp_size_t i; + i = bit / GMP_LIMB_BITS; + + return mpn_common_scan ( ptr[i] & (GMP_LIMB_MAX << (bit % GMP_LIMB_BITS)), + i, ptr, i, 0); +} + +mp_bitcnt_t +mpn_scan0 (mp_srcptr ptr, mp_bitcnt_t bit) +{ + mp_size_t i; + i = bit / GMP_LIMB_BITS; + + return mpn_common_scan (~ptr[i] & (GMP_LIMB_MAX << (bit % GMP_LIMB_BITS)), + i, ptr, i, GMP_LIMB_MAX); +} + +void +mpn_com (mp_ptr rp, mp_srcptr up, mp_size_t n) +{ + while (--n >= 0) + *rp++ = ~ *up++; +} + +mp_limb_t +mpn_neg (mp_ptr rp, mp_srcptr up, mp_size_t n) +{ + while (*up == 0) + { + *rp = 0; + if (!--n) + return 0; + ++up; ++rp; + } + *rp = - *up; + mpn_com (++rp, ++up, --n); + return 1; +} + + +/* MPN division interface. */ + +/* The 3/2 inverse is defined as + + m = floor( (B^3-1) / (B u1 + u0)) - B +*/ +mp_limb_t +mpn_invert_3by2 (mp_limb_t u1, mp_limb_t u0) +{ + mp_limb_t r, m; + + { + mp_limb_t p, ql; + unsigned ul, uh, qh; + + assert (sizeof (unsigned) * 2 >= sizeof (mp_limb_t)); + /* For notation, let b denote the half-limb base, so that B = b^2. + Split u1 = b uh + ul. */ + ul = u1 & GMP_LLIMB_MASK; + uh = u1 >> (GMP_LIMB_BITS / 2); + + /* Approximation of the high half of quotient. Differs from the 2/1 + inverse of the half limb uh, since we have already subtracted + u0. */ + qh = (u1 ^ GMP_LIMB_MAX) / uh; + + /* Adjust to get a half-limb 3/2 inverse, i.e., we want + + qh' = floor( (b^3 - 1) / u) - b = floor ((b^3 - b u - 1) / u + = floor( (b (~u) + b-1) / u), + + and the remainder + + r = b (~u) + b-1 - qh (b uh + ul) + = b (~u - qh uh) + b-1 - qh ul + + Subtraction of qh ul may underflow, which implies adjustments. + But by normalization, 2 u >= B > qh ul, so we need to adjust by + at most 2. + */ + + r = ((~u1 - (mp_limb_t) qh * uh) << (GMP_LIMB_BITS / 2)) | GMP_LLIMB_MASK; + + p = (mp_limb_t) qh * ul; + /* Adjustment steps taken from udiv_qrnnd_c */ + if (r < p) + { + qh--; + r += u1; + if (r >= u1) /* i.e. we didn't get carry when adding to r */ + if (r < p) + { + qh--; + r += u1; + } + } + r -= p; + + /* Low half of the quotient is + + ql = floor ( (b r + b-1) / u1). + + This is a 3/2 division (on half-limbs), for which qh is a + suitable inverse. */ + + p = (r >> (GMP_LIMB_BITS / 2)) * qh + r; + /* Unlike full-limb 3/2, we can add 1 without overflow. For this to + work, it is essential that ql is a full mp_limb_t. */ + ql = (p >> (GMP_LIMB_BITS / 2)) + 1; + + /* By the 3/2 trick, we don't need the high half limb. */ + r = (r << (GMP_LIMB_BITS / 2)) + GMP_LLIMB_MASK - ql * u1; + + if (r >= (GMP_LIMB_MAX & (p << (GMP_LIMB_BITS / 2)))) + { + ql--; + r += u1; + } + m = ((mp_limb_t) qh << (GMP_LIMB_BITS / 2)) + ql; + if (r >= u1) + { + m++; + r -= u1; + } + } + + /* Now m is the 2/1 inverse of u1. If u0 > 0, adjust it to become a + 3/2 inverse. */ + if (u0 > 0) + { + mp_limb_t th, tl; + r = ~r; + r += u0; + if (r < u0) + { + m--; + if (r >= u1) + { + m--; + r -= u1; + } + r -= u1; + } + gmp_umul_ppmm (th, tl, u0, m); + r += th; + if (r < th) + { + m--; + m -= ((r > u1) | ((r == u1) & (tl > u0))); + } + } + + return m; +} + +struct gmp_div_inverse +{ + /* Normalization shift count. */ + unsigned shift; + /* Normalized divisor (d0 unused for mpn_div_qr_1) */ + mp_limb_t d1, d0; + /* Inverse, for 2/1 or 3/2. */ + mp_limb_t di; +}; + +static void +mpn_div_qr_1_invert (struct gmp_div_inverse *inv, mp_limb_t d) +{ + unsigned shift; + + assert (d > 0); + gmp_clz (shift, d); + inv->shift = shift; + inv->d1 = d << shift; + inv->di = mpn_invert_limb (inv->d1); +} + +static void +mpn_div_qr_2_invert (struct gmp_div_inverse *inv, + mp_limb_t d1, mp_limb_t d0) +{ + unsigned shift; + + assert (d1 > 0); + gmp_clz (shift, d1); + inv->shift = shift; + if (shift > 0) + { + d1 = (d1 << shift) | (d0 >> (GMP_LIMB_BITS - shift)); + d0 <<= shift; + } + inv->d1 = d1; + inv->d0 = d0; + inv->di = mpn_invert_3by2 (d1, d0); +} + +static void +mpn_div_qr_invert (struct gmp_div_inverse *inv, + mp_srcptr dp, mp_size_t dn) +{ + assert (dn > 0); + + if (dn == 1) + mpn_div_qr_1_invert (inv, dp[0]); + else if (dn == 2) + mpn_div_qr_2_invert (inv, dp[1], dp[0]); + else + { + unsigned shift; + mp_limb_t d1, d0; + + d1 = dp[dn-1]; + d0 = dp[dn-2]; + assert (d1 > 0); + gmp_clz (shift, d1); + inv->shift = shift; + if (shift > 0) + { + d1 = (d1 << shift) | (d0 >> (GMP_LIMB_BITS - shift)); + d0 = (d0 << shift) | (dp[dn-3] >> (GMP_LIMB_BITS - shift)); + } + inv->d1 = d1; + inv->d0 = d0; + inv->di = mpn_invert_3by2 (d1, d0); + } +} + +/* Not matching current public gmp interface, rather corresponding to + the sbpi1_div_* functions. */ +static mp_limb_t +mpn_div_qr_1_preinv (mp_ptr qp, mp_srcptr np, mp_size_t nn, + const struct gmp_div_inverse *inv) +{ + mp_limb_t d, di; + mp_limb_t r; + mp_ptr tp = NULL; + mp_size_t tn = 0; + + if (inv->shift > 0) + { + /* Shift, reusing qp area if possible. In-place shift if qp == np. */ + tp = qp; + if (!tp) + { + tn = nn; + tp = gmp_alloc_limbs (tn); + } + r = mpn_lshift (tp, np, nn, inv->shift); + np = tp; + } + else + r = 0; + + d = inv->d1; + di = inv->di; + while (--nn >= 0) + { + mp_limb_t q; + + gmp_udiv_qrnnd_preinv (q, r, r, np[nn], d, di); + if (qp) + qp[nn] = q; + } + if (tn) + gmp_free_limbs (tp, tn); + + return r >> inv->shift; +} + +static void +mpn_div_qr_2_preinv (mp_ptr qp, mp_ptr np, mp_size_t nn, + const struct gmp_div_inverse *inv) +{ + unsigned shift; + mp_size_t i; + mp_limb_t d1, d0, di, r1, r0; + + assert (nn >= 2); + shift = inv->shift; + d1 = inv->d1; + d0 = inv->d0; + di = inv->di; + + if (shift > 0) + r1 = mpn_lshift (np, np, nn, shift); + else + r1 = 0; + + r0 = np[nn - 1]; + + i = nn - 2; + do + { + mp_limb_t n0, q; + n0 = np[i]; + gmp_udiv_qr_3by2 (q, r1, r0, r1, r0, n0, d1, d0, di); + + if (qp) + qp[i] = q; + } + while (--i >= 0); + + if (shift > 0) + { + assert ((r0 & (GMP_LIMB_MAX >> (GMP_LIMB_BITS - shift))) == 0); + r0 = (r0 >> shift) | (r1 << (GMP_LIMB_BITS - shift)); + r1 >>= shift; + } + + np[1] = r1; + np[0] = r0; +} + +static void +mpn_div_qr_pi1 (mp_ptr qp, + mp_ptr np, mp_size_t nn, mp_limb_t n1, + mp_srcptr dp, mp_size_t dn, + mp_limb_t dinv) +{ + mp_size_t i; + + mp_limb_t d1, d0; + mp_limb_t cy, cy1; + mp_limb_t q; + + assert (dn > 2); + assert (nn >= dn); + + d1 = dp[dn - 1]; + d0 = dp[dn - 2]; + + assert ((d1 & GMP_LIMB_HIGHBIT) != 0); + /* Iteration variable is the index of the q limb. + * + * We divide + * by + */ + + i = nn - dn; + do + { + mp_limb_t n0 = np[dn-1+i]; + + if (n1 == d1 && n0 == d0) + { + q = GMP_LIMB_MAX; + mpn_submul_1 (np+i, dp, dn, q); + n1 = np[dn-1+i]; /* update n1, last loop's value will now be invalid */ + } + else + { + gmp_udiv_qr_3by2 (q, n1, n0, n1, n0, np[dn-2+i], d1, d0, dinv); + + cy = mpn_submul_1 (np + i, dp, dn-2, q); + + cy1 = n0 < cy; + n0 = n0 - cy; + cy = n1 < cy1; + n1 = n1 - cy1; + np[dn-2+i] = n0; + + if (cy != 0) + { + n1 += d1 + mpn_add_n (np + i, np + i, dp, dn - 1); + q--; + } + } + + if (qp) + qp[i] = q; + } + while (--i >= 0); + + np[dn - 1] = n1; +} + +static void +mpn_div_qr_preinv (mp_ptr qp, mp_ptr np, mp_size_t nn, + mp_srcptr dp, mp_size_t dn, + const struct gmp_div_inverse *inv) +{ + assert (dn > 0); + assert (nn >= dn); + + if (dn == 1) + np[0] = mpn_div_qr_1_preinv (qp, np, nn, inv); + else if (dn == 2) + mpn_div_qr_2_preinv (qp, np, nn, inv); + else + { + mp_limb_t nh; + unsigned shift; + + assert (inv->d1 == dp[dn-1]); + assert (inv->d0 == dp[dn-2]); + assert ((inv->d1 & GMP_LIMB_HIGHBIT) != 0); + + shift = inv->shift; + if (shift > 0) + nh = mpn_lshift (np, np, nn, shift); + else + nh = 0; + + mpn_div_qr_pi1 (qp, np, nn, nh, dp, dn, inv->di); + + if (shift > 0) + gmp_assert_nocarry (mpn_rshift (np, np, dn, shift)); + } +} + +static void +mpn_div_qr (mp_ptr qp, mp_ptr np, mp_size_t nn, mp_srcptr dp, mp_size_t dn) +{ + struct gmp_div_inverse inv; + mp_ptr tp = NULL; + + assert (dn > 0); + assert (nn >= dn); + + mpn_div_qr_invert (&inv, dp, dn); + if (dn > 2 && inv.shift > 0) + { + tp = gmp_alloc_limbs (dn); + gmp_assert_nocarry (mpn_lshift (tp, dp, dn, inv.shift)); + dp = tp; + } + mpn_div_qr_preinv (qp, np, nn, dp, dn, &inv); + if (tp) + gmp_free_limbs (tp, dn); +} + + +/* MPN base conversion. */ +static unsigned +mpn_base_power_of_two_p (unsigned b) +{ + switch (b) + { + case 2: return 1; + case 4: return 2; + case 8: return 3; + case 16: return 4; + case 32: return 5; + case 64: return 6; + case 128: return 7; + case 256: return 8; + default: return 0; + } +} + +struct mpn_base_info +{ + /* bb is the largest power of the base which fits in one limb, and + exp is the corresponding exponent. */ + unsigned exp; + mp_limb_t bb; +}; + +static void +mpn_get_base_info (struct mpn_base_info *info, mp_limb_t b) +{ + mp_limb_t m; + mp_limb_t p; + unsigned exp; + + m = GMP_LIMB_MAX / b; + for (exp = 1, p = b; p <= m; exp++) + p *= b; + + info->exp = exp; + info->bb = p; +} + +static mp_bitcnt_t +mpn_limb_size_in_base_2 (mp_limb_t u) +{ + unsigned shift; + + assert (u > 0); + gmp_clz (shift, u); + return GMP_LIMB_BITS - shift; +} + +static size_t +mpn_get_str_bits (unsigned char *sp, unsigned bits, mp_srcptr up, mp_size_t un) +{ + unsigned char mask; + size_t sn, j; + mp_size_t i; + unsigned shift; + + sn = ((un - 1) * GMP_LIMB_BITS + mpn_limb_size_in_base_2 (up[un-1]) + + bits - 1) / bits; + + mask = (1U << bits) - 1; + + for (i = 0, j = sn, shift = 0; j-- > 0;) + { + unsigned char digit = up[i] >> shift; + + shift += bits; + + if (shift >= GMP_LIMB_BITS && ++i < un) + { + shift -= GMP_LIMB_BITS; + digit |= up[i] << (bits - shift); + } + sp[j] = digit & mask; + } + return sn; +} + +/* We generate digits from the least significant end, and reverse at + the end. */ +static size_t +mpn_limb_get_str (unsigned char *sp, mp_limb_t w, + const struct gmp_div_inverse *binv) +{ + mp_size_t i; + for (i = 0; w > 0; i++) + { + mp_limb_t h, l, r; + + h = w >> (GMP_LIMB_BITS - binv->shift); + l = w << binv->shift; + + gmp_udiv_qrnnd_preinv (w, r, h, l, binv->d1, binv->di); + assert ((r & (GMP_LIMB_MAX >> (GMP_LIMB_BITS - binv->shift))) == 0); + r >>= binv->shift; + + sp[i] = r; + } + return i; +} + +static size_t +mpn_get_str_other (unsigned char *sp, + int base, const struct mpn_base_info *info, + mp_ptr up, mp_size_t un) +{ + struct gmp_div_inverse binv; + size_t sn; + size_t i; + + mpn_div_qr_1_invert (&binv, base); + + sn = 0; + + if (un > 1) + { + struct gmp_div_inverse bbinv; + mpn_div_qr_1_invert (&bbinv, info->bb); + + do + { + mp_limb_t w; + size_t done; + w = mpn_div_qr_1_preinv (up, up, un, &bbinv); + un -= (up[un-1] == 0); + done = mpn_limb_get_str (sp + sn, w, &binv); + + for (sn += done; done < info->exp; done++) + sp[sn++] = 0; + } + while (un > 1); + } + sn += mpn_limb_get_str (sp + sn, up[0], &binv); + + /* Reverse order */ + for (i = 0; 2*i + 1 < sn; i++) + { + unsigned char t = sp[i]; + sp[i] = sp[sn - i - 1]; + sp[sn - i - 1] = t; + } + + return sn; +} + +size_t +mpn_get_str (unsigned char *sp, int base, mp_ptr up, mp_size_t un) +{ + unsigned bits; + + assert (un > 0); + assert (up[un-1] > 0); + + bits = mpn_base_power_of_two_p (base); + if (bits) + return mpn_get_str_bits (sp, bits, up, un); + else + { + struct mpn_base_info info; + + mpn_get_base_info (&info, base); + return mpn_get_str_other (sp, base, &info, up, un); + } +} + +static mp_size_t +mpn_set_str_bits (mp_ptr rp, const unsigned char *sp, size_t sn, + unsigned bits) +{ + mp_size_t rn; + mp_limb_t limb; + unsigned shift; + + for (limb = 0, rn = 0, shift = 0; sn-- > 0; ) + { + limb |= (mp_limb_t) sp[sn] << shift; + shift += bits; + if (shift >= GMP_LIMB_BITS) + { + shift -= GMP_LIMB_BITS; + rp[rn++] = limb; + /* Next line is correct also if shift == 0, + bits == 8, and mp_limb_t == unsigned char. */ + limb = (unsigned int) sp[sn] >> (bits - shift); + } + } + if (limb != 0) + rp[rn++] = limb; + else + rn = mpn_normalized_size (rp, rn); + return rn; +} + +/* Result is usually normalized, except for all-zero input, in which + case a single zero limb is written at *RP, and 1 is returned. */ +static mp_size_t +mpn_set_str_other (mp_ptr rp, const unsigned char *sp, size_t sn, + mp_limb_t b, const struct mpn_base_info *info) +{ + mp_size_t rn; + mp_limb_t w; + unsigned k; + size_t j; + + assert (sn > 0); + + k = 1 + (sn - 1) % info->exp; + + j = 0; + w = sp[j++]; + while (--k != 0) + w = w * b + sp[j++]; + + rp[0] = w; + + for (rn = 1; j < sn;) + { + mp_limb_t cy; + + w = sp[j++]; + for (k = 1; k < info->exp; k++) + w = w * b + sp[j++]; + + cy = mpn_mul_1 (rp, rp, rn, info->bb); + cy += mpn_add_1 (rp, rp, rn, w); + if (cy > 0) + rp[rn++] = cy; + } + assert (j == sn); + + return rn; +} + +mp_size_t +mpn_set_str (mp_ptr rp, const unsigned char *sp, size_t sn, int base) +{ + unsigned bits; + + if (sn == 0) + return 0; + + bits = mpn_base_power_of_two_p (base); + if (bits) + return mpn_set_str_bits (rp, sp, sn, bits); + else + { + struct mpn_base_info info; + + mpn_get_base_info (&info, base); + return mpn_set_str_other (rp, sp, sn, base, &info); + } +} + + +/* MPZ interface */ +void +mpz_init (mpz_t r) +{ + static const mp_limb_t dummy_limb = GMP_LIMB_MAX & 0xc1a0; + + r->_mp_alloc = 0; + r->_mp_size = 0; + r->_mp_d = (mp_ptr) &dummy_limb; +} + +/* The utility of this function is a bit limited, since many functions + assigns the result variable using mpz_swap. */ +void +mpz_init2 (mpz_t r, mp_bitcnt_t bits) +{ + mp_size_t rn; + + bits -= (bits != 0); /* Round down, except if 0 */ + rn = 1 + bits / GMP_LIMB_BITS; + + r->_mp_alloc = rn; + r->_mp_size = 0; + r->_mp_d = gmp_alloc_limbs (rn); +} + +void +mpz_clear (mpz_t r) +{ + if (r->_mp_alloc) + gmp_free_limbs (r->_mp_d, r->_mp_alloc); +} + +static mp_ptr +mpz_realloc (mpz_t r, mp_size_t size) +{ + size = GMP_MAX (size, 1); + + if (r->_mp_alloc) + r->_mp_d = gmp_realloc_limbs (r->_mp_d, r->_mp_alloc, size); + else + r->_mp_d = gmp_alloc_limbs (size); + r->_mp_alloc = size; + + if (GMP_ABS (r->_mp_size) > size) + r->_mp_size = 0; + + return r->_mp_d; +} + +/* Realloc for an mpz_t WHAT if it has less than NEEDED limbs. */ +#define MPZ_REALLOC(z,n) ((n) > (z)->_mp_alloc \ + ? mpz_realloc(z,n) \ + : (z)->_mp_d) + +/* MPZ assignment and basic conversions. */ +void +mpz_set_si (mpz_t r, signed long int x) +{ + if (x >= 0) + mpz_set_ui (r, x); + else /* (x < 0) */ + if (GMP_LIMB_BITS < GMP_ULONG_BITS) + { + mpz_set_ui (r, GMP_NEG_CAST (unsigned long int, x)); + mpz_neg (r, r); + } + else + { + r->_mp_size = -1; + MPZ_REALLOC (r, 1)[0] = GMP_NEG_CAST (unsigned long int, x); + } +} + +void +mpz_set_ui (mpz_t r, unsigned long int x) +{ + if (x > 0) + { + r->_mp_size = 1; + MPZ_REALLOC (r, 1)[0] = x; + if (GMP_LIMB_BITS < GMP_ULONG_BITS) + { + int LOCAL_GMP_LIMB_BITS = GMP_LIMB_BITS; + while (x >>= LOCAL_GMP_LIMB_BITS) + { + ++ r->_mp_size; + MPZ_REALLOC (r, r->_mp_size)[r->_mp_size - 1] = x; + } + } + } + else + r->_mp_size = 0; +} + +void +mpz_set (mpz_t r, const mpz_t x) +{ + /* Allow the NOP r == x */ + if (r != x) + { + mp_size_t n; + mp_ptr rp; + + n = GMP_ABS (x->_mp_size); + rp = MPZ_REALLOC (r, n); + + mpn_copyi (rp, x->_mp_d, n); + r->_mp_size = x->_mp_size; + } +} + +void +mpz_init_set_si (mpz_t r, signed long int x) +{ + mpz_init (r); + mpz_set_si (r, x); +} + +void +mpz_init_set_ui (mpz_t r, unsigned long int x) +{ + mpz_init (r); + mpz_set_ui (r, x); +} + +void +mpz_init_set (mpz_t r, const mpz_t x) +{ + mpz_init (r); + mpz_set (r, x); +} + +int +mpz_fits_slong_p (const mpz_t u) +{ + return mpz_cmp_si (u, LONG_MAX) <= 0 && mpz_cmp_si (u, LONG_MIN) >= 0; +} + +static int +mpn_absfits_ulong_p (mp_srcptr up, mp_size_t un) +{ + int ulongsize = GMP_ULONG_BITS / GMP_LIMB_BITS; + mp_limb_t ulongrem = 0; + + if (GMP_ULONG_BITS % GMP_LIMB_BITS != 0) + ulongrem = (mp_limb_t) (ULONG_MAX >> GMP_LIMB_BITS * ulongsize) + 1; + + return un <= ulongsize || (up[ulongsize] < ulongrem && un == ulongsize + 1); +} + +int +mpz_fits_ulong_p (const mpz_t u) +{ + mp_size_t us = u->_mp_size; + + return us >= 0 && mpn_absfits_ulong_p (u->_mp_d, us); +} + +int +mpz_fits_sint_p (const mpz_t u) +{ + return mpz_cmp_si (u, INT_MAX) <= 0 && mpz_cmp_si (u, INT_MIN) >= 0; +} + +int +mpz_fits_uint_p (const mpz_t u) +{ + return u->_mp_size >= 0 && mpz_cmpabs_ui (u, UINT_MAX) <= 0; +} + +int +mpz_fits_sshort_p (const mpz_t u) +{ + return mpz_cmp_si (u, SHRT_MAX) <= 0 && mpz_cmp_si (u, SHRT_MIN) >= 0; +} + +int +mpz_fits_ushort_p (const mpz_t u) +{ + return u->_mp_size >= 0 && mpz_cmpabs_ui (u, USHRT_MAX) <= 0; +} + +long int +mpz_get_si (const mpz_t u) +{ + unsigned long r = mpz_get_ui (u); + unsigned long c = -LONG_MAX - LONG_MIN; + + if (u->_mp_size < 0) + /* This expression is necessary to properly handle -LONG_MIN */ + return -(long) c - (long) ((r - c) & LONG_MAX); + else + return (long) (r & LONG_MAX); +} + +unsigned long int +mpz_get_ui (const mpz_t u) +{ + if (GMP_LIMB_BITS < GMP_ULONG_BITS) + { + int LOCAL_GMP_LIMB_BITS = GMP_LIMB_BITS; + unsigned long r = 0; + mp_size_t n = GMP_ABS (u->_mp_size); + n = GMP_MIN (n, 1 + (mp_size_t) (GMP_ULONG_BITS - 1) / GMP_LIMB_BITS); + while (--n >= 0) + r = (r << LOCAL_GMP_LIMB_BITS) + u->_mp_d[n]; + return r; + } + + return u->_mp_size == 0 ? 0 : u->_mp_d[0]; +} + +size_t +mpz_size (const mpz_t u) +{ + return GMP_ABS (u->_mp_size); +} + +mp_limb_t +mpz_getlimbn (const mpz_t u, mp_size_t n) +{ + if (n >= 0 && n < GMP_ABS (u->_mp_size)) + return u->_mp_d[n]; + else + return 0; +} + +void +mpz_realloc2 (mpz_t x, mp_bitcnt_t n) +{ + mpz_realloc (x, 1 + (n - (n != 0)) / GMP_LIMB_BITS); +} + +mp_srcptr +mpz_limbs_read (mpz_srcptr x) +{ + return x->_mp_d; +} + +mp_ptr +mpz_limbs_modify (mpz_t x, mp_size_t n) +{ + assert (n > 0); + return MPZ_REALLOC (x, n); +} + +mp_ptr +mpz_limbs_write (mpz_t x, mp_size_t n) +{ + return mpz_limbs_modify (x, n); +} + +void +mpz_limbs_finish (mpz_t x, mp_size_t xs) +{ + mp_size_t xn; + xn = mpn_normalized_size (x->_mp_d, GMP_ABS (xs)); + x->_mp_size = xs < 0 ? -xn : xn; +} + +static mpz_srcptr +mpz_roinit_normal_n (mpz_t x, mp_srcptr xp, mp_size_t xs) +{ + x->_mp_alloc = 0; + x->_mp_d = (mp_ptr) xp; + x->_mp_size = xs; + return x; +} + +mpz_srcptr +mpz_roinit_n (mpz_t x, mp_srcptr xp, mp_size_t xs) +{ + mpz_roinit_normal_n (x, xp, xs); + mpz_limbs_finish (x, xs); + return x; +} + + +/* Conversions and comparison to double. */ +void +mpz_set_d (mpz_t r, double x) +{ + int sign; + mp_ptr rp; + mp_size_t rn, i; + double B; + double Bi; + mp_limb_t f; + + /* x != x is true when x is a NaN, and x == x * 0.5 is true when x is + zero or infinity. */ + if (x != x || x == x * 0.5) + { + r->_mp_size = 0; + return; + } + + sign = x < 0.0 ; + if (sign) + x = - x; + + if (x < 1.0) + { + r->_mp_size = 0; + return; + } + B = 4.0 * (double) (GMP_LIMB_HIGHBIT >> 1); + Bi = 1.0 / B; + for (rn = 1; x >= B; rn++) + x *= Bi; + + rp = MPZ_REALLOC (r, rn); + + f = (mp_limb_t) x; + x -= f; + assert (x < 1.0); + i = rn-1; + rp[i] = f; + while (--i >= 0) + { + x = B * x; + f = (mp_limb_t) x; + x -= f; + assert (x < 1.0); + rp[i] = f; + } + + r->_mp_size = sign ? - rn : rn; +} + +void +mpz_init_set_d (mpz_t r, double x) +{ + mpz_init (r); + mpz_set_d (r, x); +} + +double +mpz_get_d (const mpz_t u) +{ + int m; + mp_limb_t l; + mp_size_t un; + double x; + double B = 4.0 * (double) (GMP_LIMB_HIGHBIT >> 1); + + un = GMP_ABS (u->_mp_size); + + if (un == 0) + return 0.0; + + l = u->_mp_d[--un]; + gmp_clz (m, l); + m = m + GMP_DBL_MANT_BITS - GMP_LIMB_BITS; + if (m < 0) + l &= GMP_LIMB_MAX << -m; + + for (x = l; --un >= 0;) + { + x = B*x; + if (m > 0) { + l = u->_mp_d[un]; + m -= GMP_LIMB_BITS; + if (m < 0) + l &= GMP_LIMB_MAX << -m; + x += l; + } + } + + if (u->_mp_size < 0) + x = -x; + + return x; +} + +int +mpz_cmpabs_d (const mpz_t x, double d) +{ + mp_size_t xn; + double B, Bi; + mp_size_t i; + + xn = x->_mp_size; + d = GMP_ABS (d); + + if (xn != 0) + { + xn = GMP_ABS (xn); + + B = 4.0 * (double) (GMP_LIMB_HIGHBIT >> 1); + Bi = 1.0 / B; + + /* Scale d so it can be compared with the top limb. */ + for (i = 1; i < xn; i++) + d *= Bi; + + if (d >= B) + return -1; + + /* Compare floor(d) to top limb, subtract and cancel when equal. */ + for (i = xn; i-- > 0;) + { + mp_limb_t f, xl; + + f = (mp_limb_t) d; + xl = x->_mp_d[i]; + if (xl > f) + return 1; + else if (xl < f) + return -1; + d = B * (d - f); + } + } + return - (d > 0.0); +} + +int +mpz_cmp_d (const mpz_t x, double d) +{ + if (x->_mp_size < 0) + { + if (d >= 0.0) + return -1; + else + return -mpz_cmpabs_d (x, d); + } + else + { + if (d < 0.0) + return 1; + else + return mpz_cmpabs_d (x, d); + } +} + + +/* MPZ comparisons and the like. */ +int +mpz_sgn (const mpz_t u) +{ + return GMP_CMP (u->_mp_size, 0); +} + +int +mpz_cmp_si (const mpz_t u, long v) +{ + mp_size_t usize = u->_mp_size; + + if (v >= 0) + return mpz_cmp_ui (u, v); + else if (usize >= 0) + return 1; + else + return - mpz_cmpabs_ui (u, GMP_NEG_CAST (unsigned long int, v)); +} + +int +mpz_cmp_ui (const mpz_t u, unsigned long v) +{ + mp_size_t usize = u->_mp_size; + + if (usize < 0) + return -1; + else + return mpz_cmpabs_ui (u, v); +} + +int +mpz_cmp (const mpz_t a, const mpz_t b) +{ + mp_size_t asize = a->_mp_size; + mp_size_t bsize = b->_mp_size; + + if (asize != bsize) + return (asize < bsize) ? -1 : 1; + else if (asize >= 0) + return mpn_cmp (a->_mp_d, b->_mp_d, asize); + else + return mpn_cmp (b->_mp_d, a->_mp_d, -asize); +} + +int +mpz_cmpabs_ui (const mpz_t u, unsigned long v) +{ + mp_size_t un = GMP_ABS (u->_mp_size); + + if (! mpn_absfits_ulong_p (u->_mp_d, un)) + return 1; + else + { + unsigned long uu = mpz_get_ui (u); + return GMP_CMP(uu, v); + } +} + +int +mpz_cmpabs (const mpz_t u, const mpz_t v) +{ + return mpn_cmp4 (u->_mp_d, GMP_ABS (u->_mp_size), + v->_mp_d, GMP_ABS (v->_mp_size)); +} + +void +mpz_abs (mpz_t r, const mpz_t u) +{ + mpz_set (r, u); + r->_mp_size = GMP_ABS (r->_mp_size); +} + +void +mpz_neg (mpz_t r, const mpz_t u) +{ + mpz_set (r, u); + r->_mp_size = -r->_mp_size; +} + +void +mpz_swap (mpz_t u, mpz_t v) +{ + MP_SIZE_T_SWAP (u->_mp_alloc, v->_mp_alloc); + MPN_PTR_SWAP (u->_mp_d, u->_mp_size, v->_mp_d, v->_mp_size); +} + + +/* MPZ addition and subtraction */ + + +void +mpz_add_ui (mpz_t r, const mpz_t a, unsigned long b) +{ + mpz_t bb; + mpz_init_set_ui (bb, b); + mpz_add (r, a, bb); + mpz_clear (bb); +} + +void +mpz_sub_ui (mpz_t r, const mpz_t a, unsigned long b) +{ + mpz_ui_sub (r, b, a); + mpz_neg (r, r); +} + +void +mpz_ui_sub (mpz_t r, unsigned long a, const mpz_t b) +{ + mpz_neg (r, b); + mpz_add_ui (r, r, a); +} + +static mp_size_t +mpz_abs_add (mpz_t r, const mpz_t a, const mpz_t b) +{ + mp_size_t an = GMP_ABS (a->_mp_size); + mp_size_t bn = GMP_ABS (b->_mp_size); + mp_ptr rp; + mp_limb_t cy; + + if (an < bn) + { + MPZ_SRCPTR_SWAP (a, b); + MP_SIZE_T_SWAP (an, bn); + } + + rp = MPZ_REALLOC (r, an + 1); + cy = mpn_add (rp, a->_mp_d, an, b->_mp_d, bn); + + rp[an] = cy; + + return an + cy; +} + +static mp_size_t +mpz_abs_sub (mpz_t r, const mpz_t a, const mpz_t b) +{ + mp_size_t an = GMP_ABS (a->_mp_size); + mp_size_t bn = GMP_ABS (b->_mp_size); + int cmp; + mp_ptr rp; + + cmp = mpn_cmp4 (a->_mp_d, an, b->_mp_d, bn); + if (cmp > 0) + { + rp = MPZ_REALLOC (r, an); + gmp_assert_nocarry (mpn_sub (rp, a->_mp_d, an, b->_mp_d, bn)); + return mpn_normalized_size (rp, an); + } + else if (cmp < 0) + { + rp = MPZ_REALLOC (r, bn); + gmp_assert_nocarry (mpn_sub (rp, b->_mp_d, bn, a->_mp_d, an)); + return -mpn_normalized_size (rp, bn); + } + else + return 0; +} + +void +mpz_add (mpz_t r, const mpz_t a, const mpz_t b) +{ + mp_size_t rn; + + if ( (a->_mp_size ^ b->_mp_size) >= 0) + rn = mpz_abs_add (r, a, b); + else + rn = mpz_abs_sub (r, a, b); + + r->_mp_size = a->_mp_size >= 0 ? rn : - rn; +} + +void +mpz_sub (mpz_t r, const mpz_t a, const mpz_t b) +{ + mp_size_t rn; + + if ( (a->_mp_size ^ b->_mp_size) >= 0) + rn = mpz_abs_sub (r, a, b); + else + rn = mpz_abs_add (r, a, b); + + r->_mp_size = a->_mp_size >= 0 ? rn : - rn; +} + + +/* MPZ multiplication */ +void +mpz_mul_si (mpz_t r, const mpz_t u, long int v) +{ + if (v < 0) + { + mpz_mul_ui (r, u, GMP_NEG_CAST (unsigned long int, v)); + mpz_neg (r, r); + } + else + mpz_mul_ui (r, u, v); +} + +void +mpz_mul_ui (mpz_t r, const mpz_t u, unsigned long int v) +{ + mpz_t vv; + mpz_init_set_ui (vv, v); + mpz_mul (r, u, vv); + mpz_clear (vv); + return; +} + +void +mpz_mul (mpz_t r, const mpz_t u, const mpz_t v) +{ + int sign; + mp_size_t un, vn, rn; + mpz_t t; + mp_ptr tp; + + un = u->_mp_size; + vn = v->_mp_size; + + if (un == 0 || vn == 0) + { + r->_mp_size = 0; + return; + } + + sign = (un ^ vn) < 0; + + un = GMP_ABS (un); + vn = GMP_ABS (vn); + + mpz_init2 (t, (un + vn) * GMP_LIMB_BITS); + + tp = t->_mp_d; + if (un >= vn) + mpn_mul (tp, u->_mp_d, un, v->_mp_d, vn); + else + mpn_mul (tp, v->_mp_d, vn, u->_mp_d, un); + + rn = un + vn; + rn -= tp[rn-1] == 0; + + t->_mp_size = sign ? - rn : rn; + mpz_swap (r, t); + mpz_clear (t); +} + +void +mpz_mul_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t bits) +{ + mp_size_t un, rn; + mp_size_t limbs; + unsigned shift; + mp_ptr rp; + + un = GMP_ABS (u->_mp_size); + if (un == 0) + { + r->_mp_size = 0; + return; + } + + limbs = bits / GMP_LIMB_BITS; + shift = bits % GMP_LIMB_BITS; + + rn = un + limbs + (shift > 0); + rp = MPZ_REALLOC (r, rn); + if (shift > 0) + { + mp_limb_t cy = mpn_lshift (rp + limbs, u->_mp_d, un, shift); + rp[rn-1] = cy; + rn -= (cy == 0); + } + else + mpn_copyd (rp + limbs, u->_mp_d, un); + + mpn_zero (rp, limbs); + + r->_mp_size = (u->_mp_size < 0) ? - rn : rn; +} + +void +mpz_addmul_ui (mpz_t r, const mpz_t u, unsigned long int v) +{ + mpz_t t; + mpz_init_set_ui (t, v); + mpz_mul (t, u, t); + mpz_add (r, r, t); + mpz_clear (t); +} + +void +mpz_submul_ui (mpz_t r, const mpz_t u, unsigned long int v) +{ + mpz_t t; + mpz_init_set_ui (t, v); + mpz_mul (t, u, t); + mpz_sub (r, r, t); + mpz_clear (t); +} + +void +mpz_addmul (mpz_t r, const mpz_t u, const mpz_t v) +{ + mpz_t t; + mpz_init (t); + mpz_mul (t, u, v); + mpz_add (r, r, t); + mpz_clear (t); +} + +void +mpz_submul (mpz_t r, const mpz_t u, const mpz_t v) +{ + mpz_t t; + mpz_init (t); + mpz_mul (t, u, v); + mpz_sub (r, r, t); + mpz_clear (t); +} + + +/* MPZ division */ +enum mpz_div_round_mode { GMP_DIV_FLOOR, GMP_DIV_CEIL, GMP_DIV_TRUNC }; + +/* Allows q or r to be zero. Returns 1 iff remainder is non-zero. */ +static int +mpz_div_qr (mpz_t q, mpz_t r, + const mpz_t n, const mpz_t d, enum mpz_div_round_mode mode) +{ + mp_size_t ns, ds, nn, dn, qs; + ns = n->_mp_size; + ds = d->_mp_size; + + if (ds == 0) + gmp_die("mpz_div_qr: Divide by zero."); + + if (ns == 0) + { + if (q) + q->_mp_size = 0; + if (r) + r->_mp_size = 0; + return 0; + } + + nn = GMP_ABS (ns); + dn = GMP_ABS (ds); + + qs = ds ^ ns; + + if (nn < dn) + { + if (mode == GMP_DIV_CEIL && qs >= 0) + { + /* q = 1, r = n - d */ + if (r) + mpz_sub (r, n, d); + if (q) + mpz_set_ui (q, 1); + } + else if (mode == GMP_DIV_FLOOR && qs < 0) + { + /* q = -1, r = n + d */ + if (r) + mpz_add (r, n, d); + if (q) + mpz_set_si (q, -1); + } + else + { + /* q = 0, r = d */ + if (r) + mpz_set (r, n); + if (q) + q->_mp_size = 0; + } + return 1; + } + else + { + mp_ptr np, qp; + mp_size_t qn, rn; + mpz_t tq, tr; + + mpz_init_set (tr, n); + np = tr->_mp_d; + + qn = nn - dn + 1; + + if (q) + { + mpz_init2 (tq, qn * GMP_LIMB_BITS); + qp = tq->_mp_d; + } + else + qp = NULL; + + mpn_div_qr (qp, np, nn, d->_mp_d, dn); + + if (qp) + { + qn -= (qp[qn-1] == 0); + + tq->_mp_size = qs < 0 ? -qn : qn; + } + rn = mpn_normalized_size (np, dn); + tr->_mp_size = ns < 0 ? - rn : rn; + + if (mode == GMP_DIV_FLOOR && qs < 0 && rn != 0) + { + if (q) + mpz_sub_ui (tq, tq, 1); + if (r) + mpz_add (tr, tr, d); + } + else if (mode == GMP_DIV_CEIL && qs >= 0 && rn != 0) + { + if (q) + mpz_add_ui (tq, tq, 1); + if (r) + mpz_sub (tr, tr, d); + } + + if (q) + { + mpz_swap (tq, q); + mpz_clear (tq); + } + if (r) + mpz_swap (tr, r); + + mpz_clear (tr); + + return rn != 0; + } +} + +void +mpz_cdiv_qr (mpz_t q, mpz_t r, const mpz_t n, const mpz_t d) +{ + mpz_div_qr (q, r, n, d, GMP_DIV_CEIL); +} + +void +mpz_fdiv_qr (mpz_t q, mpz_t r, const mpz_t n, const mpz_t d) +{ + mpz_div_qr (q, r, n, d, GMP_DIV_FLOOR); +} + +void +mpz_tdiv_qr (mpz_t q, mpz_t r, const mpz_t n, const mpz_t d) +{ + mpz_div_qr (q, r, n, d, GMP_DIV_TRUNC); +} + +void +mpz_cdiv_q (mpz_t q, const mpz_t n, const mpz_t d) +{ + mpz_div_qr (q, NULL, n, d, GMP_DIV_CEIL); +} + +void +mpz_fdiv_q (mpz_t q, const mpz_t n, const mpz_t d) +{ + mpz_div_qr (q, NULL, n, d, GMP_DIV_FLOOR); +} + +void +mpz_tdiv_q (mpz_t q, const mpz_t n, const mpz_t d) +{ + mpz_div_qr (q, NULL, n, d, GMP_DIV_TRUNC); +} + +void +mpz_cdiv_r (mpz_t r, const mpz_t n, const mpz_t d) +{ + mpz_div_qr (NULL, r, n, d, GMP_DIV_CEIL); +} + +void +mpz_fdiv_r (mpz_t r, const mpz_t n, const mpz_t d) +{ + mpz_div_qr (NULL, r, n, d, GMP_DIV_FLOOR); +} + +void +mpz_tdiv_r (mpz_t r, const mpz_t n, const mpz_t d) +{ + mpz_div_qr (NULL, r, n, d, GMP_DIV_TRUNC); +} + +void +mpz_mod (mpz_t r, const mpz_t n, const mpz_t d) +{ + mpz_div_qr (NULL, r, n, d, d->_mp_size >= 0 ? GMP_DIV_FLOOR : GMP_DIV_CEIL); +} + +static void +mpz_div_q_2exp (mpz_t q, const mpz_t u, mp_bitcnt_t bit_index, + enum mpz_div_round_mode mode) +{ + mp_size_t un, qn; + mp_size_t limb_cnt; + mp_ptr qp; + int adjust; + + un = u->_mp_size; + if (un == 0) + { + q->_mp_size = 0; + return; + } + limb_cnt = bit_index / GMP_LIMB_BITS; + qn = GMP_ABS (un) - limb_cnt; + bit_index %= GMP_LIMB_BITS; + + if (mode == ((un > 0) ? GMP_DIV_CEIL : GMP_DIV_FLOOR)) /* un != 0 here. */ + /* Note: Below, the final indexing at limb_cnt is valid because at + that point we have qn > 0. */ + adjust = (qn <= 0 + || !mpn_zero_p (u->_mp_d, limb_cnt) + || (u->_mp_d[limb_cnt] + & (((mp_limb_t) 1 << bit_index) - 1))); + else + adjust = 0; + + if (qn <= 0) + qn = 0; + else + { + qp = MPZ_REALLOC (q, qn); + + if (bit_index != 0) + { + mpn_rshift (qp, u->_mp_d + limb_cnt, qn, bit_index); + qn -= qp[qn - 1] == 0; + } + else + { + mpn_copyi (qp, u->_mp_d + limb_cnt, qn); + } + } + + q->_mp_size = qn; + + if (adjust) + mpz_add_ui (q, q, 1); + if (un < 0) + mpz_neg (q, q); +} + +static void +mpz_div_r_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t bit_index, + enum mpz_div_round_mode mode) +{ + mp_size_t us, un, rn; + mp_ptr rp; + mp_limb_t mask; + + us = u->_mp_size; + if (us == 0 || bit_index == 0) + { + r->_mp_size = 0; + return; + } + rn = (bit_index + GMP_LIMB_BITS - 1) / GMP_LIMB_BITS; + assert (rn > 0); + + rp = MPZ_REALLOC (r, rn); + un = GMP_ABS (us); + + mask = GMP_LIMB_MAX >> (rn * GMP_LIMB_BITS - bit_index); + + if (rn > un) + { + /* Quotient (with truncation) is zero, and remainder is + non-zero */ + if (mode == ((us > 0) ? GMP_DIV_CEIL : GMP_DIV_FLOOR)) /* us != 0 here. */ + { + /* Have to negate and sign extend. */ + mp_size_t i; + + gmp_assert_nocarry (! mpn_neg (rp, u->_mp_d, un)); + for (i = un; i < rn - 1; i++) + rp[i] = GMP_LIMB_MAX; + + rp[rn-1] = mask; + us = -us; + } + else + { + /* Just copy */ + if (r != u) + mpn_copyi (rp, u->_mp_d, un); + + rn = un; + } + } + else + { + if (r != u) + mpn_copyi (rp, u->_mp_d, rn - 1); + + rp[rn-1] = u->_mp_d[rn-1] & mask; + + if (mode == ((us > 0) ? GMP_DIV_CEIL : GMP_DIV_FLOOR)) /* us != 0 here. */ + { + /* If r != 0, compute 2^{bit_count} - r. */ + mpn_neg (rp, rp, rn); + + rp[rn-1] &= mask; + + /* us is not used for anything else, so we can modify it + here to indicate flipped sign. */ + us = -us; + } + } + rn = mpn_normalized_size (rp, rn); + r->_mp_size = us < 0 ? -rn : rn; +} + +void +mpz_cdiv_q_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t cnt) +{ + mpz_div_q_2exp (r, u, cnt, GMP_DIV_CEIL); +} + +void +mpz_fdiv_q_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t cnt) +{ + mpz_div_q_2exp (r, u, cnt, GMP_DIV_FLOOR); +} + +void +mpz_tdiv_q_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t cnt) +{ + mpz_div_q_2exp (r, u, cnt, GMP_DIV_TRUNC); +} + +void +mpz_cdiv_r_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t cnt) +{ + mpz_div_r_2exp (r, u, cnt, GMP_DIV_CEIL); +} + +void +mpz_fdiv_r_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t cnt) +{ + mpz_div_r_2exp (r, u, cnt, GMP_DIV_FLOOR); +} + +void +mpz_tdiv_r_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t cnt) +{ + mpz_div_r_2exp (r, u, cnt, GMP_DIV_TRUNC); +} + +void +mpz_divexact (mpz_t q, const mpz_t n, const mpz_t d) +{ + gmp_assert_nocarry (mpz_div_qr (q, NULL, n, d, GMP_DIV_TRUNC)); +} + +int +mpz_divisible_p (const mpz_t n, const mpz_t d) +{ + return mpz_div_qr (NULL, NULL, n, d, GMP_DIV_TRUNC) == 0; +} + +int +mpz_congruent_p (const mpz_t a, const mpz_t b, const mpz_t m) +{ + mpz_t t; + int res; + + /* a == b (mod 0) iff a == b */ + if (mpz_sgn (m) == 0) + return (mpz_cmp (a, b) == 0); + + mpz_init (t); + mpz_sub (t, a, b); + res = mpz_divisible_p (t, m); + mpz_clear (t); + + return res; +} + +static unsigned long +mpz_div_qr_ui (mpz_t q, mpz_t r, + const mpz_t n, unsigned long d, enum mpz_div_round_mode mode) +{ + unsigned long ret; + mpz_t rr, dd; + + mpz_init (rr); + mpz_init_set_ui (dd, d); + mpz_div_qr (q, rr, n, dd, mode); + mpz_clear (dd); + ret = mpz_get_ui (rr); + + if (r) + mpz_swap (r, rr); + mpz_clear (rr); + + return ret; +} + +unsigned long +mpz_cdiv_qr_ui (mpz_t q, mpz_t r, const mpz_t n, unsigned long d) +{ + return mpz_div_qr_ui (q, r, n, d, GMP_DIV_CEIL); +} + +unsigned long +mpz_fdiv_qr_ui (mpz_t q, mpz_t r, const mpz_t n, unsigned long d) +{ + return mpz_div_qr_ui (q, r, n, d, GMP_DIV_FLOOR); +} + +unsigned long +mpz_tdiv_qr_ui (mpz_t q, mpz_t r, const mpz_t n, unsigned long d) +{ + return mpz_div_qr_ui (q, r, n, d, GMP_DIV_TRUNC); +} + +unsigned long +mpz_cdiv_q_ui (mpz_t q, const mpz_t n, unsigned long d) +{ + return mpz_div_qr_ui (q, NULL, n, d, GMP_DIV_CEIL); +} + +unsigned long +mpz_fdiv_q_ui (mpz_t q, const mpz_t n, unsigned long d) +{ + return mpz_div_qr_ui (q, NULL, n, d, GMP_DIV_FLOOR); +} + +unsigned long +mpz_tdiv_q_ui (mpz_t q, const mpz_t n, unsigned long d) +{ + return mpz_div_qr_ui (q, NULL, n, d, GMP_DIV_TRUNC); +} + +unsigned long +mpz_cdiv_r_ui (mpz_t r, const mpz_t n, unsigned long d) +{ + return mpz_div_qr_ui (NULL, r, n, d, GMP_DIV_CEIL); +} +unsigned long +mpz_fdiv_r_ui (mpz_t r, const mpz_t n, unsigned long d) +{ + return mpz_div_qr_ui (NULL, r, n, d, GMP_DIV_FLOOR); +} +unsigned long +mpz_tdiv_r_ui (mpz_t r, const mpz_t n, unsigned long d) +{ + return mpz_div_qr_ui (NULL, r, n, d, GMP_DIV_TRUNC); +} + +unsigned long +mpz_cdiv_ui (const mpz_t n, unsigned long d) +{ + return mpz_div_qr_ui (NULL, NULL, n, d, GMP_DIV_CEIL); +} + +unsigned long +mpz_fdiv_ui (const mpz_t n, unsigned long d) +{ + return mpz_div_qr_ui (NULL, NULL, n, d, GMP_DIV_FLOOR); +} + +unsigned long +mpz_tdiv_ui (const mpz_t n, unsigned long d) +{ + return mpz_div_qr_ui (NULL, NULL, n, d, GMP_DIV_TRUNC); +} + +unsigned long +mpz_mod_ui (mpz_t r, const mpz_t n, unsigned long d) +{ + return mpz_div_qr_ui (NULL, r, n, d, GMP_DIV_FLOOR); +} + +void +mpz_divexact_ui (mpz_t q, const mpz_t n, unsigned long d) +{ + gmp_assert_nocarry (mpz_div_qr_ui (q, NULL, n, d, GMP_DIV_TRUNC)); +} + +int +mpz_divisible_ui_p (const mpz_t n, unsigned long d) +{ + return mpz_div_qr_ui (NULL, NULL, n, d, GMP_DIV_TRUNC) == 0; +} + + +/* GCD */ +static mp_limb_t +mpn_gcd_11 (mp_limb_t u, mp_limb_t v) +{ + unsigned shift; + + assert ( (u | v) > 0); + + if (u == 0) + return v; + else if (v == 0) + return u; + + gmp_ctz (shift, u | v); + + u >>= shift; + v >>= shift; + + if ( (u & 1) == 0) + MP_LIMB_T_SWAP (u, v); + + while ( (v & 1) == 0) + v >>= 1; + + while (u != v) + { + if (u > v) + { + u -= v; + do + u >>= 1; + while ( (u & 1) == 0); + } + else + { + v -= u; + do + v >>= 1; + while ( (v & 1) == 0); + } + } + return u << shift; +} + +unsigned long +mpz_gcd_ui (mpz_t g, const mpz_t u, unsigned long v) +{ + mpz_t t; + mpz_init_set_ui(t, v); + mpz_gcd (t, u, t); + if (v > 0) + v = mpz_get_ui (t); + + if (g) + mpz_swap (t, g); + + mpz_clear (t); + + return v; +} + +static mp_bitcnt_t +mpz_make_odd (mpz_t r) +{ + mp_bitcnt_t shift; + + assert (r->_mp_size > 0); + /* Count trailing zeros, equivalent to mpn_scan1, because we know that there is a 1 */ + shift = mpn_scan1 (r->_mp_d, 0); + mpz_tdiv_q_2exp (r, r, shift); + + return shift; +} + +void +mpz_gcd (mpz_t g, const mpz_t u, const mpz_t v) +{ + mpz_t tu, tv; + mp_bitcnt_t uz, vz, gz; + + if (u->_mp_size == 0) + { + mpz_abs (g, v); + return; + } + if (v->_mp_size == 0) + { + mpz_abs (g, u); + return; + } + + mpz_init (tu); + mpz_init (tv); + + mpz_abs (tu, u); + uz = mpz_make_odd (tu); + mpz_abs (tv, v); + vz = mpz_make_odd (tv); + gz = GMP_MIN (uz, vz); + + if (tu->_mp_size < tv->_mp_size) + mpz_swap (tu, tv); + + mpz_tdiv_r (tu, tu, tv); + if (tu->_mp_size == 0) + { + mpz_swap (g, tv); + } + else + for (;;) + { + int c; + + mpz_make_odd (tu); + c = mpz_cmp (tu, tv); + if (c == 0) + { + mpz_swap (g, tu); + break; + } + if (c < 0) + mpz_swap (tu, tv); + + if (tv->_mp_size == 1) + { + mp_limb_t *gp; + + mpz_tdiv_r (tu, tu, tv); + gp = MPZ_REALLOC (g, 1); /* gp = mpz_limbs_modify (g, 1); */ + *gp = mpn_gcd_11 (tu->_mp_d[0], tv->_mp_d[0]); + + g->_mp_size = *gp != 0; /* mpz_limbs_finish (g, 1); */ + break; + } + mpz_sub (tu, tu, tv); + } + mpz_clear (tu); + mpz_clear (tv); + mpz_mul_2exp (g, g, gz); +} + +void +mpz_gcdext (mpz_t g, mpz_t s, mpz_t t, const mpz_t u, const mpz_t v) +{ + mpz_t tu, tv, s0, s1, t0, t1; + mp_bitcnt_t uz, vz, gz; + mp_bitcnt_t power; + + if (u->_mp_size == 0) + { + /* g = 0 u + sgn(v) v */ + signed long sign = mpz_sgn (v); + mpz_abs (g, v); + if (s) + s->_mp_size = 0; + if (t) + mpz_set_si (t, sign); + return; + } + + if (v->_mp_size == 0) + { + /* g = sgn(u) u + 0 v */ + signed long sign = mpz_sgn (u); + mpz_abs (g, u); + if (s) + mpz_set_si (s, sign); + if (t) + t->_mp_size = 0; + return; + } + + mpz_init (tu); + mpz_init (tv); + mpz_init (s0); + mpz_init (s1); + mpz_init (t0); + mpz_init (t1); + + mpz_abs (tu, u); + uz = mpz_make_odd (tu); + mpz_abs (tv, v); + vz = mpz_make_odd (tv); + gz = GMP_MIN (uz, vz); + + uz -= gz; + vz -= gz; + + /* Cofactors corresponding to odd gcd. gz handled later. */ + if (tu->_mp_size < tv->_mp_size) + { + mpz_swap (tu, tv); + MPZ_SRCPTR_SWAP (u, v); + MPZ_PTR_SWAP (s, t); + MP_BITCNT_T_SWAP (uz, vz); + } + + /* Maintain + * + * u = t0 tu + t1 tv + * v = s0 tu + s1 tv + * + * where u and v denote the inputs with common factors of two + * eliminated, and det (s0, t0; s1, t1) = 2^p. Then + * + * 2^p tu = s1 u - t1 v + * 2^p tv = -s0 u + t0 v + */ + + /* After initial division, tu = q tv + tu', we have + * + * u = 2^uz (tu' + q tv) + * v = 2^vz tv + * + * or + * + * t0 = 2^uz, t1 = 2^uz q + * s0 = 0, s1 = 2^vz + */ + + mpz_tdiv_qr (t1, tu, tu, tv); + mpz_mul_2exp (t1, t1, uz); + + mpz_setbit (s1, vz); + power = uz + vz; + + if (tu->_mp_size > 0) + { + mp_bitcnt_t shift; + shift = mpz_make_odd (tu); + mpz_setbit (t0, uz + shift); + power += shift; + + for (;;) + { + int c; + c = mpz_cmp (tu, tv); + if (c == 0) + break; + + if (c < 0) + { + /* tv = tv' + tu + * + * u = t0 tu + t1 (tv' + tu) = (t0 + t1) tu + t1 tv' + * v = s0 tu + s1 (tv' + tu) = (s0 + s1) tu + s1 tv' */ + + mpz_sub (tv, tv, tu); + mpz_add (t0, t0, t1); + mpz_add (s0, s0, s1); + + shift = mpz_make_odd (tv); + mpz_mul_2exp (t1, t1, shift); + mpz_mul_2exp (s1, s1, shift); + } + else + { + mpz_sub (tu, tu, tv); + mpz_add (t1, t0, t1); + mpz_add (s1, s0, s1); + + shift = mpz_make_odd (tu); + mpz_mul_2exp (t0, t0, shift); + mpz_mul_2exp (s0, s0, shift); + } + power += shift; + } + } + else + mpz_setbit (t0, uz); + + /* Now tv = odd part of gcd, and -s0 and t0 are corresponding + cofactors. */ + + mpz_mul_2exp (tv, tv, gz); + mpz_neg (s0, s0); + + /* 2^p g = s0 u + t0 v. Eliminate one factor of two at a time. To + adjust cofactors, we need u / g and v / g */ + + mpz_divexact (s1, v, tv); + mpz_abs (s1, s1); + mpz_divexact (t1, u, tv); + mpz_abs (t1, t1); + + while (power-- > 0) + { + /* s0 u + t0 v = (s0 - v/g) u - (t0 + u/g) v */ + if (mpz_odd_p (s0) || mpz_odd_p (t0)) + { + mpz_sub (s0, s0, s1); + mpz_add (t0, t0, t1); + } + assert (mpz_even_p (t0) && mpz_even_p (s0)); + mpz_tdiv_q_2exp (s0, s0, 1); + mpz_tdiv_q_2exp (t0, t0, 1); + } + + /* Arrange so that |s| < |u| / 2g */ + mpz_add (s1, s0, s1); + if (mpz_cmpabs (s0, s1) > 0) + { + mpz_swap (s0, s1); + mpz_sub (t0, t0, t1); + } + if (u->_mp_size < 0) + mpz_neg (s0, s0); + if (v->_mp_size < 0) + mpz_neg (t0, t0); + + mpz_swap (g, tv); + if (s) + mpz_swap (s, s0); + if (t) + mpz_swap (t, t0); + + mpz_clear (tu); + mpz_clear (tv); + mpz_clear (s0); + mpz_clear (s1); + mpz_clear (t0); + mpz_clear (t1); +} + +void +mpz_lcm (mpz_t r, const mpz_t u, const mpz_t v) +{ + mpz_t g; + + if (u->_mp_size == 0 || v->_mp_size == 0) + { + r->_mp_size = 0; + return; + } + + mpz_init (g); + + mpz_gcd (g, u, v); + mpz_divexact (g, u, g); + mpz_mul (r, g, v); + + mpz_clear (g); + mpz_abs (r, r); +} + +void +mpz_lcm_ui (mpz_t r, const mpz_t u, unsigned long v) +{ + if (v == 0 || u->_mp_size == 0) + { + r->_mp_size = 0; + return; + } + + v /= mpz_gcd_ui (NULL, u, v); + mpz_mul_ui (r, u, v); + + mpz_abs (r, r); +} + +int +mpz_invert (mpz_t r, const mpz_t u, const mpz_t m) +{ + mpz_t g, tr; + int invertible; + + if (u->_mp_size == 0 || mpz_cmpabs_ui (m, 1) <= 0) + return 0; + + mpz_init (g); + mpz_init (tr); + + mpz_gcdext (g, tr, NULL, u, m); + invertible = (mpz_cmp_ui (g, 1) == 0); + + if (invertible) + { + if (tr->_mp_size < 0) + { + if (m->_mp_size >= 0) + mpz_add (tr, tr, m); + else + mpz_sub (tr, tr, m); + } + mpz_swap (r, tr); + } + + mpz_clear (g); + mpz_clear (tr); + return invertible; +} + + +/* Higher level operations (sqrt, pow and root) */ + +void +mpz_pow_ui (mpz_t r, const mpz_t b, unsigned long e) +{ + unsigned long bit; + mpz_t tr; + mpz_init_set_ui (tr, 1); + + bit = GMP_ULONG_HIGHBIT; + do + { + mpz_mul (tr, tr, tr); + if (e & bit) + mpz_mul (tr, tr, b); + bit >>= 1; + } + while (bit > 0); + + mpz_swap (r, tr); + mpz_clear (tr); +} + +void +mpz_ui_pow_ui (mpz_t r, unsigned long blimb, unsigned long e) +{ + mpz_t b; + + mpz_init_set_ui (b, blimb); + mpz_pow_ui (r, b, e); + mpz_clear (b); +} + +void +mpz_powm (mpz_t r, const mpz_t b, const mpz_t e, const mpz_t m) +{ + mpz_t tr; + mpz_t base; + mp_size_t en, mn; + mp_srcptr mp; + struct gmp_div_inverse minv; + unsigned shift; + mp_ptr tp = NULL; + + en = GMP_ABS (e->_mp_size); + mn = GMP_ABS (m->_mp_size); + if (mn == 0) + gmp_die ("mpz_powm: Zero modulo."); + + if (en == 0) + { + mpz_set_ui (r, mpz_cmpabs_ui (m, 1)); + return; + } + + mp = m->_mp_d; + mpn_div_qr_invert (&minv, mp, mn); + shift = minv.shift; + + if (shift > 0) + { + /* To avoid shifts, we do all our reductions, except the final + one, using a *normalized* m. */ + minv.shift = 0; + + tp = gmp_alloc_limbs (mn); + gmp_assert_nocarry (mpn_lshift (tp, mp, mn, shift)); + mp = tp; + } + + mpz_init (base); + + if (e->_mp_size < 0) + { + if (!mpz_invert (base, b, m)) + gmp_die ("mpz_powm: Negative exponent and non-invertible base."); + } + else + { + mp_size_t bn; + mpz_abs (base, b); + + bn = base->_mp_size; + if (bn >= mn) + { + mpn_div_qr_preinv (NULL, base->_mp_d, base->_mp_size, mp, mn, &minv); + bn = mn; + } + + /* We have reduced the absolute value. Now take care of the + sign. Note that we get zero represented non-canonically as + m. */ + if (b->_mp_size < 0) + { + mp_ptr bp = MPZ_REALLOC (base, mn); + gmp_assert_nocarry (mpn_sub (bp, mp, mn, bp, bn)); + bn = mn; + } + base->_mp_size = mpn_normalized_size (base->_mp_d, bn); + } + mpz_init_set_ui (tr, 1); + + while (--en >= 0) + { + mp_limb_t w = e->_mp_d[en]; + mp_limb_t bit; + + bit = GMP_LIMB_HIGHBIT; + do + { + mpz_mul (tr, tr, tr); + if (w & bit) + mpz_mul (tr, tr, base); + if (tr->_mp_size > mn) + { + mpn_div_qr_preinv (NULL, tr->_mp_d, tr->_mp_size, mp, mn, &minv); + tr->_mp_size = mpn_normalized_size (tr->_mp_d, mn); + } + bit >>= 1; + } + while (bit > 0); + } + + /* Final reduction */ + if (tr->_mp_size >= mn) + { + minv.shift = shift; + mpn_div_qr_preinv (NULL, tr->_mp_d, tr->_mp_size, mp, mn, &minv); + tr->_mp_size = mpn_normalized_size (tr->_mp_d, mn); + } + if (tp) + gmp_free_limbs (tp, mn); + + mpz_swap (r, tr); + mpz_clear (tr); + mpz_clear (base); +} + +void +mpz_powm_ui (mpz_t r, const mpz_t b, unsigned long elimb, const mpz_t m) +{ + mpz_t e; + + mpz_init_set_ui (e, elimb); + mpz_powm (r, b, e, m); + mpz_clear (e); +} + +/* x=trunc(y^(1/z)), r=y-x^z */ +void +mpz_rootrem (mpz_t x, mpz_t r, const mpz_t y, unsigned long z) +{ + int sgn; + mp_bitcnt_t bc; + mpz_t t, u; + + sgn = y->_mp_size < 0; + if ((~z & sgn) != 0) + gmp_die ("mpz_rootrem: Negative argument, with even root."); + if (z == 0) + gmp_die ("mpz_rootrem: Zeroth root."); + + if (mpz_cmpabs_ui (y, 1) <= 0) { + if (x) + mpz_set (x, y); + if (r) + r->_mp_size = 0; + return; + } + + mpz_init (u); + mpz_init (t); + bc = (mpz_sizeinbase (y, 2) - 1) / z + 1; + mpz_setbit (t, bc); + + if (z == 2) /* simplify sqrt loop: z-1 == 1 */ + do { + mpz_swap (u, t); /* u = x */ + mpz_tdiv_q (t, y, u); /* t = y/x */ + mpz_add (t, t, u); /* t = y/x + x */ + mpz_tdiv_q_2exp (t, t, 1); /* x'= (y/x + x)/2 */ + } while (mpz_cmpabs (t, u) < 0); /* |x'| < |x| */ + else /* z != 2 */ { + mpz_t v; + + mpz_init (v); + if (sgn) + mpz_neg (t, t); + + do { + mpz_swap (u, t); /* u = x */ + mpz_pow_ui (t, u, z - 1); /* t = x^(z-1) */ + mpz_tdiv_q (t, y, t); /* t = y/x^(z-1) */ + mpz_mul_ui (v, u, z - 1); /* v = x*(z-1) */ + mpz_add (t, t, v); /* t = y/x^(z-1) + x*(z-1) */ + mpz_tdiv_q_ui (t, t, z); /* x'=(y/x^(z-1) + x*(z-1))/z */ + } while (mpz_cmpabs (t, u) < 0); /* |x'| < |x| */ + + mpz_clear (v); + } + + if (r) { + mpz_pow_ui (t, u, z); + mpz_sub (r, y, t); + } + if (x) + mpz_swap (x, u); + mpz_clear (u); + mpz_clear (t); +} + +int +mpz_root (mpz_t x, const mpz_t y, unsigned long z) +{ + int res; + mpz_t r; + + mpz_init (r); + mpz_rootrem (x, r, y, z); + res = r->_mp_size == 0; + mpz_clear (r); + + return res; +} + +/* Compute s = floor(sqrt(u)) and r = u - s^2. Allows r == NULL */ +void +mpz_sqrtrem (mpz_t s, mpz_t r, const mpz_t u) +{ + mpz_rootrem (s, r, u, 2); +} + +void +mpz_sqrt (mpz_t s, const mpz_t u) +{ + mpz_rootrem (s, NULL, u, 2); +} + +int +mpz_perfect_square_p (const mpz_t u) +{ + if (u->_mp_size <= 0) + return (u->_mp_size == 0); + else + return mpz_root (NULL, u, 2); +} + +int +mpn_perfect_square_p (mp_srcptr p, mp_size_t n) +{ + mpz_t t; + + assert (n > 0); + assert (p [n-1] != 0); + return mpz_root (NULL, mpz_roinit_normal_n (t, p, n), 2); +} + +mp_size_t +mpn_sqrtrem (mp_ptr sp, mp_ptr rp, mp_srcptr p, mp_size_t n) +{ + mpz_t s, r, u; + mp_size_t res; + + assert (n > 0); + assert (p [n-1] != 0); + + mpz_init (r); + mpz_init (s); + mpz_rootrem (s, r, mpz_roinit_normal_n (u, p, n), 2); + + assert (s->_mp_size == (n+1)/2); + mpn_copyd (sp, s->_mp_d, s->_mp_size); + mpz_clear (s); + res = r->_mp_size; + if (rp) + mpn_copyd (rp, r->_mp_d, res); + mpz_clear (r); + return res; +} + +/* Combinatorics */ + +void +mpz_mfac_uiui (mpz_t x, unsigned long n, unsigned long m) +{ + mpz_set_ui (x, n + (n == 0)); + if (m + 1 < 2) return; + while (n > m + 1) + mpz_mul_ui (x, x, n -= m); +} + +void +mpz_2fac_ui (mpz_t x, unsigned long n) +{ + mpz_mfac_uiui (x, n, 2); +} + +void +mpz_fac_ui (mpz_t x, unsigned long n) +{ + mpz_mfac_uiui (x, n, 1); +} + +void +mpz_bin_uiui (mpz_t r, unsigned long n, unsigned long k) +{ + mpz_t t; + + mpz_set_ui (r, k <= n); + + if (k > (n >> 1)) + k = (k <= n) ? n - k : 0; + + mpz_init (t); + mpz_fac_ui (t, k); + + for (; k > 0; --k) + mpz_mul_ui (r, r, n--); + + mpz_divexact (r, r, t); + mpz_clear (t); +} + + +/* Primality testing */ + +/* Computes Kronecker (a/b) with odd b, a!=0 and GCD(a,b) = 1 */ +/* Adapted from JACOBI_BASE_METHOD==4 in mpn/generic/jacbase.c */ +static int +gmp_jacobi_coprime (mp_limb_t a, mp_limb_t b) +{ + int c, bit = 0; + + assert (b & 1); + assert (a != 0); + /* assert (mpn_gcd_11 (a, b) == 1); */ + + /* Below, we represent a and b shifted right so that the least + significant one bit is implicit. */ + b >>= 1; + + gmp_ctz(c, a); + a >>= 1; + + for (;;) + { + a >>= c; + /* (2/b) = -1 if b = 3 or 5 mod 8 */ + bit ^= c & (b ^ (b >> 1)); + if (a < b) + { + if (a == 0) + return bit & 1 ? -1 : 1; + bit ^= a & b; + a = b - a; + b -= a; + } + else + { + a -= b; + assert (a != 0); + } + + gmp_ctz(c, a); + ++c; + } +} + +static void +gmp_lucas_step_k_2k (mpz_t V, mpz_t Qk, const mpz_t n) +{ + mpz_mod (Qk, Qk, n); + /* V_{2k} <- V_k ^ 2 - 2Q^k */ + mpz_mul (V, V, V); + mpz_submul_ui (V, Qk, 2); + mpz_tdiv_r (V, V, n); + /* Q^{2k} = (Q^k)^2 */ + mpz_mul (Qk, Qk, Qk); +} + +/* Computes V_k, Q^k (mod n) for the Lucas' sequence */ +/* with P=1, Q=Q; k = (n>>b0)|1. */ +/* Requires an odd n > 4; b0 > 0; -2*Q must not overflow a long */ +/* Returns (U_k == 0) and sets V=V_k and Qk=Q^k. */ +static int +gmp_lucas_mod (mpz_t V, mpz_t Qk, long Q, + mp_bitcnt_t b0, const mpz_t n) +{ + mp_bitcnt_t bs; + mpz_t U; + int res; + + assert (b0 > 0); + assert (Q <= - (LONG_MIN / 2)); + assert (Q >= - (LONG_MAX / 2)); + assert (mpz_cmp_ui (n, 4) > 0); + assert (mpz_odd_p (n)); + + mpz_init_set_ui (U, 1); /* U1 = 1 */ + mpz_set_ui (V, 1); /* V1 = 1 */ + mpz_set_si (Qk, Q); + + for (bs = mpz_sizeinbase (n, 2) - 1; --bs >= b0;) + { + /* U_{2k} <- U_k * V_k */ + mpz_mul (U, U, V); + /* V_{2k} <- V_k ^ 2 - 2Q^k */ + /* Q^{2k} = (Q^k)^2 */ + gmp_lucas_step_k_2k (V, Qk, n); + + /* A step k->k+1 is performed if the bit in $n$ is 1 */ + /* mpz_tstbit(n,bs) or the bit is 0 in $n$ but */ + /* should be 1 in $n+1$ (bs == b0) */ + if (b0 == bs || mpz_tstbit (n, bs)) + { + /* Q^{k+1} <- Q^k * Q */ + mpz_mul_si (Qk, Qk, Q); + /* U_{k+1} <- (U_k + V_k) / 2 */ + mpz_swap (U, V); /* Keep in V the old value of U_k */ + mpz_add (U, U, V); + /* We have to compute U/2, so we need an even value, */ + /* equivalent (mod n) */ + if (mpz_odd_p (U)) + mpz_add (U, U, n); + mpz_tdiv_q_2exp (U, U, 1); + /* V_{k+1} <-(D*U_k + V_k) / 2 = + U_{k+1} + (D-1)/2*U_k = U_{k+1} - 2Q*U_k */ + mpz_mul_si (V, V, -2*Q); + mpz_add (V, U, V); + mpz_tdiv_r (V, V, n); + } + mpz_tdiv_r (U, U, n); + } + + res = U->_mp_size == 0; + mpz_clear (U); + return res; +} + +/* Performs strong Lucas' test on x, with parameters suggested */ +/* for the BPSW test. Qk is only passed to recycle a variable. */ +/* Requires GCD (x,6) = 1.*/ +static int +gmp_stronglucas (const mpz_t x, mpz_t Qk) +{ + mp_bitcnt_t b0; + mpz_t V, n; + mp_limb_t maxD, D; /* The absolute value is stored. */ + long Q; + mp_limb_t tl; + + /* Test on the absolute value. */ + mpz_roinit_normal_n (n, x->_mp_d, GMP_ABS (x->_mp_size)); + + assert (mpz_odd_p (n)); + /* assert (mpz_gcd_ui (NULL, n, 6) == 1); */ + if (mpz_root (Qk, n, 2)) + return 0; /* A square is composite. */ + + /* Check Ds up to square root (in case, n is prime) + or avoid overflows */ + maxD = (Qk->_mp_size == 1) ? Qk->_mp_d [0] - 1 : GMP_LIMB_MAX; + + D = 3; + /* Search a D such that (D/n) = -1 in the sequence 5,-7,9,-11,.. */ + /* For those Ds we have (D/n) = (n/|D|) */ + do + { + if (D >= maxD) + return 1 + (D != GMP_LIMB_MAX); /* (1 + ! ~ D) */ + D += 2; + tl = mpz_tdiv_ui (n, D); + if (tl == 0) + return 0; + } + while (gmp_jacobi_coprime (tl, D) == 1); + + mpz_init (V); + + /* n-(D/n) = n+1 = d*2^{b0}, with d = (n>>b0) | 1 */ + b0 = mpn_common_scan (~ n->_mp_d[0], 0, n->_mp_d, n->_mp_size, GMP_LIMB_MAX); + /* b0 = mpz_scan0 (n, 0); */ + + /* D= P^2 - 4Q; P = 1; Q = (1-D)/4 */ + Q = (D & 2) ? (long) (D >> 2) + 1 : -(long) (D >> 2); + + if (! gmp_lucas_mod (V, Qk, Q, b0, n)) /* If Ud != 0 */ + while (V->_mp_size != 0 && --b0 != 0) /* while Vk != 0 */ + /* V <- V ^ 2 - 2Q^k */ + /* Q^{2k} = (Q^k)^2 */ + gmp_lucas_step_k_2k (V, Qk, n); + + mpz_clear (V); + return (b0 != 0); +} + +static int +gmp_millerrabin (const mpz_t n, const mpz_t nm1, mpz_t y, + const mpz_t q, mp_bitcnt_t k) +{ + assert (k > 0); + + /* Caller must initialize y to the base. */ + mpz_powm (y, y, q, n); + + if (mpz_cmp_ui (y, 1) == 0 || mpz_cmp (y, nm1) == 0) + return 1; + + while (--k > 0) + { + mpz_powm_ui (y, y, 2, n); + if (mpz_cmp (y, nm1) == 0) + return 1; + } + return 0; +} + +/* This product is 0xc0cfd797, and fits in 32 bits. */ +#define GMP_PRIME_PRODUCT \ + (3UL*5UL*7UL*11UL*13UL*17UL*19UL*23UL*29UL) + +/* Bit (p+1)/2 is set, for each odd prime <= 61 */ +#define GMP_PRIME_MASK 0xc96996dcUL + +int +mpz_probab_prime_p (const mpz_t n, int reps) +{ + mpz_t nm1; + mpz_t q; + mpz_t y; + mp_bitcnt_t k; + int is_prime; + int j; + + /* Note that we use the absolute value of n only, for compatibility + with the real GMP. */ + if (mpz_even_p (n)) + return (mpz_cmpabs_ui (n, 2) == 0) ? 2 : 0; + + /* Above test excludes n == 0 */ + assert (n->_mp_size != 0); + + if (mpz_cmpabs_ui (n, 64) < 0) + return (GMP_PRIME_MASK >> (n->_mp_d[0] >> 1)) & 2; + + if (mpz_gcd_ui (NULL, n, GMP_PRIME_PRODUCT) != 1) + return 0; + + /* All prime factors are >= 31. */ + if (mpz_cmpabs_ui (n, 31*31) < 0) + return 2; + + mpz_init (nm1); + mpz_init (q); + + /* Find q and k, where q is odd and n = 1 + 2**k * q. */ + mpz_abs (nm1, n); + nm1->_mp_d[0] -= 1; + /* Count trailing zeros, equivalent to mpn_scan1, because we know that there is a 1 */ + k = mpn_scan1 (nm1->_mp_d, 0); + mpz_tdiv_q_2exp (q, nm1, k); + + /* BPSW test */ + mpz_init_set_ui (y, 2); + is_prime = gmp_millerrabin (n, nm1, y, q, k) && gmp_stronglucas (n, y); + reps -= 24; /* skip the first 24 repetitions */ + + /* Use Miller-Rabin, with a deterministic sequence of bases, a[j] = + j^2 + j + 41 using Euler's polynomial. We potentially stop early, + if a[j] >= n - 1. Since n >= 31*31, this can happen only if reps > + 30 (a[30] == 971 > 31*31 == 961). */ + + for (j = 0; is_prime & (j < reps); j++) + { + mpz_set_ui (y, (unsigned long) j*j+j+41); + if (mpz_cmp (y, nm1) >= 0) + { + /* Don't try any further bases. This "early" break does not affect + the result for any reasonable reps value (<=5000 was tested) */ + assert (j >= 30); + break; + } + is_prime = gmp_millerrabin (n, nm1, y, q, k); + } + mpz_clear (nm1); + mpz_clear (q); + mpz_clear (y); + + return is_prime; +} + + +/* Logical operations and bit manipulation. */ + +/* Numbers are treated as if represented in two's complement (and + infinitely sign extended). For a negative values we get the two's + complement from -x = ~x + 1, where ~ is bitwise complement. + Negation transforms + + xxxx10...0 + + into + + yyyy10...0 + + where yyyy is the bitwise complement of xxxx. So least significant + bits, up to and including the first one bit, are unchanged, and + the more significant bits are all complemented. + + To change a bit from zero to one in a negative number, subtract the + corresponding power of two from the absolute value. This can never + underflow. To change a bit from one to zero, add the corresponding + power of two, and this might overflow. E.g., if x = -001111, the + two's complement is 110001. Clearing the least significant bit, we + get two's complement 110000, and -010000. */ + +int +mpz_tstbit (const mpz_t d, mp_bitcnt_t bit_index) +{ + mp_size_t limb_index; + unsigned shift; + mp_size_t ds; + mp_size_t dn; + mp_limb_t w; + int bit; + + ds = d->_mp_size; + dn = GMP_ABS (ds); + limb_index = bit_index / GMP_LIMB_BITS; + if (limb_index >= dn) + return ds < 0; + + shift = bit_index % GMP_LIMB_BITS; + w = d->_mp_d[limb_index]; + bit = (w >> shift) & 1; + + if (ds < 0) + { + /* d < 0. Check if any of the bits below is set: If so, our bit + must be complemented. */ + if (shift > 0 && (mp_limb_t) (w << (GMP_LIMB_BITS - shift)) > 0) + return bit ^ 1; + while (--limb_index >= 0) + if (d->_mp_d[limb_index] > 0) + return bit ^ 1; + } + return bit; +} + +static void +mpz_abs_add_bit (mpz_t d, mp_bitcnt_t bit_index) +{ + mp_size_t dn, limb_index; + mp_limb_t bit; + mp_ptr dp; + + dn = GMP_ABS (d->_mp_size); + + limb_index = bit_index / GMP_LIMB_BITS; + bit = (mp_limb_t) 1 << (bit_index % GMP_LIMB_BITS); + + if (limb_index >= dn) + { + mp_size_t i; + /* The bit should be set outside of the end of the number. + We have to increase the size of the number. */ + dp = MPZ_REALLOC (d, limb_index + 1); + + dp[limb_index] = bit; + for (i = dn; i < limb_index; i++) + dp[i] = 0; + dn = limb_index + 1; + } + else + { + mp_limb_t cy; + + dp = d->_mp_d; + + cy = mpn_add_1 (dp + limb_index, dp + limb_index, dn - limb_index, bit); + if (cy > 0) + { + dp = MPZ_REALLOC (d, dn + 1); + dp[dn++] = cy; + } + } + + d->_mp_size = (d->_mp_size < 0) ? - dn : dn; +} + +static void +mpz_abs_sub_bit (mpz_t d, mp_bitcnt_t bit_index) +{ + mp_size_t dn, limb_index; + mp_ptr dp; + mp_limb_t bit; + + dn = GMP_ABS (d->_mp_size); + dp = d->_mp_d; + + limb_index = bit_index / GMP_LIMB_BITS; + bit = (mp_limb_t) 1 << (bit_index % GMP_LIMB_BITS); + + assert (limb_index < dn); + + gmp_assert_nocarry (mpn_sub_1 (dp + limb_index, dp + limb_index, + dn - limb_index, bit)); + dn = mpn_normalized_size (dp, dn); + d->_mp_size = (d->_mp_size < 0) ? - dn : dn; +} + +void +mpz_setbit (mpz_t d, mp_bitcnt_t bit_index) +{ + if (!mpz_tstbit (d, bit_index)) + { + if (d->_mp_size >= 0) + mpz_abs_add_bit (d, bit_index); + else + mpz_abs_sub_bit (d, bit_index); + } +} + +void +mpz_clrbit (mpz_t d, mp_bitcnt_t bit_index) +{ + if (mpz_tstbit (d, bit_index)) + { + if (d->_mp_size >= 0) + mpz_abs_sub_bit (d, bit_index); + else + mpz_abs_add_bit (d, bit_index); + } +} + +void +mpz_combit (mpz_t d, mp_bitcnt_t bit_index) +{ + if (mpz_tstbit (d, bit_index) ^ (d->_mp_size < 0)) + mpz_abs_sub_bit (d, bit_index); + else + mpz_abs_add_bit (d, bit_index); +} + +void +mpz_com (mpz_t r, const mpz_t u) +{ + mpz_add_ui (r, u, 1); + mpz_neg (r, r); +} + +void +mpz_and (mpz_t r, const mpz_t u, const mpz_t v) +{ + mp_size_t un, vn, rn, i; + mp_ptr up, vp, rp; + + mp_limb_t ux, vx, rx; + mp_limb_t uc, vc, rc; + mp_limb_t ul, vl, rl; + + un = GMP_ABS (u->_mp_size); + vn = GMP_ABS (v->_mp_size); + if (un < vn) + { + MPZ_SRCPTR_SWAP (u, v); + MP_SIZE_T_SWAP (un, vn); + } + if (vn == 0) + { + r->_mp_size = 0; + return; + } + + uc = u->_mp_size < 0; + vc = v->_mp_size < 0; + rc = uc & vc; + + ux = -uc; + vx = -vc; + rx = -rc; + + /* If the smaller input is positive, higher limbs don't matter. */ + rn = vx ? un : vn; + + rp = MPZ_REALLOC (r, rn + (mp_size_t) rc); + + up = u->_mp_d; + vp = v->_mp_d; + + i = 0; + do + { + ul = (up[i] ^ ux) + uc; + uc = ul < uc; + + vl = (vp[i] ^ vx) + vc; + vc = vl < vc; + + rl = ( (ul & vl) ^ rx) + rc; + rc = rl < rc; + rp[i] = rl; + } + while (++i < vn); + assert (vc == 0); + + for (; i < rn; i++) + { + ul = (up[i] ^ ux) + uc; + uc = ul < uc; + + rl = ( (ul & vx) ^ rx) + rc; + rc = rl < rc; + rp[i] = rl; + } + if (rc) + rp[rn++] = rc; + else + rn = mpn_normalized_size (rp, rn); + + r->_mp_size = rx ? -rn : rn; +} + +void +mpz_ior (mpz_t r, const mpz_t u, const mpz_t v) +{ + mp_size_t un, vn, rn, i; + mp_ptr up, vp, rp; + + mp_limb_t ux, vx, rx; + mp_limb_t uc, vc, rc; + mp_limb_t ul, vl, rl; + + un = GMP_ABS (u->_mp_size); + vn = GMP_ABS (v->_mp_size); + if (un < vn) + { + MPZ_SRCPTR_SWAP (u, v); + MP_SIZE_T_SWAP (un, vn); + } + if (vn == 0) + { + mpz_set (r, u); + return; + } + + uc = u->_mp_size < 0; + vc = v->_mp_size < 0; + rc = uc | vc; + + ux = -uc; + vx = -vc; + rx = -rc; + + /* If the smaller input is negative, by sign extension higher limbs + don't matter. */ + rn = vx ? vn : un; + + rp = MPZ_REALLOC (r, rn + (mp_size_t) rc); + + up = u->_mp_d; + vp = v->_mp_d; + + i = 0; + do + { + ul = (up[i] ^ ux) + uc; + uc = ul < uc; + + vl = (vp[i] ^ vx) + vc; + vc = vl < vc; + + rl = ( (ul | vl) ^ rx) + rc; + rc = rl < rc; + rp[i] = rl; + } + while (++i < vn); + assert (vc == 0); + + for (; i < rn; i++) + { + ul = (up[i] ^ ux) + uc; + uc = ul < uc; + + rl = ( (ul | vx) ^ rx) + rc; + rc = rl < rc; + rp[i] = rl; + } + if (rc) + rp[rn++] = rc; + else + rn = mpn_normalized_size (rp, rn); + + r->_mp_size = rx ? -rn : rn; +} + +void +mpz_xor (mpz_t r, const mpz_t u, const mpz_t v) +{ + mp_size_t un, vn, i; + mp_ptr up, vp, rp; + + mp_limb_t ux, vx, rx; + mp_limb_t uc, vc, rc; + mp_limb_t ul, vl, rl; + + un = GMP_ABS (u->_mp_size); + vn = GMP_ABS (v->_mp_size); + if (un < vn) + { + MPZ_SRCPTR_SWAP (u, v); + MP_SIZE_T_SWAP (un, vn); + } + if (vn == 0) + { + mpz_set (r, u); + return; + } + + uc = u->_mp_size < 0; + vc = v->_mp_size < 0; + rc = uc ^ vc; + + ux = -uc; + vx = -vc; + rx = -rc; + + rp = MPZ_REALLOC (r, un + (mp_size_t) rc); + + up = u->_mp_d; + vp = v->_mp_d; + + i = 0; + do + { + ul = (up[i] ^ ux) + uc; + uc = ul < uc; + + vl = (vp[i] ^ vx) + vc; + vc = vl < vc; + + rl = (ul ^ vl ^ rx) + rc; + rc = rl < rc; + rp[i] = rl; + } + while (++i < vn); + assert (vc == 0); + + for (; i < un; i++) + { + ul = (up[i] ^ ux) + uc; + uc = ul < uc; + + rl = (ul ^ ux) + rc; + rc = rl < rc; + rp[i] = rl; + } + if (rc) + rp[un++] = rc; + else + un = mpn_normalized_size (rp, un); + + r->_mp_size = rx ? -un : un; +} + +static unsigned +gmp_popcount_limb (mp_limb_t x) +{ + unsigned c; + + /* Do 16 bits at a time, to avoid limb-sized constants. */ + int LOCAL_SHIFT_BITS = 16; + for (c = 0; x > 0;) + { + unsigned w = x - ((x >> 1) & 0x5555); + w = ((w >> 2) & 0x3333) + (w & 0x3333); + w = (w >> 4) + w; + w = ((w >> 8) & 0x000f) + (w & 0x000f); + c += w; + if (GMP_LIMB_BITS > LOCAL_SHIFT_BITS) + x >>= LOCAL_SHIFT_BITS; + else + x = 0; + } + return c; +} + +mp_bitcnt_t +mpn_popcount (mp_srcptr p, mp_size_t n) +{ + mp_size_t i; + mp_bitcnt_t c; + + for (c = 0, i = 0; i < n; i++) + c += gmp_popcount_limb (p[i]); + + return c; +} + +mp_bitcnt_t +mpz_popcount (const mpz_t u) +{ + mp_size_t un; + + un = u->_mp_size; + + if (un < 0) + return ~(mp_bitcnt_t) 0; + + return mpn_popcount (u->_mp_d, un); +} + +mp_bitcnt_t +mpz_hamdist (const mpz_t u, const mpz_t v) +{ + mp_size_t un, vn, i; + mp_limb_t uc, vc, ul, vl, comp; + mp_srcptr up, vp; + mp_bitcnt_t c; + + un = u->_mp_size; + vn = v->_mp_size; + + if ( (un ^ vn) < 0) + return ~(mp_bitcnt_t) 0; + + comp = - (uc = vc = (un < 0)); + if (uc) + { + assert (vn < 0); + un = -un; + vn = -vn; + } + + up = u->_mp_d; + vp = v->_mp_d; + + if (un < vn) + MPN_SRCPTR_SWAP (up, un, vp, vn); + + for (i = 0, c = 0; i < vn; i++) + { + ul = (up[i] ^ comp) + uc; + uc = ul < uc; + + vl = (vp[i] ^ comp) + vc; + vc = vl < vc; + + c += gmp_popcount_limb (ul ^ vl); + } + assert (vc == 0); + + for (; i < un; i++) + { + ul = (up[i] ^ comp) + uc; + uc = ul < uc; + + c += gmp_popcount_limb (ul ^ comp); + } + + return c; +} + +mp_bitcnt_t +mpz_scan1 (const mpz_t u, mp_bitcnt_t starting_bit) +{ + mp_ptr up; + mp_size_t us, un, i; + mp_limb_t limb, ux; + + us = u->_mp_size; + un = GMP_ABS (us); + i = starting_bit / GMP_LIMB_BITS; + + /* Past the end there's no 1 bits for u>=0, or an immediate 1 bit + for u<0. Notice this test picks up any u==0 too. */ + if (i >= un) + return (us >= 0 ? ~(mp_bitcnt_t) 0 : starting_bit); + + up = u->_mp_d; + ux = 0; + limb = up[i]; + + if (starting_bit != 0) + { + if (us < 0) + { + ux = mpn_zero_p (up, i); + limb = ~ limb + ux; + ux = - (mp_limb_t) (limb >= ux); + } + + /* Mask to 0 all bits before starting_bit, thus ignoring them. */ + limb &= GMP_LIMB_MAX << (starting_bit % GMP_LIMB_BITS); + } + + return mpn_common_scan (limb, i, up, un, ux); +} + +mp_bitcnt_t +mpz_scan0 (const mpz_t u, mp_bitcnt_t starting_bit) +{ + mp_ptr up; + mp_size_t us, un, i; + mp_limb_t limb, ux; + + us = u->_mp_size; + ux = - (mp_limb_t) (us >= 0); + un = GMP_ABS (us); + i = starting_bit / GMP_LIMB_BITS; + + /* When past end, there's an immediate 0 bit for u>=0, or no 0 bits for + u<0. Notice this test picks up all cases of u==0 too. */ + if (i >= un) + return (ux ? starting_bit : ~(mp_bitcnt_t) 0); + + up = u->_mp_d; + limb = up[i] ^ ux; + + if (ux == 0) + limb -= mpn_zero_p (up, i); /* limb = ~(~limb + zero_p) */ + + /* Mask all bits before starting_bit, thus ignoring them. */ + limb &= GMP_LIMB_MAX << (starting_bit % GMP_LIMB_BITS); + + return mpn_common_scan (limb, i, up, un, ux); +} + + +/* MPZ base conversion. */ + +size_t +mpz_sizeinbase (const mpz_t u, int base) +{ + mp_size_t un, tn; + mp_srcptr up; + mp_ptr tp; + mp_bitcnt_t bits; + struct gmp_div_inverse bi; + size_t ndigits; + + assert (base >= 2); + assert (base <= 62); + + un = GMP_ABS (u->_mp_size); + if (un == 0) + return 1; + + up = u->_mp_d; + + bits = (un - 1) * GMP_LIMB_BITS + mpn_limb_size_in_base_2 (up[un-1]); + switch (base) + { + case 2: + return bits; + case 4: + return (bits + 1) / 2; + case 8: + return (bits + 2) / 3; + case 16: + return (bits + 3) / 4; + case 32: + return (bits + 4) / 5; + /* FIXME: Do something more clever for the common case of base + 10. */ + } + + tp = gmp_alloc_limbs (un); + mpn_copyi (tp, up, un); + mpn_div_qr_1_invert (&bi, base); + + tn = un; + ndigits = 0; + do + { + ndigits++; + mpn_div_qr_1_preinv (tp, tp, tn, &bi); + tn -= (tp[tn-1] == 0); + } + while (tn > 0); + + gmp_free_limbs (tp, un); + return ndigits; +} + +char * +mpz_get_str (char *sp, int base, const mpz_t u) +{ + unsigned bits; + const char *digits; + mp_size_t un; + size_t i, sn, osn; + + digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + if (base > 1) + { + if (base <= 36) + digits = "0123456789abcdefghijklmnopqrstuvwxyz"; + else if (base > 62) + return NULL; + } + else if (base >= -1) + base = 10; + else + { + base = -base; + if (base > 36) + return NULL; + } + + sn = 1 + mpz_sizeinbase (u, base); + if (!sp) + { + osn = 1 + sn; + sp = (char *) gmp_alloc (osn); + } + else + osn = 0; + un = GMP_ABS (u->_mp_size); + + if (un == 0) + { + sp[0] = '0'; + sn = 1; + goto ret; + } + + i = 0; + + if (u->_mp_size < 0) + sp[i++] = '-'; + + bits = mpn_base_power_of_two_p (base); + + if (bits) + /* Not modified in this case. */ + sn = i + mpn_get_str_bits ((unsigned char *) sp + i, bits, u->_mp_d, un); + else + { + struct mpn_base_info info; + mp_ptr tp; + + mpn_get_base_info (&info, base); + tp = gmp_alloc_limbs (un); + mpn_copyi (tp, u->_mp_d, un); + + sn = i + mpn_get_str_other ((unsigned char *) sp + i, base, &info, tp, un); + gmp_free_limbs (tp, un); + } + + for (; i < sn; i++) + sp[i] = digits[(unsigned char) sp[i]]; + +ret: + sp[sn] = '\0'; + if (osn && osn != sn + 1) + sp = (char*) gmp_realloc (sp, osn, sn + 1); + return sp; +} + +int +mpz_set_str (mpz_t r, const char *sp, int base) +{ + unsigned bits, value_of_a; + mp_size_t rn, alloc; + mp_ptr rp; + size_t dn, sn; + int sign; + unsigned char *dp; + + assert (base == 0 || (base >= 2 && base <= 62)); + + while (isspace( (unsigned char) *sp)) + sp++; + + sign = (*sp == '-'); + sp += sign; + + if (base == 0) + { + if (sp[0] == '0') + { + if (sp[1] == 'x' || sp[1] == 'X') + { + base = 16; + sp += 2; + } + else if (sp[1] == 'b' || sp[1] == 'B') + { + base = 2; + sp += 2; + } + else + base = 8; + } + else + base = 10; + } + + if (!*sp) + { + r->_mp_size = 0; + return -1; + } + sn = strlen(sp); + dp = (unsigned char *) gmp_alloc (sn); + + value_of_a = (base > 36) ? 36 : 10; + for (dn = 0; *sp; sp++) + { + unsigned digit; + + if (isspace ((unsigned char) *sp)) + continue; + else if (*sp >= '0' && *sp <= '9') + digit = *sp - '0'; + else if (*sp >= 'a' && *sp <= 'z') + digit = *sp - 'a' + value_of_a; + else if (*sp >= 'A' && *sp <= 'Z') + digit = *sp - 'A' + 10; + else + digit = base; /* fail */ + + if (digit >= (unsigned) base) + { + gmp_free (dp, sn); + r->_mp_size = 0; + return -1; + } + + dp[dn++] = digit; + } + + if (!dn) + { + gmp_free (dp, sn); + r->_mp_size = 0; + return -1; + } + bits = mpn_base_power_of_two_p (base); + + if (bits > 0) + { + alloc = (dn * bits + GMP_LIMB_BITS - 1) / GMP_LIMB_BITS; + rp = MPZ_REALLOC (r, alloc); + rn = mpn_set_str_bits (rp, dp, dn, bits); + } + else + { + struct mpn_base_info info; + mpn_get_base_info (&info, base); + alloc = (dn + info.exp - 1) / info.exp; + rp = MPZ_REALLOC (r, alloc); + rn = mpn_set_str_other (rp, dp, dn, base, &info); + /* Normalization, needed for all-zero input. */ + assert (rn > 0); + rn -= rp[rn-1] == 0; + } + assert (rn <= alloc); + gmp_free (dp, sn); + + r->_mp_size = sign ? - rn : rn; + + return 0; +} + +int +mpz_init_set_str (mpz_t r, const char *sp, int base) +{ + mpz_init (r); + return mpz_set_str (r, sp, base); +} + +size_t +mpz_out_str (FILE *stream, int base, const mpz_t x) +{ + char *str; + size_t len, n; + + str = mpz_get_str (NULL, base, x); + if (!str) + return 0; + len = strlen (str); + n = fwrite (str, 1, len, stream); + gmp_free (str, len + 1); + return n; +} + + +static int +gmp_detect_endian (void) +{ + static const int i = 2; + const unsigned char *p = (const unsigned char *) &i; + return 1 - *p; +} + +/* Import and export. Does not support nails. */ +void +mpz_import (mpz_t r, size_t count, int order, size_t size, int endian, + size_t nails, const void *src) +{ + const unsigned char *p; + ptrdiff_t word_step; + mp_ptr rp; + mp_size_t rn; + + /* The current (partial) limb. */ + mp_limb_t limb; + /* The number of bytes already copied to this limb (starting from + the low end). */ + size_t bytes; + /* The index where the limb should be stored, when completed. */ + mp_size_t i; + + if (nails != 0) + gmp_die ("mpz_import: Nails not supported."); + + assert (order == 1 || order == -1); + assert (endian >= -1 && endian <= 1); + + if (endian == 0) + endian = gmp_detect_endian (); + + p = (unsigned char *) src; + + word_step = (order != endian) ? 2 * size : 0; + + /* Process bytes from the least significant end, so point p at the + least significant word. */ + if (order == 1) + { + p += size * (count - 1); + word_step = - word_step; + } + + /* And at least significant byte of that word. */ + if (endian == 1) + p += (size - 1); + + rn = (size * count + sizeof(mp_limb_t) - 1) / sizeof(mp_limb_t); + rp = MPZ_REALLOC (r, rn); + + for (limb = 0, bytes = 0, i = 0; count > 0; count--, p += word_step) + { + size_t j; + for (j = 0; j < size; j++, p -= (ptrdiff_t) endian) + { + limb |= (mp_limb_t) *p << (bytes++ * CHAR_BIT); + if (bytes == sizeof(mp_limb_t)) + { + rp[i++] = limb; + bytes = 0; + limb = 0; + } + } + } + assert (i + (bytes > 0) == rn); + if (limb != 0) + rp[i++] = limb; + else + i = mpn_normalized_size (rp, i); + + r->_mp_size = i; +} + +void * +mpz_export (void *r, size_t *countp, int order, size_t size, int endian, + size_t nails, const mpz_t u) +{ + size_t count; + mp_size_t un; + + if (nails != 0) + gmp_die ("mpz_export: Nails not supported."); + + assert (order == 1 || order == -1); + assert (endian >= -1 && endian <= 1); + assert (size > 0 || u->_mp_size == 0); + + un = u->_mp_size; + count = 0; + if (un != 0) + { + size_t k; + unsigned char *p; + ptrdiff_t word_step; + /* The current (partial) limb. */ + mp_limb_t limb; + /* The number of bytes left to do in this limb. */ + size_t bytes; + /* The index where the limb was read. */ + mp_size_t i; + + un = GMP_ABS (un); + + /* Count bytes in top limb. */ + limb = u->_mp_d[un-1]; + assert (limb != 0); + + k = (GMP_LIMB_BITS <= CHAR_BIT); + if (!k) + { + do { + int LOCAL_CHAR_BIT = CHAR_BIT; + k++; limb >>= LOCAL_CHAR_BIT; + } while (limb != 0); + } + /* else limb = 0; */ + + count = (k + (un-1) * sizeof (mp_limb_t) + size - 1) / size; + + if (!r) + r = gmp_alloc (count * size); + + if (endian == 0) + endian = gmp_detect_endian (); + + p = (unsigned char *) r; + + word_step = (order != endian) ? 2 * size : 0; + + /* Process bytes from the least significant end, so point p at the + least significant word. */ + if (order == 1) + { + p += size * (count - 1); + word_step = - word_step; + } + + /* And at least significant byte of that word. */ + if (endian == 1) + p += (size - 1); + + for (bytes = 0, i = 0, k = 0; k < count; k++, p += word_step) + { + size_t j; + for (j = 0; j < size; ++j, p -= (ptrdiff_t) endian) + { + if (sizeof (mp_limb_t) == 1) + { + if (i < un) + *p = u->_mp_d[i++]; + else + *p = 0; + } + else + { + int LOCAL_CHAR_BIT = CHAR_BIT; + if (bytes == 0) + { + if (i < un) + limb = u->_mp_d[i++]; + bytes = sizeof (mp_limb_t); + } + *p = limb; + limb >>= LOCAL_CHAR_BIT; + bytes--; + } + } + } + assert (i == un); + assert (k == count); + } + + if (countp) + *countp = count; + + return r; +} + +#pragma GCC diagnostic pop diff --git a/extern/gmp/mini-gmp.h b/extern/gmp/mini-gmp.h new file mode 100644 index 0000000..711c25d --- /dev/null +++ b/extern/gmp/mini-gmp.h @@ -0,0 +1,313 @@ +/* mini-gmp, a minimalistic implementation of a GNU GMP subset. + +Copyright 2011-2015, 2017, 2019-2021 Free Software Foundation, Inc. + +This file is part of the GNU MP Library. + +The GNU MP Library is free software; you can redistribute it and/or modify +it under the terms of either: + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at your + option) any later version. + +or + + * the GNU General Public License as published by the Free Software + Foundation; either version 2 of the License, or (at your option) any + later version. + +or both in parallel, as here. + +The GNU MP Library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received copies of the GNU General Public License and the +GNU Lesser General Public License along with the GNU MP Library. If not, +see https://www.gnu.org/licenses/. */ + +/* About mini-gmp: This is a minimal implementation of a subset of the + GMP interface. It is intended for inclusion into applications which + have modest bignums needs, as a fallback when the real GMP library + is not installed. + + This file defines the public interface. */ + +#ifndef __MINI_GMP_H__ +#define __MINI_GMP_H__ + +/* For size_t */ +#include + +#if defined (__cplusplus) +extern "C" { +#endif + +void mp_set_memory_functions (void *(*) (size_t), + void *(*) (void *, size_t, size_t), + void (*) (void *, size_t)); + +void mp_get_memory_functions (void *(**) (size_t), + void *(**) (void *, size_t, size_t), + void (**) (void *, size_t)); + +#ifndef MINI_GMP_LIMB_TYPE +#define MINI_GMP_LIMB_TYPE long +#endif + +typedef unsigned MINI_GMP_LIMB_TYPE mp_limb_t; +typedef long mp_size_t; +typedef unsigned long mp_bitcnt_t; + +typedef mp_limb_t *mp_ptr; +typedef const mp_limb_t *mp_srcptr; + +typedef struct +{ + int _mp_alloc; + /* Number of *limbs* allocated and pointed + to by the _mp_d field. */ + int _mp_size; + /* abs(_mp_size) is the number of limbs the + last field points to. If _mp_size is + negative this is a negative number. */ + mp_limb_t *_mp_d; + /* Pointer to the limbs. */ +} __mpz_struct; + +typedef __mpz_struct mpz_t[1]; + +typedef __mpz_struct *mpz_ptr; +typedef const __mpz_struct *mpz_srcptr; + +extern const int mp_bits_per_limb; + +void mpn_copyi (mp_ptr, mp_srcptr, mp_size_t); +void mpn_copyd (mp_ptr, mp_srcptr, mp_size_t); +void mpn_zero (mp_ptr, mp_size_t); + +int mpn_cmp (mp_srcptr, mp_srcptr, mp_size_t); +int mpn_zero_p (mp_srcptr, mp_size_t); + +mp_limb_t mpn_add_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t); +mp_limb_t mpn_add_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t); +mp_limb_t mpn_add (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t); + +mp_limb_t mpn_sub_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t); +mp_limb_t mpn_sub_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t); +mp_limb_t mpn_sub (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t); + +mp_limb_t mpn_mul_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t); +mp_limb_t mpn_addmul_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t); +mp_limb_t mpn_submul_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t); + +mp_limb_t mpn_mul (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t); +void mpn_mul_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t); +void mpn_sqr (mp_ptr, mp_srcptr, mp_size_t); +int mpn_perfect_square_p (mp_srcptr, mp_size_t); +mp_size_t mpn_sqrtrem (mp_ptr, mp_ptr, mp_srcptr, mp_size_t); + +mp_limb_t mpn_lshift (mp_ptr, mp_srcptr, mp_size_t, unsigned int); +mp_limb_t mpn_rshift (mp_ptr, mp_srcptr, mp_size_t, unsigned int); + +mp_bitcnt_t mpn_scan0 (mp_srcptr, mp_bitcnt_t); +mp_bitcnt_t mpn_scan1 (mp_srcptr, mp_bitcnt_t); + +void mpn_com (mp_ptr, mp_srcptr, mp_size_t); +mp_limb_t mpn_neg (mp_ptr, mp_srcptr, mp_size_t); + +mp_bitcnt_t mpn_popcount (mp_srcptr, mp_size_t); + +mp_limb_t mpn_invert_3by2 (mp_limb_t, mp_limb_t); +#define mpn_invert_limb(x) mpn_invert_3by2 ((x), 0) + +size_t mpn_get_str (unsigned char *, int, mp_ptr, mp_size_t); +mp_size_t mpn_set_str (mp_ptr, const unsigned char *, size_t, int); + +void mpz_init (mpz_t); +void mpz_init2 (mpz_t, mp_bitcnt_t); +void mpz_clear (mpz_t); + +#define mpz_odd_p(z) (((z)->_mp_size != 0) & (int) (z)->_mp_d[0]) +#define mpz_even_p(z) (! mpz_odd_p (z)) + +int mpz_sgn (const mpz_t); +int mpz_cmp_si (const mpz_t, long); +int mpz_cmp_ui (const mpz_t, unsigned long); +int mpz_cmp (const mpz_t, const mpz_t); +int mpz_cmpabs_ui (const mpz_t, unsigned long); +int mpz_cmpabs (const mpz_t, const mpz_t); +int mpz_cmp_d (const mpz_t, double); +int mpz_cmpabs_d (const mpz_t, double); + +void mpz_abs (mpz_t, const mpz_t); +void mpz_neg (mpz_t, const mpz_t); +void mpz_swap (mpz_t, mpz_t); + +void mpz_add_ui (mpz_t, const mpz_t, unsigned long); +void mpz_add (mpz_t, const mpz_t, const mpz_t); +void mpz_sub_ui (mpz_t, const mpz_t, unsigned long); +void mpz_ui_sub (mpz_t, unsigned long, const mpz_t); +void mpz_sub (mpz_t, const mpz_t, const mpz_t); + +void mpz_mul_si (mpz_t, const mpz_t, long int); +void mpz_mul_ui (mpz_t, const mpz_t, unsigned long int); +void mpz_mul (mpz_t, const mpz_t, const mpz_t); +void mpz_mul_2exp (mpz_t, const mpz_t, mp_bitcnt_t); +void mpz_addmul_ui (mpz_t, const mpz_t, unsigned long int); +void mpz_addmul (mpz_t, const mpz_t, const mpz_t); +void mpz_submul_ui (mpz_t, const mpz_t, unsigned long int); +void mpz_submul (mpz_t, const mpz_t, const mpz_t); + +void mpz_cdiv_qr (mpz_t, mpz_t, const mpz_t, const mpz_t); +void mpz_fdiv_qr (mpz_t, mpz_t, const mpz_t, const mpz_t); +void mpz_tdiv_qr (mpz_t, mpz_t, const mpz_t, const mpz_t); +void mpz_cdiv_q (mpz_t, const mpz_t, const mpz_t); +void mpz_fdiv_q (mpz_t, const mpz_t, const mpz_t); +void mpz_tdiv_q (mpz_t, const mpz_t, const mpz_t); +void mpz_cdiv_r (mpz_t, const mpz_t, const mpz_t); +void mpz_fdiv_r (mpz_t, const mpz_t, const mpz_t); +void mpz_tdiv_r (mpz_t, const mpz_t, const mpz_t); + +void mpz_cdiv_q_2exp (mpz_t, const mpz_t, mp_bitcnt_t); +void mpz_fdiv_q_2exp (mpz_t, const mpz_t, mp_bitcnt_t); +void mpz_tdiv_q_2exp (mpz_t, const mpz_t, mp_bitcnt_t); +void mpz_cdiv_r_2exp (mpz_t, const mpz_t, mp_bitcnt_t); +void mpz_fdiv_r_2exp (mpz_t, const mpz_t, mp_bitcnt_t); +void mpz_tdiv_r_2exp (mpz_t, const mpz_t, mp_bitcnt_t); + +void mpz_mod (mpz_t, const mpz_t, const mpz_t); + +void mpz_divexact (mpz_t, const mpz_t, const mpz_t); + +int mpz_divisible_p (const mpz_t, const mpz_t); +int mpz_congruent_p (const mpz_t, const mpz_t, const mpz_t); + +unsigned long mpz_cdiv_qr_ui (mpz_t, mpz_t, const mpz_t, unsigned long); +unsigned long mpz_fdiv_qr_ui (mpz_t, mpz_t, const mpz_t, unsigned long); +unsigned long mpz_tdiv_qr_ui (mpz_t, mpz_t, const mpz_t, unsigned long); +unsigned long mpz_cdiv_q_ui (mpz_t, const mpz_t, unsigned long); +unsigned long mpz_fdiv_q_ui (mpz_t, const mpz_t, unsigned long); +unsigned long mpz_tdiv_q_ui (mpz_t, const mpz_t, unsigned long); +unsigned long mpz_cdiv_r_ui (mpz_t, const mpz_t, unsigned long); +unsigned long mpz_fdiv_r_ui (mpz_t, const mpz_t, unsigned long); +unsigned long mpz_tdiv_r_ui (mpz_t, const mpz_t, unsigned long); +unsigned long mpz_cdiv_ui (const mpz_t, unsigned long); +unsigned long mpz_fdiv_ui (const mpz_t, unsigned long); +unsigned long mpz_tdiv_ui (const mpz_t, unsigned long); + +unsigned long mpz_mod_ui (mpz_t, const mpz_t, unsigned long); + +void mpz_divexact_ui (mpz_t, const mpz_t, unsigned long); + +int mpz_divisible_ui_p (const mpz_t, unsigned long); + +unsigned long mpz_gcd_ui (mpz_t, const mpz_t, unsigned long); +void mpz_gcd (mpz_t, const mpz_t, const mpz_t); +void mpz_gcdext (mpz_t, mpz_t, mpz_t, const mpz_t, const mpz_t); +void mpz_lcm_ui (mpz_t, const mpz_t, unsigned long); +void mpz_lcm (mpz_t, const mpz_t, const mpz_t); +int mpz_invert (mpz_t, const mpz_t, const mpz_t); + +void mpz_sqrtrem (mpz_t, mpz_t, const mpz_t); +void mpz_sqrt (mpz_t, const mpz_t); +int mpz_perfect_square_p (const mpz_t); + +void mpz_pow_ui (mpz_t, const mpz_t, unsigned long); +void mpz_ui_pow_ui (mpz_t, unsigned long, unsigned long); +void mpz_powm (mpz_t, const mpz_t, const mpz_t, const mpz_t); +void mpz_powm_ui (mpz_t, const mpz_t, unsigned long, const mpz_t); + +void mpz_rootrem (mpz_t, mpz_t, const mpz_t, unsigned long); +int mpz_root (mpz_t, const mpz_t, unsigned long); + +void mpz_fac_ui (mpz_t, unsigned long); +void mpz_2fac_ui (mpz_t, unsigned long); +void mpz_mfac_uiui (mpz_t, unsigned long, unsigned long); +void mpz_bin_uiui (mpz_t, unsigned long, unsigned long); + +int mpz_probab_prime_p (const mpz_t, int); + +int mpz_tstbit (const mpz_t, mp_bitcnt_t); +void mpz_setbit (mpz_t, mp_bitcnt_t); +void mpz_clrbit (mpz_t, mp_bitcnt_t); +void mpz_combit (mpz_t, mp_bitcnt_t); + +void mpz_com (mpz_t, const mpz_t); +void mpz_and (mpz_t, const mpz_t, const mpz_t); +void mpz_ior (mpz_t, const mpz_t, const mpz_t); +void mpz_xor (mpz_t, const mpz_t, const mpz_t); + +mp_bitcnt_t mpz_popcount (const mpz_t); +mp_bitcnt_t mpz_hamdist (const mpz_t, const mpz_t); +mp_bitcnt_t mpz_scan0 (const mpz_t, mp_bitcnt_t); +mp_bitcnt_t mpz_scan1 (const mpz_t, mp_bitcnt_t); + +int mpz_fits_slong_p (const mpz_t); +int mpz_fits_ulong_p (const mpz_t); +int mpz_fits_sint_p (const mpz_t); +int mpz_fits_uint_p (const mpz_t); +int mpz_fits_sshort_p (const mpz_t); +int mpz_fits_ushort_p (const mpz_t); +long int mpz_get_si (const mpz_t); +unsigned long int mpz_get_ui (const mpz_t); +double mpz_get_d (const mpz_t); +size_t mpz_size (const mpz_t); +mp_limb_t mpz_getlimbn (const mpz_t, mp_size_t); + +void mpz_realloc2 (mpz_t, mp_bitcnt_t); +mp_srcptr mpz_limbs_read (mpz_srcptr); +mp_ptr mpz_limbs_modify (mpz_t, mp_size_t); +mp_ptr mpz_limbs_write (mpz_t, mp_size_t); +void mpz_limbs_finish (mpz_t, mp_size_t); +mpz_srcptr mpz_roinit_n (mpz_t, mp_srcptr, mp_size_t); + +#define MPZ_ROINIT_N(xp, xs) {{0, (xs),(xp) }} + +void mpz_set_si (mpz_t, signed long int); +void mpz_set_ui (mpz_t, unsigned long int); +void mpz_set (mpz_t, const mpz_t); +void mpz_set_d (mpz_t, double); + +void mpz_init_set_si (mpz_t, signed long int); +void mpz_init_set_ui (mpz_t, unsigned long int); +void mpz_init_set (mpz_t, const mpz_t); +void mpz_init_set_d (mpz_t, double); + +size_t mpz_sizeinbase (const mpz_t, int); +char *mpz_get_str (char *, int, const mpz_t); +int mpz_set_str (mpz_t, const char *, int); +int mpz_init_set_str (mpz_t, const char *, int); + +/* This long list taken from gmp.h. */ +/* For reference, "defined(EOF)" cannot be used here. In g++ 2.95.4, + defines EOF but not FILE. */ +#if defined (FILE) \ + || defined (H_STDIO) \ + || defined (_H_STDIO) /* AIX */ \ + || defined (_STDIO_H) /* glibc, Sun, SCO */ \ + || defined (_STDIO_H_) /* BSD, OSF */ \ + || defined (__STDIO_H) /* Borland */ \ + || defined (__STDIO_H__) /* IRIX */ \ + || defined (_STDIO_INCLUDED) /* HPUX */ \ + || defined (__dj_include_stdio_h_) /* DJGPP */ \ + || defined (_FILE_DEFINED) /* Microsoft */ \ + || defined (__STDIO__) /* Apple MPW MrC */ \ + || defined (_MSL_STDIO_H) /* Metrowerks */ \ + || defined (_STDIO_H_INCLUDED) /* QNX4 */ \ + || defined (_ISO_STDIO_ISO_H) /* Sun C++ */ \ + || defined (__STDIO_LOADED) /* VMS */ \ + || defined (_STDIO) /* HPE NonStop */ \ + || defined (__DEFINED_FILE) /* musl */ +size_t mpz_out_str (FILE *, int, const mpz_t); +#endif + +void mpz_import (mpz_t, size_t, int, size_t, int, size_t, const void *); +void *mpz_export (void *, size_t *, int, size_t, int, size_t, const mpz_t); + +#if defined (__cplusplus) +} +#endif +#endif /* __MINI_GMP_H__ */ diff --git a/extern/gmp/mini-mpq.c b/extern/gmp/mini-mpq.c new file mode 100644 index 0000000..167d883 --- /dev/null +++ b/extern/gmp/mini-mpq.c @@ -0,0 +1,562 @@ +/* mini-mpq, a minimalistic implementation of a GNU GMP subset. + + Contributed to the GNU project by Marco Bodrato + + Acknowledgment: special thanks to Bradley Lucier for his comments + to the preliminary version of this code. + +Copyright 2018-2022 Free Software Foundation, Inc. + +This file is part of the GNU MP Library. + +The GNU MP Library is free software; you can redistribute it and/or modify +it under the terms of either: + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at your + option) any later version. + +or + + * the GNU General Public License as published by the Free Software + Foundation; either version 2 of the License, or (at your option) any + later version. + +or both in parallel, as here. + +The GNU MP Library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received copies of the GNU General Public License and the +GNU Lesser General Public License along with the GNU MP Library. If not, +see https://www.gnu.org/licenses/. */ + +#include +#include +#include +#include +#include + +#include "mini-mpq.h" + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#pragma GCC diagnostic ignored "-Wsign-conversion" + +#ifndef GMP_LIMB_HIGHBIT +/* Define macros and static functions already defined by mini-gmp.c */ +#define GMP_LIMB_BITS (sizeof(mp_limb_t) * CHAR_BIT) +#define GMP_LIMB_HIGHBIT ((mp_limb_t) 1 << (GMP_LIMB_BITS - 1)) +#define GMP_LIMB_MAX ((mp_limb_t) ~ (mp_limb_t) 0) +#define GMP_NEG_CAST(T,x) (-((T)((x) + 1) - 1)) +#define GMP_MIN(a, b) ((a) < (b) ? (a) : (b)) + +static mpz_srcptr +mpz_roinit_normal_n (mpz_t x, mp_srcptr xp, mp_size_t xs) +{ + x->_mp_alloc = 0; + x->_mp_d = (mp_ptr) xp; + x->_mp_size = xs; + return x; +} + +static void +gmp_die (const char *msg) +{ + fprintf (stderr, "%s\n", msg); + abort(); +} +#endif + + +/* MPQ helper functions */ +static mpq_srcptr +mpq_roinit_normal_nn (mpq_t x, mp_srcptr np, mp_size_t ns, + mp_srcptr dp, mp_size_t ds) +{ + mpz_roinit_normal_n (mpq_numref(x), np, ns); + mpz_roinit_normal_n (mpq_denref(x), dp, ds); + return x; +} + +static mpq_srcptr +mpq_roinit_zz (mpq_t x, mpz_srcptr n, mpz_srcptr d) +{ + return mpq_roinit_normal_nn (x, n->_mp_d, n->_mp_size, + d->_mp_d, d->_mp_size); +} + +static void +mpq_nan_init (mpq_t x) +{ + mpz_init (mpq_numref (x)); + mpz_init (mpq_denref (x)); +} + +void +mpq_init (mpq_t x) +{ + mpz_init (mpq_numref (x)); + mpz_init_set_ui (mpq_denref (x), 1); +} + +void +mpq_clear (mpq_t x) +{ + mpz_clear (mpq_numref (x)); + mpz_clear (mpq_denref (x)); +} + +static void +mpq_canonical_sign (mpq_t r) +{ + mp_size_t ds = mpq_denref (r)->_mp_size; + if (ds <= 0) + { + if (ds == 0) + gmp_die("mpq: Fraction with zero denominator."); + mpz_neg (mpq_denref (r), mpq_denref (r)); + mpz_neg (mpq_numref (r), mpq_numref (r)); + } +} + +static void +mpq_helper_canonicalize (mpq_t r, const mpz_t num, const mpz_t den) +{ + if (num->_mp_size == 0) + mpq_set_ui (r, 0, 1); + else + { + mpz_t g; + + mpz_init (g); + mpz_gcd (g, num, den); + mpz_tdiv_q (mpq_numref (r), num, g); + mpz_tdiv_q (mpq_denref (r), den, g); + mpz_clear (g); + mpq_canonical_sign (r); + } +} + +void +mpq_canonicalize (mpq_t r) +{ + mpq_helper_canonicalize (r, mpq_numref (r), mpq_denref (r)); +} + +void +mpq_swap (mpq_t a, mpq_t b) +{ + mpz_swap (mpq_numref (a), mpq_numref (b)); + mpz_swap (mpq_denref (a), mpq_denref (b)); +} + + +/* MPQ assignment and conversions. */ +void +mpz_set_q (mpz_t r, const mpq_t q) +{ + mpz_tdiv_q (r, mpq_numref (q), mpq_denref (q)); +} + +void +mpq_set (mpq_t r, const mpq_t q) +{ + mpz_set (mpq_numref (r), mpq_numref (q)); + mpz_set (mpq_denref (r), mpq_denref (q)); +} + +void +mpq_set_ui (mpq_t r, unsigned long n, unsigned long d) +{ + mpz_set_ui (mpq_numref (r), n); + mpz_set_ui (mpq_denref (r), d); +} + +void +mpq_set_si (mpq_t r, signed long n, unsigned long d) +{ + mpz_set_si (mpq_numref (r), n); + mpz_set_ui (mpq_denref (r), d); +} + +void +mpq_set_z (mpq_t r, const mpz_t n) +{ + mpz_set_ui (mpq_denref (r), 1); + mpz_set (mpq_numref (r), n); +} + +void +mpq_set_num (mpq_t r, const mpz_t z) +{ + mpz_set (mpq_numref (r), z); +} + +void +mpq_set_den (mpq_t r, const mpz_t z) +{ + mpz_set (mpq_denref (r), z); +} + +void +mpq_get_num (mpz_t r, const mpq_t q) +{ + mpz_set (r, mpq_numref (q)); +} + +void +mpq_get_den (mpz_t r, const mpq_t q) +{ + mpz_set (r, mpq_denref (q)); +} + + +/* MPQ comparisons and the like. */ +int +mpq_cmp (const mpq_t a, const mpq_t b) +{ + mpz_t t1, t2; + int res; + + mpz_init (t1); + mpz_init (t2); + mpz_mul (t1, mpq_numref (a), mpq_denref (b)); + mpz_mul (t2, mpq_numref (b), mpq_denref (a)); + res = mpz_cmp (t1, t2); + mpz_clear (t1); + mpz_clear (t2); + + return res; +} + +int +mpq_cmp_z (const mpq_t a, const mpz_t b) +{ + mpz_t t; + int res; + + mpz_init (t); + mpz_mul (t, b, mpq_denref (a)); + res = mpz_cmp (mpq_numref (a), t); + mpz_clear (t); + + return res; +} + +int +mpq_equal (const mpq_t a, const mpq_t b) +{ + return (mpz_cmp (mpq_numref (a), mpq_numref (b)) == 0) && + (mpz_cmp (mpq_denref (a), mpq_denref (b)) == 0); +} + +int +mpq_cmp_ui (const mpq_t q, unsigned long n, unsigned long d) +{ + mpq_t t; + assert (d != 0); + if (ULONG_MAX <= GMP_LIMB_MAX) { + mp_limb_t nl = n, dl = d; + return mpq_cmp (q, mpq_roinit_normal_nn (t, &nl, n != 0, &dl, 1)); + } else { + int ret; + + mpq_nan_init (t); + mpq_set_ui (t, n, d); + ret = mpq_cmp (q, t); + mpq_clear (t); + + return ret; + } +} + +int +mpq_cmp_si (const mpq_t q, signed long n, unsigned long d) +{ + assert (d != 0); + + if (n >= 0) + return mpq_cmp_ui (q, n, d); + else + { + mpq_t t; + + if (ULONG_MAX <= GMP_LIMB_MAX) + { + mp_limb_t nl = GMP_NEG_CAST (unsigned long, n), dl = d; + return mpq_cmp (q, mpq_roinit_normal_nn (t, &nl, -1, &dl, 1)); + } + else + { + unsigned long l_n = GMP_NEG_CAST (unsigned long, n); + + mpq_roinit_normal_nn (t, mpq_numref (q)->_mp_d, - mpq_numref (q)->_mp_size, + mpq_denref (q)->_mp_d, mpq_denref (q)->_mp_size); + return - mpq_cmp_ui (t, l_n, d); + } + } +} + +int +mpq_sgn (const mpq_t a) +{ + return mpz_sgn (mpq_numref (a)); +} + + +/* MPQ arithmetic. */ +void +mpq_abs (mpq_t r, const mpq_t q) +{ + mpz_abs (mpq_numref (r), mpq_numref (q)); + mpz_set (mpq_denref (r), mpq_denref (q)); +} + +void +mpq_neg (mpq_t r, const mpq_t q) +{ + mpz_neg (mpq_numref (r), mpq_numref (q)); + mpz_set (mpq_denref (r), mpq_denref (q)); +} + +void +mpq_add (mpq_t r, const mpq_t a, const mpq_t b) +{ + mpz_t t; + + mpz_init (t); + mpz_gcd (t, mpq_denref (a), mpq_denref (b)); + if (mpz_cmp_ui (t, 1) == 0) + { + mpz_mul (t, mpq_numref (a), mpq_denref (b)); + mpz_addmul (t, mpq_numref (b), mpq_denref (a)); + mpz_mul (mpq_denref (r), mpq_denref (a), mpq_denref (b)); + mpz_swap (mpq_numref (r), t); + } + else + { + mpz_t x, y; + mpz_init (x); + mpz_init (y); + + mpz_tdiv_q (x, mpq_denref (b), t); + mpz_tdiv_q (y, mpq_denref (a), t); + mpz_mul (x, mpq_numref (a), x); + mpz_addmul (x, mpq_numref (b), y); + + mpz_gcd (t, x, t); + mpz_tdiv_q (mpq_numref (r), x, t); + mpz_tdiv_q (x, mpq_denref (b), t); + mpz_mul (mpq_denref (r), x, y); + + mpz_clear (x); + mpz_clear (y); + } + mpz_clear (t); +} + +void +mpq_sub (mpq_t r, const mpq_t a, const mpq_t b) +{ + mpq_t t; + + mpq_roinit_normal_nn (t, mpq_numref (b)->_mp_d, - mpq_numref (b)->_mp_size, + mpq_denref (b)->_mp_d, mpq_denref (b)->_mp_size); + mpq_add (r, a, t); +} + +void +mpq_div (mpq_t r, const mpq_t a, const mpq_t b) +{ + mpq_t t; + mpq_mul (r, a, mpq_roinit_zz (t, mpq_denref (b), mpq_numref (b))); +} + +void +mpq_mul (mpq_t r, const mpq_t a, const mpq_t b) +{ + mpq_t t; + mpq_nan_init (t); + + if (a != b) { + mpq_helper_canonicalize (t, mpq_numref (a), mpq_denref (b)); + mpq_helper_canonicalize (r, mpq_numref (b), mpq_denref (a)); + + a = r; + b = t; + } + + mpz_mul (mpq_numref (r), mpq_numref (a), mpq_numref (b)); + mpz_mul (mpq_denref (r), mpq_denref (a), mpq_denref (b)); + mpq_clear (t); +} + +static void +mpq_helper_2exp (mpz_t rn, mpz_t rd, const mpz_t qn, const mpz_t qd, mp_bitcnt_t e) +{ + mp_bitcnt_t z = mpz_scan1 (qd, 0); + z = GMP_MIN (z, e); + mpz_mul_2exp (rn, qn, e - z); + mpz_tdiv_q_2exp (rd, qd, z); +} + +void +mpq_div_2exp (mpq_t r, const mpq_t q, mp_bitcnt_t e) +{ + mpq_helper_2exp (mpq_denref (r), mpq_numref (r), mpq_denref (q), mpq_numref (q), e); +} + +void +mpq_mul_2exp (mpq_t r, const mpq_t q, mp_bitcnt_t e) +{ + mpq_helper_2exp (mpq_numref (r), mpq_denref (r), mpq_numref (q), mpq_denref (q), e); +} + +void +mpq_inv (mpq_t r, const mpq_t q) +{ + mpq_set (r, q); + mpz_swap (mpq_denref (r), mpq_numref (r)); + mpq_canonical_sign (r); +} + + +/* MPQ to/from double. */ +void +mpq_set_d (mpq_t r, double x) +{ + mpz_set_ui (mpq_denref (r), 1); + + /* x != x is true when x is a NaN, and x == x * 0.5 is true when x is + zero or infinity. */ + if (x == x * 0.5 || x != x) + mpq_numref (r)->_mp_size = 0; + else + { + double B; + mp_bitcnt_t e; + + B = 4.0 * (double) (GMP_LIMB_HIGHBIT >> 1); + for (e = 0; x != x + 0.5; e += GMP_LIMB_BITS) + x *= B; + + mpz_set_d (mpq_numref (r), x); + mpq_div_2exp (r, r, e); + } +} + +double +mpq_get_d (const mpq_t u) +{ + mp_bitcnt_t ne, de, ee; + mpz_t z; + double B, ret; + + ne = mpz_sizeinbase (mpq_numref (u), 2); + de = mpz_sizeinbase (mpq_denref (u), 2); + + ee = CHAR_BIT * sizeof (double); + if (de == 1 || ne > de + ee) + ee = 0; + else + ee = (ee + de - ne) / GMP_LIMB_BITS + 1; + + mpz_init (z); + mpz_mul_2exp (z, mpq_numref (u), ee * GMP_LIMB_BITS); + mpz_tdiv_q (z, z, mpq_denref (u)); + ret = mpz_get_d (z); + mpz_clear (z); + + B = 4.0 * (double) (GMP_LIMB_HIGHBIT >> 1); + for (B = 1 / B; ee != 0; --ee) + ret *= B; + + return ret; +} + + +/* MPQ and strings/streams. */ +char * +mpq_get_str (char *sp, int base, const mpq_t q) +{ + char *res; + char *rden; + size_t len; + + res = mpz_get_str (sp, base, mpq_numref (q)); + if (res == NULL || mpz_cmp_ui (mpq_denref (q), 1) == 0) + return res; + + len = strlen (res) + 1; + rden = sp ? sp + len : NULL; + rden = mpz_get_str (rden, base, mpq_denref (q)); + assert (rden != NULL); + + if (sp == NULL) { + void * (*gmp_reallocate_func) (void *, size_t, size_t); + void (*gmp_free_func) (void *, size_t); + size_t lden; + + mp_get_memory_functions (NULL, &gmp_reallocate_func, &gmp_free_func); + lden = strlen (rden) + 1; + res = (char *) gmp_reallocate_func (res, len, (lden + len) * sizeof (char)); + memcpy (res + len, rden, lden); + gmp_free_func (rden, lden); + } + + res [len - 1] = '/'; + return res; +} + +size_t +mpq_out_str (FILE *stream, int base, const mpq_t x) +{ + char * str; + size_t len, n; + void (*gmp_free_func) (void *, size_t); + + str = mpq_get_str (NULL, base, x); + if (!str) + return 0; + len = strlen (str); + n = fwrite (str, 1, len, stream); + mp_get_memory_functions (NULL, NULL, &gmp_free_func); + gmp_free_func (str, len + 1); + return n; +} + +int +mpq_set_str (mpq_t r, const char *sp, int base) +{ + const char *slash; + + slash = strchr (sp, '/'); + if (slash == NULL) { + mpz_set_ui (mpq_denref(r), 1); + return mpz_set_str (mpq_numref(r), sp, base); + } else { + char *num; + size_t numlen; + int ret; + void * (*gmp_allocate_func) (size_t); + void (*gmp_free_func) (void *, size_t); + + mp_get_memory_functions (&gmp_allocate_func, NULL, &gmp_free_func); + numlen = slash - sp; + num = (char *) gmp_allocate_func (numlen + 1); + memcpy (num, sp, numlen); + num[numlen] = '\0'; + ret = mpz_set_str (mpq_numref(r), num, base); + gmp_free_func (num, numlen + 1); + + if (ret != 0) + return ret; + + return mpz_set_str (mpq_denref(r), slash + 1, base); + } +} + +#pragma GCC diagnostic pop diff --git a/extern/gmp/mini-mpq.h b/extern/gmp/mini-mpq.h new file mode 100644 index 0000000..8eabcec --- /dev/null +++ b/extern/gmp/mini-mpq.h @@ -0,0 +1,114 @@ +/* mini-mpq, a minimalistic implementation of a GNU GMP subset. + +Copyright 2018, 2019 Free Software Foundation, Inc. + +This file is part of the GNU MP Library. + +The GNU MP Library is free software; you can redistribute it and/or modify +it under the terms of either: + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at your + option) any later version. + +or + + * the GNU General Public License as published by the Free Software + Foundation; either version 2 of the License, or (at your option) any + later version. + +or both in parallel, as here. + +The GNU MP Library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received copies of the GNU General Public License and the +GNU Lesser General Public License along with the GNU MP Library. If not, +see https://www.gnu.org/licenses/. */ + +/* Header */ + +#ifndef __MINI_MPQ_H__ +#define __MINI_MPQ_H__ + +#include "mini-gmp.h" + +#if defined (__cplusplus) +extern "C" { +#endif + +typedef struct +{ + __mpz_struct _mp_num; + __mpz_struct _mp_den; +} __mpq_struct; + +typedef __mpq_struct mpq_t[1]; + +typedef const __mpq_struct *mpq_srcptr; +typedef __mpq_struct *mpq_ptr; + +#define mpq_numref(Q) (&((Q)->_mp_num)) +#define mpq_denref(Q) (&((Q)->_mp_den)) + +void mpq_abs (mpq_t, const mpq_t); +void mpq_add (mpq_t, const mpq_t, const mpq_t); +void mpq_canonicalize (mpq_t); +void mpq_clear (mpq_t); +int mpq_cmp (const mpq_t, const mpq_t); +int mpq_cmp_si (const mpq_t, signed long, unsigned long); +int mpq_cmp_ui (const mpq_t, unsigned long, unsigned long); +int mpq_cmp_z (const mpq_t, const mpz_t); +void mpq_div (mpq_t, const mpq_t, const mpq_t); +void mpq_div_2exp (mpq_t, const mpq_t, mp_bitcnt_t); +int mpq_equal (const mpq_t, const mpq_t); +double mpq_get_d (const mpq_t); +void mpq_get_den (mpz_t, const mpq_t); +void mpq_get_num (mpz_t, const mpq_t); +char * mpq_get_str (char *, int, const mpq_t q); +void mpq_init (mpq_t); +void mpq_inv (mpq_t, const mpq_t); +void mpq_mul (mpq_t, const mpq_t, const mpq_t); +void mpq_mul_2exp (mpq_t, const mpq_t, mp_bitcnt_t); +void mpq_neg (mpq_t, const mpq_t); +void mpq_set (mpq_t, const mpq_t); +void mpq_set_d (mpq_t, double); +void mpq_set_den (mpq_t, const mpz_t); +void mpq_set_num (mpq_t, const mpz_t); +void mpq_set_si (mpq_t, signed long, unsigned long); +int mpq_set_str (mpq_t, const char *, int); +void mpq_set_ui (mpq_t, unsigned long, unsigned long); +void mpq_set_z (mpq_t, const mpz_t); +int mpq_sgn (const mpq_t); +void mpq_sub (mpq_t, const mpq_t, const mpq_t); +void mpq_swap (mpq_t, mpq_t); + +/* This long list taken from gmp.h. */ +/* For reference, "defined(EOF)" cannot be used here. In g++ 2.95.4, + defines EOF but not FILE. */ +#if defined (FILE) \ + || defined (H_STDIO) \ + || defined (_H_STDIO) /* AIX */ \ + || defined (_STDIO_H) /* glibc, Sun, SCO */ \ + || defined (_STDIO_H_) /* BSD, OSF */ \ + || defined (__STDIO_H) /* Borland */ \ + || defined (__STDIO_H__) /* IRIX */ \ + || defined (_STDIO_INCLUDED) /* HPUX */ \ + || defined (__dj_include_stdio_h_) /* DJGPP */ \ + || defined (_FILE_DEFINED) /* Microsoft */ \ + || defined (__STDIO__) /* Apple MPW MrC */ \ + || defined (_MSL_STDIO_H) /* Metrowerks */ \ + || defined (_STDIO_H_INCLUDED) /* QNX4 */ \ + || defined (_ISO_STDIO_ISO_H) /* Sun C++ */ \ + || defined (__STDIO_LOADED) /* VMS */ +size_t mpq_out_str (FILE *, int, const mpq_t); +#endif + +void mpz_set_q (mpz_t, const mpq_t); + +#if defined (__cplusplus) +} +#endif +#endif /* __MINI_MPQ_H__ */ diff --git a/handle_file.c b/handle_file.c new file mode 100644 index 0000000..e69de29 diff --git a/handle_file.h b/handle_file.h new file mode 100644 index 0000000..e69de29 diff --git a/handle_init_file.c b/handle_init_file.c new file mode 100644 index 0000000..0268680 --- /dev/null +++ b/handle_init_file.c @@ -0,0 +1,132 @@ + +#include + +#include + +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include + +#include + +#include "handle_init_file.h" + +void handle_init_file( + struct environment** environment, + struct booleans* booleans, + const char* init_file_path) +{ + ENTER; + + dpvs(init_file_path); + + assert(init_file_path); + + struct istream* stream = new_file_istream( + /* path: */ init_file_path); + + struct wcistream* wcstream = new_istream_wcistream( + /* binary stream: */ stream); + + struct string* filename = new_string_from_ascii( + /* data: */ init_file_path, + /* len: */ (size_t) -1); + + struct position* position = new_position( + /* filename: */ filename, + /* line number: */ 1, + /* column: */ 1); + + struct tokenizer* tokenizer = new_tokenizer( + /* wide-character stream: */ wcstream, + /* inital position (mutated): */ position); + + istream_read(stream); + + wcistream_read(wcstream); + + tokenizer_next(tokenizer); + + while (tokenizer->token->kind == tk_newline) + { + tokenizer_next(tokenizer); + } + + if (tokenizer->token->kind == tk_EOF) + { + // error: empty file + TODO; + } + + while (tokenizer->token->kind != tk_EOF) + { + struct statement* statement = parse( + /* tokenizer: */ tokenizer); + + struct stringtree* error_messages = + statement_prettyprint_errors(statement); + + if (error_messages) + { + // print one (or more) error expressions + TODO; + + // exit(1); + TODO; + } + + statement_execute( + /* instance: */ statement, + /* environment: */ environment, + /* booleans: */ booleans, + /* color factory: */ NULL, + /* wide-character stdout: */ NULL, + /* print value: */ false, + /* print with color?: */ false); + + while (tokenizer->token->kind == tk_newline) + { + tokenizer_next(tokenizer); + } + + free_stringtree(error_messages); + + free_statement(statement); + } + + free_tokenizer(tokenizer); + + free_position(position); + + free_string(filename); + + free_wcistream(wcstream); + + free_istream(stream); + + EXIT; +} + diff --git a/handle_init_file.h b/handle_init_file.h new file mode 100644 index 0000000..fae0611 --- /dev/null +++ b/handle_init_file.h @@ -0,0 +1,9 @@ + +struct environment; + +void handle_init_file( + struct environment** environment, + struct booleans* booleans, + const char* init_file_path); + + diff --git a/handle_interactive.c b/handle_interactive.c new file mode 100644 index 0000000..e69de29 diff --git a/handle_interactive.h b/handle_interactive.h new file mode 100644 index 0000000..e69de29 diff --git a/handle_string.c b/handle_string.c new file mode 100644 index 0000000..e69de29 diff --git a/handle_string.h b/handle_string.h new file mode 100644 index 0000000..e69de29 diff --git a/main.c b/main.c new file mode 100644 index 0000000..e069991 --- /dev/null +++ b/main.c @@ -0,0 +1,364 @@ + +#include + +#include + +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include + +#include + +#include +#include +#include + +#include + +int main(int argc, char* const* argv) +{ + ENTER; + + struct cmdln_flags* flags = new_cmdln_flags(argc, argv); + + struct booleans* booleans = new_booleans(); + + struct color_factory* cfactory = new_color_factory(); + + struct environment* environment = new_environment( + /* fallback: */ NULL); + + environment_declare_builtins( + /* this: */ environment, + /* booleans: */ booleans); + + if (flags->read_init_file) + { + dpvs(flags->custom_init_path); + + handle_init_file(&environment, booleans, flags->custom_init_path); + } + + switch (flags->input_kind) + { + case ik_string: + { + TODO; + #if 0 + assert(flags->input_string); + + struct istream* stream = new_string_istream( + /* read-only text: */ (const uint8_t*) flags->input_string); + + struct string* filename = new_string( + /* data: */ (const uint8_t*) "", + /* len: */ (size_t) -1); + + struct position* position = new_position( + /* filename: */ filename, + /* line number: */ 1, + /* column: */ 1); + + struct tokenizer* tokenizer = new_tokenizer( + /* stream: */ stream, + /* inital position (mutated): */ position); + + istream_read(stream); + + tokenizer_next(tokenizer); + + if (tokenizer->token->kind == tk_EOF) + { + // error: empty file + TODO; + } + + struct environment* environment = new_environment( + /* fallback: */ NULL); + + environment_declare_builtins( + /* this: */ environment); + + while (tokenizer->token->kind != tk_EOF) + { + struct statement* statement = parse( + /* tokenizer: */ tokenizer); + + struct stringtree* error_messages = + statement_prettyprint_errors(statement); + + if (error_messages) + { + // print one (or more) error expressions + TODO; + + // exit(1); + TODO; + } + + if (flags->echo) + { + struct stringtree* stree = statement_prettyprint( + /* instance: */ statement, + /* color factory: */ cfactory, + /* precedence level: */ 0); + + stringtree_println(stree); + + free_stringtree(stree); + } + + statement_execute( + /* instance: */ statement, + /* environment: */ environment, + /* color factory: */ cfactory, + /* print value: */ true); + + free_stringtree(error_messages); + + free_statement(statement); + } + + free_environment(environment); + + free_tokenizer(tokenizer); + + free_position(position); + + free_string(filename); + + free_istream(stream); + #endif + break; + } + + case ik_file: + { + dpvs(flags->input_file); + + assert(flags->input_file); + + struct ostream* b_stdout = new_file_ostream( + /* file descriptor: */ 1); + + struct wcostream* wc_stdout = new_ostream_wcostream( + /* binary stream: */ b_stdout); + + struct istream* stream = new_file_istream( + /* path: */ flags->input_file); + + struct wcistream* wcstream = new_istream_wcistream( + /* binary stream: */ stream); + + struct string* filename = new_string_from_ascii( + /* data: */ flags->input_file, + /* len: */ (size_t) -1); + + struct position* position = new_position( + /* filename: */ filename, + /* line number: */ 1, + /* column: */ 1); + + struct tokenizer* tokenizer = new_tokenizer( + /* wide-character stream: */ wcstream, + /* inital position (mutated): */ position); + + istream_read(stream); + + wcistream_read(wcstream); + + tokenizer_next(tokenizer); + + while (tokenizer->token->kind == tk_newline) + { + tokenizer_next(tokenizer); + } + + if (tokenizer->token->kind == tk_EOF) + { + // error: empty file + TODO; + } + + while (tokenizer->token->kind != tk_EOF) + { + struct statement* statement = parse( + /* tokenizer: */ tokenizer); + + struct stringtree* error_messages = + statement_prettyprint_errors(statement); + + if (error_messages) + { + // print one (or more) error expressions + TODO; + + // exit(1); + TODO; + } + + if (flags->echo) + { + struct stringtree* stree = statement_prettyprint( + /* chosen color reference: */ NULL, + /* instance: */ statement, + /* color factory: */ cfactory, + /* print with color? */ flags->rainbow); + + stringtree_println(stree, wc_stdout); + + free_stringtree(stree); + } + + statement_execute( + /* instance: */ statement, + /* environment: */ &environment, + /* booleans: */ booleans, + /* color factory: */ cfactory, + /* wide-character stdout: */ wc_stdout, + /* print value: */ true, + /* print with color?: */ flags->rainbow); + + while (tokenizer->token->kind == tk_newline) + { + tokenizer_next(tokenizer); + } + + free_stringtree(error_messages); + + free_statement(statement); + } + + free_tokenizer(tokenizer); + + free_position(position); + + free_string(filename); + + free_wcostream(wc_stdout); + + free_wcistream(wcstream); + + free_istream(stream); + + free_ostream(b_stdout); + + break; + } + + case ik_interactive: + { + TODO; + + // maybe this should go into it's own file, because it's complicated \ + beyond parsing and executing the expression. + // maintain the line as a character array + // whenever there's a mutation, re-parse + // if the text is empty: + // grey the prompt + // the input will never contain a newline, it might contain a semicolon + // color the expression \ + which will color the tokens \ + maybe set all tokens to grey first? + // redraw the input line with colored tokens + // the parse will come back happy or unhappy: + // if happy: + // make the prompt green + // if unhappy: + // make prompt red + // for all found 'syntax error' expressions: + // print it's message on a new line, offset at the position \ + of the incedent. + // if the user hits enter: + // ... on an empty prompt: + // new line, redraw grey prompt. + // ... on an unhappy expression: + // maybe blink the error messages? + // ... on a happy expression: + // new line + // evaluate + // '${id} = ' print result + // new line + // grey the prompt. + // increment line number + // save the result into '${id++}' + // free result + break; + } + + default: + { + TODO; + break; + } + } + + free_environment(environment); + + free_color_factory(cfactory); + + free_booleans(booleans); + + free_cmdln_flags(flags); + + EXIT; + return 0; +} + + + + + + + + + + + + diff --git a/makefile b/makefile new file mode 100644 index 0000000..e58d0de --- /dev/null +++ b/makefile @@ -0,0 +1,77 @@ + +# vim: noexpandtab tabstop=4 : + +buildtype ?= release + +optionset = buildtypes/${buildtype}.txt + +prefix = bin/${buildtype}-buildtype + +default: ${prefix}/13 + +on_error ?= do_nothing +ifeq ($(on_error), do_nothing) +on_error_command = +else ifeq ($(on_error), open_editor) +on_error_command += || ($$EDITOR $<; false) +else +$(error "invalid on_error option!"); +endif + +.PRECIOUS: %/ + +%/: + @mkdir -p $@ + +srclist.mk: + find -name '*.c' -! -path '*/junk/*' | sed "s/^/srcs += /" | sort -V > ${@} + +include srclist.mk + +${prefix}/%.o ${prefix}/%.d: %.c ${optionset} | ${prefix}/%/ + @echo "compiling (${buildtype}) ${<} ..." + @gcc -c @${optionset} $< -MD -MF ${prefix}/${*}.d -o ${prefix}/${*}.o $(on_error_command) + +objs = $(patsubst %.c,${prefix}/%.o,${srcs}) + +${prefix}/13: ${objs} ${optionset} | ${prefix}/${1}/ + @echo "linking (${buildtype}) ${1}" + @gcc @${optionset} ${objs} -o ${@} -lm + +#args += --echo +args += --echo-rainbow +#args += --no-init + +args += --custom-init-path ./examples/init.txt + +#args += -c '1' + +args += ./examples/sandbox.txt + +run: ${prefix}/13 + $< ${args} + +valrun: ${prefix}/13 + valgrind --exit-on-first-error=yes --error-exitcode=1 -- $< ${args} + +valrun-leak: ${prefix}/13 + valgrind --exit-on-first-error=yes --error-exitcode=1 --leak-check=full -- $< ${args} + +include $(patsubst %.c,${prefix}/%.d,${srcs}) + + + + + + + + + + + + + + + + + diff --git a/memory/smalloc.c b/memory/smalloc.c new file mode 100644 index 0000000..8d5de92 --- /dev/null +++ b/memory/smalloc.c @@ -0,0 +1,25 @@ + +#include +#include + +#include + +#include "smalloc.h" + +void* smalloc(size_t size) +{ + ENTER; + + dpvlu(size); + + void* ptr = malloc(size); + + if (!ptr) + { + TODO; + } + + EXIT; + return ptr; +} + diff --git a/memory/smalloc.h b/memory/smalloc.h new file mode 100644 index 0000000..63e1aa5 --- /dev/null +++ b/memory/smalloc.h @@ -0,0 +1,4 @@ + +#include + +void* smalloc(size_t size); diff --git a/memory/srealloc.c b/memory/srealloc.c new file mode 100644 index 0000000..c5f442c --- /dev/null +++ b/memory/srealloc.c @@ -0,0 +1,25 @@ + +#include +#include + +#include + +#include "srealloc.h" + +void* srealloc( + void* oldptr, + size_t size) +{ + ENTER; + + void* newptr = realloc(oldptr, size); + + if (!newptr) + { + TODO; + } + + EXIT; + return newptr; +} + diff --git a/memory/srealloc.h b/memory/srealloc.h new file mode 100644 index 0000000..e19cf80 --- /dev/null +++ b/memory/srealloc.h @@ -0,0 +1,6 @@ + +#include + +void* srealloc( + void* oldptr, + size_t size); diff --git a/misc/wcindex.c b/misc/wcindex.c new file mode 100644 index 0000000..9bd1ee6 --- /dev/null +++ b/misc/wcindex.c @@ -0,0 +1,18 @@ + +#include + +#include "wcindex.h" + +const wchar_t* wcindex( + const wchar_t* str, + wchar_t wc) +{ + while (*str) + if (*str == wc) + return str; + else + str++; + + return NULL; +} + diff --git a/misc/wcindex.h b/misc/wcindex.h new file mode 100644 index 0000000..e13d564 --- /dev/null +++ b/misc/wcindex.h @@ -0,0 +1,8 @@ + +#include + +const wchar_t* wcindex( + const wchar_t* str, + wchar_t wc); + + diff --git a/notes.md b/notes.md new file mode 100644 index 0000000..590dc40 --- /dev/null +++ b/notes.md @@ -0,0 +1,86 @@ + +I want a command-line interpreter with optional echo and rainbow parenthessis. +I want to read from a file, printing what was read and then the result. + +I want 'define' or 'def' or some symbol creates a new global namespace/envronment +that falls back to the previous. + +// this is mostly a neat calculator + +// let's also read an .13rc init file. There's a command-line option not to. + +// main will be a parse, eval, print and free loop. + +// I want to be able to change things interactively + // using extra syntax not allowed in the files? + +// I want a good interactive prompt: + // colors + // syntax errors + +// in order to get that, the tokenizer will have to hand out token objects \ + that are assigned colors? + +// the parser will also have to gracefully handle syntax errors, by creating \ + 'syntax error' expressions + +// main will have to scan for these? and partially color things that make \ + sense and give a message for the rest? + +// reading from a file will be senstive to newlines. newlines end a statement. \ + that is, a statement is ended with a newline only if the statement would \ + validily parse ending where it is. otherwise, ignore the newline. +// semicolons delimit multiple statements on the same line. + +// a b c => (a(b))(c) + +// a lambda: b c + // a(lambda: b c) + // (a(lambda: b))(c) + +// lambda x: x 4 + +// lambda x: x (lambda y: y) + +// (lambda x: x) 4 + +// lambda n: lambda f: lambda x: f (n f x) + // lambda n: (lambda f: (lambda x: f((n(f))(x)))) + +// a b c d e + // (((a(b))(c))(d))(e) + +``` +primary-expression + : variable-name // use of variable + | integer-literal // literal + | '(' root-expression ')' // higher operator preceidence + ; + +abstraction: ('lambda' | 'λ') (variable-name (',' variable-name)*)? (':' | '.') postfix-expression; + +postfix-expression + : primary-expression + | postfix-expression primary-expression // function call + | postfix-expression abstraction // function call passing in a function declaration + ; + +lambda-expression + : postfix-expression + | abstraction + ; + +root-expression: lambda-expression; + +expression: root-expression; + +statement: (variable-name '=')* expression; + +statements: statement (';' statement)* ';'?; + +%start: statements; +``` + + + + diff --git a/number/add.c b/number/add.c new file mode 100644 index 0000000..7a63803 --- /dev/null +++ b/number/add.c @@ -0,0 +1,23 @@ + +#include + +#include + +#include "struct.h" +#include "new.h" +#include "add.h" + +struct number* number_add( + struct number* left, + struct number* right) +{ + ENTER; + + struct number* this = new_number(); + + mpq_add(this->number, left->number, right->number); + + EXIT; + return this; +} + diff --git a/number/add.h b/number/add.h new file mode 100644 index 0000000..00ef17d --- /dev/null +++ b/number/add.h @@ -0,0 +1,6 @@ + +struct number* number_add( + struct number* left, + struct number* right); + + diff --git a/number/compare.c b/number/compare.c new file mode 100644 index 0000000..a324ddd --- /dev/null +++ b/number/compare.c @@ -0,0 +1,13 @@ + +#include + +#include "struct.h" +#include "compare.h" + +int compare_number( + const struct number* a, + const struct number* b) +{ + return mpq_cmp(a->number, b->number); +} + diff --git a/number/compare.h b/number/compare.h new file mode 100644 index 0000000..e3bd46b --- /dev/null +++ b/number/compare.h @@ -0,0 +1,8 @@ + +struct number; + +int compare_number( + const struct number* a, + const struct number* b); + + diff --git a/number/free.c b/number/free.c new file mode 100644 index 0000000..e2dd14f --- /dev/null +++ b/number/free.c @@ -0,0 +1,22 @@ + +#include + +#include + +#include "struct.h" +#include "free.h" + +void free_number( + struct number* this) +{ + ENTER; + + if (this && !--this->refcount) + { + mpq_clear(this->number); + + free(this); + } + + EXIT; +} diff --git a/number/free.h b/number/free.h new file mode 100644 index 0000000..32e87b8 --- /dev/null +++ b/number/free.h @@ -0,0 +1,7 @@ + +struct number; + +void free_number( + struct number* this); + + diff --git a/number/inc.c b/number/inc.c new file mode 100644 index 0000000..75d6586 --- /dev/null +++ b/number/inc.c @@ -0,0 +1,15 @@ + +#include + +#include "struct.h" +#include "inc.h" + +struct number* inc_number( + struct number* this) +{ + if (this) + this->refcount++; + + return this; +} + diff --git a/number/inc.h b/number/inc.h new file mode 100644 index 0000000..03ce0f5 --- /dev/null +++ b/number/inc.h @@ -0,0 +1,6 @@ + +struct number; + +struct number* inc_number( + struct number* this); + diff --git a/number/multiply.c b/number/multiply.c new file mode 100644 index 0000000..903d445 --- /dev/null +++ b/number/multiply.c @@ -0,0 +1,23 @@ + +#include + +#include + +#include "struct.h" +#include "new.h" +#include "add.h" + +struct number* number_multiply( + struct number* left, + struct number* right) +{ + ENTER; + + struct number* this = new_number(); + + mpq_mul(this->number, left->number, right->number); + + EXIT; + return this; +} + diff --git a/number/multiply.h b/number/multiply.h new file mode 100644 index 0000000..c257c41 --- /dev/null +++ b/number/multiply.h @@ -0,0 +1,8 @@ + +struct number; + +struct number* number_multiply( + struct number* left, + struct number* right); + + diff --git a/number/new.c b/number/new.c new file mode 100644 index 0000000..7395133 --- /dev/null +++ b/number/new.c @@ -0,0 +1,25 @@ + +#include + +#include + +#include + +#include "struct.h" +#include "new.h" + +struct number* new_number(void) +{ + ENTER; + + struct number* this = smalloc(sizeof(*this)); + + mpq_init(this->number); + + this->refcount = 1; + + EXIT; + return this; +} + + diff --git a/number/new.h b/number/new.h new file mode 100644 index 0000000..d9eb4e7 --- /dev/null +++ b/number/new.h @@ -0,0 +1,5 @@ + + +struct number* new_number( + void); + diff --git a/number/prettyprint.c b/number/prettyprint.c new file mode 100644 index 0000000..f0bc533 --- /dev/null +++ b/number/prettyprint.c @@ -0,0 +1,154 @@ + +#include + +#include + +#include +#include + +#include +#include +#include +#include + +#include "struct.h" +#include "prettyprint.h" + +static struct stringtree* prettyprint_mpn( + mpz_srcptr printme, + const wchar_t* digits) +{ + ENTER; + + struct stringtree* tree = new_stringtree(); + + mpz_t countdown, digit, ten; + + mpz_init(digit); + + mpz_init_set_ui(ten, 10); + + mpz_init_set(countdown, printme); + + assert(mpz_sgn(countdown) >= 0); + + if (mpz_sgn(countdown) == 0) + { + stringtree_append_cstr(tree, L"0"); + } + else while (mpz_sgn(countdown)) + { + mpz_fdiv_qr(countdown, digit, countdown, ten); + + wchar_t wc = digits[mpz_get_ui(digit)]; + + dpvwc(wc); + + struct string* d = new_string(&wc, 1); + + stringtree_prepend_string(tree, d); + + free_string(d); + } + + mpz_clear(countdown); + + mpz_clear(digit); + + mpz_clear(ten); + + EXIT; + return tree; +} + +struct stringtree* number_prettyprint( + struct number* this) +{ + ENTER; + + struct stringtree* tree = new_stringtree(); + + mpq_t clone; + + mpq_init(clone); + + mpq_set(clone, this->number); + + if (mpq_sgn(clone) < 0) + { + stringtree_append_cstr(tree, L"-"); + + mpq_abs(clone, clone); + } + + mpz_t whole; + + mpz_init(whole); + + mpz_fdiv_q(whole, mpq_numref(clone), mpq_denref(clone)); + + struct stringtree* whole_tree = prettyprint_mpn(whole, L"0123456789"); + + stringtree_append_stringtree(tree, whole_tree); + + // subtract whole out of clone: + { + mpq_t tmp; + + mpq_init(tmp); + + mpq_set_z(tmp, whole); + + mpq_sub(clone, clone, tmp); + + mpq_clear(tmp); + } + + // print decimal: + if (mpq_sgn(clone)) + { + struct stringtree* num_tree = prettyprint_mpn( + mpq_numref(clone), L"⁰¹²³⁴⁵⁶⁷⁸⁹"); + + struct stringtree* den_tree = prettyprint_mpn( + mpq_denref(clone), L"₀₁₂₃₄₅₆₇₈₉"); + + // stringtree_append_cstr(tree, L" "); + + stringtree_append_stringtree(tree, num_tree); + + stringtree_append_cstr(tree, L"/"); + + stringtree_append_stringtree(tree, den_tree); + + free_stringtree(num_tree); + + free_stringtree(den_tree); + } + + free_stringtree(whole_tree); + + mpz_clear(whole); + + mpq_clear(clone); + + EXIT; + return tree; +} + + + + + + + + + + + + + + + + + diff --git a/number/prettyprint.h b/number/prettyprint.h new file mode 100644 index 0000000..d925a76 --- /dev/null +++ b/number/prettyprint.h @@ -0,0 +1,6 @@ + +struct number; + +struct stringtree* number_prettyprint( + struct number* this); + diff --git a/number/set_int.c b/number/set_int.c new file mode 100644 index 0000000..4502593 --- /dev/null +++ b/number/set_int.c @@ -0,0 +1,13 @@ + +#include + +#include "struct.h" +#include "set_int.h" + +void number_set_int( + struct number* this, + int x) +{ + mpq_set_si(this->number, x, 1); +} + diff --git a/number/set_int.h b/number/set_int.h new file mode 100644 index 0000000..03e71ff --- /dev/null +++ b/number/set_int.h @@ -0,0 +1,8 @@ + +struct number; + +void number_set_int( + struct number* this, + int x); + + diff --git a/number/set_str.c b/number/set_str.c new file mode 100644 index 0000000..088a2df --- /dev/null +++ b/number/set_str.c @@ -0,0 +1,142 @@ + +#include + +#include + +#include + +#include + +#include "struct.h" +#include "set_str.h" + +void number_set_str( + struct number* this, + const wchar_t* text) +{ + // "text" might be binary, octal, hexadecimal, or a float. + // "text" might contain a decimal point. Hopefully just one. + ENTER; + + assert(text); + assert(*text); + + dpvws(text); + + mpq_t base; + + mpq_init(base); + + const wchar_t* start = text; + + if (*start != L'0') + { + mpq_set_ui(base, 10, 1); + } + else switch (start[1]) + { + case L'x': + mpq_set_ui(base, 16, 1), start += 2; + break; + + case L'b': + mpq_set_ui(base, 2, 1), start += 2; + break; + + default: + mpq_set_ui(base, 8, 1); + break; + } + + mpq_ptr result = this->number; + + // initalize result to 0. + mpq_set_ui(result, 0, 1); + + const wchar_t* dot = wcindex(text, L'.'); + + // parse whole number: + { + const wchar_t* end = dot ? dot - 1 : start + wcslen(start) - 1; + + assert(start <= end); + + mpq_t multiplier, digit; + + mpq_init(multiplier); + mpq_init(digit); + + mpq_set_ui(multiplier, 1, 1); + + while (start <= end) + { + wchar_t e = *end--; + + dpvc(e); + + assert(e >= L'0'); + + mpq_set_ui(digit, (unsigned) (e - '0'), 1); + + mpq_mul(digit, digit, multiplier); + + mpq_add(result, result, digit); + + mpq_mul(multiplier, multiplier, base); + } + + mpq_clear(multiplier); + mpq_clear(digit); + } + + if (dot) + { + const wchar_t* moving = dot + 1; + + dpvws(moving); + + mpq_t multiplier, digit; + + mpq_init(multiplier); + mpq_init(digit); + + mpq_set_ui(multiplier, 1, 1); + + mpq_div(multiplier, multiplier, base); + + while (*moving) + { + wchar_t e = *moving++; + + dpvwc(e); + + assert(e >= '0'); + + mpq_set_ui(digit, (unsigned) (e - '0'), 1); + + mpq_mul(digit, digit, multiplier); + + mpq_add(result, result, digit); + + mpq_div(multiplier, multiplier, base); + } + + mpq_clear(multiplier); + mpq_clear(digit); + } + + mpq_clear(base); + + EXIT; +} + + + + + + + + + + + diff --git a/number/set_str.h b/number/set_str.h new file mode 100644 index 0000000..cbbd1bd --- /dev/null +++ b/number/set_str.h @@ -0,0 +1,9 @@ + +struct number; + +void number_set_str( + struct number* this, + const wchar_t* text); + + + diff --git a/number/struct.h b/number/struct.h new file mode 100644 index 0000000..76c6d4e --- /dev/null +++ b/number/struct.h @@ -0,0 +1,11 @@ + +#include + +struct number +{ + mpq_t number; + + unsigned refcount; +}; + + diff --git a/number/subtract.c b/number/subtract.c new file mode 100644 index 0000000..636493d --- /dev/null +++ b/number/subtract.c @@ -0,0 +1,23 @@ + +#include + +#include + +#include "struct.h" +#include "new.h" +#include "subtract.h" + +struct number* number_subtract( + struct number* left, + struct number* right) +{ + ENTER; + + struct number* this = new_number(); + + mpq_sub(this->number, left->number, right->number); + + EXIT; + return this; +} + diff --git a/number/subtract.h b/number/subtract.h new file mode 100644 index 0000000..bb194d1 --- /dev/null +++ b/number/subtract.h @@ -0,0 +1,5 @@ + +struct number* number_subtract( + struct number* left, + struct number* right); + diff --git a/ostream/file/free.c b/ostream/file/free.c new file mode 100644 index 0000000..7c976e6 --- /dev/null +++ b/ostream/file/free.c @@ -0,0 +1,23 @@ + +#include + +#include + +#include "struct.h" +#include "free.h" + +void free_file_ostream( + struct ostream* super) +{ + ENTER; + + struct file_ostream* const this = (void*) super; + + if (this->fd > 2) + { + TODO; + } + + EXIT; +} + diff --git a/ostream/file/free.h b/ostream/file/free.h new file mode 100644 index 0000000..d610fb1 --- /dev/null +++ b/ostream/file/free.h @@ -0,0 +1,7 @@ + +struct ostream; + +void free_file_ostream( + struct ostream* super); + + diff --git a/ostream/file/inheritance.c b/ostream/file/inheritance.c new file mode 100644 index 0000000..b2b5e5b --- /dev/null +++ b/ostream/file/inheritance.c @@ -0,0 +1,14 @@ + +#include + +#include "write.h" +#include "free.h" + +#include "inheritance.h" + +struct ostream_inheritance file_ostream_inheritance = { + .write = file_ostream_write, + + .free = free_file_ostream +}; + diff --git a/ostream/file/inheritance.h b/ostream/file/inheritance.h new file mode 100644 index 0000000..0bb5167 --- /dev/null +++ b/ostream/file/inheritance.h @@ -0,0 +1,6 @@ + +#include "../inheritance.h" + +extern struct ostream_inheritance file_ostream_inheritance; + + diff --git a/ostream/file/new.c b/ostream/file/new.c new file mode 100644 index 0000000..a235e50 --- /dev/null +++ b/ostream/file/new.c @@ -0,0 +1,24 @@ + +#include + +#include "../new.h" + +#include "inheritance.h" +#include "struct.h" +#include "new.h" + +struct ostream* new_file_ostream( + int fd) +{ + ENTER; + + struct file_ostream* this = (void*) new_ostream( + /* inheritance: */ &file_ostream_inheritance, + /* alloc size: */ sizeof(*this)); + + this->fd = fd; + + EXIT; + return (void*) this; +} + diff --git a/ostream/file/new.h b/ostream/file/new.h new file mode 100644 index 0000000..abc6d29 --- /dev/null +++ b/ostream/file/new.h @@ -0,0 +1,4 @@ + +struct ostream* new_file_ostream( + int fd); + diff --git a/ostream/file/struct.h b/ostream/file/struct.h new file mode 100644 index 0000000..9b5bd04 --- /dev/null +++ b/ostream/file/struct.h @@ -0,0 +1,10 @@ + +#include "../struct.h" + +struct file_ostream +{ + struct ostream super; + + int fd; +}; + diff --git a/ostream/file/write.c b/ostream/file/write.c new file mode 100644 index 0000000..8af1c02 --- /dev/null +++ b/ostream/file/write.c @@ -0,0 +1,31 @@ + +#include +#include +#include + +#include + +#include "struct.h" +#include "write.h" + +void file_ostream_write( + struct ostream* super, + const uint8_t* data, + size_t len) +{ + ENTER; + + struct file_ostream* const this = (void*) super; + + ssize_t retval = write(this->fd, data, len); + + if (retval < 0) + { + TODO; + } + + EXIT; +} + + + diff --git a/ostream/file/write.h b/ostream/file/write.h new file mode 100644 index 0000000..4e4127f --- /dev/null +++ b/ostream/file/write.h @@ -0,0 +1,12 @@ + +#include +#include + +struct ostream; + +void file_ostream_write( + struct ostream* super, + const uint8_t* data, + size_t len); + + diff --git a/ostream/free.c b/ostream/free.c new file mode 100644 index 0000000..9967fbe --- /dev/null +++ b/ostream/free.c @@ -0,0 +1,29 @@ + +#include +#include + +#include + +#include "inheritance.h" +#include "struct.h" +#include "free.h" + +void free_ostream( + struct ostream* this) +{ + ENTER; + + if (this && !--this->refcount) + { + assert(this); + assert(this->inheritance); + assert(this->inheritance->free); + + (this->inheritance->free)(this); + + free(this); + } + + EXIT; +} + diff --git a/ostream/free.h b/ostream/free.h new file mode 100644 index 0000000..6494b91 --- /dev/null +++ b/ostream/free.h @@ -0,0 +1,6 @@ + +struct ostream; + +void free_ostream( + struct ostream* this); + diff --git a/ostream/inc.c b/ostream/inc.c new file mode 100644 index 0000000..cbbf60a --- /dev/null +++ b/ostream/inc.c @@ -0,0 +1,15 @@ + +#include + +#include "struct.h" +#include "inc.h" + +struct ostream* inc_ostream( + struct ostream* this) +{ + if (this) + this->refcount++; + + return this; +} + diff --git a/ostream/inc.h b/ostream/inc.h new file mode 100644 index 0000000..3c67354 --- /dev/null +++ b/ostream/inc.h @@ -0,0 +1,7 @@ + +struct ostream; + +struct ostream* inc_ostream( + struct ostream* this); + + diff --git a/ostream/inheritance.h b/ostream/inheritance.h new file mode 100644 index 0000000..794b250 --- /dev/null +++ b/ostream/inheritance.h @@ -0,0 +1,16 @@ + +#include +#include + +struct ostream; + +struct ostream_inheritance +{ + void (*write)( + struct ostream*, + const uint8_t*, + size_t); + + void (*free)( + struct ostream*); +}; diff --git a/ostream/new.c b/ostream/new.c new file mode 100644 index 0000000..abbba6c --- /dev/null +++ b/ostream/new.c @@ -0,0 +1,24 @@ + +#include + +#include + +#include "struct.h" +#include "new.h" + +struct ostream* new_ostream( + const struct ostream_inheritance* inheritance, + size_t alloc_size) +{ + ENTER; + + struct ostream* this = smalloc(alloc_size); + + this->inheritance = inheritance; + + this->refcount = 1; + + EXIT; + return this; +} + diff --git a/ostream/new.h b/ostream/new.h new file mode 100644 index 0000000..523923b --- /dev/null +++ b/ostream/new.h @@ -0,0 +1,10 @@ + +#include + +struct ostream_inheritance; + +struct ostream* new_ostream( + const struct ostream_inheritance* inheritance, + size_t alloc_size); + + diff --git a/ostream/struct.h b/ostream/struct.h new file mode 100644 index 0000000..166b6a5 --- /dev/null +++ b/ostream/struct.h @@ -0,0 +1,12 @@ + +struct ostream_inheritance; + +struct ostream +{ + const struct ostream_inheritance* inheritance; + + unsigned refcount; +}; + + + diff --git a/ostream/write.c b/ostream/write.c new file mode 100644 index 0000000..b5e931e --- /dev/null +++ b/ostream/write.c @@ -0,0 +1,25 @@ + +#include + +#include + +#include "struct.h" +#include "inheritance.h" +#include "write.h" + +void ostream_write( + struct ostream* this, + const uint8_t* data, + size_t len) +{ + ENTER; + + assert(this); + assert(this->inheritance); + assert(this->inheritance->write); + + (this->inheritance->write)(this, data, len); + + EXIT; +} + diff --git a/ostream/write.h b/ostream/write.h new file mode 100644 index 0000000..063e49e --- /dev/null +++ b/ostream/write.h @@ -0,0 +1,11 @@ + +#include + +#include + +struct ostream; + +void ostream_write( + struct ostream* this, + const uint8_t* data, + size_t len); diff --git a/parse/istream/file/free.c b/parse/istream/file/free.c new file mode 100644 index 0000000..9c453c1 --- /dev/null +++ b/parse/istream/file/free.c @@ -0,0 +1,20 @@ + +#include + +#include + +#include "struct.h" +#include "free.h" + +void free_file_istream( + struct istream* super) +{ + ENTER; + + struct file_istream* this = (void*) super; + + close(this->fd); + + EXIT; +} + diff --git a/parse/istream/file/free.h b/parse/istream/file/free.h new file mode 100644 index 0000000..e57b287 --- /dev/null +++ b/parse/istream/file/free.h @@ -0,0 +1,3 @@ + +void free_file_istream( + struct istream* super); diff --git a/parse/istream/file/inheritance.c b/parse/istream/file/inheritance.c new file mode 100644 index 0000000..2628ad1 --- /dev/null +++ b/parse/istream/file/inheritance.c @@ -0,0 +1,16 @@ + +#include + +#include "../inheritance.h" + +#include "free.h" +#include "read.h" +#include "inheritance.h" + +struct istream_inheritance file_istream_inheritance = +{ + .read = file_istream_read, + + .free = free_file_istream, +}; + diff --git a/parse/istream/file/inheritance.h b/parse/istream/file/inheritance.h new file mode 100644 index 0000000..c79a5f4 --- /dev/null +++ b/parse/istream/file/inheritance.h @@ -0,0 +1,6 @@ + +#include "../inheritance.h" + +extern struct istream_inheritance file_istream_inheritance; + + diff --git a/parse/istream/file/new.c b/parse/istream/file/new.c new file mode 100644 index 0000000..9ac0003 --- /dev/null +++ b/parse/istream/file/new.c @@ -0,0 +1,40 @@ + +#include +#include + +#include + +#include "../new.h" + +#include "inheritance.h" +#include "struct.h" +#include "new.h" + +struct istream* new_file_istream( + const char* input_file) +{ + ENTER; + + struct file_istream* this = (void*) new_istream( + &file_istream_inheritance, + sizeof(*this)); + + int fd = open(input_file, O_RDONLY); + + if (fd < 0) + { + TODO; + } + + this->fd = fd; + + this->i = 0; + this->n = 0; + + EXIT; + return (void*) this; +} + + + + diff --git a/parse/istream/file/new.h b/parse/istream/file/new.h new file mode 100644 index 0000000..638002a --- /dev/null +++ b/parse/istream/file/new.h @@ -0,0 +1,3 @@ + +struct istream* new_file_istream( + const char* input_file); diff --git a/parse/istream/file/read.c b/parse/istream/file/read.c new file mode 100644 index 0000000..8ba85bd --- /dev/null +++ b/parse/istream/file/read.c @@ -0,0 +1,49 @@ + +#include +#include +#include + +#include + +#include "struct.h" +#include "read.h" + +void file_istream_read( + struct istream* super) +{ + ENTER; + + struct file_istream* this = (void*) super; + + if (this->i < this->n) + { + super->c = this->buffer[this->i++]; + + dpvc(super->c); + } + else + { + ssize_t read_retval = read(this->fd, this->buffer, sizeof(this->buffer)); + + if (read_retval < 0) + { + TODO; + } + else if (!read_retval) + { + super->c = 0; + } + else + { + this->i = 0; + this->n = (size_t) read_retval; + + super->c = this->buffer[this->i++]; + + dpvc(super->c); + } + } + + EXIT; +} + diff --git a/parse/istream/file/read.h b/parse/istream/file/read.h new file mode 100644 index 0000000..986c836 --- /dev/null +++ b/parse/istream/file/read.h @@ -0,0 +1,3 @@ + +void file_istream_read( + struct istream* this); diff --git a/parse/istream/file/struct.h b/parse/istream/file/struct.h new file mode 100644 index 0000000..898e8c1 --- /dev/null +++ b/parse/istream/file/struct.h @@ -0,0 +1,18 @@ + +#include +#include + +#include "../struct.h" + +struct file_istream +{ + struct istream super; + + int fd; + + uint8_t buffer[4096]; + + size_t i, n; +}; + + diff --git a/parse/istream/free.c b/parse/istream/free.c new file mode 100644 index 0000000..7b8b822 --- /dev/null +++ b/parse/istream/free.c @@ -0,0 +1,29 @@ + +#include +#include + +#include + +#include "inheritance.h" +#include "struct.h" +#include "free.h" + +void free_istream( + struct istream* this) +{ + ENTER; + + if (this && !--this->refcount) + { + assert(this); + assert(this->inheritance); + assert(this->inheritance->free); + + (this->inheritance->free)(this); + + free(this); + } + + EXIT; +} + diff --git a/parse/istream/free.h b/parse/istream/free.h new file mode 100644 index 0000000..2674800 --- /dev/null +++ b/parse/istream/free.h @@ -0,0 +1,5 @@ + +struct istream; + +void free_istream( + struct istream* this); diff --git a/parse/istream/inc.c b/parse/istream/inc.c new file mode 100644 index 0000000..97848f2 --- /dev/null +++ b/parse/istream/inc.c @@ -0,0 +1,15 @@ + +#include + +#include "struct.h" +#include "inc.h" + +struct istream* inc_istream( + struct istream* this) +{ + if (this) + this->refcount++; + + return this; +} + diff --git a/parse/istream/inc.h b/parse/istream/inc.h new file mode 100644 index 0000000..71f5e4b --- /dev/null +++ b/parse/istream/inc.h @@ -0,0 +1,3 @@ + +struct istream* inc_istream( + struct istream* this); diff --git a/parse/istream/inheritance.h b/parse/istream/inheritance.h new file mode 100644 index 0000000..569225f --- /dev/null +++ b/parse/istream/inheritance.h @@ -0,0 +1,16 @@ + +#ifndef STRUCT_ISTREAM_INHERITANCE +#define STRUCT_ISTREAM_INHERITANCE + +struct istream; + +struct istream_inheritance +{ + void (*read)( + struct istream*); + + void (*free)( + struct istream*); +}; + +#endif diff --git a/parse/istream/new.c b/parse/istream/new.c new file mode 100644 index 0000000..c22798a --- /dev/null +++ b/parse/istream/new.c @@ -0,0 +1,26 @@ + +#include + +#include + +#include "struct.h" +#include "new.h" + +struct istream* new_istream( + const struct istream_inheritance* inheritance, + size_t alloc_size) +{ + ENTER; + + struct istream* this = smalloc(alloc_size); + + this->inheritance = inheritance; + + this->c = 0; + + this->refcount = 1; + + EXIT; + return this; +} + diff --git a/parse/istream/new.h b/parse/istream/new.h new file mode 100644 index 0000000..8707050 --- /dev/null +++ b/parse/istream/new.h @@ -0,0 +1,9 @@ + +#include + +struct istream_inheritance; + +struct istream* new_istream( + const struct istream_inheritance* inheritance, + size_t alloc_size); + diff --git a/parse/istream/read.c b/parse/istream/read.c new file mode 100644 index 0000000..294e61c --- /dev/null +++ b/parse/istream/read.c @@ -0,0 +1,23 @@ + +#include + +#include + +#include "inheritance.h" +#include "struct.h" +#include "read.h" + +void istream_read( + struct istream* this) +{ + ENTER; + + assert(this); + assert(this->inheritance); + assert(this->inheritance->read); + + (this->inheritance->read)(this); + + EXIT; +} + diff --git a/parse/istream/read.h b/parse/istream/read.h new file mode 100644 index 0000000..c052b84 --- /dev/null +++ b/parse/istream/read.h @@ -0,0 +1,3 @@ + +void istream_read( + struct istream* this); diff --git a/parse/istream/string/free.c b/parse/istream/string/free.c new file mode 100644 index 0000000..0b1db36 --- /dev/null +++ b/parse/istream/string/free.c @@ -0,0 +1,21 @@ + +#include +#include + +#include + +#include "struct.h" +#include "free.h" + +void free_string_istream( + struct istream* super) +{ + ENTER; + +/* struct string_istream* this = (void*) super;*/ + + TODO; + + EXIT; +} + diff --git a/parse/istream/string/free.h b/parse/istream/string/free.h new file mode 100644 index 0000000..a34c723 --- /dev/null +++ b/parse/istream/string/free.h @@ -0,0 +1,3 @@ + +void free_string_istream( + struct istream* super); diff --git a/parse/istream/string/inheritance.c b/parse/istream/string/inheritance.c new file mode 100644 index 0000000..c7ad15f --- /dev/null +++ b/parse/istream/string/inheritance.c @@ -0,0 +1,16 @@ + +#include + +#include "../inheritance.h" + +#include "free.h" +#include "read.h" +#include "inheritance.h" + +struct istream_inheritance string_istream_inheritance = +{ + .read = string_istream_read, + + .free = free_string_istream, +}; + diff --git a/parse/istream/string/inheritance.h b/parse/istream/string/inheritance.h new file mode 100644 index 0000000..989d161 --- /dev/null +++ b/parse/istream/string/inheritance.h @@ -0,0 +1,6 @@ + +#include "../inheritance.h" + +extern struct istream_inheritance string_istream_inheritance; + + diff --git a/parse/istream/string/new.c b/parse/istream/string/new.c new file mode 100644 index 0000000..cb269e9 --- /dev/null +++ b/parse/istream/string/new.c @@ -0,0 +1,34 @@ + +#include +#include + +#include + +#include "../new.h" + +#include "inheritance.h" +#include "struct.h" +#include "new.h" + +struct istream* new_string_istream( + const uint8_t* input_string) +{ + ENTER; + + dpvp(input_string); + + assert(input_string); + + struct string_istream* this = (void*) new_istream( + &string_istream_inheritance, + sizeof(*this)); + + this->moving = input_string; + + EXIT; + return (void*) this; +} + + + + diff --git a/parse/istream/string/new.h b/parse/istream/string/new.h new file mode 100644 index 0000000..0413276 --- /dev/null +++ b/parse/istream/string/new.h @@ -0,0 +1,3 @@ + +struct istream* new_string_istream( + const uint8_t* input_string); diff --git a/parse/istream/string/read.c b/parse/istream/string/read.c new file mode 100644 index 0000000..5a43034 --- /dev/null +++ b/parse/istream/string/read.c @@ -0,0 +1,25 @@ + +#include +#include +#include + +#include + +#include "struct.h" +#include "read.h" + +void string_istream_read( + struct istream* super) +{ + ENTER; + + struct string_istream* this = (void*) super; + + dpvp(this); + dpvp(this->moving); + + super->c = *this->moving++; + + EXIT; +} + diff --git a/parse/istream/string/read.h b/parse/istream/string/read.h new file mode 100644 index 0000000..68852f1 --- /dev/null +++ b/parse/istream/string/read.h @@ -0,0 +1,3 @@ + +void string_istream_read( + struct istream* this); diff --git a/parse/istream/string/struct.h b/parse/istream/string/struct.h new file mode 100644 index 0000000..d8ab588 --- /dev/null +++ b/parse/istream/string/struct.h @@ -0,0 +1,14 @@ + +#include +#include + +#include "../struct.h" + +struct string_istream +{ + struct istream super; + + const uint8_t* moving; +}; + + diff --git a/parse/istream/struct.h b/parse/istream/struct.h new file mode 100644 index 0000000..e382a81 --- /dev/null +++ b/parse/istream/struct.h @@ -0,0 +1,14 @@ + +#include + +struct istream_inheritance; + +struct istream +{ + const struct istream_inheritance* inheritance; + + uint8_t c; + + unsigned refcount; +}; + diff --git a/parse/parse.c b/parse/parse.c new file mode 100644 index 0000000..3c04bbb --- /dev/null +++ b/parse/parse.c @@ -0,0 +1,606 @@ + +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include + +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "token/struct.h" +#include "token/inc.h" +#include "token/free.h" + +#include "tokenizer/struct.h" +#include "tokenizer/put_back.h" +#include "tokenizer/next.h" + +#include "parse.h" + +// we need to gracefully handle errors + +// we also need to allow for newlines ending statements only when they \ + could. + +struct expression* parse_application_expression( + struct tokenizer* tokenizer, + bool in_parentheses); + +struct expression* parse_lambda_expression( + struct tokenizer* tokenizer, + bool in_parentheses) +{ + ENTER; + + assert(tokenizer->token->kind == tk_lambda); + + tokenizer_next(tokenizer); + + while (tokenizer->token->kind == tk_newline) + { + tokenizer_next(tokenizer); + } + + if (tokenizer->token->kind != tk_identifier) + { + TODO; + exit(1); + } + + struct { + struct string** data; + size_t n, cap; + } names = {}; + + while (tokenizer->token->kind == tk_identifier) + { + if (names.n == names.cap) + { + names.cap = names.cap << 1 ?: 1; + + names.data = srealloc(names.data, + sizeof(*names.data) * names.cap); + } + + names.data[names.n++] = inc_string(tokenizer->token->text); + + tokenizer_next(tokenizer); + + while (tokenizer->token->kind == tk_newline) + { + tokenizer_next(tokenizer); + } + + if (tokenizer->token->kind == tk_comma) + { + tokenizer_next(tokenizer); + } + } + + assert(names.n); + + while (tokenizer->token->kind == tk_newline) + { + tokenizer_next(tokenizer); + } + + if (true + && tokenizer->token->kind != tk_colon + && tokenizer->token->kind != tk_dot) + { + dpvu(tokenizer->token->kind); + + TODO; + exit(1); + } + + tokenizer_next(tokenizer); + + struct expression* body = parse_application_expression( + tokenizer, in_parentheses); + + struct expression* retval = inc_expression(body); + + for (size_t i = names.n; i > 0; i--) + { + struct expression* prev = retval; + + retval = new_lambda_expression( + /* variable name: */ names.data[i - 1], + /* body: */ prev); + + free_expression(prev); + } + + for (size_t i = 0; i < names.n; i++) + { + free_string(names.data[i]); + } + + free_expression(body); + + free(names.data); + + EXIT; + return retval; +} + +// def parse-primary(): + // literal + // variable + // parenthesis: + // parse-application(in-parenthesis = true) + // lambda: + // eat zero or more newlines + // if error token: + // return error expression ("unknown token when reading \ + lambda expression") + // while not colon: + // if error token: + // return error expression ("unknown token when reading \ + lambda expression") + // expect identifier: + // return error expression ("unexpected token when reading \ + lambda expression") + // add to variable list + // eat identifier + // eat zero or more newlines + // if error token: + // return error expression ("unknown token when \ + reading lambda expression") + // expect comma + // return error expression ("unexpected token when reading \ + lambda expression, expected comma or colon") + // eat comma + // eat colon + // eat zero or more newlines + // if error token: + // return error expression ("unknown token when reading \ + lambda expression") + // parse-application + // tk_error: + // create error expression ("unknown token") + // EOF: + // create error expression ("unexpected EOF, expected expression") + // default: + // create error expression ("unexpected token") + +struct expression* parse_primary_expression( + struct tokenizer* tokenizer, + bool in_parentheses) +{ + struct expression* retval; + ENTER; + + switch (tokenizer->token->kind) + { + case tk_newline: + { + TODO; + break; + } + + case tk_literal: + { + struct number* literal = new_number(); + + number_set_str( + /* instance: */ literal, + /* literal string: */ tokenizer->token->text->data); + + struct value* value = new_number_value(literal); + + retval = new_literal_expression(value); + + tokenizer_next(tokenizer); + + free_value(value); + + free_number(literal); + break; + } + + case tk_identifier: + { + retval = new_variable_expression( + /* variable name: */ tokenizer->token->text); + + tokenizer_next(tokenizer); + + break; + } + + case tk_oparen: + { + tokenizer_next(tokenizer); + + struct expression* subexpression = + parse_application_expression(tokenizer, + /* in parenthesis: */ true); + + retval = new_parenthesis_expression(subexpression); + + tokenizer_next(tokenizer); + + free_expression(subexpression); + + break; + } + + case tk_lambda: + { + retval = parse_lambda_expression(tokenizer, in_parentheses); + + break; + } + + case tk_error: + TODO; + break; + + default: + TODO; + break; + } + + EXIT; + return retval; +} + +// # parse-application is greedy, and since it's called for parsing the \ + # body of lambdas, and lambdas inside that lambda, etc. the shift/reduce \ + # error will work out in our favor + +// def parse-application(in-parenthesis = false): + // parse parse-primary + + // # newlines can't stop us if we're in parenthesis: + // if in-parenthesis: + // while current token is newline: + // eat the newline + + // match (current token): + // case (number, variable, oparen, lambda): + // parse that primary, connect the two with an 'application' \ + expression + // continue as you can + + // case (close paren, EOF, newline, semicolon): + // if in-parenthesis = false: + // create error expression + // otherwise: + // return what you have + + // tk_error: + // create error expression ("unknown token") + // connect the two with an 'application' expression + // return what you have + +struct expression* parse_application_expression( + struct tokenizer* tokenizer, + bool in_parentheses) +{ + struct expression* retval; + ENTER; + + while (tokenizer->token->kind == tk_newline) + { + tokenizer_next(tokenizer); + } + + switch (tokenizer->token->kind) + { + case tk_identifier: + case tk_lambda: + case tk_literal: + case tk_oparen: + { + retval = parse_primary_expression( + /* tokenizer: */ tokenizer, + /* in parenthesis? */ in_parentheses); + break; + } + + case tk_error: + TODO; + break; + + default: + TODO; + break; + } + + // is the next thing a part of the application? + + again: switch (tokenizer->token->kind) + { + case tk_identifier: + case tk_lambda: + case tk_literal: + case tk_oparen: + { + struct expression* left = retval; + + struct expression* right = parse_primary_expression( + tokenizer, in_parentheses); + + retval = new_application_expression(left, right); + + free_expression(left); + + free_expression(right); + + goto again; + } + + case tk_newline: + { + if (in_parentheses) + { + TODO; + } + + break; + } + + case tk_semicolon: + case tk_EOF: + { + if (in_parentheses) + { + TODO; + } + break; + } + + case tk_cparen: + { + break; + } + + case tk_error: + { + TODO; + break; + } + + default: + { + TODO; + break; + } + } + + EXIT; + return retval; +} + +struct statement* parse_statement( + struct tokenizer* tokenizer) +{ + struct statement* retval; + ENTER; + + switch (tokenizer->token->kind) + { + case tk_identifier: + { + struct token* token = inc_token(tokenizer->token); + + tokenizer_next(tokenizer); + + switch (tokenizer->token->kind) + { + case tk_arrow: + { + tokenizer_next(tokenizer); + + struct expression* expression = + parse_application_expression( + /* tokenizer: */ tokenizer, + /* in parenthesis: */ false); + + retval = new_assignment_statement( + /* variable name: */ token->text, + /* expression: */ expression); + + free_expression(expression); + + break; + } + + case tk_newline: + case tk_EOF: + case tk_semicolon: + { + struct expression* expression = new_variable_expression( + /* variable name: */ token->text); + + retval = new_expression_statement(expression); + + free_expression(expression); + + break; + } + + case tk_oparen: + case tk_identifier: + case tk_literal: + case tk_lambda: + { + tokenizer_put_back(tokenizer, token); + + struct expression* exp = parse_application_expression( + /* tokenizer: */ tokenizer, + /* in parenthesis? */ false); + + retval = new_expression_statement( + /* expression: */ exp); + + free_expression(exp); + break; + } + + case tk_error: + TODO; + // create error statement ("unknown token", + // stragglers = [first token]) + // return what you have + break; + + default: + TODO; + break; + } + + free_token(token); + + break; + } + + case tk_lambda: + case tk_literal: + case tk_oparen: + { + // call parse-application + struct expression* exp = parse_application_expression( + /* tokenizer: */ tokenizer, + /* in parenthesis? */ false); + + retval = new_expression_statement( + /* expression: */ exp); + + free_expression(exp); + break; + } + + case tk_semicolon: + TODO; + break; + + case tk_error: + TODO; + // create error statement ("unknown token") + // return what you have + break; + + default: + TODO; + // create error statement ("unexpected token") + // return what you have + break; + } + + EXIT; + return retval; +} + +struct statement* parse_statements( + struct tokenizer* tokenizer) +{ + ENTER; + + assert(tokenizer->token->kind != tk_newline); + assert(tokenizer->token->kind != tk_EOF); + + struct statement* left = NULL; + + while (true + && tokenizer->token->kind != tk_newline + && tokenizer->token->kind != tk_EOF) + { + struct statement* right = parse_statement(tokenizer); + + if (left) + { + struct statement* oldleft = left; + + left = new_substatements_statement(left, right); + + free_statement(oldleft); + } + else + { + left = inc_statement(right); + } + + if (tokenizer->token->kind == tk_cparen) + { + TODO; + } + + if (tokenizer->token->kind == tk_semicolon) + { + tokenizer_next(tokenizer); + } + + free_statement(right); + } + + if (tokenizer->token->kind == tk_newline) + { + tokenizer_next(tokenizer); + } + + assert(left); + + EXIT; + return left; +} + +struct statement* parse( + struct tokenizer* tokenizer) +{ + ENTER; + + struct statement* root = parse_statements(tokenizer); + + EXIT; + return root; +} + + + + + + + + + + + + + + + + + + + + diff --git a/parse/parse.h b/parse/parse.h new file mode 100644 index 0000000..f655d86 --- /dev/null +++ b/parse/parse.h @@ -0,0 +1,6 @@ + +struct statement* parse( + struct tokenizer* tokenizer); + + + diff --git a/parse/position/assign.c b/parse/position/assign.c new file mode 100644 index 0000000..ac38ad6 --- /dev/null +++ b/parse/position/assign.c @@ -0,0 +1,19 @@ + +#include + +#include "struct.h" +#include "assign.h" + +void assign_position( + struct position* this, + const struct position* from) +{ + ENTER; + + this->line = from->line; + + this->column = from->column; + + EXIT; +} + diff --git a/parse/position/assign.h b/parse/position/assign.h new file mode 100644 index 0000000..6849d92 --- /dev/null +++ b/parse/position/assign.h @@ -0,0 +1,6 @@ + +void assign_position( + struct position* this, + const struct position* from); + + diff --git a/parse/position/clone.c b/parse/position/clone.c new file mode 100644 index 0000000..41262c9 --- /dev/null +++ b/parse/position/clone.c @@ -0,0 +1,29 @@ + +#include + +#include + +#include + +#include "struct.h" +#include "clone.h" + +struct position* clone_position( + const struct position* cloneme) +{ + ENTER; + + struct position* this = smalloc(sizeof(*this)); + + this->filename = inc_string(cloneme->filename); + + this->line = cloneme->line; + + this->column = cloneme->column; + + this->refcount = 1; + + EXIT; + return this; +} + diff --git a/parse/position/clone.h b/parse/position/clone.h new file mode 100644 index 0000000..f7bbacf --- /dev/null +++ b/parse/position/clone.h @@ -0,0 +1,6 @@ + + +struct position* clone_position( + const struct position* cloneme); + + diff --git a/parse/position/free.c b/parse/position/free.c new file mode 100644 index 0000000..e0ce03a --- /dev/null +++ b/parse/position/free.c @@ -0,0 +1,25 @@ + +#include + +#include + +#include + +#include "struct.h" +#include "free.h" + +void free_position( + struct position* this) +{ + ENTER; + + if (this && !--this->refcount) + { + free_string(this->filename); + + free(this); + } + + EXIT; +} + diff --git a/parse/position/free.h b/parse/position/free.h new file mode 100644 index 0000000..4105c01 --- /dev/null +++ b/parse/position/free.h @@ -0,0 +1,7 @@ + +struct position; + +void free_position( + struct position* this); + + diff --git a/parse/position/inc.c b/parse/position/inc.c new file mode 100644 index 0000000..61a7420 --- /dev/null +++ b/parse/position/inc.c @@ -0,0 +1,15 @@ + +#include + +#include "struct.h" +#include "inc.h" + +struct position* inc_position( + struct position* this) +{ + if (this) + this->refcount++; + + return this; +} + diff --git a/parse/position/inc.h b/parse/position/inc.h new file mode 100644 index 0000000..fca32f5 --- /dev/null +++ b/parse/position/inc.h @@ -0,0 +1,6 @@ + +struct position* inc_position( + struct position* this); + + + diff --git a/parse/position/new.c b/parse/position/new.c new file mode 100644 index 0000000..7e8ac18 --- /dev/null +++ b/parse/position/new.c @@ -0,0 +1,31 @@ + +#include + +#include + +#include + +#include "struct.h" +#include "new.h" + +struct position* new_position( + struct string* filename, + unsigned line, + unsigned column) +{ + ENTER; + + struct position* this = smalloc(sizeof(*this)); + + this->filename = inc_string(filename); + + this->line = line; + + this->column = column; + + this->refcount = 1; + + EXIT; + return this; +} + diff --git a/parse/position/new.h b/parse/position/new.h new file mode 100644 index 0000000..efa2e1d --- /dev/null +++ b/parse/position/new.h @@ -0,0 +1,10 @@ + +struct string; + +struct position* new_position( + struct string* filename, + unsigned line, + unsigned column); + + + diff --git a/parse/position/print.c b/parse/position/print.c new file mode 100644 index 0000000..e69de29 diff --git a/parse/position/print.h b/parse/position/print.h new file mode 100644 index 0000000..e69de29 diff --git a/parse/position/struct.h b/parse/position/struct.h new file mode 100644 index 0000000..276cee3 --- /dev/null +++ b/parse/position/struct.h @@ -0,0 +1,12 @@ + +struct position +{ + struct string* filename; + + unsigned line, column; + + unsigned refcount; +}; + + + diff --git a/parse/token/free.c b/parse/token/free.c new file mode 100644 index 0000000..9bb19ea --- /dev/null +++ b/parse/token/free.c @@ -0,0 +1,31 @@ + +#include + +#include + +#include + +#include "../position/free.h" + +#include "struct.h" +#include "free.h" + +void free_token( + struct token* this) +{ + ENTER; + + if (this && !--this->refcount) + { + free_position(this->start); + + free_position(this->end); + + free_string(this->text); + + free(this); + } + + EXIT; +} + diff --git a/parse/token/free.h b/parse/token/free.h new file mode 100644 index 0000000..b7ceffc --- /dev/null +++ b/parse/token/free.h @@ -0,0 +1,7 @@ + +struct token; + +void free_token( + struct token* this); + + diff --git a/parse/token/inc.c b/parse/token/inc.c new file mode 100644 index 0000000..04d67c0 --- /dev/null +++ b/parse/token/inc.c @@ -0,0 +1,15 @@ + +#include + +#include "struct.h" +#include "inc.h" + +struct token* inc_token( + struct token* this) +{ + if (this) + this->refcount++; + + return this; +} + diff --git a/parse/token/inc.h b/parse/token/inc.h new file mode 100644 index 0000000..bb4a3e4 --- /dev/null +++ b/parse/token/inc.h @@ -0,0 +1,5 @@ + +struct token* inc_token( + struct token* this); + + diff --git a/parse/token/kind.h b/parse/token/kind.h new file mode 100644 index 0000000..5c618df --- /dev/null +++ b/parse/token/kind.h @@ -0,0 +1,34 @@ + +#ifndef ENUM_TOKEN_KIND +#define ENUM_TOKEN_KIND + +enum token_kind +{ + tk_error, + + tk_EOF, + + tk_newline, + + tk_literal, + + tk_dot, + + tk_arrow, + + tk_semicolon, + + tk_identifier, + + tk_oparen, + + tk_cparen, + + tk_colon, + + tk_lambda, + + tk_comma, +}; + +#endif diff --git a/parse/token/new.c b/parse/token/new.c new file mode 100644 index 0000000..1eb36d3 --- /dev/null +++ b/parse/token/new.c @@ -0,0 +1,37 @@ + +#include + +#include + +#include + +#include "../position/inc.h" + +#include "struct.h" +#include "new.h" + +struct token* new_token( + enum token_kind kind, + struct string* text, + struct position* start_position, + struct position* end_position) +{ + ENTER; + + struct token* this = smalloc(sizeof(*this)); + + this->kind = kind; + + this->text = inc_string(text); + + this->start = inc_position(start_position); + + this->end = inc_position(end_position); + + this->refcount = 1; + + EXIT; + return this; +} + + diff --git a/parse/token/new.h b/parse/token/new.h new file mode 100644 index 0000000..5c005c3 --- /dev/null +++ b/parse/token/new.h @@ -0,0 +1,12 @@ + +#include "kind.h" + +struct position; + +struct token* new_token( + enum token_kind kind, + struct string* text, + struct position* start_position, + struct position* end_position); + + diff --git a/parse/token/struct.h b/parse/token/struct.h new file mode 100644 index 0000000..459192b --- /dev/null +++ b/parse/token/struct.h @@ -0,0 +1,19 @@ + +#include "kind.h" + +struct position; + +struct token +{ + enum token_kind kind; + + struct string* text; + + struct position *start, *end; + + unsigned refcount; +}; + + + + diff --git a/parse/tokenizer/free.c b/parse/tokenizer/free.c new file mode 100644 index 0000000..4b156e7 --- /dev/null +++ b/parse/tokenizer/free.c @@ -0,0 +1,37 @@ + +#include + +#include + +#include "../wcistream/free.h" + +#include "../position/free.h" + +#include "../token/free.h" + +#include "struct.h" +#include "free.h" + +void free_tokenizer( + struct tokenizer* this) +{ + ENTER; + + if (this) + { + free_wcistream(this->stream); + + free_position(this->position); + + free_token(this->token); + + free_token(this->put_back); + + free(this->rawtoken.data); + + free(this); + } + + EXIT; +} + diff --git a/parse/tokenizer/free.h b/parse/tokenizer/free.h new file mode 100644 index 0000000..e6e681f --- /dev/null +++ b/parse/tokenizer/free.h @@ -0,0 +1,5 @@ + +void free_tokenizer( + struct tokenizer* this); + + diff --git a/parse/tokenizer/inc.c b/parse/tokenizer/inc.c new file mode 100644 index 0000000..e69de29 diff --git a/parse/tokenizer/inc.h b/parse/tokenizer/inc.h new file mode 100644 index 0000000..e69de29 diff --git a/parse/tokenizer/new.c b/parse/tokenizer/new.c new file mode 100644 index 0000000..7480190 --- /dev/null +++ b/parse/tokenizer/new.c @@ -0,0 +1,53 @@ + +#include + +#include + +#include + +#include + +#include "struct.h" +#include "new.h" + +struct tokenizer* new_tokenizer( + struct wcistream* istream, + struct position* position) +{ + ENTER; + + struct tokenizer* this = smalloc(sizeof(*this)); + + this->stream = inc_wcistream(istream); + + this->position = inc_position(position); + + this->token = NULL; + + this->put_back = NULL; + + this->rawtoken.data = NULL; + this->rawtoken.n = 0; + this->rawtoken.cap = 0; + + this->buffer.i = 0; + this->buffer.n = 0; + + EXIT; + return this; +} + + + + + + + + + + + + + + + diff --git a/parse/tokenizer/new.h b/parse/tokenizer/new.h new file mode 100644 index 0000000..bff0390 --- /dev/null +++ b/parse/tokenizer/new.h @@ -0,0 +1,10 @@ + +struct wcistream; +struct position; + +struct tokenizer* new_tokenizer( + struct wcistream* istream, + struct position* position); + + + diff --git a/parse/tokenizer/next.c b/parse/tokenizer/next.c new file mode 100644 index 0000000..e4c59b4 --- /dev/null +++ b/parse/tokenizer/next.c @@ -0,0 +1,432 @@ + +#include + +#include + +#include + +#include + +#include +#include + +#include "../wcistream/struct.h" +#include "../wcistream/read.h" + +#include "../position/struct.h" +#include "../position/clone.h" +#include "../position/inc.h" +#include "../position/assign.h" +#include "../position/free.h" + +#include "../token/new.h" +#include "../token/inc.h" +#include "../token/free.h" + +#include "struct.h" +#include "next.h" + +static const enum state { + s_error, + + s_EOF, + + s_number, + + s_colon, + s_comma, + s_equals, + s_semicolon, + s_oparen, + s_cparen, + + s_newline, + + s_identifier, + + s_start, + + s_reading_newline, + + s_reading_slash, + + s_skipping_comment, + s_skipping_comment_slash, + + s_reading_colon, + s_reading_comma, + s_reading_equals, + s_reading_semicolon, + s_reading_oparen, + s_reading_cparen, + + s_reading_number, + + s_reading_identifier, + + number_of_states, +} lookup[number_of_states][127 + 1 + 1] = { + + #define ANY 0 ... 128 + + // EOF: + [s_start][0] = s_EOF, + + // skip whitespace + [s_start][' '] = s_start, + [s_start]['\t'] = s_start, + [s_start]['\n'] = s_reading_newline, + [s_reading_newline][ANY] = s_newline, + + // skip comments: + [s_start]['#'] = s_skipping_comment, + [s_skipping_comment][ANY] = s_skipping_comment, + [s_skipping_comment]['\\'] = s_skipping_comment_slash, + [s_skipping_comment_slash][ANY] = s_skipping_comment, + [s_skipping_comment]['\n'] = s_start, + + // skip escaped newlines: + [s_start]['\\'] = s_reading_slash, + [s_reading_slash][ANY] = s_start, + + // symbols: + [s_start][':'] = s_reading_colon, + [s_reading_colon][ANY] = s_colon, + [s_start][','] = s_reading_comma, + [s_reading_comma][ANY] = s_comma, + [s_start][';'] = s_reading_semicolon, + [s_reading_semicolon][ANY] = s_semicolon, + + // brackets: + [s_start]['('] = s_reading_oparen, + [s_reading_oparen][ANY] = s_oparen, + [s_start][')'] = s_reading_cparen, + [s_reading_cparen][ANY] = s_cparen, + + // numeric literals: + [s_start]['0' ... '9'] = s_reading_number, + [s_reading_number][ ANY ] = s_number, + [s_reading_number]['.'] = s_reading_number, + [s_reading_number]['0' ... '9'] = s_reading_number, + + // identifiers + [s_start]['?'] = s_reading_identifier, + [s_start]['!'] = s_reading_identifier, + [s_start]['-'] = s_reading_identifier, + [s_start]['>'] = s_reading_identifier, + [s_start]['='] = s_reading_identifier, + [s_start]['<'] = s_reading_identifier, + [s_start]['+'] = s_reading_identifier, + [s_start]['*'] = s_reading_identifier, + [s_start]['_'] = s_reading_identifier, + [s_start]['-'] = s_reading_identifier, + [s_start]['/'] = s_reading_identifier, + [s_start]['a' ... 'z'] = s_reading_identifier, + [s_start]['A' ... 'Z'] = s_reading_identifier, + [s_start][128] = s_reading_identifier, + [s_reading_identifier][ANY] = s_identifier, + [s_reading_identifier]['!'] = s_reading_identifier, + [s_reading_identifier]['+'] = s_reading_identifier, + [s_reading_identifier]['*'] = s_reading_identifier, + [s_reading_identifier]['_'] = s_reading_identifier, + [s_reading_identifier]['/'] = s_reading_identifier, + [s_reading_identifier]['-'] = s_reading_identifier, + [s_reading_identifier]['a' ... 'z'] = s_reading_identifier, + [s_reading_identifier]['A' ... 'Z'] = s_reading_identifier, + [s_reading_identifier]['0' ... '9'] = s_reading_identifier, + [s_reading_identifier][128] = s_reading_identifier, +}; + +void tokenizer_next( + struct tokenizer* this) +{ + ENTER; + + if (this->put_back) + { + free_token(this->token); + + this->token = inc_token(this->put_back); + + free_token(this->put_back); + + this->put_back = NULL; + } + else + { + this->rawtoken.n = 0; + + void append(wchar_t c) + { + ENTER; + + if (this->rawtoken.n == this->rawtoken.cap) + { + this->rawtoken.cap = this->rawtoken.cap << 1 ?: 1; + + this->rawtoken.data = srealloc( + this->rawtoken.data, + sizeof(*this->rawtoken.data) * this->rawtoken.cap); + } + + this->rawtoken.data[this->rawtoken.n++] = c; + + EXIT; + } + + struct position* start_position = clone_position(this->position); + struct position* end_position = this->position; + + enum state state = s_start; + + while (state >= s_start) + { + dpvu(this->stream->wc); + dpvwc(this->stream->wc); + + state = lookup[state][MIN(this->stream->wc, 128)]; + + if (state > s_start) + { + append(this->stream->wc); + + switch (this->stream->wc) + { + case '\t': end_position->column += 4; break; + + case '\n': end_position->line++, end_position->column = 1; break; + + default: end_position->column++; break; + } + + wcistream_read(this->stream); + } + + if (state == s_start) + { + this->rawtoken.n = 0; + + assign_position(start_position, end_position); + + wcistream_read(this->stream); + } + } + + append(0), this->rawtoken.n--; + + free_token(this->token), this->token = NULL; + + struct position* end_clone = clone_position(end_position); + + switch (state) + { + case s_error: + { + dpvws(this->rawtoken.data); + + TODO; + + break; + } + + case s_EOF: + { + this->token = new_token( + /* kind: */ tk_EOF, + /* text: */ NULL, + /* start position: */ end_clone, + /* end position: */ end_clone); + + break; + } + + case s_newline: + { + struct string* text = new_string( + /* data: */ this->rawtoken.data, + /* len: */ this->rawtoken.n); + + this->token = new_token( + /* kind: */ tk_newline, + /* text: */ text, + /* start position: */ start_position, + /* end position: */ end_clone); + + free_string(text); + + break; + } + + case s_identifier: + { + dpvws(this->rawtoken.data); + + struct string* text = new_string( + /* data: */ this->rawtoken.data, + /* len: */ this->rawtoken.n); + + if (!wcscmp(this->rawtoken.data, L"λ")) + { + this->token = new_token( + /* kind: */ tk_lambda, + /* text: */ text, + /* start position: */ start_position, + /* end position: */ end_clone); + } + else if (!wcscmp(this->rawtoken.data, L"<-")) + { + this->token = new_token( + /* kind: */ tk_arrow, + /* text: */ text, + /* start position: */ start_position, + /* end position: */ end_clone); + } + else + { + this->token = new_token( + /* kind: */ tk_identifier, + /* text: */ text, + /* start position: */ start_position, + /* end position: */ end_clone); + } + + free_string(text); + + break; + } + + case s_colon: + { + struct string* text = new_string( + /* data: */ this->rawtoken.data, + /* len: */ this->rawtoken.n); + + this->token = new_token( + /* kind: */ tk_colon, + /* text: */ text, + /* start position: */ start_position, + /* end position: */ end_clone); + + free_string(text); + + break; + } + + case s_comma: + { + struct string* text = new_string( + /* data: */ this->rawtoken.data, + /* len: */ this->rawtoken.n); + + this->token = new_token( + /* kind: */ tk_comma, + /* text: */ text, + /* start position: */ start_position, + /* end position: */ end_clone); + + free_string(text); + + break; + } + + case s_semicolon: + { + struct string* text = new_string( + /* data: */ this->rawtoken.data, + /* len: */ this->rawtoken.n); + + this->token = new_token( + /* kind: */ tk_semicolon, + /* text: */ text, + /* start position: */ start_position, + /* end position: */ end_clone); + + free_string(text); + + break; + } + + case s_oparen: + { + struct string* text = new_string( + /* data: */ this->rawtoken.data, + /* len: */ this->rawtoken.n); + + this->token = new_token( + /* kind: */ tk_oparen, + /* text: */ text, + /* start position: */ start_position, + /* end position: */ end_clone); + + free_string(text); + + break; + } + + case s_cparen: + { + struct string* text = new_string( + /* data: */ this->rawtoken.data, + /* len: */ this->rawtoken.n); + + this->token = new_token( + /* kind: */ tk_cparen, + /* text: */ text, + /* start position: */ start_position, + /* end position: */ end_clone); + + free_string(text); + + break; + } + + case s_number: + { + struct string* text = new_string( + /* data: */ this->rawtoken.data, + /* len: */ this->rawtoken.n); + + this->token = new_token( + /* kind: */ tk_literal, + /* text: */ text, + /* start position: */ start_position, + /* end position: */ end_clone); + + free_string(text); + + break; + } + + default: + TODO; + break; + } + + free_position(start_position); + + free_position(end_clone); + } + + EXIT; +} + + + + + + + + + + + + + + + + + + + + + diff --git a/parse/tokenizer/next.h b/parse/tokenizer/next.h new file mode 100644 index 0000000..430f49a --- /dev/null +++ b/parse/tokenizer/next.h @@ -0,0 +1,3 @@ + +void tokenizer_next( + struct tokenizer* this); diff --git a/parse/tokenizer/put_back.c b/parse/tokenizer/put_back.c new file mode 100644 index 0000000..6d7df0d --- /dev/null +++ b/parse/tokenizer/put_back.c @@ -0,0 +1,26 @@ + +#include + +#include + +#include "../token/inc.h" +#include "../token/free.h" + +#include "struct.h" +#include "put_back.h" + +void tokenizer_put_back( + struct tokenizer* this, + struct token* token) +{ + ENTER; + + assert(!this->put_back); + + this->put_back = inc_token(this->token); + + free_token(this->token), this->token = inc_token(token); + + EXIT; +} + diff --git a/parse/tokenizer/put_back.h b/parse/tokenizer/put_back.h new file mode 100644 index 0000000..398f1fb --- /dev/null +++ b/parse/tokenizer/put_back.h @@ -0,0 +1,9 @@ + +struct tokenizer; + +struct token; + +void tokenizer_put_back( + struct tokenizer* this, + struct token* token); + diff --git a/parse/tokenizer/struct.h b/parse/tokenizer/struct.h new file mode 100644 index 0000000..29dc58b --- /dev/null +++ b/parse/tokenizer/struct.h @@ -0,0 +1,36 @@ + +#include + +struct token; + +struct tokenizer +{ + struct wcistream* stream; + + struct position* position; + + struct token* token; + + struct token* put_back; + + struct { + wchar_t data[1024]; + size_t i, n; + } buffer; + + struct { + wchar_t* data; + size_t n, cap; + } rawtoken; +}; + +// keep track of line and column position + +// all tokens want a line number and start and end column position + // and file name + +// I think we can make it work if the tokenizer does NOT keep references to \ + tokens, only expressions and statements do. + + + diff --git a/parse/wcistream/file/free.c b/parse/wcistream/file/free.c new file mode 100644 index 0000000..eee525d --- /dev/null +++ b/parse/wcistream/file/free.c @@ -0,0 +1,20 @@ + +#include + +#include + +#include "struct.h" +#include "free.h" + +void free_file_wcistream( + struct wcistream* super) +{ + ENTER; + + struct file_wcistream* this = (void*) super; + + close(this->fd); + + EXIT; +} + diff --git a/parse/wcistream/file/free.h b/parse/wcistream/file/free.h new file mode 100644 index 0000000..74c82cf --- /dev/null +++ b/parse/wcistream/file/free.h @@ -0,0 +1,3 @@ + +void free_file_wcistream( + struct wcistream* super); diff --git a/parse/wcistream/file/inheritance.c b/parse/wcistream/file/inheritance.c new file mode 100644 index 0000000..07d6017 --- /dev/null +++ b/parse/wcistream/file/inheritance.c @@ -0,0 +1,16 @@ + +#include + +#include "../inheritance.h" + +#include "free.h" +#include "read.h" +#include "inheritance.h" + +struct wcistream_inheritance file_wcistream_inheritance = +{ + .read = file_wcistream_read, + + .free = free_file_wcistream, +}; + diff --git a/parse/wcistream/file/inheritance.h b/parse/wcistream/file/inheritance.h new file mode 100644 index 0000000..8863a84 --- /dev/null +++ b/parse/wcistream/file/inheritance.h @@ -0,0 +1,6 @@ + +#include "../inheritance.h" + +extern struct wcistream_inheritance file_wcistream_inheritance; + + diff --git a/parse/wcistream/file/new.c b/parse/wcistream/file/new.c new file mode 100644 index 0000000..dfc075d --- /dev/null +++ b/parse/wcistream/file/new.c @@ -0,0 +1,40 @@ + +#include +#include + +#include + +#include "../new.h" + +#include "inheritance.h" +#include "struct.h" +#include "new.h" + +struct wcistream* new_file_wcistream( + const char* input_file) +{ + ENTER; + + struct file_wcistream* this = (void*) new_wcistream( + &file_wcistream_inheritance, + sizeof(*this)); + + int fd = open(input_file, O_RDONLY); + + if (fd < 0) + { + TODO; + } + + this->fd = fd; + + this->i = 0; + this->n = 0; + + EXIT; + return (void*) this; +} + + + + diff --git a/parse/wcistream/file/new.h b/parse/wcistream/file/new.h new file mode 100644 index 0000000..37203e3 --- /dev/null +++ b/parse/wcistream/file/new.h @@ -0,0 +1,3 @@ + +struct wcistream* new_file_wcistream( + const char* input_file); diff --git a/parse/wcistream/file/read.c b/parse/wcistream/file/read.c new file mode 100644 index 0000000..aed2b8f --- /dev/null +++ b/parse/wcistream/file/read.c @@ -0,0 +1,52 @@ + +#include +#include +#include + +#include + +#include "struct.h" +#include "read.h" + +void file_wcistream_read( + struct wcistream* super) +{ + ENTER; + + TODO; + #if 0 + struct file_wcistream* this = (void*) super; + + if (this->i < this->n) + { + super->c = this->buffer[this->i++]; + + dpvc(super->c); + } + else + { + ssize_t read_retval = read(this->fd, this->buffer, sizeof(this->buffer)); + + if (read_retval < 0) + { + TODO; + } + else if (!read_retval) + { + super->c = 0; + } + else + { + this->i = 0; + this->n = (size_t) read_retval; + + super->c = this->buffer[this->i++]; + + dpvc(super->c); + } + } + #endif + + EXIT; +} + diff --git a/parse/wcistream/file/read.h b/parse/wcistream/file/read.h new file mode 100644 index 0000000..474dab7 --- /dev/null +++ b/parse/wcistream/file/read.h @@ -0,0 +1,3 @@ + +void file_wcistream_read( + struct wcistream* this); diff --git a/parse/wcistream/file/struct.h b/parse/wcistream/file/struct.h new file mode 100644 index 0000000..8caa948 --- /dev/null +++ b/parse/wcistream/file/struct.h @@ -0,0 +1,18 @@ + +#include +#include + +#include "../struct.h" + +struct file_wcistream +{ + struct wcistream super; + + int fd; + + uint8_t buffer[4096]; + + size_t i, n; +}; + + diff --git a/parse/wcistream/free.c b/parse/wcistream/free.c new file mode 100644 index 0000000..e4ee681 --- /dev/null +++ b/parse/wcistream/free.c @@ -0,0 +1,29 @@ + +#include +#include + +#include + +#include "inheritance.h" +#include "struct.h" +#include "free.h" + +void free_wcistream( + struct wcistream* this) +{ + ENTER; + + if (this && !--this->refcount) + { + assert(this); + assert(this->inheritance); + assert(this->inheritance->free); + + (this->inheritance->free)(this); + + free(this); + } + + EXIT; +} + diff --git a/parse/wcistream/free.h b/parse/wcistream/free.h new file mode 100644 index 0000000..b747141 --- /dev/null +++ b/parse/wcistream/free.h @@ -0,0 +1,5 @@ + +struct wcistream; + +void free_wcistream( + struct wcistream* this); diff --git a/parse/wcistream/inc.c b/parse/wcistream/inc.c new file mode 100644 index 0000000..16ffcfc --- /dev/null +++ b/parse/wcistream/inc.c @@ -0,0 +1,15 @@ + +#include + +#include "struct.h" +#include "inc.h" + +struct wcistream* inc_wcistream( + struct wcistream* this) +{ + if (this) + this->refcount++; + + return this; +} + diff --git a/parse/wcistream/inc.h b/parse/wcistream/inc.h new file mode 100644 index 0000000..28b541c --- /dev/null +++ b/parse/wcistream/inc.h @@ -0,0 +1,3 @@ + +struct wcistream* inc_wcistream( + struct wcistream* this); diff --git a/parse/wcistream/inheritance.h b/parse/wcistream/inheritance.h new file mode 100644 index 0000000..f4b9a57 --- /dev/null +++ b/parse/wcistream/inheritance.h @@ -0,0 +1,16 @@ + +#ifndef STRUCT_ISTREAM_INHERITANCE +#define STRUCT_ISTREAM_INHERITANCE + +struct wcistream; + +struct wcistream_inheritance +{ + void (*read)( + struct wcistream*); + + void (*free)( + struct wcistream*); +}; + +#endif diff --git a/parse/wcistream/istream/free.c b/parse/wcistream/istream/free.c new file mode 100644 index 0000000..5007185 --- /dev/null +++ b/parse/wcistream/istream/free.c @@ -0,0 +1,22 @@ + +#include + +#include + +#include + +#include "struct.h" +#include "free.h" + +void free_stream_wcistream( + struct wcistream* super) +{ + ENTER; + + struct stream_wcistream* this = (void*) super; + + free_istream(this->stream); + + EXIT; +} + diff --git a/parse/wcistream/istream/free.h b/parse/wcistream/istream/free.h new file mode 100644 index 0000000..2cbbd1e --- /dev/null +++ b/parse/wcistream/istream/free.h @@ -0,0 +1,3 @@ + +void free_stream_wcistream( + struct wcistream* super); diff --git a/parse/wcistream/istream/inheritance.c b/parse/wcistream/istream/inheritance.c new file mode 100644 index 0000000..cfa33e7 --- /dev/null +++ b/parse/wcistream/istream/inheritance.c @@ -0,0 +1,16 @@ + +#include + +#include "../inheritance.h" + +#include "free.h" +#include "read.h" +#include "inheritance.h" + +struct wcistream_inheritance stream_wcistream_inheritance = +{ + .read = stream_wcistream_read, + + .free = free_stream_wcistream, +}; + diff --git a/parse/wcistream/istream/inheritance.h b/parse/wcistream/istream/inheritance.h new file mode 100644 index 0000000..df37fa7 --- /dev/null +++ b/parse/wcistream/istream/inheritance.h @@ -0,0 +1,6 @@ + +#include "../inheritance.h" + +extern struct wcistream_inheritance stream_wcistream_inheritance; + + diff --git a/parse/wcistream/istream/new.c b/parse/wcistream/istream/new.c new file mode 100644 index 0000000..93028e9 --- /dev/null +++ b/parse/wcistream/istream/new.c @@ -0,0 +1,34 @@ + +#include +#include + +#include + +#include "../../istream/inc.h" + +#include "../new.h" + +#include "inheritance.h" +#include "struct.h" +#include "new.h" + +struct wcistream* new_istream_wcistream( + struct istream* stream) +{ + ENTER; + + assert(stream); + + struct stream_wcistream* this = (void*) new_wcistream( + &stream_wcistream_inheritance, + sizeof(*this)); + + this->stream = inc_istream(stream); + + EXIT; + return (void*) this; +} + + + + diff --git a/parse/wcistream/istream/new.h b/parse/wcistream/istream/new.h new file mode 100644 index 0000000..2f3e34e --- /dev/null +++ b/parse/wcistream/istream/new.h @@ -0,0 +1,3 @@ + +struct wcistream* new_istream_wcistream( + struct istream* stream); diff --git a/parse/wcistream/istream/read.c b/parse/wcistream/istream/read.c new file mode 100644 index 0000000..de6a7d0 --- /dev/null +++ b/parse/wcistream/istream/read.c @@ -0,0 +1,136 @@ + +#include +#include +#include + +#include + +#include "../../istream/struct.h" +#include "../../istream/read.h" + +#include "struct.h" +#include "read.h" + +void stream_wcistream_read( + struct wcistream* super) +{ + ENTER; + + struct stream_wcistream* this = (void*) super; + + dpvhhx(this->stream->c); + + wchar_t wc; + + switch (this->stream->c) + { + // 0x00000000 - 0x0000007F: + // 0xxxxxxx + + case 0b00000000 ... 0b01111111: + { + wc = (wchar_t) this->stream->c; + + istream_read(this->stream); + break; + } + + // 0x00000080 - 0x000007FF: + // 110xxxxx 10xxxxxx + + case 0b11000000 ... 0b11011111: + { + uint8_t first = this->stream->c; istream_read(this->stream); + + uint8_t second = this->stream->c; istream_read(this->stream); + + wc = 0 + | ((0b00011111 & first) << 6) + | ((0b00111111 & second) << 0); + + break; + } + + // 0x00000800 - 0x0000FFFF: + // 1110xxxx 10xxxxxx 10xxxxxx + + case 0b11100000 ... 0b11101111: + { + uint8_t first = this->stream->c; istream_read(this->stream); + + uint8_t second = this->stream->c; istream_read(this->stream); + + uint8_t third = this->stream->c; istream_read(this->stream); + + wc = 0 + | ((0b00001111 & first) << 12) + | ((0b00111111 & second) << 6) + | ((0b00111111 & third) << 0); + + break; + } + + // 0x00010000 - 0x001FFFFF: + // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + + case 0b11110000 ... 0b11110111: + { + uint8_t first = this->stream->c; istream_read(this->stream); + + uint8_t second = this->stream->c; istream_read(this->stream); + + uint8_t third = this->stream->c; istream_read(this->stream); + + uint8_t fourth = this->stream->c; istream_read(this->stream); + + wc = 0 + | ((0b00000111 & first) << 18) + | ((0b00111111 & second) << 12) + | ((0b00111111 & third) << 6) + | ((0b00111111 & fourth) << 0); + + break; + } + + // 0x00200000 - 0x03FFFFFF: + // 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + + case 0b11111000 ... 0b11111011: + { + TODO; + break; + } + + // 0x04000000 - 0x7FFFFFFF: + // 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + + case 0b11111100 ... 0b11111101: + { + TODO; + break; + } + + default: + TODO; + break; + } + + dpvu(wc); + + super->wc = wc; + + EXIT; +} + + + + + + + + + + + + + diff --git a/parse/wcistream/istream/read.h b/parse/wcistream/istream/read.h new file mode 100644 index 0000000..d48716e --- /dev/null +++ b/parse/wcistream/istream/read.h @@ -0,0 +1,3 @@ + +void stream_wcistream_read( + struct wcistream* this); diff --git a/parse/wcistream/istream/struct.h b/parse/wcistream/istream/struct.h new file mode 100644 index 0000000..f47dc19 --- /dev/null +++ b/parse/wcistream/istream/struct.h @@ -0,0 +1,14 @@ + +#include +#include + +#include "../struct.h" + +struct stream_wcistream +{ + struct wcistream super; + + struct istream* stream; +}; + + diff --git a/parse/wcistream/new.c b/parse/wcistream/new.c new file mode 100644 index 0000000..eca56d7 --- /dev/null +++ b/parse/wcistream/new.c @@ -0,0 +1,26 @@ + +#include + +#include + +#include "struct.h" +#include "new.h" + +struct wcistream* new_wcistream( + const struct wcistream_inheritance* inheritance, + size_t alloc_size) +{ + ENTER; + + struct wcistream* this = smalloc(alloc_size); + + this->inheritance = inheritance; + + this->wc = 0; + + this->refcount = 1; + + EXIT; + return this; +} + diff --git a/parse/wcistream/new.h b/parse/wcistream/new.h new file mode 100644 index 0000000..6c4eb58 --- /dev/null +++ b/parse/wcistream/new.h @@ -0,0 +1,9 @@ + +#include + +struct wcistream_inheritance; + +struct wcistream* new_wcistream( + const struct wcistream_inheritance* inheritance, + size_t alloc_size); + diff --git a/parse/wcistream/read.c b/parse/wcistream/read.c new file mode 100644 index 0000000..e920fc2 --- /dev/null +++ b/parse/wcistream/read.c @@ -0,0 +1,23 @@ + +#include + +#include + +#include "inheritance.h" +#include "struct.h" +#include "read.h" + +void wcistream_read( + struct wcistream* this) +{ + ENTER; + + assert(this); + assert(this->inheritance); + assert(this->inheritance->read); + + (this->inheritance->read)(this); + + EXIT; +} + diff --git a/parse/wcistream/read.h b/parse/wcistream/read.h new file mode 100644 index 0000000..f87495e --- /dev/null +++ b/parse/wcistream/read.h @@ -0,0 +1,3 @@ + +void wcistream_read( + struct wcistream* this); diff --git a/parse/wcistream/string/free.c b/parse/wcistream/string/free.c new file mode 100644 index 0000000..2c9598a --- /dev/null +++ b/parse/wcistream/string/free.c @@ -0,0 +1,18 @@ + +#include + +#include + +#include "struct.h" +#include "free.h" + +void free_string_wcistream( + struct wcistream* super) +{ + ENTER; + +/* struct string_wcistream* this = (void*) super;*/ + + EXIT; +} + diff --git a/parse/wcistream/string/free.h b/parse/wcistream/string/free.h new file mode 100644 index 0000000..9dafc74 --- /dev/null +++ b/parse/wcistream/string/free.h @@ -0,0 +1,3 @@ + +void free_string_wcistream( + struct wcistream* super); diff --git a/parse/wcistream/string/inheritance.c b/parse/wcistream/string/inheritance.c new file mode 100644 index 0000000..7d37e79 --- /dev/null +++ b/parse/wcistream/string/inheritance.c @@ -0,0 +1,16 @@ + +#include + +#include "../inheritance.h" + +#include "free.h" +#include "read.h" +#include "inheritance.h" + +struct wcistream_inheritance string_wcistream_inheritance = +{ + .read = string_wcistream_read, + + .free = free_string_wcistream, +}; + diff --git a/parse/wcistream/string/inheritance.h b/parse/wcistream/string/inheritance.h new file mode 100644 index 0000000..280627b --- /dev/null +++ b/parse/wcistream/string/inheritance.h @@ -0,0 +1,6 @@ + +#include "../inheritance.h" + +extern struct wcistream_inheritance string_wcistream_inheritance; + + diff --git a/parse/wcistream/string/new.c b/parse/wcistream/string/new.c new file mode 100644 index 0000000..32274e0 --- /dev/null +++ b/parse/wcistream/string/new.c @@ -0,0 +1,34 @@ + +#include +#include + +#include + +#include "../new.h" + +#include "inheritance.h" +#include "struct.h" +#include "new.h" + +struct wcistream* new_string_wcistream( + const wchar_t* input_string) +{ + ENTER; + + dpvp(input_string); + + assert(input_string); + + struct string_wcistream* this = (void*) new_wcistream( + &string_wcistream_inheritance, + sizeof(*this)); + + this->moving = input_string; + + EXIT; + return (void*) this; +} + + + + diff --git a/parse/wcistream/string/new.h b/parse/wcistream/string/new.h new file mode 100644 index 0000000..cb28a9b --- /dev/null +++ b/parse/wcistream/string/new.h @@ -0,0 +1,3 @@ + +struct wcistream* new_string_wcistream( + const wchar_t* input_string); diff --git a/parse/wcistream/string/read.c b/parse/wcistream/string/read.c new file mode 100644 index 0000000..e14e9f7 --- /dev/null +++ b/parse/wcistream/string/read.c @@ -0,0 +1,25 @@ + +#include +#include +#include + +#include + +#include "struct.h" +#include "read.h" + +void string_wcistream_read( + struct wcistream* super) +{ + ENTER; + + struct string_wcistream* this = (void*) super; + + dpvp(this); + dpvp(this->moving); + + super->wc = *this->moving++; + + EXIT; +} + diff --git a/parse/wcistream/string/read.h b/parse/wcistream/string/read.h new file mode 100644 index 0000000..d9a7f3a --- /dev/null +++ b/parse/wcistream/string/read.h @@ -0,0 +1,3 @@ + +void string_wcistream_read( + struct wcistream* this); diff --git a/parse/wcistream/string/struct.h b/parse/wcistream/string/struct.h new file mode 100644 index 0000000..ef2f614 --- /dev/null +++ b/parse/wcistream/string/struct.h @@ -0,0 +1,14 @@ + +#include +#include + +#include "../struct.h" + +struct string_wcistream +{ + struct wcistream super; + + const wchar_t* moving; +}; + + diff --git a/parse/wcistream/struct.h b/parse/wcistream/struct.h new file mode 100644 index 0000000..56f33b0 --- /dev/null +++ b/parse/wcistream/struct.h @@ -0,0 +1,15 @@ + +#include +#include + +struct wcistream_inheritance; + +struct wcistream +{ + const struct wcistream_inheritance* inheritance; + + wchar_t wc; + + unsigned refcount; +}; + diff --git a/srclist.mk b/srclist.mk new file mode 100644 index 0000000..40d3e5a --- /dev/null +++ b/srclist.mk @@ -0,0 +1,208 @@ +srcs += ./booleans/free.c +srcs += ./booleans/new.c +srcs += ./builtin/compare/eq.c +srcs += ./builtin/compare/gt.c +srcs += ./builtin/compare/gte.c +srcs += ./builtin/compare/lt.c +srcs += ./builtin/compare/lte.c +srcs += ./builtin/compare/neq.c +srcs += ./builtin/numeric/add.c +srcs += ./builtin/numeric/divide.c +srcs += ./builtin/numeric/multiply.c +srcs += ./builtin/numeric/subtract.c +srcs += ./cmdln/free.c +srcs += ./cmdln/new.c +srcs += ./color_factory/free.c +srcs += ./color_factory/new.c +srcs += ./debug.c +srcs += ./environment/declare.c +srcs += ./environment/declare_builtins.c +srcs += ./environment/free.c +srcs += ./environment/inc.c +srcs += ./environment/lookup.c +srcs += ./environment/new.c +srcs += ./environment/variable/compare.c +srcs += ./environment/variable/free.c +srcs += ./environment/variable/new.c +srcs += ./expression/application/evaluate.c +srcs += ./expression/application/free.c +srcs += ./expression/application/inheritance.c +srcs += ./expression/application/new.c +srcs += ./expression/application/prettyprint.c +srcs += ./expression/application/prettyprint_errors.c +srcs += ./expression/evaluate.c +srcs += ./expression/free.c +srcs += ./expression/inc.c +srcs += ./expression/lambda/evaluate.c +srcs += ./expression/lambda/free.c +srcs += ./expression/lambda/inheritance.c +srcs += ./expression/lambda/new.c +srcs += ./expression/lambda/prettyprint.c +srcs += ./expression/lambda/prettyprint_errors.c +srcs += ./expression/literal/evaluate.c +srcs += ./expression/literal/free.c +srcs += ./expression/literal/inheritance.c +srcs += ./expression/literal/new.c +srcs += ./expression/literal/prettyprint.c +srcs += ./expression/literal/prettyprint_errors.c +srcs += ./expression/new.c +srcs += ./expression/parenthesis/evaluate.c +srcs += ./expression/parenthesis/free.c +srcs += ./expression/parenthesis/inheritance.c +srcs += ./expression/parenthesis/new.c +srcs += ./expression/parenthesis/prettyprint.c +srcs += ./expression/parenthesis/prettyprint_errors.c +srcs += ./expression/prettyprint.c +srcs += ./expression/prettyprint_errors.c +srcs += ./expression/print.c +srcs += ./expression/variable/evaluate.c +srcs += ./expression/variable/free.c +srcs += ./expression/variable/inheritance.c +srcs += ./expression/variable/new.c +srcs += ./expression/variable/prettyprint.c +srcs += ./expression/variable/prettyprint_errors.c +srcs += ./extern/avl/avl.c +srcs += ./extern/gmp/mini-gmp.c +srcs += ./extern/gmp/mini-mpq.c +srcs += ./handle_file.c +srcs += ./handle_init_file.c +srcs += ./handle_interactive.c +srcs += ./handle_string.c +srcs += ./main.c +srcs += ./memory/smalloc.c +srcs += ./memory/srealloc.c +srcs += ./misc/wcindex.c +srcs += ./number/add.c +srcs += ./number/compare.c +srcs += ./number/free.c +srcs += ./number/inc.c +srcs += ./number/multiply.c +srcs += ./number/new.c +srcs += ./number/prettyprint.c +srcs += ./number/set_int.c +srcs += ./number/set_str.c +srcs += ./number/subtract.c +srcs += ./ostream/file/free.c +srcs += ./ostream/file/inheritance.c +srcs += ./ostream/file/new.c +srcs += ./ostream/file/write.c +srcs += ./ostream/free.c +srcs += ./ostream/inc.c +srcs += ./ostream/new.c +srcs += ./ostream/write.c +srcs += ./parse/istream/file/free.c +srcs += ./parse/istream/file/inheritance.c +srcs += ./parse/istream/file/new.c +srcs += ./parse/istream/file/read.c +srcs += ./parse/istream/free.c +srcs += ./parse/istream/inc.c +srcs += ./parse/istream/new.c +srcs += ./parse/istream/read.c +srcs += ./parse/istream/string/free.c +srcs += ./parse/istream/string/inheritance.c +srcs += ./parse/istream/string/new.c +srcs += ./parse/istream/string/read.c +srcs += ./parse/parse.c +srcs += ./parse/position/assign.c +srcs += ./parse/position/clone.c +srcs += ./parse/position/free.c +srcs += ./parse/position/inc.c +srcs += ./parse/position/new.c +srcs += ./parse/position/print.c +srcs += ./parse/tokenizer/free.c +srcs += ./parse/tokenizer/inc.c +srcs += ./parse/tokenizer/new.c +srcs += ./parse/tokenizer/next.c +srcs += ./parse/tokenizer/put_back.c +srcs += ./parse/token/free.c +srcs += ./parse/token/inc.c +srcs += ./parse/token/new.c +srcs += ./parse/wcistream/file/free.c +srcs += ./parse/wcistream/file/inheritance.c +srcs += ./parse/wcistream/file/new.c +srcs += ./parse/wcistream/file/read.c +srcs += ./parse/wcistream/free.c +srcs += ./parse/wcistream/inc.c +srcs += ./parse/wcistream/istream/free.c +srcs += ./parse/wcistream/istream/inheritance.c +srcs += ./parse/wcistream/istream/new.c +srcs += ./parse/wcistream/istream/read.c +srcs += ./parse/wcistream/new.c +srcs += ./parse/wcistream/read.c +srcs += ./parse/wcistream/string/free.c +srcs += ./parse/wcistream/string/inheritance.c +srcs += ./parse/wcistream/string/new.c +srcs += ./parse/wcistream/string/read.c +srcs += ./statement/assignment/execute.c +srcs += ./statement/assignment/free.c +srcs += ./statement/assignment/inheritance.c +srcs += ./statement/assignment/new.c +srcs += ./statement/assignment/prettyprint.c +srcs += ./statement/assignment/prettyprint_errors.c +srcs += ./statement/execute.c +srcs += ./statement/expression/execute.c +srcs += ./statement/expression/free.c +srcs += ./statement/expression/inheritance.c +srcs += ./statement/expression/new.c +srcs += ./statement/expression/prettyprint.c +srcs += ./statement/expression/prettyprint_errors.c +srcs += ./statement/free.c +srcs += ./statement/inc.c +srcs += ./statement/new.c +srcs += ./statement/prettyprint.c +srcs += ./statement/prettyprint_errors.c +srcs += ./statement/print.c +srcs += ./statement/substatements/execute.c +srcs += ./statement/substatements/free.c +srcs += ./statement/substatements/inheritance.c +srcs += ./statement/substatements/new.c +srcs += ./statement/substatements/prettyprint.c +srcs += ./statement/substatements/prettyprint_errors.c +srcs += ./stringtree/append.c +srcs += ./stringtree/free.c +srcs += ./stringtree/inc.c +srcs += ./stringtree/new.c +srcs += ./stringtree/prepend.c +srcs += ./stringtree/print.c +srcs += ./stringtree/println.c +srcs += ./string/compare.c +srcs += ./string/free.c +srcs += ./string/inc.c +srcs += ./string/new.c +srcs += ./string/print.c +srcs += ./string/println.c +srcs += ./value/builtin_lambda/free.c +srcs += ./value/builtin_lambda/inheritance.c +srcs += ./value/builtin_lambda/new.c +srcs += ./value/builtin_lambda/prettyprint.c +srcs += ./value/free.c +srcs += ./value/inc.c +srcs += ./value/lambda/free.c +srcs += ./value/lambda/inheritance.c +srcs += ./value/lambda/new.c +srcs += ./value/lambda/prettyprint.c +srcs += ./value/lazy/free.c +srcs += ./value/lazy/inheritance.c +srcs += ./value/lazy/new.c +srcs += ./value/lazy/prettyprint.c +srcs += ./value/lazy/unlazy.c +srcs += ./value/new.c +srcs += ./value/number/free.c +srcs += ./value/number/inheritance.c +srcs += ./value/number/new.c +srcs += ./value/number/prettyprint.c +srcs += ./value/prettyprint.c +srcs += ./wcostream/file/free.c +srcs += ./wcostream/file/new.c +srcs += ./wcostream/file/write.c +srcs += ./wcostream/free.c +srcs += ./wcostream/inc.c +srcs += ./wcostream/new.c +srcs += ./wcostream/ostream/free.c +srcs += ./wcostream/ostream/inheritance.c +srcs += ./wcostream/ostream/new.c +srcs += ./wcostream/ostream/write.c +srcs += ./wcostream/string/free.c +srcs += ./wcostream/string/new.c +srcs += ./wcostream/string/write.c +srcs += ./wcostream/write.c diff --git a/statement/assignment/execute.c b/statement/assignment/execute.c new file mode 100644 index 0000000..c81900e --- /dev/null +++ b/statement/assignment/execute.c @@ -0,0 +1,80 @@ + +#include + +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include + +#include "struct.h" +#include "execute.h" + +void assignment_statement_execute( + struct statement* super, + struct environment** environment, + struct booleans* booleans, + struct color_factory* cfactory, + struct wcostream* ostream, + bool print_value, + bool print_with_color) +{ + ENTER; + + struct assignment_statement* this = (void*) super; + + struct value* value = expression_evaluate( + /* assignment: */ this->expression, + /* environment: */ *environment, + /* booleans: */ booleans); + + struct value* vvalue = lazy_value_unlazy(value, booleans); + + struct environment* new = new_environment(*environment); + + environment_declare(new, this->variable_name, vvalue); + + free_environment(*environment); + + *environment = new; + + if (print_value) + { + struct stringtree* tree = value_prettyprint( + /* outgoing chosen color: */ NULL, + /* value: */ vvalue, + /* color factory: */ cfactory, + /* print with color? */ print_with_color); + + stringtree_println(tree, ostream); + + free_stringtree(tree); + } + + free_value(vvalue); + + free_value(value); + + EXIT; +} + + + + + + + + + + + diff --git a/statement/assignment/execute.h b/statement/assignment/execute.h new file mode 100644 index 0000000..0174d44 --- /dev/null +++ b/statement/assignment/execute.h @@ -0,0 +1,13 @@ + +struct statement; +struct environment; +struct color_factory; + +void assignment_statement_execute( + struct statement* this, + struct environment** environment, + struct booleans* booleans, + struct color_factory* cfactory, + struct wcostream* ostream, + bool print_value, + bool print_with_color); diff --git a/statement/assignment/free.c b/statement/assignment/free.c new file mode 100644 index 0000000..aa213e7 --- /dev/null +++ b/statement/assignment/free.c @@ -0,0 +1,24 @@ + +#include + +#include + +#include + +#include "struct.h" +#include "free.h" + +void free_assignment_statement( + struct statement* super) +{ + ENTER; + + struct assignment_statement* this = (void*) super; + + free_string(this->variable_name); + + free_expression(this->expression); + + EXIT; +} + diff --git a/statement/assignment/free.h b/statement/assignment/free.h new file mode 100644 index 0000000..2a166d9 --- /dev/null +++ b/statement/assignment/free.h @@ -0,0 +1,5 @@ + +struct statement; + +void free_assignment_statement( + struct statement* this); diff --git a/statement/assignment/inheritance.c b/statement/assignment/inheritance.c new file mode 100644 index 0000000..d29fee1 --- /dev/null +++ b/statement/assignment/inheritance.c @@ -0,0 +1,21 @@ + +#include + +#include "../inheritance.h" + +#include "inheritance.h" + +#include "prettyprint.h" +#include "prettyprint_errors.h" +#include "execute.h" +#include "free.h" + +struct statement_inheritance assignment_statement_inheritance = { + .prettyprint_errors = assignment_statement_prettyprint_errors, + + .prettyprint = assignment_statement_prettyprint, + + .execute = assignment_statement_execute, + + .free = free_assignment_statement, +}; diff --git a/statement/assignment/inheritance.h b/statement/assignment/inheritance.h new file mode 100644 index 0000000..5485f26 --- /dev/null +++ b/statement/assignment/inheritance.h @@ -0,0 +1,3 @@ + +extern struct statement_inheritance assignment_statement_inheritance; + diff --git a/statement/assignment/new.c b/statement/assignment/new.c new file mode 100644 index 0000000..fc9b991 --- /dev/null +++ b/statement/assignment/new.c @@ -0,0 +1,31 @@ + +#include + +#include + +#include + +#include "../new.h" + +#include "inheritance.h" +#include "struct.h" +#include "new.h" + +struct statement* new_assignment_statement( + struct string* variable_name, + struct expression* expression) +{ + ENTER; + + struct assignment_statement* this = (void*) new_statement( + /* inheritance: */ &assignment_statement_inheritance, + /* alloc size: */ sizeof(*this)); + + this->variable_name = inc_string(variable_name); + + this->expression = inc_expression(expression); + + EXIT; + return (void*) this; +} + diff --git a/statement/assignment/new.h b/statement/assignment/new.h new file mode 100644 index 0000000..81b19c0 --- /dev/null +++ b/statement/assignment/new.h @@ -0,0 +1,6 @@ + +struct assignment; + +struct statement* new_assignment_statement( + struct string* variable_name, + struct expression* assignment); diff --git a/statement/assignment/prettyprint.c b/statement/assignment/prettyprint.c new file mode 100644 index 0000000..942cbd0 --- /dev/null +++ b/statement/assignment/prettyprint.c @@ -0,0 +1,66 @@ + +#include + +#include + +#include + +#include +#include +#include +#include + +#include + +#include "struct.h" +#include "prettyprint.h" + +struct stringtree* assignment_statement_prettyprint( + int *out_chosen_color, + struct statement* super, + struct color_factory* cfactory, + bool with_color) +{ + ENTER; + + struct assignment_statement* const this = (void*) super; + + int inner_color; + + struct stringtree* header = new_stringtree(); + + stringtree_append_string(header, this->variable_name); + + stringtree_append_cstr(header, L" <- "); + + struct stringtree* tree = expression_prettyprint( + &inner_color, + this->expression, + cfactory, + with_color); + + if (with_color) + { + int my_color = (inner_color + 1) % (int) N(cfactory->colors); + + stringtree_prepend_string(header, cfactory->colors[my_color]); + + stringtree_append_string(header, cfactory->reset); + + if (out_chosen_color) + *out_chosen_color = my_color; + } + + stringtree_prepend_stringtree(tree, header); + + free_stringtree(header); + + EXIT; + return tree; +} + + + + + + diff --git a/statement/assignment/prettyprint.h b/statement/assignment/prettyprint.h new file mode 100644 index 0000000..40fa604 --- /dev/null +++ b/statement/assignment/prettyprint.h @@ -0,0 +1,11 @@ + +#include + +struct color_factory; + +struct stringtree* assignment_statement_prettyprint( + int *out_chosen_color, + struct statement* this, + struct color_factory* cfactory, + bool with_color); + diff --git a/statement/assignment/prettyprint_errors.c b/statement/assignment/prettyprint_errors.c new file mode 100644 index 0000000..88ec68a --- /dev/null +++ b/statement/assignment/prettyprint_errors.c @@ -0,0 +1,20 @@ + +#include + +#include + +#include "struct.h" +#include "prettyprint_errors.h" + +struct stringtree* assignment_statement_prettyprint_errors( + struct statement* super) +{ + ENTER; + + struct assignment_statement* this = (void*) super; + + struct stringtree* tree = expression_prettyprint_errors(this->expression); + + EXIT; + return tree; +} diff --git a/statement/assignment/prettyprint_errors.h b/statement/assignment/prettyprint_errors.h new file mode 100644 index 0000000..ae16e48 --- /dev/null +++ b/statement/assignment/prettyprint_errors.h @@ -0,0 +1,4 @@ + +struct stringtree* assignment_statement_prettyprint_errors( + struct statement* super); + diff --git a/statement/assignment/struct.h b/statement/assignment/struct.h new file mode 100644 index 0000000..a207d07 --- /dev/null +++ b/statement/assignment/struct.h @@ -0,0 +1,12 @@ + +#include "../struct.h" + +struct assignment_statement +{ + struct statement super; + + struct string* variable_name; + + struct expression* expression; +}; + diff --git a/statement/execute.c b/statement/execute.c new file mode 100644 index 0000000..6a5cfb4 --- /dev/null +++ b/statement/execute.c @@ -0,0 +1,30 @@ + +#include + +#include + +#include "struct.h" +#include "inheritance.h" +#include "execute.h" + +void statement_execute( + struct statement* this, + struct environment** environment, + struct booleans* booleans, + struct color_factory* cfactory, + struct wcostream* ostream, + bool print_value, + bool print_with_color) +{ + ENTER; + + assert(this); + assert(this->inheritance); + assert(this->inheritance->execute); + + (this->inheritance->execute)( + this, environment, booleans, cfactory, ostream, print_value, print_with_color); + + EXIT; +} + diff --git a/statement/execute.h b/statement/execute.h new file mode 100644 index 0000000..f981f3f --- /dev/null +++ b/statement/execute.h @@ -0,0 +1,19 @@ + +#include + +struct booleans; +struct environment; +struct wcostream; +struct color_factory; +struct statement; + +void statement_execute( + struct statement* this, + struct environment** environment, + struct booleans* booleans, + struct color_factory* cfactory, + struct wcostream* ostream, + bool print_value, + bool print_with_color); + + diff --git a/statement/expression/execute.c b/statement/expression/execute.c new file mode 100644 index 0000000..aee81b3 --- /dev/null +++ b/statement/expression/execute.c @@ -0,0 +1,68 @@ + +#include + +#include + +#include +#include +#include + +#include +#include +#include + +#include + +#include "struct.h" +#include "execute.h" + +void expression_statement_execute( + struct statement* super, + struct environment** environment, + struct booleans* booleans, + struct color_factory* cfactory, + struct wcostream* ostream, + bool print_value, + bool print_with_color) +{ + ENTER; + + struct expression_statement* this = (void*) super; + + struct value* value = expression_evaluate( + /* expression: */ this->expression, + /* environment: */ *environment, + /* booleans: */ booleans); + + struct value* vvalue = lazy_value_unlazy(value, booleans); + + if (print_value) + { + struct stringtree* tree = value_prettyprint( + /* outgoing chosen color: */ NULL, + /* value: */ vvalue, + /* color factory: */ cfactory, + /* print with color? */ print_with_color); + + stringtree_println(tree, ostream); + + free_stringtree(tree); + } + + free_value(vvalue); + + free_value(value); + + EXIT; +} + + + + + + + + + + + diff --git a/statement/expression/execute.h b/statement/expression/execute.h new file mode 100644 index 0000000..77f998c --- /dev/null +++ b/statement/expression/execute.h @@ -0,0 +1,13 @@ + +struct statement; +struct environment; +struct color_factory; + +void expression_statement_execute( + struct statement* this, + struct environment** environment, + struct booleans* booleans, + struct color_factory* cfactory, + struct wcostream* ostream, + bool print_value, + bool print_with_color); diff --git a/statement/expression/free.c b/statement/expression/free.c new file mode 100644 index 0000000..1e16cd0 --- /dev/null +++ b/statement/expression/free.c @@ -0,0 +1,20 @@ + +#include + +#include + +#include "struct.h" +#include "free.h" + +void free_expression_statement( + struct statement* super) +{ + ENTER; + + struct expression_statement* this = (void*) super; + + free_expression(this->expression); + + EXIT; +} + diff --git a/statement/expression/free.h b/statement/expression/free.h new file mode 100644 index 0000000..605521f --- /dev/null +++ b/statement/expression/free.h @@ -0,0 +1,5 @@ + +struct statement; + +void free_expression_statement( + struct statement* this); diff --git a/statement/expression/inheritance.c b/statement/expression/inheritance.c new file mode 100644 index 0000000..407e15c --- /dev/null +++ b/statement/expression/inheritance.c @@ -0,0 +1,21 @@ + +#include + +#include "../inheritance.h" + +#include "inheritance.h" + +#include "prettyprint.h" +#include "prettyprint_errors.h" +#include "execute.h" +#include "free.h" + +struct statement_inheritance expression_statement_inheritance = { + .prettyprint_errors = expression_statement_prettyprint_errors, + + .prettyprint = expression_statement_prettyprint, + + .execute = expression_statement_execute, + + .free = free_expression_statement, +}; diff --git a/statement/expression/inheritance.h b/statement/expression/inheritance.h new file mode 100644 index 0000000..141fd50 --- /dev/null +++ b/statement/expression/inheritance.h @@ -0,0 +1,3 @@ + +extern struct statement_inheritance expression_statement_inheritance; + diff --git a/statement/expression/new.c b/statement/expression/new.c new file mode 100644 index 0000000..f3a4a46 --- /dev/null +++ b/statement/expression/new.c @@ -0,0 +1,26 @@ + +#include + +#include + +#include "../new.h" + +#include "inheritance.h" +#include "struct.h" +#include "new.h" + +struct statement* new_expression_statement( + struct expression* expression) +{ + ENTER; + + struct expression_statement* this = (void*) new_statement( + /* inheritance: */ &expression_statement_inheritance, + /* alloc size: */ sizeof(*this)); + + this->expression = inc_expression(expression); + + EXIT; + return (void*) this; +} + diff --git a/statement/expression/new.h b/statement/expression/new.h new file mode 100644 index 0000000..5fd964b --- /dev/null +++ b/statement/expression/new.h @@ -0,0 +1,6 @@ + +struct expression; + +struct statement* new_expression_statement( + struct expression* expression); + diff --git a/statement/expression/prettyprint.c b/statement/expression/prettyprint.c new file mode 100644 index 0000000..af74d2e --- /dev/null +++ b/statement/expression/prettyprint.c @@ -0,0 +1,26 @@ + +#include + +#include + +#include "struct.h" +#include "prettyprint.h" + +struct stringtree* expression_statement_prettyprint( + int *out_chosen_color, + struct statement* super, + struct color_factory* cfactory, + bool with_color) +{ + ENTER; + + struct expression_statement* const this = (void*) super; + + struct stringtree* tree = expression_prettyprint( + out_chosen_color, + this->expression, cfactory, with_color); + + EXIT; + return tree; +} + diff --git a/statement/expression/prettyprint.h b/statement/expression/prettyprint.h new file mode 100644 index 0000000..8fe5712 --- /dev/null +++ b/statement/expression/prettyprint.h @@ -0,0 +1,11 @@ + +#include + +struct color_factory; + +struct stringtree* expression_statement_prettyprint( + int *out_chosen_color, + struct statement* this, + struct color_factory* cfactory, + bool with_color); + diff --git a/statement/expression/prettyprint_errors.c b/statement/expression/prettyprint_errors.c new file mode 100644 index 0000000..61cfa97 --- /dev/null +++ b/statement/expression/prettyprint_errors.c @@ -0,0 +1,20 @@ + +#include + +#include + +#include "struct.h" +#include "prettyprint_errors.h" + +struct stringtree* expression_statement_prettyprint_errors( + struct statement* super) +{ + ENTER; + + struct expression_statement* this = (void*) super; + + struct stringtree* tree = expression_prettyprint_errors(this->expression); + + EXIT; + return tree; +} diff --git a/statement/expression/prettyprint_errors.h b/statement/expression/prettyprint_errors.h new file mode 100644 index 0000000..06d1d7b --- /dev/null +++ b/statement/expression/prettyprint_errors.h @@ -0,0 +1,4 @@ + +struct stringtree* expression_statement_prettyprint_errors( + struct statement* super); + diff --git a/statement/expression/struct.h b/statement/expression/struct.h new file mode 100644 index 0000000..0dba823 --- /dev/null +++ b/statement/expression/struct.h @@ -0,0 +1,10 @@ + +#include "../struct.h" + +struct expression_statement +{ + struct statement super; + + struct expression* expression; +}; + diff --git a/statement/free.c b/statement/free.c new file mode 100644 index 0000000..83dad32 --- /dev/null +++ b/statement/free.c @@ -0,0 +1,29 @@ + +#include + +#include + +#include + +#include "inheritance.h" +#include "struct.h" +#include "free.h" + +void free_statement( + struct statement* this) +{ + ENTER; + + if (this && !--this->refcount) + { + assert(this->inheritance); + assert(this->inheritance->free); + + (this->inheritance->free)(this); + + free(this); + } + + EXIT; +} + diff --git a/statement/free.h b/statement/free.h new file mode 100644 index 0000000..c6faf72 --- /dev/null +++ b/statement/free.h @@ -0,0 +1,7 @@ + +struct statement; + +void free_statement( + struct statement* this); + + diff --git a/statement/inc.c b/statement/inc.c new file mode 100644 index 0000000..c8fcd81 --- /dev/null +++ b/statement/inc.c @@ -0,0 +1,15 @@ + +#include + +#include "struct.h" +#include "inc.h" + +struct statement* inc_statement( + struct statement* this) +{ + if (this) + this->refcount++; + + return this; +} + diff --git a/statement/inc.h b/statement/inc.h new file mode 100644 index 0000000..e69942f --- /dev/null +++ b/statement/inc.h @@ -0,0 +1,7 @@ + +struct statement; + +struct statement* inc_statement( + struct statement* this); + + diff --git a/statement/inheritance.h b/statement/inheritance.h new file mode 100644 index 0000000..c3b1d78 --- /dev/null +++ b/statement/inheritance.h @@ -0,0 +1,33 @@ + +#include + +struct wcostream; +struct color_factory; +struct statement; +struct booleans; +struct environment; + +struct statement_inheritance +{ + struct stringtree* (*prettyprint)( + int *out_chosen_color, + struct statement* this, + struct color_factory* cfactory, + bool with_color); + + struct stringtree* (*prettyprint_errors)( + struct statement* this); + + void (*execute)( + struct statement*, + struct environment**, + struct booleans* booleans, + struct color_factory*, + struct wcostream*, + bool print_value, + bool print_with_color); + + void (*free)( + struct statement*); +}; + diff --git a/statement/new.c b/statement/new.c new file mode 100644 index 0000000..3a10b2b --- /dev/null +++ b/statement/new.c @@ -0,0 +1,25 @@ + +#include + +#include + +#include "struct.h" +#include "new.h" + +struct statement* new_statement( + const struct statement_inheritance* inheritance, + size_t alloc_size) +{ + ENTER; + + struct statement* this = smalloc(alloc_size); + + this->inheritance = inheritance; + + this->refcount = 1; + + EXIT; + return this; +} + + diff --git a/statement/new.h b/statement/new.h new file mode 100644 index 0000000..90c19b9 --- /dev/null +++ b/statement/new.h @@ -0,0 +1,10 @@ + +#include + +struct statement_inheritance; + +struct statement* new_statement( + const struct statement_inheritance* inheritance, + size_t alloc_size); + + diff --git a/statement/prettyprint.c b/statement/prettyprint.c new file mode 100644 index 0000000..110e7e2 --- /dev/null +++ b/statement/prettyprint.c @@ -0,0 +1,31 @@ + +#include + +#include + +#include "struct.h" +#include "inheritance.h" +#include "prettyprint.h" + +struct stringtree* statement_prettyprint( + int *out_chosen_color, + struct statement* this, + struct color_factory* cfactory, + unsigned precedence_level) +{ + ENTER; + + assert(this); + assert(this->inheritance); + assert(this->inheritance->prettyprint); + + struct stringtree* tree = (this->inheritance->prettyprint)( + /* out: */ out_chosen_color, + /* this: */ this, + /* color factory: */ cfactory, + /* precedence level: */ precedence_level); + + EXIT; + return tree; +} + diff --git a/statement/prettyprint.h b/statement/prettyprint.h new file mode 100644 index 0000000..8198fde --- /dev/null +++ b/statement/prettyprint.h @@ -0,0 +1,11 @@ + +struct statement; + +struct color_factory; + +struct stringtree* statement_prettyprint( + int *out_chosen_color, + struct statement* this, + struct color_factory* cfactory, + unsigned precedence_level); + diff --git a/statement/prettyprint_errors.c b/statement/prettyprint_errors.c new file mode 100644 index 0000000..887863e --- /dev/null +++ b/statement/prettyprint_errors.c @@ -0,0 +1,24 @@ + +#include + +#include + +#include "struct.h" +#include "inheritance.h" +#include "prettyprint_errors.h" + +struct stringtree* statement_prettyprint_errors( + struct statement* this) +{ + ENTER; + + assert(this); + assert(this->inheritance); + assert(this->inheritance->prettyprint_errors); + + struct stringtree* tree = (this->inheritance->prettyprint_errors)(this); + + EXIT; + return tree; +} + diff --git a/statement/prettyprint_errors.h b/statement/prettyprint_errors.h new file mode 100644 index 0000000..2713803 --- /dev/null +++ b/statement/prettyprint_errors.h @@ -0,0 +1,5 @@ + +struct statement; + +struct stringtree* statement_prettyprint_errors( + struct statement* this); diff --git a/statement/print.c b/statement/print.c new file mode 100644 index 0000000..e69de29 diff --git a/statement/print.h b/statement/print.h new file mode 100644 index 0000000..e69de29 diff --git a/statement/struct.h b/statement/struct.h new file mode 100644 index 0000000..df0d465 --- /dev/null +++ b/statement/struct.h @@ -0,0 +1,10 @@ + +struct statement_inheritance; + +struct statement +{ + const struct statement_inheritance* inheritance; + + unsigned refcount; +}; + diff --git a/statement/substatements/execute.c b/statement/substatements/execute.c new file mode 100644 index 0000000..5f0b0e5 --- /dev/null +++ b/statement/substatements/execute.c @@ -0,0 +1,28 @@ + +#include + +#include "../execute.h" + +#include "struct.h" +#include "execute.h" + +void substatements_statement_execute( + struct statement* super, + struct environment** environment, + struct booleans* booleans, + struct color_factory* cfactory, + struct wcostream* ostream, + bool print_value, + bool print_with_color) +{ + ENTER; + + struct substatements_statement* this = (void*) super; + + statement_execute(this->left, environment, booleans, cfactory, ostream, print_value, print_with_color); + + statement_execute(this->right, environment, booleans, cfactory, ostream, print_value, print_with_color); + + EXIT; +} + diff --git a/statement/substatements/execute.h b/statement/substatements/execute.h new file mode 100644 index 0000000..5f5d167 --- /dev/null +++ b/statement/substatements/execute.h @@ -0,0 +1,11 @@ + +struct wcostream; + +void substatements_statement_execute( + struct statement* this, + struct environment** environment, + struct booleans* booleans, + struct color_factory* cfactory, + struct wcostream* ostream, + bool print_value, + bool print_with_color); diff --git a/statement/substatements/free.c b/statement/substatements/free.c new file mode 100644 index 0000000..c225a95 --- /dev/null +++ b/statement/substatements/free.c @@ -0,0 +1,22 @@ + +#include + +#include "../free.h" + +#include "struct.h" +#include "free.h" + +void free_substatements_statement( + struct statement* super) +{ + ENTER; + + struct substatements_statement* this = (void*) super; + + free_statement(this->left); + + free_statement(this->right); + + EXIT; +} + diff --git a/statement/substatements/free.h b/statement/substatements/free.h new file mode 100644 index 0000000..f4a72c4 --- /dev/null +++ b/statement/substatements/free.h @@ -0,0 +1,5 @@ + +struct statement; + +void free_substatements_statement( + struct statement* this); diff --git a/statement/substatements/inheritance.c b/statement/substatements/inheritance.c new file mode 100644 index 0000000..641fab2 --- /dev/null +++ b/statement/substatements/inheritance.c @@ -0,0 +1,21 @@ + +#include + +#include "../inheritance.h" + +#include "inheritance.h" + +#include "prettyprint.h" +#include "prettyprint_errors.h" +#include "execute.h" +#include "free.h" + +struct statement_inheritance substatements_statement_inheritance = { + .prettyprint_errors = substatements_statement_prettyprint_errors, + + .prettyprint = substatements_statement_prettyprint, + + .execute = substatements_statement_execute, + + .free = free_substatements_statement, +}; diff --git a/statement/substatements/inheritance.h b/statement/substatements/inheritance.h new file mode 100644 index 0000000..8bd8961 --- /dev/null +++ b/statement/substatements/inheritance.h @@ -0,0 +1,3 @@ + +extern struct statement_inheritance substatements_statement_inheritance; + diff --git a/statement/substatements/new.c b/statement/substatements/new.c new file mode 100644 index 0000000..9cf6ff6 --- /dev/null +++ b/statement/substatements/new.c @@ -0,0 +1,29 @@ + +#include + +#include + +#include "../new.h" +#include "../inc.h" + +#include "inheritance.h" +#include "struct.h" +#include "new.h" + +struct statement* new_substatements_statement( + struct statement* left, + struct statement* right) +{ + ENTER; + + struct substatements_statement* this = (void*) new_statement( + /* inheritance: */ &substatements_statement_inheritance, + /* alloc size: */ sizeof(*this)); + + this->left = inc_statement(left); + this->right = inc_statement(right); + + EXIT; + return (void*) this; +} + diff --git a/statement/substatements/new.h b/statement/substatements/new.h new file mode 100644 index 0000000..63c0901 --- /dev/null +++ b/statement/substatements/new.h @@ -0,0 +1,6 @@ + +struct statement; + +struct statement* new_substatements_statement( + struct statement* left, + struct statement* right); diff --git a/statement/substatements/prettyprint.c b/statement/substatements/prettyprint.c new file mode 100644 index 0000000..d267da1 --- /dev/null +++ b/statement/substatements/prettyprint.c @@ -0,0 +1,86 @@ + +#include + +#include + +#include + +#include + +/*#include */ +#include +#include +#include +#include + +#include "../prettyprint.h" + +#include "struct.h" +#include "prettyprint.h" + +struct stringtree* substatements_statement_prettyprint( + int *out_chosen_color, + struct statement* super, + struct color_factory* cfactory, + bool with_color) +{ + ENTER; + + struct substatements_statement* const this = (void*) super; + + int left_color, right_color; + + struct stringtree* left = statement_prettyprint( + &left_color, + /* instance: */ this->left, + /* color factory: */ cfactory, + with_color); + + struct stringtree* right = statement_prettyprint( + &right_color, + /* instance: */ this->right, + /* color factory: */ cfactory, + with_color); + + struct stringtree* semicolon = new_stringtree(); + + stringtree_append_cstr(semicolon, L"; "); + + if (with_color) + { + int my_color = (MAX(left_color, right_color) + 1) % (int) N(cfactory->colors); + + dpvu(my_color); + + stringtree_prepend_string(semicolon, cfactory->colors[my_color]); + + stringtree_prepend_string(semicolon, cfactory->reset); + + if (out_chosen_color) + *out_chosen_color = my_color; + } + + struct stringtree* tree = new_stringtree(); + + stringtree_append_stringtree(tree, left); + stringtree_append_stringtree(tree, semicolon); + stringtree_append_stringtree(tree, right); + + free_stringtree(left); + + free_stringtree(semicolon); + + free_stringtree(right); + + EXIT; + return tree; +} + + + + + + + + + diff --git a/statement/substatements/prettyprint.h b/statement/substatements/prettyprint.h new file mode 100644 index 0000000..088623f --- /dev/null +++ b/statement/substatements/prettyprint.h @@ -0,0 +1,12 @@ + +#include + +struct color_factory; + +struct stringtree* substatements_statement_prettyprint( + int *out_chosen_color, + struct statement* this, + struct color_factory* cfactory, + bool with_color); + + diff --git a/statement/substatements/prettyprint_errors.c b/statement/substatements/prettyprint_errors.c new file mode 100644 index 0000000..f702d40 --- /dev/null +++ b/statement/substatements/prettyprint_errors.c @@ -0,0 +1,34 @@ + +#include +#include + +#include + +#include "../prettyprint_errors.h" + +#include "struct.h" +#include "prettyprint_errors.h" + +struct stringtree* substatements_statement_prettyprint_errors( + struct statement* super) +{ + ENTER; + + struct substatements_statement* this = (void*) super; + + struct stringtree* tree = NULL; + + tree = statement_prettyprint_errors(this->left); + + if (tree) + { + TODO; + } + else + { + tree = statement_prettyprint_errors(this->right); + } + + EXIT; + return tree; +} diff --git a/statement/substatements/prettyprint_errors.h b/statement/substatements/prettyprint_errors.h new file mode 100644 index 0000000..3a495b7 --- /dev/null +++ b/statement/substatements/prettyprint_errors.h @@ -0,0 +1,7 @@ + +struct statement; + +struct stringtree* substatements_statement_prettyprint_errors( + struct statement* this); + + diff --git a/statement/substatements/struct.h b/statement/substatements/struct.h new file mode 100644 index 0000000..7427383 --- /dev/null +++ b/statement/substatements/struct.h @@ -0,0 +1,11 @@ + +#include "../struct.h" + +struct substatements_statement +{ + struct statement super; + + struct statement* left; + struct statement* right; +}; + diff --git a/string/compare.c b/string/compare.c new file mode 100644 index 0000000..fb479cc --- /dev/null +++ b/string/compare.c @@ -0,0 +1,17 @@ + +#include + +#include + +#include + +#include "struct.h" +#include "compare.h" + +int compare_strings( + const struct string* a, + const struct string* b) +{ + return wcscmp(a->data, b->data); +} + diff --git a/string/compare.h b/string/compare.h new file mode 100644 index 0000000..5c8474a --- /dev/null +++ b/string/compare.h @@ -0,0 +1,6 @@ + +struct string; + +int compare_strings( + const struct string* a, + const struct string* b); diff --git a/string/free.c b/string/free.c new file mode 100644 index 0000000..daddd37 --- /dev/null +++ b/string/free.c @@ -0,0 +1,21 @@ + +#include + +#include + +#include "struct.h" +#include "free.h" + +void free_string( + struct string* this) +{ + ENTER; + + if (this && !--this->refcount) + { + free(this->data); + free(this); + } + + EXIT; +} diff --git a/string/free.h b/string/free.h new file mode 100644 index 0000000..ca6ef08 --- /dev/null +++ b/string/free.h @@ -0,0 +1,5 @@ + +struct string; + +void free_string( + struct string* this); diff --git a/string/inc.c b/string/inc.c new file mode 100644 index 0000000..71af1cf --- /dev/null +++ b/string/inc.c @@ -0,0 +1,18 @@ + +#include + +#include "struct.h" +#include "inc.h" + +struct string* inc_string( + struct string* this) +{ + ENTER; + + if (this) + this->refcount++; + + EXIT; + return this; +} + diff --git a/string/inc.h b/string/inc.h new file mode 100644 index 0000000..edbd190 --- /dev/null +++ b/string/inc.h @@ -0,0 +1,3 @@ + +struct string* inc_string( + struct string* this); diff --git a/string/new.c b/string/new.c new file mode 100644 index 0000000..ed5afbc --- /dev/null +++ b/string/new.c @@ -0,0 +1,140 @@ + +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "struct.h" +#include "new.h" + +struct string* new_string( + const wchar_t* str, + size_t olen) +{ + ENTER; + + struct string* this = smalloc(sizeof(*this)); + + size_t len = wcsnlen(str, olen); + + wchar_t* data = (wchar_t*) smalloc((len + 1) * sizeof(*data)); + + memcpy(data, str, len * sizeof(*data)); + + data[len] = 0; + + this->data = data; + this->n = len; + this->refcount = 1; + + EXIT; + return this; +} + +struct string* new_string_from_ascii( + const char* str, + size_t olen) +{ + ENTER; + + size_t true_len = strnlen(str, olen); + + wchar_t* data = smalloc((true_len + 1) * sizeof(*data)); + + wchar_t* writing = data; + + for (const uint8_t* reading = (void*) str; *reading; ) + { + switch (*reading) + { + case 0b00000000 ... 0b01111111: + { + *writing++ = (wchar_t) *reading++; + + break; + } + + default: + TODO; + break; + } + } + + struct string* this = smalloc(sizeof(*this)); + + this->data = data; + this->n = (size_t) (writing - data); + this->refcount = 1; + + EXIT; + return this; +} + +struct string* new_string_from_ascii_format( + const char* fmt, ...) +{ + ENTER; + + va_list arg; + + va_start(arg, fmt); + + char *out = NULL; + + int len = vasprintf(&out, fmt, arg); + + if (len < 0) + { + TODO; + } + + dpvs(out); + + struct string* this = new_string_from_ascii(out, (size_t) len); + + free(out); + + va_end(arg); + + EXIT; + return this; +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/string/new.h b/string/new.h new file mode 100644 index 0000000..d4c160e --- /dev/null +++ b/string/new.h @@ -0,0 +1,16 @@ + +#include +#include +#include + +struct string* new_string( + const wchar_t* str, + size_t olen); + +struct string* new_string_from_ascii( + const char* str, + size_t olen); + +struct string* new_string_from_ascii_format( + const char* fmt, ...); + diff --git a/string/print.c b/string/print.c new file mode 100644 index 0000000..39aaec1 --- /dev/null +++ b/string/print.c @@ -0,0 +1,22 @@ + +#include + +#include + +#include "struct.h" +#include "print.h" + +void string_write( + struct string* this, + struct wcostream* stream) +{ + ENTER; + + wcostream_write( + /* stream: */ stream, + /* data: */ this->data, + /* len: */ this->n); + + EXIT; +} + diff --git a/string/print.h b/string/print.h new file mode 100644 index 0000000..df11e5e --- /dev/null +++ b/string/print.h @@ -0,0 +1,8 @@ + +struct string; +struct wcostream; + +void string_write( + struct string* this, + struct wcostream* stream); + diff --git a/string/println.c b/string/println.c new file mode 100644 index 0000000..e69de29 diff --git a/string/println.h b/string/println.h new file mode 100644 index 0000000..e69de29 diff --git a/string/struct.h b/string/struct.h new file mode 100644 index 0000000..02aae85 --- /dev/null +++ b/string/struct.h @@ -0,0 +1,12 @@ + +#include +#include + +struct string +{ + wchar_t* data; + size_t n; + + unsigned refcount; +}; + diff --git a/stringtree/append.c b/stringtree/append.c new file mode 100644 index 0000000..effe3e0 --- /dev/null +++ b/stringtree/append.c @@ -0,0 +1,158 @@ + +#include +#include + +#include + +#include +#include +#include + +#include "inc.h" +#include "struct.h" +#include "append.h" + +void stringtree_append_cstr( + struct stringtree* this, + const wchar_t* cstr) +{ + ENTER; + + struct child* new = smalloc(sizeof(*new)); + + new->kind = ck_cstr; + new->cstr = cstr; + new->prev = NULL; + new->next = NULL; + + if (this->tail) + { + this->tail->next = new; + new->prev = this->tail; + + this->tail = new; + } + else + { + this->head = new; + this->tail = new; + } + + EXIT; +} + + +void stringtree_append_formatstr( + struct stringtree* this, + const char* fmt, ...) +{ + ENTER; + + TODO; + #if 0 + va_list va; + + va_start(va, fmt); + + struct string* string = new_string_from_vargs(fmt, va); + + stringtree_append_string(this, string); + + free_string(string); + + va_end(va); + #endif + + EXIT; +} + +void stringtree_append_string( + struct stringtree* this, + struct string* string) +{ + ENTER; + + struct child* new = smalloc(sizeof(*new)); + + new->kind = ck_string; + new->string = inc_string(string); + new->prev = NULL; + new->next = NULL; + + if (this->tail) + { + this->tail->next = new; + new->prev = this->tail; + + this->tail = new; + } + else + { + this->head = new; + this->tail = new; + } + + EXIT; +} + +void stringtree_append_stringtree( + struct stringtree* this, + struct stringtree* stringtree) +{ + ENTER; + + struct child* new = smalloc(sizeof(*new)); + + new->kind = ck_stringtree; + new->stringtree = inc_stringtree(stringtree); + new->prev = NULL; + new->next = NULL; + + if (this->tail) + { + this->tail->next = new; + new->prev = this->tail; + + this->tail = new; + } + else + { + this->head = new; + this->tail = new; + } + + EXIT; +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/stringtree/append.h b/stringtree/append.h new file mode 100644 index 0000000..225aafd --- /dev/null +++ b/stringtree/append.h @@ -0,0 +1,21 @@ + +#include + +struct stringtree; +struct string; + +void stringtree_append_cstr( + struct stringtree* this, + const wchar_t* cstr); + +void stringtree_append_string( + struct stringtree* this, + struct string* string); + +void stringtree_append_formatstr( + struct stringtree* this, + const char* fmt, ...); + +void stringtree_append_stringtree( + struct stringtree* this, + struct stringtree* subtree); diff --git a/stringtree/free.c b/stringtree/free.c new file mode 100644 index 0000000..fed7564 --- /dev/null +++ b/stringtree/free.c @@ -0,0 +1,61 @@ + +#include +#include + +#include + +#include + +#include "struct.h" +#include "free.h" + +void free_stringtree( + struct stringtree* this) +{ + ENTER; + + if (this && !--this->refcount) + { + struct child* c = this->head; + + struct child* n = c->next; + + for (; c; c = n) + { + n = c->next; + + switch (c->kind) + { + case ck_cstr: + { + break; + } + + case ck_string: + { + free_string(c->string); + + break; + } + + case ck_stringtree: + { + free_stringtree(c->stringtree); + + break; + } + + default: + TODO; + break; + } + + free(c); + } + + free(this); + } + + EXIT; +} + diff --git a/stringtree/free.h b/stringtree/free.h new file mode 100644 index 0000000..bcdfff3 --- /dev/null +++ b/stringtree/free.h @@ -0,0 +1,6 @@ + +struct stringtree; + +void free_stringtree( + struct stringtree* this); + diff --git a/stringtree/inc.c b/stringtree/inc.c new file mode 100644 index 0000000..a548e85 --- /dev/null +++ b/stringtree/inc.c @@ -0,0 +1,18 @@ + +#include + +#include "struct.h" +#include "inc.h" + +struct stringtree* inc_stringtree( + struct stringtree* this) +{ + ENTER; + + if (this) + this->refcount++; + + EXIT; + return this; +} + diff --git a/stringtree/inc.h b/stringtree/inc.h new file mode 100644 index 0000000..c9936a2 --- /dev/null +++ b/stringtree/inc.h @@ -0,0 +1,3 @@ + +struct stringtree* inc_stringtree( + struct stringtree* this); diff --git a/stringtree/new.c b/stringtree/new.c new file mode 100644 index 0000000..f673212 --- /dev/null +++ b/stringtree/new.c @@ -0,0 +1,23 @@ + +#include + +#include + +#include "struct.h" +#include "new.h" + +struct stringtree* new_stringtree(void) +{ + ENTER; + + struct stringtree* this = smalloc(sizeof(*this)); + + this->head = NULL; + this->tail = NULL; + + this->refcount = 1; + + EXIT; + return this; +} + diff --git a/stringtree/new.h b/stringtree/new.h new file mode 100644 index 0000000..d1bd579 --- /dev/null +++ b/stringtree/new.h @@ -0,0 +1,2 @@ + +struct stringtree* new_stringtree(void); diff --git a/stringtree/prepend.c b/stringtree/prepend.c new file mode 100644 index 0000000..2cec381 --- /dev/null +++ b/stringtree/prepend.c @@ -0,0 +1,156 @@ + +#include + +#include + +#include + +#include +#include +#include + +#include "inc.h" +#include "struct.h" +#include "prepend.h" + +void stringtree_prepend_cstr( + struct stringtree* this, + const wchar_t* cstr) +{ + ENTER; + + struct child* new = smalloc(sizeof(*new)); + + new->kind = ck_cstr; + new->cstr = cstr; + new->prev = NULL; + new->next = NULL; + + if (this->head) + { + new->next = this->head; + + this->head = new; + } + else + { + this->head = new; + this->tail = new; + } + + EXIT; +} + + +void stringtree_prepend_formatstr( + struct stringtree* this, + const char* fmt, ...) +{ + ENTER; + + TODO; + #if 0 + va_list va; + + va_start(va, fmt); + + struct string* string = new_string_from_vargs(fmt, va); + + stringtree_prepend_string(this, string); + + free_string(string); + + va_end(va); + #endif + + EXIT; +} + +void stringtree_prepend_string( + struct stringtree* this, + struct string* string) +{ + ENTER; + + struct child* new = smalloc(sizeof(*new)); + + new->kind = ck_string; + new->string = inc_string(string); + new->prev = NULL; + new->next = NULL; + + if (this->head) + { + new->next = this->head; + + this->head = new; + } + else + { + this->head = new; + this->tail = new; + } + + EXIT; +} + +void stringtree_prepend_stringtree( + struct stringtree* this, + struct stringtree* stringtree) +{ + ENTER; + + struct child* new = smalloc(sizeof(*new)); + + new->kind = ck_stringtree; + new->stringtree = inc_stringtree(stringtree); + new->prev = NULL; + new->next = NULL; + + if (this->head) + { + new->next = this->head; + + this->head = new; + } + else + { + this->head = new; + this->tail = new; + } + + EXIT; +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/stringtree/prepend.h b/stringtree/prepend.h new file mode 100644 index 0000000..6e55407 --- /dev/null +++ b/stringtree/prepend.h @@ -0,0 +1,21 @@ + +#include + +struct stringtree; +struct string; + +void stringtree_prepend_cstr( + struct stringtree* this, + const wchar_t* cstr); + +void stringtree_prepend_string( + struct stringtree* this, + struct string* string); + +void stringtree_prepend_formatstr( + struct stringtree* this, + const char* fmt, ...); + +void stringtree_prepend_stringtree( + struct stringtree* this, + struct stringtree* subtree); diff --git a/stringtree/print.c b/stringtree/print.c new file mode 100644 index 0000000..6f7f7c7 --- /dev/null +++ b/stringtree/print.c @@ -0,0 +1,48 @@ + +#include + +#include + +#include + +#include + +#include "struct.h" +#include "print.h" + +void stringtree_print( + struct stringtree* this, + struct wcostream* stream) +{ + for (struct child* c = this->head; c; c = c->next) + { + switch (c->kind) + { + case ck_cstr: + { + wcostream_write(stream, c->cstr, wcslen(c->cstr)); + + break; + } + + case ck_string: + { + string_write(c->string, stream); + + break; + } + + case ck_stringtree: + { + stringtree_print(c->stringtree, stream); + + break; + } + + default: + TODO; + break; + } + } +} + diff --git a/stringtree/print.h b/stringtree/print.h new file mode 100644 index 0000000..9d03fc5 --- /dev/null +++ b/stringtree/print.h @@ -0,0 +1,9 @@ + +struct wcostream; +struct stringtree; + +void stringtree_print( + struct stringtree* this, + struct wcostream* stream); + + diff --git a/stringtree/println.c b/stringtree/println.c new file mode 100644 index 0000000..f6449b7 --- /dev/null +++ b/stringtree/println.c @@ -0,0 +1,21 @@ + +#include + +#include + +#include "print.h" +#include "println.h" + +void stringtree_println( + struct stringtree* this, + struct wcostream* stream) +{ + ENTER; + + stringtree_print(this, stream); + + wcostream_write(stream, L"\n", 1); + + EXIT; +} + diff --git a/stringtree/println.h b/stringtree/println.h new file mode 100644 index 0000000..e51d412 --- /dev/null +++ b/stringtree/println.h @@ -0,0 +1,8 @@ + +struct wcostream; +struct stringtree; + +void stringtree_println( + struct stringtree* this, + struct wcostream* stream); + diff --git a/stringtree/struct.h b/stringtree/struct.h new file mode 100644 index 0000000..acddd86 --- /dev/null +++ b/stringtree/struct.h @@ -0,0 +1,27 @@ + +#include + +struct stringtree +{ + struct child + { + enum child_kind { + ck_cstr, + ck_string, + ck_stringtree, + } kind; + + union { + const wchar_t* cstr; + + struct string* string; + + struct stringtree* stringtree; + }; + + struct child *prev, *next; + } *head, *tail; + + unsigned refcount; +}; + diff --git a/value/builtin_lambda/free.c b/value/builtin_lambda/free.c new file mode 100644 index 0000000..52001e8 --- /dev/null +++ b/value/builtin_lambda/free.c @@ -0,0 +1,26 @@ + +#include + +#include + +#include "../free.h" + +#include "struct.h" +#include "free.h" + +void free_builtin_lambda_value( + struct value* super) +{ + ENTER; + + struct builtin_lambda_value* this = (void*) super; + + free_string(this->name); + + free_value(this->value); + + free_value((struct value*) this->prev); + + EXIT; +} + diff --git a/value/builtin_lambda/free.h b/value/builtin_lambda/free.h new file mode 100644 index 0000000..a87d7d9 --- /dev/null +++ b/value/builtin_lambda/free.h @@ -0,0 +1,6 @@ + +struct value; + +void free_builtin_lambda_value( + struct value* super); + diff --git a/value/builtin_lambda/inheritance.c b/value/builtin_lambda/inheritance.c new file mode 100644 index 0000000..cdeab88 --- /dev/null +++ b/value/builtin_lambda/inheritance.c @@ -0,0 +1,15 @@ + +#include + +#include "../inheritance.h" + +#include "prettyprint.h" +#include "free.h" +#include "inheritance.h" + +struct value_inheritance builtin_lambda_value_inheritance = { + .prettyprint = builtin_lambda_value_prettyprint, + + .free = free_builtin_lambda_value, +}; + diff --git a/value/builtin_lambda/inheritance.h b/value/builtin_lambda/inheritance.h new file mode 100644 index 0000000..0665e95 --- /dev/null +++ b/value/builtin_lambda/inheritance.h @@ -0,0 +1,7 @@ + +#include + +#include "../inheritance.h" + +extern struct value_inheritance builtin_lambda_value_inheritance; + diff --git a/value/builtin_lambda/new.c b/value/builtin_lambda/new.c new file mode 100644 index 0000000..d8b4608 --- /dev/null +++ b/value/builtin_lambda/new.c @@ -0,0 +1,53 @@ + +#include + +#include + +#include "../new.h" +#include "../inc.h" + +#include "inheritance.h" +#include "struct.h" +#include "new.h" + +struct value* new_builtin_lambda_value( + struct string* name, + struct value* (*funcptr)( + struct booleans*, + struct builtin_lambda_value* prev, + struct value* tail), + size_t number_of_parameters, + struct value* value, + struct builtin_lambda_value* prev) +{ + ENTER; + + struct builtin_lambda_value* this = (void*) new_value( + vk_builtin_lambda, + &builtin_lambda_value_inheritance, + sizeof(*this)); + + this->name = inc_string(name); + + this->funcptr = funcptr; + + this->number_of_parameters = number_of_parameters; + + this->value = inc_value(value); + + this->prev = (void*) inc_value((void*) prev); + + EXIT; + return (void*) this; +} + + + + + + + + + + + diff --git a/value/builtin_lambda/new.h b/value/builtin_lambda/new.h new file mode 100644 index 0000000..b1e8e2f --- /dev/null +++ b/value/builtin_lambda/new.h @@ -0,0 +1,14 @@ + +struct string; + +struct value* new_builtin_lambda_value( + struct string* name, + struct value* (*funcptr)( + struct booleans*, + struct builtin_lambda_value* prev, + struct value* tail), + size_t number_of_parameters, + struct value* value, + struct builtin_lambda_value* prev); + + diff --git a/value/builtin_lambda/prettyprint.c b/value/builtin_lambda/prettyprint.c new file mode 100644 index 0000000..8b0ebc7 --- /dev/null +++ b/value/builtin_lambda/prettyprint.c @@ -0,0 +1,127 @@ + +#include + +#include + +#include + +#include + +#include +#include +#include +#include + +#include + +#include "struct.h" +#include "inheritance.h" +#include "prettyprint.h" + +struct stringtree* builtin_lambda_value_prettyprint( + int *out_chosen_color, + struct value* super, + struct color_factory* cfactory, + bool with_color) +{ + ENTER; + + struct stringtree* helper( + int* out, + struct builtin_lambda_value* this, + bool initial_call) + { + ENTER; + + struct stringtree* tree = new_stringtree(); + + if (this->prev) + { + int left_color, right_color; + + struct stringtree* left = helper(&left_color, this->prev, false); + + struct stringtree* right = value_prettyprint(&right_color, this->value, + cfactory, with_color); + + stringtree_append_stringtree(tree, left); + stringtree_append_cstr(tree, L" "); + stringtree_append_stringtree(tree, right); + + if (initial_call) + { + if (with_color) + { + int my_color = (MAX(left_color, right_color) + 1) % (int) N(cfactory->colors); + + stringtree_prepend_string(tree, cfactory->reset); + stringtree_prepend_cstr(tree, L"("); + stringtree_prepend_string(tree, cfactory->colors[my_color]); + + stringtree_append_string(tree, cfactory->colors[my_color]); + stringtree_append_cstr(tree, L")"); + stringtree_append_string(tree, cfactory->reset); + + if (out) + { + *out = my_color; + } + } + else + { + stringtree_prepend_cstr(tree, L"("); + stringtree_append_cstr(tree, L")"); + } + } + else + { + if (with_color && out) + { + *out = MAX(left_color, right_color); + } + } + + free_stringtree(left); + + free_stringtree(right); + } + else + { + stringtree_append_string(tree, this->name); + + if (with_color) + { + stringtree_prepend_string(tree, cfactory->variable); + + stringtree_append_string(tree, cfactory->reset); + + if (out) + *out = -1; + } + } + + EXIT; + return tree; + } + + struct builtin_lambda_value* this = (void*) super; + + struct stringtree* tree = helper( + /* out color: */ out_chosen_color, + /* this: */ this, + /* initial call?: */ true); + + EXIT; + return tree; +} + + + + + + + + + + + diff --git a/value/builtin_lambda/prettyprint.h b/value/builtin_lambda/prettyprint.h new file mode 100644 index 0000000..85a946d --- /dev/null +++ b/value/builtin_lambda/prettyprint.h @@ -0,0 +1,7 @@ + +struct stringtree* builtin_lambda_value_prettyprint( + int *out_chosen_color, + struct value* super, + struct color_factory* cfactory, + bool with_color); + diff --git a/value/builtin_lambda/struct.h b/value/builtin_lambda/struct.h new file mode 100644 index 0000000..f00280b --- /dev/null +++ b/value/builtin_lambda/struct.h @@ -0,0 +1,27 @@ + +#include + +#include "../struct.h" + +struct booleans; +struct builtin_lambda_value; +struct value; + +struct builtin_lambda_value +{ + struct value super; + + struct string* name; + + struct value* (*funcptr)( + struct booleans* booleans, + struct builtin_lambda_value* prev, + struct value* tail); + + size_t number_of_parameters; + + struct value* value; + + struct builtin_lambda_value* prev; +}; + diff --git a/value/free.c b/value/free.c new file mode 100644 index 0000000..c58cc0e --- /dev/null +++ b/value/free.c @@ -0,0 +1,25 @@ + +#include +#include + +#include + +#include "struct.h" +#include "inheritance.h" +#include "free.h" + +void free_value( + struct value* this) +{ + if (this && !--this->refcount) + { + assert(this); + assert(this->inheritance); + assert(this->inheritance->free); + + (this->inheritance->free)(this); + + free(this); + } +} + diff --git a/value/free.h b/value/free.h new file mode 100644 index 0000000..383981f --- /dev/null +++ b/value/free.h @@ -0,0 +1,7 @@ + +struct value; + +void free_value( + struct value* this); + + diff --git a/value/inc.c b/value/inc.c new file mode 100644 index 0000000..218ce67 --- /dev/null +++ b/value/inc.c @@ -0,0 +1,15 @@ + +#include + +#include "struct.h" +#include "inc.h" + +struct value* inc_value( + struct value* this) +{ + if (this) + this->refcount++; + + return this; +} + diff --git a/value/inc.h b/value/inc.h new file mode 100644 index 0000000..15a3bc5 --- /dev/null +++ b/value/inc.h @@ -0,0 +1,5 @@ + +struct value* inc_value( + struct value* this); + + diff --git a/value/inheritance.h b/value/inheritance.h new file mode 100644 index 0000000..6916097 --- /dev/null +++ b/value/inheritance.h @@ -0,0 +1,23 @@ + +#ifndef STRUCT_VALUE_INHERITANCE +#define STRUCT_VALUE_INHERITANCE + +#include + +struct stringtree; +struct value; +struct color_factory; + +struct value_inheritance +{ + struct stringtree* (*prettyprint)( + int *out_chosen_color, + struct value* this, + struct color_factory* cfactory, + bool with_color); + + void (*free)( + struct value* this); +}; + +#endif diff --git a/value/kind.h b/value/kind.h new file mode 100644 index 0000000..b07cf6e --- /dev/null +++ b/value/kind.h @@ -0,0 +1,16 @@ + +#ifndef ENUM_VALUE_KIND +#define ENUM_VALUE_KIND + +enum value_kind +{ + vk_number, + + vk_lambda, + + vk_lazy, + + vk_builtin_lambda, +}; + +#endif diff --git a/value/lambda/free.c b/value/lambda/free.c new file mode 100644 index 0000000..8526c44 --- /dev/null +++ b/value/lambda/free.c @@ -0,0 +1,28 @@ + +#include + +#include + +#include + +#include + +#include "struct.h" +#include "free.h" + +void free_lambda_value( + struct value* super) +{ + ENTER; + + struct lambda_value* this = (void*) super; + + free_environment(this->environment); + + free_string(this->variable_name); + + free_expression(this->body); + + EXIT; +} + diff --git a/value/lambda/free.h b/value/lambda/free.h new file mode 100644 index 0000000..5a3d2a2 --- /dev/null +++ b/value/lambda/free.h @@ -0,0 +1,6 @@ + +struct value; + +void free_lambda_value( + struct value* super); + diff --git a/value/lambda/inheritance.c b/value/lambda/inheritance.c new file mode 100644 index 0000000..736d6b6 --- /dev/null +++ b/value/lambda/inheritance.c @@ -0,0 +1,15 @@ + +#include + +#include "../inheritance.h" + +#include "prettyprint.h" +#include "free.h" +#include "inheritance.h" + +struct value_inheritance lambda_value_inheritance = { + .prettyprint = lambda_value_prettyprint, + + .free = free_lambda_value, +}; + diff --git a/value/lambda/inheritance.h b/value/lambda/inheritance.h new file mode 100644 index 0000000..9246ced --- /dev/null +++ b/value/lambda/inheritance.h @@ -0,0 +1,7 @@ + +#include + +#include "../inheritance.h" + +extern struct value_inheritance lambda_value_inheritance; + diff --git a/value/lambda/new.c b/value/lambda/new.c new file mode 100644 index 0000000..18a3767 --- /dev/null +++ b/value/lambda/new.c @@ -0,0 +1,37 @@ + +#include + +#include + +#include + +#include + +#include "../new.h" + +#include "inheritance.h" +#include "struct.h" +#include "new.h" + +struct value* new_lambda_value( + struct environment* environment, + struct string* variable_name, + struct expression* body) +{ + ENTER; + + struct lambda_value* this = (void*) new_value( + vk_lambda, + &lambda_value_inheritance, + sizeof(*this)); + + this->environment = inc_environment(environment); + + this->variable_name = inc_string(variable_name); + + this->body = inc_expression(body); + + EXIT; + return (void*) this; +} + diff --git a/value/lambda/new.h b/value/lambda/new.h new file mode 100644 index 0000000..0b04c1c --- /dev/null +++ b/value/lambda/new.h @@ -0,0 +1,11 @@ + +struct environment; +struct string; +struct expression; + +struct value* new_lambda_value( + struct environment* environment, + struct string* variable_name, + struct expression* body); + + diff --git a/value/lambda/prettyprint.c b/value/lambda/prettyprint.c new file mode 100644 index 0000000..18ac4c7 --- /dev/null +++ b/value/lambda/prettyprint.c @@ -0,0 +1,75 @@ + +#include + +#include + +#include + +#include +#include +#include +#include + +/*#include */ + +#include + +#include "struct.h" +#include "inheritance.h" +#include "prettyprint.h" + +struct stringtree* lambda_value_prettyprint( + int *out_chosen_color, + struct value* super, + struct color_factory* cfactory, + bool with_color) +{ + ENTER; + + struct lambda_value* this = (void*) super; + + int chosen_color; + + struct stringtree* tree = new_stringtree(); + + stringtree_append_cstr(tree, L"λ"); + + stringtree_append_string(tree, this->variable_name); + + stringtree_append_cstr(tree, L": "); + + struct stringtree* subtree = expression_prettyprint( + &chosen_color, + this->body, + cfactory, + with_color); + + if (with_color) + { + int my_color = (chosen_color + 1) % (int) N(cfactory->colors); + + stringtree_prepend_string(tree, cfactory->colors[my_color]); + + stringtree_append_string(tree, cfactory->reset); + + if (out_chosen_color) + *out_chosen_color = my_color; + } + + stringtree_append_stringtree(tree, subtree); + + free_stringtree(subtree); + + EXIT; + return tree; +} + + + + + + + + + + diff --git a/value/lambda/prettyprint.h b/value/lambda/prettyprint.h new file mode 100644 index 0000000..89553fc --- /dev/null +++ b/value/lambda/prettyprint.h @@ -0,0 +1,7 @@ + +struct stringtree* lambda_value_prettyprint( + int *out_chosen_color, + struct value* super, + struct color_factory* cfactory, + bool with_color); + diff --git a/value/lambda/struct.h b/value/lambda/struct.h new file mode 100644 index 0000000..e0bcc66 --- /dev/null +++ b/value/lambda/struct.h @@ -0,0 +1,14 @@ + +#include "../struct.h" + +struct lambda_value +{ + struct value super; + + struct environment* environment; + + struct string* variable_name; + + struct expression* body; +}; + diff --git a/value/lazy/free.c b/value/lazy/free.c new file mode 100644 index 0000000..c5433f5 --- /dev/null +++ b/value/lazy/free.c @@ -0,0 +1,28 @@ + +#include + +#include + +#include + +#include "../free.h" + +#include "struct.h" +#include "free.h" + +void free_lazy_value( + struct value* super) +{ + ENTER; + + struct lazy_value* this = (void*) super; + + free_environment(this->environment); + + free_expression(this->expression); + + free_value(this->value); + + EXIT; +} + diff --git a/value/lazy/free.h b/value/lazy/free.h new file mode 100644 index 0000000..44601a4 --- /dev/null +++ b/value/lazy/free.h @@ -0,0 +1,6 @@ + +struct value; + +void free_lazy_value( + struct value* super); + diff --git a/value/lazy/inheritance.c b/value/lazy/inheritance.c new file mode 100644 index 0000000..da29225 --- /dev/null +++ b/value/lazy/inheritance.c @@ -0,0 +1,15 @@ + +#include + +#include "../inheritance.h" + +#include "prettyprint.h" +#include "free.h" +#include "inheritance.h" + +struct value_inheritance lazy_value_inheritance = { + .prettyprint = lazy_value_prettyprint, + + .free = free_lazy_value, +}; + diff --git a/value/lazy/inheritance.h b/value/lazy/inheritance.h new file mode 100644 index 0000000..c536ac7 --- /dev/null +++ b/value/lazy/inheritance.h @@ -0,0 +1,7 @@ + +#include + +#include "../inheritance.h" + +extern struct value_inheritance lazy_value_inheritance; + diff --git a/value/lazy/new.c b/value/lazy/new.c new file mode 100644 index 0000000..ae169f2 --- /dev/null +++ b/value/lazy/new.c @@ -0,0 +1,34 @@ + +#include + +#include + +#include + +#include "../new.h" + +#include "inheritance.h" +#include "struct.h" +#include "new.h" + +struct value* new_lazy_value( + struct environment* environment, + struct expression* expression) +{ + ENTER; + + struct lazy_value* this = (void*) new_value( + vk_lazy, + &lazy_value_inheritance, + sizeof(*this)); + + this->environment = inc_environment(environment); + + this->expression = inc_expression(expression); + + this->value = NULL; + + EXIT; + return (void*) this; +} + diff --git a/value/lazy/new.h b/value/lazy/new.h new file mode 100644 index 0000000..ee3fe3b --- /dev/null +++ b/value/lazy/new.h @@ -0,0 +1,6 @@ + +struct value* new_lazy_value( + struct environment* environment, + struct expression* expression); + + diff --git a/value/lazy/prettyprint.c b/value/lazy/prettyprint.c new file mode 100644 index 0000000..a92adc7 --- /dev/null +++ b/value/lazy/prettyprint.c @@ -0,0 +1,48 @@ + +#include + +/*#include */ + +/*#include */ +#include +#include + +#include + +#include "struct.h" +#include "inheritance.h" +#include "prettyprint.h" + +struct stringtree* lazy_value_prettyprint( + int *out_chosen_color, + struct value* super, + struct color_factory* cfactory, + bool with_color) +{ + ENTER; + + struct lazy_value* this = (void*) super; + + struct stringtree* tree = expression_prettyprint( + out_chosen_color, + this->expression, + cfactory, + with_color); + +/* stringtree_prepend_cstr(tree, L"lazy(");*/ +/* stringtree_append_cstr(tree, L")");*/ + + EXIT; + return tree; +} + + + + + + + + + + + diff --git a/value/lazy/prettyprint.h b/value/lazy/prettyprint.h new file mode 100644 index 0000000..379b20f --- /dev/null +++ b/value/lazy/prettyprint.h @@ -0,0 +1,7 @@ + +struct stringtree* lazy_value_prettyprint( + int *out_chosen_color, + struct value* super, + struct color_factory* cfactory, + bool with_color); + diff --git a/value/lazy/struct.h b/value/lazy/struct.h new file mode 100644 index 0000000..0b93c9b --- /dev/null +++ b/value/lazy/struct.h @@ -0,0 +1,14 @@ + +#include "../struct.h" + +struct lazy_value +{ + struct value super; + + struct environment* environment; + + struct expression* expression; + + struct value* value; +}; + diff --git a/value/lazy/unlazy.c b/value/lazy/unlazy.c new file mode 100644 index 0000000..380f972 --- /dev/null +++ b/value/lazy/unlazy.c @@ -0,0 +1,58 @@ + +#include + +#include + +#include "../inc.h" +#include "../free.h" + +#include "struct.h" +#include "unlazy.h" + +struct value* lazy_value_unlazy( + struct value* super, + struct booleans* booleans) +{ + struct value* retval; + ENTER; + + if (super->kind == vk_lazy) + { + struct lazy_value* this = (void*) super; + + if (!this->value) + { + struct value* value = expression_evaluate( + this->expression, this->environment, booleans); + + this->value = lazy_value_unlazy(value, booleans); + + free_value(value); + } + + retval = inc_value(this->value); + } + else + { + retval = inc_value(super); + } + + EXIT; + return retval; +} + + + + + + + + + + + + + + + + diff --git a/value/lazy/unlazy.h b/value/lazy/unlazy.h new file mode 100644 index 0000000..eb62b48 --- /dev/null +++ b/value/lazy/unlazy.h @@ -0,0 +1,8 @@ + +struct value; +struct booleans; + +struct value* lazy_value_unlazy( + struct value* this, + struct booleans* booleans); + diff --git a/value/new.c b/value/new.c new file mode 100644 index 0000000..a697845 --- /dev/null +++ b/value/new.c @@ -0,0 +1,27 @@ + +#include + +#include + +#include "struct.h" +#include "new.h" + +struct value* new_value( + enum value_kind kind, + const struct value_inheritance* inheritance, + size_t alloc_size) +{ + ENTER; + + struct value* this = smalloc(alloc_size); + + this->kind = kind; + + this->inheritance = inheritance; + + this->refcount = 1; + + EXIT; + return this; +} + diff --git a/value/new.h b/value/new.h new file mode 100644 index 0000000..66e91c7 --- /dev/null +++ b/value/new.h @@ -0,0 +1,13 @@ + +#include + +#include "kind.h" + +struct value_inheritance; + +struct value* new_value( + enum value_kind kind, + const struct value_inheritance* inheritance, + size_t alloc_size); + + diff --git a/value/number/free.c b/value/number/free.c new file mode 100644 index 0000000..2da7487 --- /dev/null +++ b/value/number/free.c @@ -0,0 +1,20 @@ + +#include + +#include + +#include "struct.h" +#include "free.h" + +void free_number_value( + struct value* super) +{ + ENTER; + + struct number_value* this = (void*) super; + + free_number(this->value); + + EXIT; +} + diff --git a/value/number/free.h b/value/number/free.h new file mode 100644 index 0000000..60d0912 --- /dev/null +++ b/value/number/free.h @@ -0,0 +1,6 @@ + +struct value; + +void free_number_value( + struct value* super); + diff --git a/value/number/inheritance.c b/value/number/inheritance.c new file mode 100644 index 0000000..433066e --- /dev/null +++ b/value/number/inheritance.c @@ -0,0 +1,15 @@ + +#include + +#include "../inheritance.h" + +#include "prettyprint.h" +#include "free.h" +#include "inheritance.h" + +struct value_inheritance number_value_inheritance = { + .prettyprint = number_value_prettyprint, + + .free = free_number_value, +}; + diff --git a/value/number/inheritance.h b/value/number/inheritance.h new file mode 100644 index 0000000..fd1e520 --- /dev/null +++ b/value/number/inheritance.h @@ -0,0 +1,7 @@ + +#include + +#include "../inheritance.h" + +extern struct value_inheritance number_value_inheritance; + diff --git a/value/number/new.c b/value/number/new.c new file mode 100644 index 0000000..645c235 --- /dev/null +++ b/value/number/new.c @@ -0,0 +1,27 @@ + +#include + +#include + +#include "../new.h" + +#include "inheritance.h" +#include "struct.h" +#include "new.h" + +struct value* new_number_value( + struct number* value) +{ + ENTER; + + struct number_value* this = (void*) new_value( + vk_number, + &number_value_inheritance, + sizeof(*this)); + + this->value = inc_number(value); + + EXIT; + return (void*) this; +} + diff --git a/value/number/new.h b/value/number/new.h new file mode 100644 index 0000000..591aa2c --- /dev/null +++ b/value/number/new.h @@ -0,0 +1,5 @@ + +struct value* new_number_value( + struct number* value); + + diff --git a/value/number/prettyprint.c b/value/number/prettyprint.c new file mode 100644 index 0000000..717b96d --- /dev/null +++ b/value/number/prettyprint.c @@ -0,0 +1,51 @@ + +#include + +#include + +#include +#include +#include + +#include + +#include "struct.h" +#include "inheritance.h" +#include "prettyprint.h" + +struct stringtree* number_value_prettyprint( + int *out_chosen_color, + struct value* super, + struct color_factory* cfactory, + bool with_color) +{ + ENTER; + + struct number_value* this = (void*) super; + + struct stringtree* tree = number_prettyprint(this->value); + + if (with_color) + { + stringtree_prepend_string(tree, cfactory->numeric); + + stringtree_append_string(tree, cfactory->reset); + + if (out_chosen_color) + *out_chosen_color = -1; + } + + EXIT; + return tree; +} + + + + + + + + + + + diff --git a/value/number/prettyprint.h b/value/number/prettyprint.h new file mode 100644 index 0000000..cc4dea7 --- /dev/null +++ b/value/number/prettyprint.h @@ -0,0 +1,7 @@ + +struct stringtree* number_value_prettyprint( + int *out_chosen_color, + struct value* super, + struct color_factory* cfactory, + bool with_color); + diff --git a/value/number/struct.h b/value/number/struct.h new file mode 100644 index 0000000..3e79f44 --- /dev/null +++ b/value/number/struct.h @@ -0,0 +1,10 @@ + +#include "../struct.h" + +struct number_value +{ + struct value super; + + struct number* value; +}; + diff --git a/value/prettyprint.c b/value/prettyprint.c new file mode 100644 index 0000000..dda45d2 --- /dev/null +++ b/value/prettyprint.c @@ -0,0 +1,28 @@ + +#include + +#include + +#include "struct.h" +#include "inheritance.h" +#include "prettyprint.h" + +struct stringtree* value_prettyprint( + int *out_chosen_color, + struct value* this, + struct color_factory* cfactory, + bool with_color) +{ + ENTER; + + assert(this); + assert(this->inheritance); + assert(this->inheritance->prettyprint); + + struct stringtree* tree = (this->inheritance->prettyprint)( + out_chosen_color, this, cfactory, with_color); + + EXIT; + return tree; +} + diff --git a/value/prettyprint.h b/value/prettyprint.h new file mode 100644 index 0000000..ff23074 --- /dev/null +++ b/value/prettyprint.h @@ -0,0 +1,13 @@ + +#include + +struct value; + +struct color_factory; + +struct stringtree* value_prettyprint( + int *out_chosen_color, + struct value* this, + struct color_factory* cfactory, + bool with_color); + diff --git a/value/struct.h b/value/struct.h new file mode 100644 index 0000000..0704f99 --- /dev/null +++ b/value/struct.h @@ -0,0 +1,18 @@ + +#ifndef STRUCT_VALUE +#define STRUCT_VALUE + +#include "kind.h" + +struct value_inheritance; + +struct value +{ + const struct value_inheritance* inheritance; + + enum value_kind kind; + + unsigned refcount; +}; + +#endif diff --git a/wcostream/file/free.c b/wcostream/file/free.c new file mode 100644 index 0000000..e69de29 diff --git a/wcostream/file/free.h b/wcostream/file/free.h new file mode 100644 index 0000000..e69de29 diff --git a/wcostream/file/new.c b/wcostream/file/new.c new file mode 100644 index 0000000..e69de29 diff --git a/wcostream/file/new.h b/wcostream/file/new.h new file mode 100644 index 0000000..e69de29 diff --git a/wcostream/file/struct.h b/wcostream/file/struct.h new file mode 100644 index 0000000..e69de29 diff --git a/wcostream/file/write.c b/wcostream/file/write.c new file mode 100644 index 0000000..e69de29 diff --git a/wcostream/file/write.h b/wcostream/file/write.h new file mode 100644 index 0000000..e69de29 diff --git a/wcostream/free.c b/wcostream/free.c new file mode 100644 index 0000000..37e7b9f --- /dev/null +++ b/wcostream/free.c @@ -0,0 +1,30 @@ + +#include + +#include + +#include + +#include "inheritance.h" +#include "struct.h" +#include "free.h" + +void free_wcostream( + struct wcostream* this) +{ + ENTER; + + if (this && !--this->refcount) + { + assert(this); + assert(this->inheritance); + assert(this->inheritance->free); + + (this->inheritance->free)(this); + + free(this); + } + + EXIT; +} + diff --git a/wcostream/free.h b/wcostream/free.h new file mode 100644 index 0000000..23977b3 --- /dev/null +++ b/wcostream/free.h @@ -0,0 +1,7 @@ + +struct wcostream; + +void free_wcostream( + struct wcostream* this); + + diff --git a/wcostream/inc.c b/wcostream/inc.c new file mode 100644 index 0000000..e69de29 diff --git a/wcostream/inc.h b/wcostream/inc.h new file mode 100644 index 0000000..e69de29 diff --git a/wcostream/inheritance.h b/wcostream/inheritance.h new file mode 100644 index 0000000..8c0dbf3 --- /dev/null +++ b/wcostream/inheritance.h @@ -0,0 +1,20 @@ + +#ifndef STRUCT_WCOSTREAM_INHERITANCE +#define STRUCT_WCOSTREAM_INHERITANCE + +#include + +struct wcostream; + +struct wcostream_inheritance +{ + void (*write)( + struct wcostream*, + const wchar_t*, + size_t); + + void (*free)( + struct wcostream* this); +}; + +#endif diff --git a/wcostream/new.c b/wcostream/new.c new file mode 100644 index 0000000..0ad8180 --- /dev/null +++ b/wcostream/new.c @@ -0,0 +1,24 @@ + +#include + +#include + +#include "struct.h" +#include "new.h" + +struct wcostream* new_wcostream( + const struct wcostream_inheritance* inheritance, + size_t alloc_size) +{ + ENTER; + + struct wcostream* this = smalloc(alloc_size); + + this->inheritance = inheritance; + + this->refcount = 1; + + EXIT; + return this; +} + diff --git a/wcostream/new.h b/wcostream/new.h new file mode 100644 index 0000000..8b6810e --- /dev/null +++ b/wcostream/new.h @@ -0,0 +1,10 @@ + +#include + +struct wcostream_inheritance; + +struct wcostream* new_wcostream( + const struct wcostream_inheritance* inheritance, + size_t alloc_size); + + diff --git a/wcostream/ostream/free.c b/wcostream/ostream/free.c new file mode 100644 index 0000000..5c8aef8 --- /dev/null +++ b/wcostream/ostream/free.c @@ -0,0 +1,21 @@ + +#include + +#include + +#include "struct.h" +#include "free.h" + +void free_ostream_wcostream( + struct wcostream* super) +{ + ENTER; + + struct ostream_wcostream* const this = (void*) super; + + free_ostream(this->stream); + + EXIT; +} + + diff --git a/wcostream/ostream/free.h b/wcostream/ostream/free.h new file mode 100644 index 0000000..3513d75 --- /dev/null +++ b/wcostream/ostream/free.h @@ -0,0 +1,7 @@ + +struct wcostream; + +void free_ostream_wcostream( + struct wcostream* super); + + diff --git a/wcostream/ostream/inheritance.c b/wcostream/ostream/inheritance.c new file mode 100644 index 0000000..b80cafe --- /dev/null +++ b/wcostream/ostream/inheritance.c @@ -0,0 +1,15 @@ + +#include + +#include "../inheritance.h" + +#include "write.h" +#include "free.h" + +#include "inheritance.h" + +struct wcostream_inheritance ostream_wcostream_inheritance = { + .write = ostream_wcostream_write, + + .free = free_ostream_wcostream, +}; diff --git a/wcostream/ostream/inheritance.h b/wcostream/ostream/inheritance.h new file mode 100644 index 0000000..c7d00c0 --- /dev/null +++ b/wcostream/ostream/inheritance.h @@ -0,0 +1,6 @@ + +#include "../inheritance.h" + +extern struct wcostream_inheritance ostream_wcostream_inheritance; + + diff --git a/wcostream/ostream/new.c b/wcostream/ostream/new.c new file mode 100644 index 0000000..41b7d6a --- /dev/null +++ b/wcostream/ostream/new.c @@ -0,0 +1,26 @@ + +#include + +#include + +#include "../new.h" + +#include "inheritance.h" +#include "struct.h" +#include "new.h" + +struct wcostream* new_ostream_wcostream( + struct ostream* stream) +{ + ENTER; + + struct ostream_wcostream* this = (void*) new_wcostream( + &ostream_wcostream_inheritance, + sizeof(*this)); + + this->stream = inc_ostream(stream); + + EXIT; + return (void*) this; +} + diff --git a/wcostream/ostream/new.h b/wcostream/ostream/new.h new file mode 100644 index 0000000..bfa8605 --- /dev/null +++ b/wcostream/ostream/new.h @@ -0,0 +1,7 @@ + +struct ostream; + +struct wcostream* new_ostream_wcostream( + struct ostream* stream); + + diff --git a/wcostream/ostream/struct.h b/wcostream/ostream/struct.h new file mode 100644 index 0000000..e1bf1f8 --- /dev/null +++ b/wcostream/ostream/struct.h @@ -0,0 +1,12 @@ + +#include "../struct.h" + +struct ostream; + +struct ostream_wcostream +{ + struct wcostream super; + + struct ostream* stream; +}; + diff --git a/wcostream/ostream/write.c b/wcostream/ostream/write.c new file mode 100644 index 0000000..147c005 --- /dev/null +++ b/wcostream/ostream/write.c @@ -0,0 +1,122 @@ + +#include + +#include + +#include + +#include "struct.h" +#include "write.h" + +void ostream_wcostream_write( + struct wcostream* super, + const wchar_t* data, + size_t len) +{ + ENTER; + + dpvi(data[0]); + dpvlu(len); + + struct ostream_wcostream* this = (void*) super; + + uint8_t buffer[6 * len], *start = buffer, *writing = buffer; + + for (size_t i = 0; i < len; i++) + { + wchar_t wc = data[i]; + + switch (wc) + { + // 0x00000000 - 0x0000007F: + // 0xxxxxxx + + case 0x00000000 ... 0x0000007F: + { + *writing++ = (uint8_t) data[i]; + + break; + } + + // 0x00000080 - 0x000007FF: + // 110xxxxx 10xxxxxx + case 0x00000080 ... 0x000007FF: + { + *writing++ = 0b11000000 | (0b011111 & (wc >> 6)); + + *writing++ = 0b10000000 | (0b111111 & (wc >> 0)); + + break; + } + + // 0x00000800 - 0x0000FFFF: + // 1110xxxx 10xxxxxx 10xxxxxx + + case 0x00000800 ... 0x0000FFFF: + { + *writing++ = 0b11100000 | (0b001111 & (wc >> 12)); + + *writing++ = 0b10000000 | (0b111111 & (wc >> 6)); + + *writing++ = 0b10000000 | (0b111111 & (wc >> 0)); + + break; + } + + // 0x00010000 - 0x001FFFFF: + // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + + case 0x00010000 ... 0x001FFFFF: + { + *writing++ = 0b11110000 | (0b000111 & (wc >> 18)); + + *writing++ = 0b10000000 | (0b111111 & (wc >> 12)); + + *writing++ = 0b10000000 | (0b111111 & (wc >> 6)); + + *writing++ = 0b10000000 | (0b111111 & (wc >> 0)); + + break; + } + + // 0x00200000 - 0x03FFFFFF: + // 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + + case 0x00200000 ... 0x03FFFFFF: + { + TODO; + + break; + } + + // 0x04000000 - 0x7FFFFFFF: + // 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + + case 0x04000000 ... 0x7FFFFFFF: + { + TODO; + + break; + } + + default: + { + dpvi(data[i]); + + TODO; + + break; + } + } + } + + dpvsn(start, writing - start); + + ostream_write(this->stream, buffer, (size_t) (writing - start)); + + EXIT; +} + + + + diff --git a/wcostream/ostream/write.h b/wcostream/ostream/write.h new file mode 100644 index 0000000..f347768 --- /dev/null +++ b/wcostream/ostream/write.h @@ -0,0 +1,9 @@ + +struct wcostream; + +void ostream_wcostream_write( + struct wcostream* super, + const wchar_t*, + size_t); + + diff --git a/wcostream/string/free.c b/wcostream/string/free.c new file mode 100644 index 0000000..e69de29 diff --git a/wcostream/string/free.h b/wcostream/string/free.h new file mode 100644 index 0000000..e69de29 diff --git a/wcostream/string/new.c b/wcostream/string/new.c new file mode 100644 index 0000000..e69de29 diff --git a/wcostream/string/new.h b/wcostream/string/new.h new file mode 100644 index 0000000..e69de29 diff --git a/wcostream/string/struct.h b/wcostream/string/struct.h new file mode 100644 index 0000000..e69de29 diff --git a/wcostream/string/write.c b/wcostream/string/write.c new file mode 100644 index 0000000..e69de29 diff --git a/wcostream/string/write.h b/wcostream/string/write.h new file mode 100644 index 0000000..e69de29 diff --git a/wcostream/struct.h b/wcostream/struct.h new file mode 100644 index 0000000..ca7de7d --- /dev/null +++ b/wcostream/struct.h @@ -0,0 +1,10 @@ + +struct wcostream_inheritance; + +struct wcostream +{ + const struct wcostream_inheritance* inheritance; + + unsigned refcount; +}; + diff --git a/wcostream/write.c b/wcostream/write.c new file mode 100644 index 0000000..82762dc --- /dev/null +++ b/wcostream/write.c @@ -0,0 +1,25 @@ + +#include + +#include + +#include "struct.h" +#include "inheritance.h" +#include "write.h" + +void wcostream_write( + struct wcostream* this, + const wchar_t* data, + size_t len) +{ + ENTER; + + assert(this); + assert(this->inheritance); + assert(this->inheritance->write); + + (this->inheritance->write)(this, data, len); + + EXIT; +} + diff --git a/wcostream/write.h b/wcostream/write.h new file mode 100644 index 0000000..69f6ecd --- /dev/null +++ b/wcostream/write.h @@ -0,0 +1,11 @@ + +#include + +struct wcostream; + +void wcostream_write( + struct wcostream* this, + const wchar_t* data, + size_t len); + +