From 7f220c97b831ff1a300645c001ed09d6cf7376a1 Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Sun, 30 Jan 2022 16:57:21 -0500 Subject: [PATCH] Finally make a clean sweep and delete / organize old files. Add skeleton for LaTeX formal writeup in doc/ and change license (since this is all new code from the past few years) to BSD-2-Clause-Patent --- .gitignore | 1 + Kraken_Compiled_Grammer_file_format.txt | 41 - LICENCE.md | 32 +- README.md | 29 +- captain.sh | 147 -- current_stats.sh | 2 - deprecated_compiler/.gitignore | 5 - deprecated_compiler/CMakeLists.txt | 29 - deprecated_compiler/include/ASTData.h | 41 - .../include/ASTTransformation.h | 87 - deprecated_compiler/include/CCodeTriple.h | 25 - deprecated_compiler/include/CGenerator.h | 72 - .../include/CollapseTransformation.h | 52 - .../include/DeleteTransformation.h | 48 - .../include/GraphStructuredStack.h | 38 - deprecated_compiler/include/Importer.h | 48 - deprecated_compiler/include/Lexer.h | 26 - .../include/NodeTransformation.h | 35 - deprecated_compiler/include/NodeTree.h | 277 --- deprecated_compiler/include/ParseAction.h | 36 - deprecated_compiler/include/ParseRule.h | 53 - deprecated_compiler/include/Parser.h | 73 - deprecated_compiler/include/Poset.h | 126 -- deprecated_compiler/include/RNGLRParser.h | 68 - deprecated_compiler/include/RegEx.h | 29 - deprecated_compiler/include/RegExState.h | 32 - .../include/RemovalTransformation.h | 50 - deprecated_compiler/include/State.h | 46 - deprecated_compiler/include/StringReader.h | 28 - deprecated_compiler/include/Symbol.h | 37 - deprecated_compiler/include/Table.h | 37 - deprecated_compiler/include/Tester.h | 32 - deprecated_compiler/include/Type.h | 64 - deprecated_compiler/include/util.h | 92 - deprecated_compiler/main.cpp | 190 -- deprecated_compiler/src/ASTData.cpp | 88 - deprecated_compiler/src/ASTTransformation.cpp | 1903 ----------------- deprecated_compiler/src/CCodeTriple.cpp | 45 - deprecated_compiler/src/CGenerator.cpp | 1390 ------------ .../src/GraphStructuredStack.cpp | 145 -- deprecated_compiler/src/Importer.cpp | 238 --- deprecated_compiler/src/Lexer.cpp | 120 -- deprecated_compiler/src/ParseAction.cpp | 79 - deprecated_compiler/src/ParseRule.cpp | 145 -- deprecated_compiler/src/Parser.cpp | 407 ---- deprecated_compiler/src/RNGLRParser.cpp | 565 ----- deprecated_compiler/src/RegEx.cpp | 225 -- deprecated_compiler/src/RegExState.cpp | 82 - deprecated_compiler/src/State.cpp | 164 -- deprecated_compiler/src/StringReader.cpp | 166 -- deprecated_compiler/src/Symbol.cpp | 52 - deprecated_compiler/src/Table.cpp | 388 ---- deprecated_compiler/src/Tester.cpp | 62 - deprecated_compiler/src/Type.cpp | 268 --- deprecated_compiler/src/util.cpp | 92 - doc/.gitignore | 9 + doc/Manual.tex | 345 --- doc/cited-paper.bib | 11 + doc/make_paper.sh | 2 + doc/nix/sources.json | 38 + doc/nix/sources.nix | 174 ++ doc/shell.nix | 11 + doc/writeup.tex | 269 +++ fib.c | 17 - fungll.krak | 440 ---- future_features.txt | 7 - k.krak | 1870 ---------------- k_prime.krak | 1544 ------------- kraken.krak | 220 -- krakenGrammer.kgm | 158 -- kraken_cloc_definition.txt | 6 - llvm.krak | 78 - mal.krak | 1578 -------------- shell.nix | 6 - stdlib/.math.krak.un~ | Bin 27548 -> 0 bytes stdlib/address_of_ensure_variable_lower.krak | 51 - stdlib/adt_lower.krak | 200 -- stdlib/ast.krak | 324 --- stdlib/ast_nodes.krak | 1207 ----------- stdlib/ast_transformation.krak | 1077 ---------- stdlib/binding.krak | 111 - stdlib/bytecode_generator.krak | 1261 ----------- stdlib/c_generator.krak | 509 ----- stdlib/c_line_control.krak | 37 - stdlib/ctce_lower.krak | 46 - stdlib/defer_lower.krak | 81 - stdlib/function_value_lower.krak | 329 --- stdlib/future.krak | 86 - stdlib/grammer.krak | 639 ------ stdlib/hash_map.krak | 120 -- stdlib/hash_set.krak | 147 -- stdlib/importer.krak | 134 -- stdlib/interpreter.krak | 1067 --------- stdlib/io.krak | 160 -- stdlib/lexer.krak | 89 - stdlib/map.krak | 130 -- stdlib/math.krak | 29 - stdlib/matrix.krak | 146 -- stdlib/mem.krak | 126 -- stdlib/node_counter.krak | 35 - stdlib/obj_lower.krak | 384 ---- stdlib/os.krak | 32 - stdlib/parser.krak | 488 ----- stdlib/pass_common.krak | 515 ----- stdlib/poset.krak | 96 - stdlib/queue.krak | 70 - stdlib/rc.krak | 44 - stdlib/ref_lower.krak | 97 - stdlib/regex.krak | 269 --- stdlib/serialize.krak | 30 - stdlib/set.krak | 160 -- stdlib/stack.krak | 109 - stdlib/str.krak | 337 --- stdlib/symbol.krak | 117 - stdlib/thread.krak | 51 - stdlib/tree.krak | 72 - stdlib/type.krak | 285 --- stdlib/type2.krak | 335 --- stdlib/util.krak | 276 --- stdlib/vec.krak | 403 ---- stdlib/vec_literals.krak | 134 -- stress_generator.py | 21 - syntax.gp | 29 - tests/.gitignore | 13 - tests/.test_trigTest.krak.un~ | Bin 1379 -> 0 bytes tests/SupressOut.sh | 2 - tests/c_passthrough_diff.krak | 17 - .../disabled_test_ctce_pass.expected_results | 1 - tests/disabled_test_ctce_pass.krak | 12 - tests/error_test.krak | 13 - tests/new_runner.sh | 15 - tests/sameNameOne.krak | 7 - tests/sameNameTwo.krak | 6 - tests/scopeQualified.krak | 27 - tests/scopeUnqualified.krak | 27 - tests/syntax_error.krak | 34 - ...test_OperatorOverloadTest.expected_results | 5 - tests/test_OperatorOverloadTest.krak | 64 - tests/test_RecursiveTest.expected_results | 1 - tests/test_RecursiveTest.krak | 14 - tests/test_access_expression.expected_results | 1 - tests/test_access_expression.krak | 23 - tests/test_adt.expected_results | 55 - tests/test_adt.krak | 163 -- tests/test_auto_void.expected_results | 3 - tests/test_auto_void.krak | 16 - tests/test_badMath.expected_results | 11 - tests/test_badMath.krak | 26 - tests/test_bracket_assign.expected_results | 3 - tests/test_bracket_assign.krak | 26 - ...test_break_continue_defer.expected_results | 17 - tests/test_break_continue_defer.krak | 27 - tests/test_c_comments.expected_results | 1 - tests/test_c_comments.krak | 11 - tests/test_cgen_bug.expected_results | 2 - tests/test_cgen_bug.krak | 14 - ..._chainedIndirectTemplates.expected_results | 1 - tests/test_chainedIndirectTemplates.krak | 15 - .../test_close_over_members.expected_results | 5 - tests/test_close_over_members.krak | 55 - ...est_close_over_references.expected_results | 2 - tests/test_close_over_references.krak | 17 - tests/test_commentFirstTest.expected_results | 2 - tests/test_commentFirstTest.krak | 9 - .../test_comparison_overload.expected_results | 1 - tests/test_comparison_overload.krak | 25 - .../test_compiler_intrinsic.expected_results | 5 - tests/test_compiler_intrinsic.krak | 12 - tests/test_conversions.expected_results | 11 - tests/test_conversions.krak | 25 - tests/test_ctce.expected_results | 53 - tests/test_ctce.krak | 110 - tests/test_declarationsTest.expected_results | 3 - tests/test_declarationsTest.krak | 26 - ...structor_copy_constructor.expected_results | 47 - tests/test_destructor_copy_constructor.krak | 105 - tests/test_else.expected_results | 2 - tests/test_else.krak | 16 - .../test_emptyBracesFunction.expected_results | 1 - tests/test_emptyBracesFunction.krak | 9 - tests/test_extern.expected_results | 1 - tests/test_extern.krak | 9 - tests/test_fileio.expected_results | 3 - tests/test_fileio.krak | 7 - ...ctionMultipleTemplateTest.expected_results | 1 - tests/test_functionMultipleTemplateTest.krak | 13 - tests/test_functionOperator.expected_results | 2 - tests/test_functionOperator.krak | 17 - ...test_functionOrderingTest.expected_results | 1 - tests/test_functionOrderingTest.krak | 17 - ...functionTemplateInference.expected_results | 5 - tests/test_functionTemplateInference.krak | 43 - ...test_functionTemplateTest.expected_results | 1 - tests/test_functionTemplateTest.krak | 13 - tests/test_functionsValues.expected_results | 8 - tests/test_functionsValues.krak | 56 - tests/test_future.expected_results | 3 - tests/test_future.krak | 28 - tests/test_lambda.expected_results | 22 - tests/test_lambda.krak | 45 - tests/test_lexer.expected_results | 22 - tests/test_lexer.krak | 57 - tests/test_literal.expected_results | 4 - tests/test_literal.krak | 25 - tests/test_map.expected_results | 26 - tests/test_map.krak | 39 - tests/test_math.expected_results | 7 - tests/test_math.krak | 36 - tests/test_memTest.expected_results | 3 - tests/test_memTest.krak | 27 - ...est_moreComplexObjectTest.expected_results | 2 - tests/test_moreComplexObjectTest.krak | 27 - ...st_moreObjectTemplateTest.expected_results | 1 - tests/test_moreObjectTemplateTest.krak | 36 - tests/test_multiline_strings.expected_results | 10 - tests/test_multiline_strings.krak | 18 - ...est_negative_number_unary.expected_results | 5 - tests/test_nequals.expected_results | 1 - tests/test_nequals.krak | 10 - tests/test_newScoping.expected_results | 13 - tests/test_newScoping.krak | 32 - tests/test_nosemicolon.expected_results | 3 - tests/test_nosemicolon.krak | 9 - tests/test_obj_create_scope.expected_results | 1 - tests/test_obj_create_scope.krak | 23 - .../test_objectOrderingTest.expected_results | 1 - tests/test_objectOrderingTest.krak | 27 - ...test_oneStatementFunction.expected_results | 6 - tests/test_oneStatementFunction.krak | 24 - tests/test_poset.expected_results | 4 - tests/test_poset.krak | 28 - tests/test_queue.expected_results | 67 - tests/test_queue.krak | 39 - tests/test_rec_closure.expected_results | 5 - tests/test_rec_closure.krak | 12 - tests/test_references.expected_results | 11 - tests/test_references.krak | 67 - tests/test_regex.expected_results | 46 - tests/test_regex.krak | 75 - tests/test_sameName.expected_results | 10 - tests/test_sameName.krak | 40 - tests/test_serialization.expected_results | 6 - tests/test_serialization.krak | 71 - tests/test_set.expected_results | 21 - tests/test_set.krak | 33 - tests/test_short_circuit.expected_results | 8 - tests/test_short_circuit.krak | 38 - .../test_simpleFunctionTest.expected_results | 1 - tests/test_simpleFunctionTest.krak | 14 - ...bjectMultipleTemplateTest.expected_results | 4 - ...test_simpleObjectMultipleTemplateTest.krak | 30 - ..._simpleObjectTemplateTest.expected_results | 4 - tests/test_simpleObjectTemplateTest.krak | 30 - tests/test_simpleObjectTest.expected_results | 1 - tests/test_simpleObjectTest.krak | 17 - tests/test_string.expected_results | 15 - tests/test_string.krak | 30 - tests/test_templateFuncInfr.expected_results | 5 - tests/test_templateFuncInfr.krak | 32 - ...st_templateMemberFunction.expected_results | 3 - tests/test_templateMemberFunction.krak | 30 - tests/test_templateTest.expected_results | 8 - tests/test_templateTest.krak | 51 - ...emplate_operator_overload.expected_results | 1 - tests/test_template_operator_overload.krak | 14 - ...emplatedFunctionInference.expected_results | 2 - ...latedObjectTemplatedFunctionInference.krak | 19 - tests/test_testArrayNotation.expected_results | 1 - tests/test_testArrayNotation.krak | 12 - tests/test_thread.expected_results | 5 - tests/test_thread.krak | 20 - tests/test_topLevelVarInit.expected_results | 2 - tests/test_topLevelVarInit.krak | 10 - tests/test_traitsTest.expected_results | 23 - tests/test_traitsTest.krak | 78 - tests/test_typeExpr.expected_results | 2 - tests/test_typeExpr.krak | 20 - tests/test_typeInfr.expected_results | 10 - tests/test_typeInfr.krak | 51 - tests/test_union.expected_results | 3 - tests/test_union.krak | 22 - tests/test_util.expected_results | 33 - tests/test_util.krak | 52 - tests/test_vectorTest.expected_results | 80 - tests/test_vectorTest.krak | 160 -- tests/tester.krak | 65 - tests/trivial_container.krak | 9 - try.html | 80 - bf.kp => working_files/bf.kp | 0 .../collections.kp | 0 comp_wasm.kp => working_files/comp_wasm.kp | 0 .../compile_for_web.sh | 0 .../damas_hindley_milner.kp | 0 .../damas_hindley_milner_test.kp | 0 working_files/dlambda_test.kp | 20 + even_odd.kp => working_files/even_odd.kp | 0 fib-comp.kp => working_files/fib-comp.kp | 0 fib-interp.kp => working_files/fib-interp.kp | 0 fungll.kp => working_files/fungll.kp | 0 .../fungll_test.kp | 0 .../import_test.kp | 0 index.html => working_files/index.html | 0 .../k_prime_stdlib}/method.kp | 0 .../k_prime_stdlib}/prelude.kp | 0 match.kp => working_files/match.kp | 0 match_test.kp => working_files/match_test.kp | 0 working_files/method.kp | 103 + new_kraken.kp => working_files/new_kraken.kp | 0 .../new_kraken_test.kp | 0 .../partial_eval.kp | 0 working_files/partial_eval_test.csc | 35 + .../partial_eval_test.kp | 0 .../partial_eval_test_rec.kp | 0 prelude.kp => working_files/prelude.kp | 0 rb.kp => working_files/rb.kp | 0 rb_test.kp => working_files/rb_test.kp | 0 sierpinski.kp => working_files/sierpinski.kp | 0 working_files/smaller_new_kraken_test.kp | 15 + working_files/test.csc | 35 + working_files/test_parse_in | 3 + working_files/test_parse_in_large | 1 + working_files/test_ystar_vau.kp | 6 + working_files/types.kp | 141 ++ working_files/types_test.kp | 2 + wasm.kp => working_files/wasm.kp | 0 325 files changed, 901 insertions(+), 31024 deletions(-) delete mode 100644 Kraken_Compiled_Grammer_file_format.txt delete mode 100755 captain.sh delete mode 100755 current_stats.sh delete mode 100644 deprecated_compiler/.gitignore delete mode 100644 deprecated_compiler/CMakeLists.txt delete mode 100644 deprecated_compiler/include/ASTData.h delete mode 100644 deprecated_compiler/include/ASTTransformation.h delete mode 100644 deprecated_compiler/include/CCodeTriple.h delete mode 100644 deprecated_compiler/include/CGenerator.h delete mode 100644 deprecated_compiler/include/CollapseTransformation.h delete mode 100644 deprecated_compiler/include/DeleteTransformation.h delete mode 100644 deprecated_compiler/include/GraphStructuredStack.h delete mode 100644 deprecated_compiler/include/Importer.h delete mode 100644 deprecated_compiler/include/Lexer.h delete mode 100644 deprecated_compiler/include/NodeTransformation.h delete mode 100644 deprecated_compiler/include/NodeTree.h delete mode 100644 deprecated_compiler/include/ParseAction.h delete mode 100644 deprecated_compiler/include/ParseRule.h delete mode 100644 deprecated_compiler/include/Parser.h delete mode 100644 deprecated_compiler/include/Poset.h delete mode 100644 deprecated_compiler/include/RNGLRParser.h delete mode 100644 deprecated_compiler/include/RegEx.h delete mode 100644 deprecated_compiler/include/RegExState.h delete mode 100644 deprecated_compiler/include/RemovalTransformation.h delete mode 100644 deprecated_compiler/include/State.h delete mode 100644 deprecated_compiler/include/StringReader.h delete mode 100644 deprecated_compiler/include/Symbol.h delete mode 100644 deprecated_compiler/include/Table.h delete mode 100644 deprecated_compiler/include/Tester.h delete mode 100644 deprecated_compiler/include/Type.h delete mode 100644 deprecated_compiler/include/util.h delete mode 100644 deprecated_compiler/main.cpp delete mode 100644 deprecated_compiler/src/ASTData.cpp delete mode 100644 deprecated_compiler/src/ASTTransformation.cpp delete mode 100644 deprecated_compiler/src/CCodeTriple.cpp delete mode 100644 deprecated_compiler/src/CGenerator.cpp delete mode 100644 deprecated_compiler/src/GraphStructuredStack.cpp delete mode 100644 deprecated_compiler/src/Importer.cpp delete mode 100644 deprecated_compiler/src/Lexer.cpp delete mode 100644 deprecated_compiler/src/ParseAction.cpp delete mode 100644 deprecated_compiler/src/ParseRule.cpp delete mode 100644 deprecated_compiler/src/Parser.cpp delete mode 100644 deprecated_compiler/src/RNGLRParser.cpp delete mode 100644 deprecated_compiler/src/RegEx.cpp delete mode 100644 deprecated_compiler/src/RegExState.cpp delete mode 100644 deprecated_compiler/src/State.cpp delete mode 100644 deprecated_compiler/src/StringReader.cpp delete mode 100644 deprecated_compiler/src/Symbol.cpp delete mode 100644 deprecated_compiler/src/Table.cpp delete mode 100644 deprecated_compiler/src/Tester.cpp delete mode 100644 deprecated_compiler/src/Type.cpp delete mode 100644 deprecated_compiler/src/util.cpp create mode 100644 doc/.gitignore delete mode 100644 doc/Manual.tex create mode 100644 doc/cited-paper.bib create mode 100755 doc/make_paper.sh create mode 100644 doc/nix/sources.json create mode 100644 doc/nix/sources.nix create mode 100644 doc/shell.nix create mode 100644 doc/writeup.tex delete mode 100644 fib.c delete mode 100644 fungll.krak delete mode 100644 future_features.txt delete mode 100644 k.krak delete mode 100644 k_prime.krak delete mode 100644 kraken.krak delete mode 100644 krakenGrammer.kgm delete mode 100644 kraken_cloc_definition.txt delete mode 100644 llvm.krak delete mode 100644 mal.krak delete mode 100644 stdlib/.math.krak.un~ delete mode 100644 stdlib/address_of_ensure_variable_lower.krak delete mode 100644 stdlib/adt_lower.krak delete mode 100644 stdlib/ast.krak delete mode 100644 stdlib/ast_nodes.krak delete mode 100644 stdlib/ast_transformation.krak delete mode 100644 stdlib/binding.krak delete mode 100644 stdlib/bytecode_generator.krak delete mode 100644 stdlib/c_generator.krak delete mode 100644 stdlib/c_line_control.krak delete mode 100644 stdlib/ctce_lower.krak delete mode 100644 stdlib/defer_lower.krak delete mode 100644 stdlib/function_value_lower.krak delete mode 100644 stdlib/future.krak delete mode 100644 stdlib/grammer.krak delete mode 100644 stdlib/hash_map.krak delete mode 100644 stdlib/hash_set.krak delete mode 100644 stdlib/importer.krak delete mode 100644 stdlib/interpreter.krak delete mode 100644 stdlib/io.krak delete mode 100644 stdlib/lexer.krak delete mode 100644 stdlib/map.krak delete mode 100644 stdlib/math.krak delete mode 100644 stdlib/matrix.krak delete mode 100644 stdlib/mem.krak delete mode 100644 stdlib/node_counter.krak delete mode 100644 stdlib/obj_lower.krak delete mode 100644 stdlib/os.krak delete mode 100644 stdlib/parser.krak delete mode 100644 stdlib/pass_common.krak delete mode 100644 stdlib/poset.krak delete mode 100644 stdlib/queue.krak delete mode 100644 stdlib/rc.krak delete mode 100644 stdlib/ref_lower.krak delete mode 100644 stdlib/regex.krak delete mode 100644 stdlib/serialize.krak delete mode 100644 stdlib/set.krak delete mode 100644 stdlib/stack.krak delete mode 100644 stdlib/str.krak delete mode 100644 stdlib/symbol.krak delete mode 100644 stdlib/thread.krak delete mode 100644 stdlib/tree.krak delete mode 100644 stdlib/type.krak delete mode 100644 stdlib/type2.krak delete mode 100644 stdlib/util.krak delete mode 100644 stdlib/vec.krak delete mode 100644 stdlib/vec_literals.krak delete mode 100644 stress_generator.py delete mode 100644 syntax.gp delete mode 100644 tests/.gitignore delete mode 100644 tests/.test_trigTest.krak.un~ delete mode 100755 tests/SupressOut.sh delete mode 100644 tests/c_passthrough_diff.krak delete mode 100644 tests/disabled_test_ctce_pass.expected_results delete mode 100644 tests/disabled_test_ctce_pass.krak delete mode 100644 tests/error_test.krak delete mode 100755 tests/new_runner.sh delete mode 100644 tests/sameNameOne.krak delete mode 100644 tests/sameNameTwo.krak delete mode 100644 tests/scopeQualified.krak delete mode 100644 tests/scopeUnqualified.krak delete mode 100644 tests/syntax_error.krak delete mode 100644 tests/test_OperatorOverloadTest.expected_results delete mode 100644 tests/test_OperatorOverloadTest.krak delete mode 100644 tests/test_RecursiveTest.expected_results delete mode 100644 tests/test_RecursiveTest.krak delete mode 100644 tests/test_access_expression.expected_results delete mode 100644 tests/test_access_expression.krak delete mode 100644 tests/test_adt.expected_results delete mode 100644 tests/test_adt.krak delete mode 100644 tests/test_auto_void.expected_results delete mode 100644 tests/test_auto_void.krak delete mode 100644 tests/test_badMath.expected_results delete mode 100644 tests/test_badMath.krak delete mode 100644 tests/test_bracket_assign.expected_results delete mode 100644 tests/test_bracket_assign.krak delete mode 100644 tests/test_break_continue_defer.expected_results delete mode 100644 tests/test_break_continue_defer.krak delete mode 100644 tests/test_c_comments.expected_results delete mode 100644 tests/test_c_comments.krak delete mode 100644 tests/test_cgen_bug.expected_results delete mode 100644 tests/test_cgen_bug.krak delete mode 100644 tests/test_chainedIndirectTemplates.expected_results delete mode 100644 tests/test_chainedIndirectTemplates.krak delete mode 100644 tests/test_close_over_members.expected_results delete mode 100644 tests/test_close_over_members.krak delete mode 100644 tests/test_close_over_references.expected_results delete mode 100644 tests/test_close_over_references.krak delete mode 100644 tests/test_commentFirstTest.expected_results delete mode 100644 tests/test_commentFirstTest.krak delete mode 100644 tests/test_comparison_overload.expected_results delete mode 100644 tests/test_comparison_overload.krak delete mode 100644 tests/test_compiler_intrinsic.expected_results delete mode 100644 tests/test_compiler_intrinsic.krak delete mode 100644 tests/test_conversions.expected_results delete mode 100644 tests/test_conversions.krak delete mode 100644 tests/test_ctce.expected_results delete mode 100644 tests/test_ctce.krak delete mode 100644 tests/test_declarationsTest.expected_results delete mode 100644 tests/test_declarationsTest.krak delete mode 100644 tests/test_destructor_copy_constructor.expected_results delete mode 100644 tests/test_destructor_copy_constructor.krak delete mode 100644 tests/test_else.expected_results delete mode 100644 tests/test_else.krak delete mode 100644 tests/test_emptyBracesFunction.expected_results delete mode 100644 tests/test_emptyBracesFunction.krak delete mode 100644 tests/test_extern.expected_results delete mode 100644 tests/test_extern.krak delete mode 100644 tests/test_fileio.expected_results delete mode 100644 tests/test_fileio.krak delete mode 100644 tests/test_functionMultipleTemplateTest.expected_results delete mode 100644 tests/test_functionMultipleTemplateTest.krak delete mode 100644 tests/test_functionOperator.expected_results delete mode 100644 tests/test_functionOperator.krak delete mode 100644 tests/test_functionOrderingTest.expected_results delete mode 100644 tests/test_functionOrderingTest.krak delete mode 100644 tests/test_functionTemplateInference.expected_results delete mode 100644 tests/test_functionTemplateInference.krak delete mode 100644 tests/test_functionTemplateTest.expected_results delete mode 100644 tests/test_functionTemplateTest.krak delete mode 100644 tests/test_functionsValues.expected_results delete mode 100644 tests/test_functionsValues.krak delete mode 100644 tests/test_future.expected_results delete mode 100644 tests/test_future.krak delete mode 100644 tests/test_lambda.expected_results delete mode 100644 tests/test_lambda.krak delete mode 100644 tests/test_lexer.expected_results delete mode 100644 tests/test_lexer.krak delete mode 100644 tests/test_literal.expected_results delete mode 100644 tests/test_literal.krak delete mode 100644 tests/test_map.expected_results delete mode 100644 tests/test_map.krak delete mode 100644 tests/test_math.expected_results delete mode 100644 tests/test_math.krak delete mode 100644 tests/test_memTest.expected_results delete mode 100644 tests/test_memTest.krak delete mode 100644 tests/test_moreComplexObjectTest.expected_results delete mode 100644 tests/test_moreComplexObjectTest.krak delete mode 100644 tests/test_moreObjectTemplateTest.expected_results delete mode 100644 tests/test_moreObjectTemplateTest.krak delete mode 100644 tests/test_multiline_strings.expected_results delete mode 100644 tests/test_multiline_strings.krak delete mode 100644 tests/test_negative_number_unary.expected_results delete mode 100644 tests/test_nequals.expected_results delete mode 100644 tests/test_nequals.krak delete mode 100644 tests/test_newScoping.expected_results delete mode 100644 tests/test_newScoping.krak delete mode 100644 tests/test_nosemicolon.expected_results delete mode 100644 tests/test_nosemicolon.krak delete mode 100644 tests/test_obj_create_scope.expected_results delete mode 100644 tests/test_obj_create_scope.krak delete mode 100644 tests/test_objectOrderingTest.expected_results delete mode 100644 tests/test_objectOrderingTest.krak delete mode 100644 tests/test_oneStatementFunction.expected_results delete mode 100644 tests/test_oneStatementFunction.krak delete mode 100644 tests/test_poset.expected_results delete mode 100644 tests/test_poset.krak delete mode 100644 tests/test_queue.expected_results delete mode 100644 tests/test_queue.krak delete mode 100644 tests/test_rec_closure.expected_results delete mode 100644 tests/test_rec_closure.krak delete mode 100644 tests/test_references.expected_results delete mode 100644 tests/test_references.krak delete mode 100644 tests/test_regex.expected_results delete mode 100644 tests/test_regex.krak delete mode 100644 tests/test_sameName.expected_results delete mode 100644 tests/test_sameName.krak delete mode 100644 tests/test_serialization.expected_results delete mode 100644 tests/test_serialization.krak delete mode 100644 tests/test_set.expected_results delete mode 100644 tests/test_set.krak delete mode 100644 tests/test_short_circuit.expected_results delete mode 100644 tests/test_short_circuit.krak delete mode 100644 tests/test_simpleFunctionTest.expected_results delete mode 100644 tests/test_simpleFunctionTest.krak delete mode 100644 tests/test_simpleObjectMultipleTemplateTest.expected_results delete mode 100644 tests/test_simpleObjectMultipleTemplateTest.krak delete mode 100644 tests/test_simpleObjectTemplateTest.expected_results delete mode 100644 tests/test_simpleObjectTemplateTest.krak delete mode 100644 tests/test_simpleObjectTest.expected_results delete mode 100644 tests/test_simpleObjectTest.krak delete mode 100644 tests/test_string.expected_results delete mode 100644 tests/test_string.krak delete mode 100644 tests/test_templateFuncInfr.expected_results delete mode 100644 tests/test_templateFuncInfr.krak delete mode 100644 tests/test_templateMemberFunction.expected_results delete mode 100644 tests/test_templateMemberFunction.krak delete mode 100644 tests/test_templateTest.expected_results delete mode 100644 tests/test_templateTest.krak delete mode 100644 tests/test_template_operator_overload.expected_results delete mode 100644 tests/test_template_operator_overload.krak delete mode 100644 tests/test_templatedObjectTemplatedFunctionInference.expected_results delete mode 100644 tests/test_templatedObjectTemplatedFunctionInference.krak delete mode 100644 tests/test_testArrayNotation.expected_results delete mode 100644 tests/test_testArrayNotation.krak delete mode 100644 tests/test_thread.expected_results delete mode 100644 tests/test_thread.krak delete mode 100644 tests/test_topLevelVarInit.expected_results delete mode 100644 tests/test_topLevelVarInit.krak delete mode 100644 tests/test_traitsTest.expected_results delete mode 100644 tests/test_traitsTest.krak delete mode 100644 tests/test_typeExpr.expected_results delete mode 100644 tests/test_typeExpr.krak delete mode 100644 tests/test_typeInfr.expected_results delete mode 100644 tests/test_typeInfr.krak delete mode 100644 tests/test_union.expected_results delete mode 100644 tests/test_union.krak delete mode 100644 tests/test_util.expected_results delete mode 100644 tests/test_util.krak delete mode 100644 tests/test_vectorTest.expected_results delete mode 100644 tests/test_vectorTest.krak delete mode 100644 tests/tester.krak delete mode 100644 tests/trivial_container.krak delete mode 100644 try.html rename bf.kp => working_files/bf.kp (100%) rename collections.kp => working_files/collections.kp (100%) rename comp_wasm.kp => working_files/comp_wasm.kp (100%) rename compile_for_web.sh => working_files/compile_for_web.sh (100%) rename types.kp => working_files/damas_hindley_milner.kp (100%) rename types_test.kp => working_files/damas_hindley_milner_test.kp (100%) create mode 100644 working_files/dlambda_test.kp rename even_odd.kp => working_files/even_odd.kp (100%) rename fib-comp.kp => working_files/fib-comp.kp (100%) rename fib-interp.kp => working_files/fib-interp.kp (100%) rename fungll.kp => working_files/fungll.kp (100%) rename fungll_test.kp => working_files/fungll_test.kp (100%) rename import_test.kp => working_files/import_test.kp (100%) rename index.html => working_files/index.html (100%) rename {k_prime_stdlib => working_files/k_prime_stdlib}/method.kp (100%) rename {k_prime_stdlib => working_files/k_prime_stdlib}/prelude.kp (100%) rename match.kp => working_files/match.kp (100%) rename match_test.kp => working_files/match_test.kp (100%) create mode 100644 working_files/method.kp rename new_kraken.kp => working_files/new_kraken.kp (100%) rename new_kraken_test.kp => working_files/new_kraken_test.kp (100%) rename partial_eval.kp => working_files/partial_eval.kp (100%) create mode 100644 working_files/partial_eval_test.csc rename partial_eval_test.kp => working_files/partial_eval_test.kp (100%) rename partial_eval_test_rec.kp => working_files/partial_eval_test_rec.kp (100%) rename prelude.kp => working_files/prelude.kp (100%) rename rb.kp => working_files/rb.kp (100%) rename rb_test.kp => working_files/rb_test.kp (100%) rename sierpinski.kp => working_files/sierpinski.kp (100%) create mode 100644 working_files/smaller_new_kraken_test.kp create mode 100644 working_files/test.csc create mode 100644 working_files/test_parse_in create mode 100644 working_files/test_parse_in_large create mode 100644 working_files/test_ystar_vau.kp create mode 100644 working_files/types.kp create mode 100644 working_files/types_test.kp rename wasm.kp => working_files/wasm.kp (100%) diff --git a/.gitignore b/.gitignore index f69c238..da108b0 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,4 @@ bootstrap_kalypso kraken_bootstrap compiler_version.krak untracked_misc +k_prime diff --git a/Kraken_Compiled_Grammer_file_format.txt b/Kraken_Compiled_Grammer_file_format.txt deleted file mode 100644 index 32a40ac..0000000 --- a/Kraken_Compiled_Grammer_file_format.txt +++ /dev/null @@ -1,41 +0,0 @@ -Kraken Compiled Grammer file format (.kgm.comp) - -This file is generated on first run, and regenerated everytime the grammer changes. -It contains the RNGLR table generated from the specified grammer so that it does not -have to be remade every time Kraken is run, saving a lot of time. -(at time of writing, non-cached: ~30 seconds, cached: <1 second) - - -This is a binary format. The first bytes are a magic number (KRAK in asci) - -The next bytes are an unsigned integer indicating how many characters follow. -Next are these characters, which are the grammer file as one long string. - -Next is the parse table length, followed by the table itself, exported with the table's export method. -It can be imported with the import method. -Note that within the parse table's data are parse actions, and within that, Symbols. - -The format: (more or less) -____________________ -|KRAK -|length_of_grammer_text -|GRAMMER_TEXT -|PARSE_TABLE -|-|length_of_symbol_index_vector -|-|SYMBOL_INDEX_VECTOR -|-|length_of_out_table_vector -|-|OUT_TABLE_VECTOR -|-|-|length_of_mid_table_vector -|-|-|MID_TABLE_VECTOR -|-|-|-|length_of_in_table_vector -|-|-|-|IN_TABLE_VECTOR -|-|-|-|-|length_of_parse_action -|-|-|-|-|PARSE_ACTION -|-|-|-|-|-|ActionType -|-|-|-|-|-|ParseRule__if_exists -|-|-|-|-|-|-|pointerIndex -|-|-|-|-|-|-|Symbol_left_handel -|-|-|-|-|-|-|rightside_vector_symbol -|-|-|-|-|-|shiftState -____________________ - diff --git a/LICENCE.md b/LICENCE.md index 3b756d5..952d17a 100644 --- a/LICENCE.md +++ b/LICENCE.md @@ -1,21 +1,19 @@ -The MIT License (MIT) +Copyright (c) 2020-2022 Nathan Braswell -Copyright (c) 2014-2016 Nathan Christopher Braswell, Google Inc. +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Subject to the terms and conditions of this license, each copyright holder and contributor hereby grants to those receiving rights under this license a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except for failure to satisfy the conditions of this license) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer this software, where such license applies only to those patent claims, already acquired or hereafter acquired, licensable by such copyright holder or contributor that are necessarily infringed by: + +(a) their Contribution(s) (the licensed copyrights of copyright holders and non-copyrightable additions of contributors, in source or binary form) alone; or + +(b) combination of their Contribution(s) with the work of authorship to which such Contribution(s) was added by such copyright holder or contributor, if, at the time the Contribution is added, such addition causes such combination to be necessarily infringed. The patent license shall not apply to any other combinations which include the Contribution. + +Except as expressly stated above, no rights or licenses from any copyright holder or contributor is granted under this license, whether expressly, by implication, estoppel or otherwise. + +DISCLAIMER + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md index eb54cb4..763fd08 100644 --- a/README.md +++ b/README.md @@ -3,30 +3,21 @@ Kraken The Kraken Programming Language -(try it out online at http://www.kraken-lang.org/) +(more information online at http://www.kraken-lang.org/ which is also under construction / needs to be updated / has a try-it-online feature for an older version without partial evaluation) -(vim integration (filetype, syntax highlighting, Syntastic) at https://github.com/Limvot/kraken.vim) -(emacs integration (filetype, syntax highlighting) at https://github.com/Limvot/kraken-mode) +Currently developing the third iteration, a Scheme-like based on a functional Vau calculus partially-evaluated for efficency and compiling to WebAssembly. -The Kraken Programming Language is functional but very much still in development. -It has both the normal features you might expect of a modern language, (functions, variables, an object system, dynamic memory), as well as some more advanced ones (mutually recursive definitions, lambdas/closures, algebraic data types, templates, marker traits, defer statements, etc). +*Heavily* inspiried by John Shutt's thesis: https://web.wpi.edu/Pubs/ETD/Available/etd-090110-124904/unrestricted/jshutt.pdf +with partial evaluation during compilation to make it efficient. -Kraken can either compile to C or its own bytecode which is then interpreted. -Dependencies -============ -Kraken is self-hosted - in order to build it, a script is included that will compile the original C++ version (which depends on CMake) and then checks out each necessary version to compile up to the current one. This can take quite a while - when it hits 1.0 I am planning on removing the old C++ version and checking in a pre-compiled-to-c version to use for further bootstrapping. +Licensed under +SPDX-License-Identifier: BSD-2-Clause-Patent + +Note: This license is designed to provide: a) a simple permissive license; b) that is compatible with the GNU General Public License (GPL), version 2; and c) which also has an express patent grant included. + +(Note taken from https://opensource.org/licenses/BSDplusPatent ) -Goals -===== -It has the following design goals: -* Compiled -* Clean -* Fast (both running and writing) -* Good for Systems (including Operating Systems) programming -* Very powerful libraries (say, a library that allows you import from automatically parsed C header files) -* Minimal "magic" code. (no runtime, other libraries automatically included) -It is inspired by C, Kotlin, Rust, and Jai. diff --git a/captain.sh b/captain.sh deleted file mode 100755 index f3ecfd9..0000000 --- a/captain.sh +++ /dev/null @@ -1,147 +0,0 @@ -#!/usr/bin/env bash - -kraken="kraken" -bootstrap_commits=(cf46fb13afe66ba475db9725e9269c9c1cd3bbc3 2cd43e5a217318c70097334b3598d2924f64b362 2051f54b559ac5edf67277d4f1134aca2cb9215d ecbbcb4eda56e2467efb0a04e7d668b95856aa4b d126cbf24ba8b26e3814e2260d555ecaee86508c 947384cced5397a517a71963edc8f47e668d734f cfcaff7887a804fe77dadaf2ebb0251d6e8ae8e2 12dfa837e31bf09adb1335219473b9a7e6db9eac acb0e48324f353d30d148eb11d1bf2843d83b51a 29eff2a23e5c8afc59dc71a9ecd74cedbd5663c3 0f2ac1421a4da5ff63a2df94efa2bcb37eec40b8 f71b5f3576b5ddbb19b8df4e5d786f0147160c13 fb63eee9e8a38a9df68903ec9acac7408aebc824 6f659ece49debe79b9f1a0b272ab7cce14d84c85 c0209118e5c06a9f03bb56d032aeccbc28bfbf73 5b46089694d9c51cc302c8dbb952495f3e6301c6) - -if ! [ -s "cached_builds" ] -then - mkdir cached_builds -fi - -if [[ $1 == "clean" ]] -then - rm ${kraken} - rm ${kraken}_bac - rm ${kraken}_deprecated - rm ${kraken}_bootstrap - rm -rf bootstrap_kalypso -else - if [[ $1 == "backup" ]] - then - rm ${kraken} - fi - if [[ $1 == "from_old" ]] - then - rm ${kraken} - rm ${kraken}_bac - rm ${kraken}_deprecated - fi - if [[ $1 == "rebuild" ]] - then - rm ${kraken} - rm ${kraken}_bac - rm ${kraken}_deprecated - rm ${kraken}_bootstrap - rm -rf bootstrap_kalypso - fi - - if [ -s "$kraken" ] - then - #echo "$kraken exists, calling" - ./${kraken} ${kraken}.krak ${kraken} - else - echo "gotta make $kraken, testing for compilers to do so" - if ! [ -s "${kraken}_bac" ] - then - if ! [ -s "${kraken}_deprecated" ] - then - echo "no ${kraken}_deprecated, bootstrapping using kraken_bootstrap" - if ! [ -s "${kraken}_bootstrap" ] - then - # Check to see if we have a chached version - cached_index=0 - for ((i=1; i < ${#bootstrap_commits[@]}; i++)) - do - echo "checking for cached kalypso part $i" - echo "commit hash: ${bootstrap_commits[$i]}" - if [ -s "cached_builds/${bootstrap_commits[i]}" ] - then - cached_index=$i - echo "have cached: ${bootstrap_commits[$i]}" - else - echo "do not have cached: ${bootstrap_commits[$i]}" - fi - done - - git clone . bootstrap_kalypso - pushd bootstrap_kalypso - if [[ $cached_index == "0" ]] - then - echo "no ${kraken}_bootstrap, bootstrapping using Cephelpod and a chain of old Kalypsos" - git checkout ${bootstrap_commits[0]} - cp -r stdlib deprecated_compiler - cp krakenGrammer.kgm deprecated_compiler - cp kraken.krak deprecated_compiler - pushd deprecated_compiler - mkdir build - pushd build - cmake .. - make - popd - mkdir build_kraken - mv kraken.krak build_kraken - pushd build_kraken - ../build/kraken kraken.krak - popd - popd - pushd deprecated_compiler/build_kraken/kraken - sh kraken.sh - popd - cp deprecated_compiler/build_kraken/kraken/kraken ./${kraken}_bootstrap - else - echo "no ${kraken}_bootstrap, bootstrapping using starting from cached version" - git checkout ${bootstrap_commits[$cached_index]} - cp "../cached_builds/${bootstrap_commits[$cached_index]}/kraken.krak.c" "./" - cc kraken.krak.c -lm -lpthread -O3 -o kraken_bootstrap - fi - - # loop through the chain - for ((i=$cached_index+1; i < ${#bootstrap_commits[@]}; i++)) - do - echo "building kalypso bootstrap part $i" - echo "commit hash: ${bootstrap_commits[$i]}" - mv ./krakenGrammer.kgm krakenGrammer.kgm_old - git checkout ${bootstrap_commits[$i]} - echo "var version_string = \"BOOTSTRAPPING VERSION - Self-hosted Kraken compiler \\\"Kalypso\\\" - revision $(git rev-list HEAD | wc -l), commit: $(git rev-parse HEAD)\";" > compiler_version.krak - mv ./krakenGrammer.kgm krakenGrammer.kgm_new - mv ./krakenGrammer.kgm_old krakenGrammer.kgm - # Quick fix - I made a commit that actually depends on it's own grammer to be built - if [[ ${bootstrap_commits[$i]} == "12dfa837e31bf09adb1335219473b9a7e6db9eac" ]] - then - echo "Hot fixing mistake - using new grammer instead of old" - cp ./krakenGrammer.kgm_new krakenGrammer.kgm - fi - ./${kraken}_bootstrap kraken.krak ${kraken}_bootstrap - mkdir "../cached_builds/${bootstrap_commits[$i]}" - cp "./kraken.krak.c" "../cached_builds/${bootstrap_commits[$i]}/" - mv ./krakenGrammer.kgm_new krakenGrammer.kgm - done - popd # out of bootstrap - fi - echo "making kraken_deprecated - the first current Kraken version, but built with an old compiler" - - # Now make real - mv ./krakenGrammer.kgm krakenGrammer.kgm_new - mv ./krakenGrammer.kgm.comp_new krakenGrammer.kgm.comp_new_new - cp bootstrap_kalypso/krakenGrammer.kgm ./ - cp bootstrap_kalypso/krakenGrammer.kgm.comp_new ./ - cp bootstrap_kalypso/${kraken}_bootstrap ./${kraken}_bootstrap - ./${kraken}_bootstrap kraken.krak ${kraken}_deprecated - mv ./krakenGrammer.kgm_new krakenGrammer.kgm - mv ./krakenGrammer.kgm.comp_new_new krakenGrammer.kgm.comp_new - else - echo "${kraken}_deprecated exists, calling" - fi - echo "making kraken_bac, a current compiler built with kraken_deprecated" - ./${kraken}_deprecated kraken.krak ${kraken}_bac - else - echo "${kraken}_bac exists, calling" - fi - echo "making kraken, the real current compiler built with kraken_bac" - ./${kraken}_bac kraken.krak ${kraken} - fi -fi - -#./${kraken} $@ - - diff --git a/current_stats.sh b/current_stats.sh deleted file mode 100755 index c05e1cd..0000000 --- a/current_stats.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -cloc --read-lang-def=kraken_cloc_definition.txt kraken.krak stdlib/ diff --git a/deprecated_compiler/.gitignore b/deprecated_compiler/.gitignore deleted file mode 100644 index 1200625..0000000 --- a/deprecated_compiler/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -build -build_kraken -krakenGrammer.kgm -krakenGrammer.kgm.comp -stdlib diff --git a/deprecated_compiler/CMakeLists.txt b/deprecated_compiler/CMakeLists.txt deleted file mode 100644 index 5803f04..0000000 --- a/deprecated_compiler/CMakeLists.txt +++ /dev/null @@ -1,29 +0,0 @@ -cmake_minimum_required (VERSION 2.6) - -project(Kraken) - - -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -g") -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3") - -set( MY_INCLUDES ${PROJECT_SOURCE_DIR}/include) - -set( MY_SOURCES main.cpp src/Parser.cpp src/GraphStructuredStack.cpp - src/RNGLRParser.cpp src/ParseAction.cpp src/ParseRule.cpp src/Symbol.cpp - src/StringReader.cpp src/State.cpp src/util.cpp src/Lexer.cpp - src/RegEx.cpp src/RegExState.cpp src/Table.cpp src/ASTData.cpp - src/ASTTransformation.cpp src/CGenerator.cpp src/Type.cpp src/Importer.cpp - src/Tester.cpp src/CCodeTriple.cpp) - -add_custom_target(STDLibCopy ALL) -add_custom_command(TARGET STDLibCopy POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_directory - "${PROJECT_SOURCE_DIR}/stdlib" - "${PROJECT_BINARY_DIR}/stdlib") - -include_directories( ${MY_INCLUDES} ) - -add_executable(kraken ${MY_SOURCES}) - - - diff --git a/deprecated_compiler/include/ASTData.h b/deprecated_compiler/include/ASTData.h deleted file mode 100644 index 3fb5e34..0000000 --- a/deprecated_compiler/include/ASTData.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef ASTDATA_H -#define ASTDATA_H - -#include -#include -#include - -#include "Symbol.h" -//Circular dependency -class Type; -#include "Type.h" - -#ifndef NULL -#define NULL ((void*)0) -#endif - -enum ASTType {undef, translation_unit, import, identifier, type_def, adt_def, - function, code_block, typed_parameter, expression, boolean_expression, statement, - if_statement, match_statement, case_statement, while_loop, for_loop, return_statement, break_statement, - continue_statement, defer_statement, assignment_statement, declaration_statement, if_comp, simple_passthrough, - passthrough_params, in_passthrough_params, out_passthrough_params, opt_string, param_assign, function_call, value}; - -class ASTData { - public: - ASTData(); - ASTData(ASTType type, Type *valueType = NULL); - ASTData(ASTType type, Symbol symbol, Type *valueType = NULL); - ~ASTData(); - std::string toString(); - static std::string ASTTypeToString(ASTType type); - - ASTType type; - Type* valueType; - Symbol symbol; - std::map*>> scope; - std::set*> closedVariables; - private: - -}; - -#endif diff --git a/deprecated_compiler/include/ASTTransformation.h b/deprecated_compiler/include/ASTTransformation.h deleted file mode 100644 index bda6ad0..0000000 --- a/deprecated_compiler/include/ASTTransformation.h +++ /dev/null @@ -1,87 +0,0 @@ -#ifndef ASTTRANSFORMATION_H -#define ASTTRANSFORMATION_H - -#include -#include - -#include -#include - -#include "Type.h" -#include "ASTData.h" -#include "NodeTransformation.h" -#include "Importer.h" - -class Importer; - -class ASTTransformation: public NodeTransformation { - public: - ASTTransformation(Importer* importerIn); - ~ASTTransformation(); - - NodeTree* getNode(std::string lookup, std::vector*> nodes); - NodeTree* getNode(std::string lookup, NodeTree* parent); - std::vector*> getNodes(std::string lookup, std::vector*> nodes); - std::vector*> getNodes(std::string lookup, NodeTree* parent); - - //First pass defines all type_defs (objects and ailises) - NodeTree* firstPass(std::string fileName, NodeTree* parseTree); - std::set parseTraits(NodeTree* traitsNode); - - //Second pass defines data inside objects, outside declaration statements, and function prototpyes (since we have type_defs now) - void secondPass(NodeTree* ast, NodeTree* parseTree); - void secondPassDoClassInsides(NodeTree* typeDef, std::vector*> typedefChildren, std::map templateTypeReplacements); - NodeTree* secondPassDeclaration(NodeTree* from, NodeTree* scope, std::map templateTypeReplacements); - NodeTree* secondPassFunction(NodeTree* from, NodeTree* scope, std::map templateTypeReplacements); - - //The third pass does all the function bodies - void thirdPass(NodeTree* ast, NodeTree* parseTree); - NodeTree* searchScopeForFunctionDef(NodeTree* scope, NodeTree* parseTree, std::map templateTypeReplacements); - void thirdPassFunction(NodeTree* from, NodeTree* functionDef, std::map templateTypeReplacements); - - //The fourth pass finishes instantiation of templated objects - //it used to be a part of the third pass, but it was split out because it has to be done in a loop - //with all the other asts until none change anymore (it returns a bool if it instantiated a new one) - bool fourthPass(NodeTree* ast, NodeTree* parseTree); - - virtual NodeTree* transform(NodeTree* from); - NodeTree* transform(NodeTree* from, NodeTree* scope, std::vector types, bool limitToFunction, std::map templateTypeReplacements); - std::vector*> transformChildren(std::vector*> children, std::set skipChildren, NodeTree* scope, std::vector types, bool limitToFunction, std::map templateTypeReplacements); - std::string concatSymbolTree(NodeTree* root); - NodeTree* doFunction(NodeTree* scope, std::string lookup, std::vector*> nodes, std::map templateTypeReplacements); - - NodeTree* generateThis(NodeTree* scope); - std::set*> findVariablesToClose(NodeTree* func, NodeTree* stat, NodeTree* scope); - bool inScopeChain(NodeTree* node, NodeTree* scope); - NodeTree* functionLookup(NodeTree* scope, std::string lookup, std::vector types); - NodeTree* templateFunctionLookup(NodeTree* scope, std::string lookup, std::vector* templateInstantiationTypes, std::vector types, std::map scopeTypeMap); - std::vector*> scopeLookup(NodeTree* scope, std::string lookup, bool includeModules = false); - std::vector*> scopeLookup(NodeTree* scope, std::string lookup, bool includeModules, std::set*> visited); - - NodeTree* getUpperTranslationUnit(NodeTree* node); - NodeTree* addToScope(std::string name, NodeTree* toAdd, NodeTree* addTo); - Type* typeFromTypeNode(NodeTree* typeNode, NodeTree* scope, std::map templateTypeReplacements); - NodeTree* templateClassLookup(NodeTree* scope, std::string name, std::vector templateInstantiationTypes); - void unifyType(NodeTree *syntaxType, Type type, std::map* templateTypeMap, std::map typeMap); - void unifyTemplateFunction(NodeTree* templateFunction, std::vector types, std::vector* templateInstantiationTypes, std::map typeMap); - NodeTree* tryToFindOrInstantiateFunctionTemplate(std::string functionName, NodeTree* scope, std::vector types, std::map templateTypeReplacements); - NodeTree* findOrInstantiateFunctionTemplate(std::string functionName, NodeTree* scope, std::vector types, std::map templateTypeReplacements); - NodeTree* findOrInstantiateFunctionTemplate(std::vector*> children, NodeTree* scope, std::vector types, std::map templateTypeReplacements); - NodeTree* findOrInstantiateFunctionTemplate(std::string functionName, std::vector*> children, NodeTree* scope, std::vector types, std::map templateTypeReplacements); - std::map makeTemplateFunctionTypeMap(NodeTree* templateNode, std::vector types, std::map scopeTypeMap); - std::vector>> makeTemplateNameTraitPairs(NodeTree* templateNode); - - private: - Importer * importer; - NodeTree* builtin_trans_unit; // the top scope for language level stuff - std::map*>> languageLevelReservedWords; - std::map*>> languageLevelOperators; - std::map*, NodeTree*> this_map; // used to map implicit "this" variables to their type - NodeTree* topScope; //maintained for templates that need to add themselves to the top scope no matter where they are instantiated - int lambdaID = 0; -}; - -std::vector mapNodesToTypes(std::vector*> nodes); -std::vector mapNodesToTypePointers(std::vector*> nodes); - -#endif diff --git a/deprecated_compiler/include/CCodeTriple.h b/deprecated_compiler/include/CCodeTriple.h deleted file mode 100644 index 81637e8..0000000 --- a/deprecated_compiler/include/CCodeTriple.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef CCODETRIPLE_H -#define CCODETRIPLE_H - -#include -#include -#include "util.h" - -class CCodeTriple { - public: - CCodeTriple(std::string pre, std::string val, std::string post); - CCodeTriple(std::string val); - CCodeTriple(const char* val); - CCodeTriple(); - ~CCodeTriple(); - std::string oneString(bool endValue = false); - CCodeTriple & operator=(const CCodeTriple &rhs); - CCodeTriple & operator+=(const CCodeTriple &rhs); - - std::string preValue; - std::string value; - std::string postValue; - private: -}; -CCodeTriple operator+(const CCodeTriple &a, const CCodeTriple &b); -#endif //CCODETRIPLE_H diff --git a/deprecated_compiler/include/CGenerator.h b/deprecated_compiler/include/CGenerator.h deleted file mode 100644 index d5faa65..0000000 --- a/deprecated_compiler/include/CGenerator.h +++ /dev/null @@ -1,72 +0,0 @@ -#ifndef CGENERATOR_H -#define CGENERATOR_H - -#include -#include -#include -#include -#include -#include - -#include "CCodeTriple.h" -#include "NodeTree.h" -#include "ASTData.h" -#include "Type.h" -// for mapNodesToTypes -#include "ASTTransformation.h" - -#include "util.h" -#include "Poset.h" - -// Note the use of std::pair to hold two strings - the running string for the header file and the running string for the c file. - -enum ClosureTypeSpecialType { ClosureTypeRegularNone, ClosureFunctionPointerTypeWithoutClosedParam, ClosureFunctionPointerTypeWithClosedParam }; - -class CGenerator { - public: - CGenerator(); - ~CGenerator(); - int generateCompSet(std::map*> ASTs, std::string outputName); - std::string generateTypeStruct(NodeTree* from); - bool isUnderNodeWithType(NodeTree* from, ASTType type); - bool isUnderTranslationUnit(NodeTree* from, NodeTree* typeDefinition); - NodeTree* highestScope(NodeTree* node); - std::pair generateTranslationUnit(std::string name, std::map*> ASTs); - CCodeTriple generate(NodeTree* from, NodeTree* enclosingObject = NULL, bool justFuncName = false, NodeTree* enclosingFunction = NULL); - std::string generateAliasChains(std::map*> ASTs, NodeTree* definition); - - std::string closureStructType(std::set*> closedVariables); - std::string ValueTypeToCType(Type *type, std::string, ClosureTypeSpecialType closureSpecial = ClosureTypeRegularNone); - std::string ValueTypeToCTypeDecoration(Type *type, ClosureTypeSpecialType closureSpecial = ClosureTypeRegularNone); - std::string ValueTypeToCTypeThingHelper(Type *type, std::string ptrStr, ClosureTypeSpecialType closureSpecial); - static std::string CifyName(std::string name); - static std::string scopePrefix(NodeTree* from); - std::string simpleComplexName(std::string simpleName, std::string complexName); - std::string prefixIfNeeded(std::string prefix, std::string name); - std::string generateObjectMethod(NodeTree* enclosingObject, NodeTree* from, std::string *functionPrototype); - NodeTree* getMethodsObjectType(NodeTree* scope, std::string functionName); - NodeTree* getMethod(Type* type, std::string method, std::vector types); - bool methodExists(Type* type, std::string method, std::vector types); - std::string generateMethodIfExists(Type* type, std::string method, std::string parameter, std::vector methodTypes); - std::string emitDestructors(std::vector*> possibleDeclarations, NodeTree* enclosingObject); - std::string tabs(); - std::string getID(); - - int tabLevel; - int id; - std::string function_header; - std::string generatorString; - std::string linkerString; - std::string functionTypedefString; - std::string functionTypedefStringPre; - std::set usedNameSet; - std::map simpleComplexNameMap; - std::map> functionTypedefMap; - std::map*>, std::string> closureStructMap; - std::vector*>> distructDoubleStack; - std::stack loopDistructStackDepth; - std::vector*>> deferDoubleStack; - std::stack loopDeferStackDepth; - private: -}; -#endif diff --git a/deprecated_compiler/include/CollapseTransformation.h b/deprecated_compiler/include/CollapseTransformation.h deleted file mode 100644 index a4c8c88..0000000 --- a/deprecated_compiler/include/CollapseTransformation.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef COLLAPSETRANSFORMATION_H -#define COLLAPSETRANSFORMATION_H - -#include -#include - -#include "NodeTransformation.h" - -template -class CollapseTransformation: public NodeTransformation { - public: - CollapseTransformation(T toCollapse); - ~CollapseTransformation(); - virtual NodeTree* transform(NodeTree* from); - - private: - T toCollapse; -}; - -#endif - -template -CollapseTransformation::CollapseTransformation(T toCollapse) { - this->toCollapse = toCollapse; -} - -template -CollapseTransformation::~CollapseTransformation() { - // -} - -template -NodeTree* CollapseTransformation::transform(NodeTree* from) { - std::queue*> toProcess; - toProcess.push(from); - while(!toProcess.empty()) { - NodeTree* node = toProcess.front(); - toProcess.pop(); - std::vector*> children = node->getChildren(); - for (int i = 0; i < children.size(); i++) { - if (children[i]->getData() == toCollapse) { - node->removeChild(children[i]); - std::vector*> newChildren = children[i]->getChildren(); - node->insertChildren(i,newChildren); - toProcess.push(node); //Do this node again - } - else - toProcess.push(children[i]); - } - } - return from; -} diff --git a/deprecated_compiler/include/DeleteTransformation.h b/deprecated_compiler/include/DeleteTransformation.h deleted file mode 100644 index f5434b5..0000000 --- a/deprecated_compiler/include/DeleteTransformation.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef DELETETRANSFORMATION_H -#define DELETETRANSFORMATION_H - -#include -#include - -#include "NodeTransformation.h" - -template -class DeleteTransformation: public NodeTransformation { - public: - DeleteTransformation(T toDelete); - ~DeleteTransformation(); - virtual NodeTree* transform(NodeTree* from); - - private: - T toRemove; -}; - -#endif - -template -DeleteTransformation::DeleteTransformation(T toRemove) { - this->toRemove = toRemove; -} - -template -DeleteTransformation::~DeleteTransformation() { - // -} - -template -NodeTree* DeleteTransformation::transform(NodeTree* from) { - std::queue*> toProcess; - toProcess.push(from); - while(!toProcess.empty()) { - NodeTree* node = toProcess.front(); - toProcess.pop(); - std::vector*> children = node->getChildren(); - for (int i = 0; i < children.size(); i++) { - if (children[i]->getData() == toRemove) - node->removeChild(children[i]); - else - toProcess.push(children[i]); - } - } - return from; -} diff --git a/deprecated_compiler/include/GraphStructuredStack.h b/deprecated_compiler/include/GraphStructuredStack.h deleted file mode 100644 index 65e6b12..0000000 --- a/deprecated_compiler/include/GraphStructuredStack.h +++ /dev/null @@ -1,38 +0,0 @@ -#include -#include -#include -#include -#include "NodeTree.h" -#include "Symbol.h" -#include "util.h" - -#ifndef GRAPH_STRUCTURED_STACK -#define GRAPH_STRUCTURED_STACK - -class GraphStructuredStack { - public: - GraphStructuredStack(); - ~GraphStructuredStack(); - NodeTree* newNode(int stateNum); - void addToFrontier(int frontier, NodeTree* node); - NodeTree* inFrontier(int frontier, int state); - int getContainingFrontier(NodeTree* node); - bool frontierIsEmpty(int frontier); - NodeTree* frontierGetAccState(int frontier); - std::vector*>* getReachable(NodeTree* start, int lenght); - std::vector*> >* getReachablePaths(NodeTree* start, int lenght); - void recursivePathFind(NodeTree* start, int length, std::vector*> currentPath, std::vector*> >* paths); - bool hasEdge(NodeTree* start, NodeTree* end); - NodeTree* getEdge(NodeTree* start, NodeTree* end); - void addEdge(NodeTree* start, NodeTree* end, NodeTree* edge); - void clear(); - - std::vector getFrontier(int frontier); - std::string toString(); - private: - std::vector*>*> gss; - std::map< std::pair< NodeTree*, NodeTree* >, NodeTree* > edges; - std::map< NodeTree*, int > containing_frontier_map; -}; - -#endif diff --git a/deprecated_compiler/include/Importer.h b/deprecated_compiler/include/Importer.h deleted file mode 100644 index 644c3b4..0000000 --- a/deprecated_compiler/include/Importer.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef __IMPORTER__H_ -#define __IMPORTER__H_ - -#include -#include -#include -#include - -#include - -#include "Parser.h" -#include "NodeTree.h" -#include "ASTData.h" -#include "Symbol.h" -#include "RemovalTransformation.h" -#include "CollapseTransformation.h" -#include "ASTTransformation.h" - -class ASTTransformation; - -class Importer { - public: - Importer(Parser* parserIn, std::vector includePaths, std::string outputName, bool only_parseIn = false); - ~Importer(); - void import(std::string fileName); - NodeTree* getUnit(std::string fileName); - NodeTree* importFirstPass(std::string fileName); - NodeTree* parseAndTrim(std::string fileName); - void registerAST(std::string name, NodeTree* ast, NodeTree* syntaxTree); - std::map*> getASTMap(); - private: - std::string outputName; - ASTTransformation *ASTTransformer; - struct importTriplet { - std::string name; - NodeTree* ast; - NodeTree* syntaxTree; - }; - bool only_parse; - std::vector importedTrips; - std::vector includePaths; - Parser* parser; - std::vector removeSymbols; - std::vector collapseSymbols; - std::map*> imported; -}; - -#endif diff --git a/deprecated_compiler/include/Lexer.h b/deprecated_compiler/include/Lexer.h deleted file mode 100644 index 1574a02..0000000 --- a/deprecated_compiler/include/Lexer.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef LEXER_H -#define LEXER_H - -#include "util.h" -#include "StringReader.h" -#include "RegEx.h" -#include "Symbol.h" - -#include - -class Lexer { - public: - Lexer(); - Lexer(std::string inputString); - ~Lexer(); - void addRegEx(std::string regExString); - void setInput(std::string inputString); - Symbol next(); - void reset(); - static void test(); - private: - std::vector regExs; - std::string input; - int currentPosition; -}; -#endif diff --git a/deprecated_compiler/include/NodeTransformation.h b/deprecated_compiler/include/NodeTransformation.h deleted file mode 100644 index ff51944..0000000 --- a/deprecated_compiler/include/NodeTransformation.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef NODETRANSFORMATION_H -#define NODETRANSFORMATION_H - -#include "NodeTree.h" - -#ifndef NULL -#define NULL ((void*)0) -#endif - -template -class NodeTransformation { - public: - NodeTransformation(); - virtual ~NodeTransformation(); - virtual NodeTree* transform(NodeTree* from)=0; - private: - -}; - -template -NodeTransformation::NodeTransformation() { - //Nothing -} - -template -NodeTransformation::~NodeTransformation() { - //Nothing -} - -// template -// NodeTree* NodeTransformation::transform(NodeTree* from) { -// return (NodeTree*)0x1234; -// } - -#endif \ No newline at end of file diff --git a/deprecated_compiler/include/NodeTree.h b/deprecated_compiler/include/NodeTree.h deleted file mode 100644 index a04d008..0000000 --- a/deprecated_compiler/include/NodeTree.h +++ /dev/null @@ -1,277 +0,0 @@ -#ifndef NODETREE_H -#define NODETREE_H - -#ifndef NULL -#define NULL ((void*)0) -#endif - -#include -#include -#include - -#include "util.h" - -template -class NodeTree { - public: - NodeTree(); - NodeTree(std::string name, T inData); - ~NodeTree(); - - bool const operator==(NodeTree &other); - bool const operator<(const NodeTree &other) const; - - void setParent(NodeTree* parent); - void addParent(NodeTree* parent); - NodeTree* getParent(); - std::vector*> getParents(); - - void addChild(NodeTree* child); - void insertChild(int i, NodeTree* child); - void addChildren(std::vector*>* children); - void addChildren(std::vector*> children); - void insertChildren(int index, std::vector*>* children); - void insertChildren(int index, std::vector*> children); - int findChild(NodeTree* child); - void removeChild(NodeTree* child); - void removeChild(int index); - void clearChildren(); - std::vector*> getChildren(); - - NodeTree* get(int index); - std::string getName(); - void setName(std::string); - - T getData() const; - T* getDataRef(); - void setData(T data); - - int size(); - std::string DOTGraphString(); - - private: - std::string DOTGraphStringHelper(std::vector*> avoidList); - std::string getDOTName(); - std::string name; - T data; - std::vector*> parents; - std::vector*> children; - - static int idCounter; - int id; -}; - -template - -int NodeTree::idCounter; - -template -NodeTree::NodeTree() { - name = "UnnamedNode"; - id = idCounter++; -} - -template -NodeTree::NodeTree(std::string name, T inData) { - this->name = name; - this->data = inData; - id = idCounter++; -} - -template -NodeTree::~NodeTree() { - children.clear(); - parents.clear(); //? Will this segfault? -} - -template -const bool NodeTree::operator==(NodeTree &other) { - if (!(data == other.data)) - return false; - if (children.size() != other.getChildren().size()) - return false; - for (typename std::vector*>::size_type i = 0; i < children.size(); i++) - if (! (*(children[i]) == *(other.getChildren()[i]))) - return false; - return true; -} - -//Used when making a map of NodeTrees -template -const bool NodeTree::operator<(const NodeTree &other) const { - return data < other.getData(); -} - -template -void NodeTree::setParent(NodeTree* parent) { - parents.clear(); - parents.push_back(parent); -} - -template -void NodeTree::addParent(NodeTree* parent) { - parents.push_back(parent); -} - -template -NodeTree* NodeTree::getParent() { - if (parents.size() > 0) - return parents[0]; - return NULL; -} - -template -std::vector*> NodeTree::getParents() { - return parents; -} - - -template -void NodeTree::addChild(NodeTree* child) { - if (!child) - throw "Help, NULL child"; - //if (findChild(child) == -1) - children.push_back(child); -} - -template -void NodeTree::insertChild(int i, NodeTree* child) { - if (!child) - throw "Help, NULL child"; - //if (findChild(child) == -1) - children.insert(children.begin()+i,child); -} - -template -void NodeTree::addChildren(std::vector*>* children) { - for (typename std::vector*>::size_type i = 0; i < children->size(); i++) - addChild((*children)[i]); -} - -template -void NodeTree::addChildren(std::vector*> children) { - for (typename std::vector*>::size_type i = 0; i < children.size(); i++) - addChild(children[i]); -} - -template -void NodeTree::insertChildren(int index, std::vector*>* children) { - for (typename std::vector*>::size_type i = 0; i < children->size(); i++) - insertChild(index+i,(*children)[i]); -} - -template -void NodeTree::insertChildren(int index, std::vector*> children) { - for (typename std::vector*>::size_type i = 0; i < children.size(); i++) - insertChild(index+i, children[i]); -} - -template -int NodeTree::findChild(NodeTree* child) { - for (int i = 0; i < children.size(); i++) { - if (children[i] == child) { - return i; - } - } - return -1; -} - -template -void NodeTree::removeChild(int index) { - children[index] = NULL; - children.erase(children.begin()+index); -} - -template -void NodeTree::removeChild(NodeTree* child) { - int index = findChild(child); - if (index != -1) { - removeChild(index); - } -} - -template -void NodeTree::clearChildren() { - for (typename std::vector::size_type i = 0; i < children.size(); i++) - children[i] = NULL; - children.clear(); -} - -template -std::vector*> NodeTree::getChildren() { - return children; -} - -template -int NodeTree::size() { - int count = 0; - for (int i = 0; i < children.size(); i++) { - count += children[i]->size(); - } - return 1+count; -} - -template -NodeTree* NodeTree::get(int index) { - return children[index]; -} - -template -std::string NodeTree::getName() { - return name; -} - -template -void NodeTree::setName(std::string name) { - this->name = name; -} - -template -T NodeTree::getData() const { - return data; -} - -template -T* NodeTree::getDataRef() { - return &data; -} - -template -void NodeTree::setData(T data) { - this->data = data; -} - -template -std::string NodeTree::DOTGraphString() { - return( "digraph Kraken { \n" + DOTGraphStringHelper(std::vector*>()) + "}"); -} - -template -std::string NodeTree::DOTGraphStringHelper(std::vector*> avoidList) { - for (typename std::vector*>::size_type i = 0; i < avoidList.size(); i++) - if (this == avoidList[i]) - return ""; - avoidList.push_back(this); - - std::string ourDOTRelation = ""; - for (int i = 0; i < children.size(); i++) { - if (children[i] != NULL) - ourDOTRelation += getDOTName() + " -> " + children[i]->getDOTName() + ";\n" + children[i]->DOTGraphStringHelper(avoidList); - else - ourDOTRelation += getDOTName() + " -> BAD_NULL_" + getDOTName() + "\n"; - } - return(ourDOTRelation); -} - -template -std::string NodeTree::getDOTName() { - std::string DOTName = ""; - DOTName = "\"" + replaceExEscape(name + "-" + data.toString(), "\"", "\\\"") + "_" + intToString(id) + "\""; //Note that terminals already have a quote in the front of their name, so we don't need to add one - // if (data != NULL) - // DOTName = "\"" + replaceExEscape(name + "-" + data->toString(), "\"", "\\\"") + "_" + intToString(id) + "\""; //Note that terminals already have a quote in the front of their name, so we don't need to add one - // else - // DOTName = "\"" + replaceExEscape(name, "\"", " \\\"") + "_" + intToString(id) + "\""; - return(replaceExEscape(DOTName, "\n", "\\n")); -} - -#endif diff --git a/deprecated_compiler/include/ParseAction.h b/deprecated_compiler/include/ParseAction.h deleted file mode 100644 index a15aca0..0000000 --- a/deprecated_compiler/include/ParseAction.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef PARSE_ACTION_H -#define PARSE_ACTION_H - -#ifndef NULL -#define NULL ((void*)0) -#endif - -#include "util.h" -#include "ParseRule.h" - -#include -#include - - -class ParseAction { - public: - enum ActionType { INVALID, REDUCE, SHIFT, ACCEPT, REJECT }; - ParseAction(ActionType action); - ParseAction(ActionType action, ParseRule* reduceRule); - ParseAction(ActionType action, int shiftState); - ~ParseAction(); - bool const equalsExceptLookahead(const ParseAction &other) const; - bool const operator==(const ParseAction &other) const; - bool const operator!=(const ParseAction &other) const; - bool const operator<(const ParseAction &other) const; - std::string toString(bool printRuleLookahead = true); - static std::string actionToString(ActionType action); - - ActionType action; - ParseRule* reduceRule; - int shiftState; - - -}; - -#endif diff --git a/deprecated_compiler/include/ParseRule.h b/deprecated_compiler/include/ParseRule.h deleted file mode 100644 index e81fc33..0000000 --- a/deprecated_compiler/include/ParseRule.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef PARSERULE_H -#define PARSERULE_H - -#ifndef NULL -#define NULL ((void*)0) -#endif - -#include "Symbol.h" - -#include -#include -#include - -class ParseRule { - private: - int pointerIndex; - Symbol leftHandle; - std::vector lookahead; - std::vector rightSide; - - public: - ParseRule(); - ParseRule(Symbol leftHandle, int pointerIndex, std::vector &rightSide, std::vector lookahead); - ~ParseRule(); - const bool equalsExceptLookahead(const ParseRule &other) const; - bool const operator==(const ParseRule &other) const; - bool const operator!=(const ParseRule &other) const; - bool const operator<(const ParseRule &other) const; //Used for ordering so we can put ParseRule's in sets, and also so that ParseActions will have an ordering - ParseRule* clone(); - - void setLeftHandle(Symbol leftHandle); - void appendToRight(Symbol appendee); - - Symbol getLeftSide(); - void setRightSide(std::vector rightSide); - std::vector getRightSide(); - Symbol getAtNextIndex(); - Symbol getAtIndex(); - int getRightSize(); - int getIndex(); - - bool advancePointer(); - bool isAtEnd(); - - void setLookahead(std::vector lookahead); - void addLookahead(std::vector lookahead); - std::vector getLookahead(); - - std::string toString(bool printLookahead = true); - std::string toDOT(); -}; - -#endif diff --git a/deprecated_compiler/include/Parser.h b/deprecated_compiler/include/Parser.h deleted file mode 100644 index a0d9543..0000000 --- a/deprecated_compiler/include/Parser.h +++ /dev/null @@ -1,73 +0,0 @@ -#ifndef PARSER_H -#define PARSER_H - -#include "util.h" -#include "ParseRule.h" -#include "ParseAction.h" -#include "Symbol.h" -#include "State.h" -#include "StringReader.h" -#include "Lexer.h" -#include "NodeTree.h" -#include "Table.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -class Parser { - public: - Parser(); - ~Parser(); - - virtual void loadGrammer(std::string grammerInputString); - virtual void createStateSet(); - virtual std::string stateSetToString(); - virtual NodeTree* parseInput(std::string inputString, std::string filename, bool highlight_errors) = 0; // filename for error reporting - virtual std::string grammerToString(); - virtual std::string grammerToDOT(); - - std::string tableToString(); - void exportTable(std::ofstream &file); - void importTable(char* tableData); - - protected: - std::vector firstSet(Symbol token, std::vector avoidList = std::vector(), bool addNewTokens = true); - bool isNullable(Symbol token); - bool isNullableHelper(Symbol token, std::set done); - - std::map> tokenFirstSet; - std::map tokenNullable; - - std::vector incrementiveFollowSet(ParseRule* rule); - virtual void closure(State* state); - virtual void addStates(std::vector< State* >* stateSets, State* state, std::queue* toDo); - int stateNum(State* state); - - - StringReader reader; - Lexer lexer; - std::map, Symbol> symbols; - std::vector loadedGrammer; - - std::vector< State* > stateSets; - - Symbol EOFSymbol; - Symbol nullSymbol; - Symbol invalidSymbol; - - Table table; - - - std::stack stateStack; - std::stack symbolStack; - - Symbol getOrAddSymbol(std::string symbolString, bool isTerminal); -}; - -#endif diff --git a/deprecated_compiler/include/Poset.h b/deprecated_compiler/include/Poset.h deleted file mode 100644 index f29d350..0000000 --- a/deprecated_compiler/include/Poset.h +++ /dev/null @@ -1,126 +0,0 @@ - -#ifndef POSET_H -#define POSET_H - -#include -#include -#include -#include - -#include - -#include "util.h" - -template -class Poset { - public: - Poset(); - ~Poset(); - void addRelationship(T first, T second); - void addVertex(T vertex); - bool zeroDependencies(T vertex); - std::set getDependsOn(T dependency); - std::vector getTopoSort(); - static void test(); - private: - //backing data structures - std::map> adjMatrix; - std::set verticies; -}; - -template -Poset::Poset() { - //Nothing needed -} - -template -Poset::~Poset() { - //Ditto -} - - -template -void Poset::addRelationship(T first, T second) { - verticies.insert(first); - verticies.insert(second); - adjMatrix[first][second] = true; -} - -template -void Poset::addVertex(T vertex) { - verticies.insert(vertex); -} - -template -bool Poset::zeroDependencies(T vertex) { - auto depMapItr = adjMatrix.find(vertex); - if (depMapItr == adjMatrix.end()) - return true; - for (auto i : depMapItr->second) - if (i.second == true) - return false; - return true; -} - -template -std::set Poset::getDependsOn(T dependency) { - std::set vertsThatDependOn; - for (auto i : adjMatrix) { - auto depItr = i.second.find(dependency); - if (depItr != i.second.end() && depItr->second) - vertsThatDependOn.insert(i.first); - } - return vertsThatDependOn; -} - -template -std::vector Poset::getTopoSort() { - std::vector sorted; - std::queue toDo; - for (auto i : verticies) - if (zeroDependencies(i)) - toDo.push(i); - while(!toDo.empty()) { - T current = toDo.front(); toDo.pop(); - sorted.push_back(current); - for (T depOnCurrent : getDependsOn(current)) { - adjMatrix[depOnCurrent][current] = false; //Remove the edge to current, since current's now been taken care of - if (zeroDependencies(depOnCurrent)) - toDo.push(depOnCurrent); - } - } - return sorted; -} - - -//would make it just an int specilization, but then we get multiple definition complaints.... -template -void Poset::test() { - std::string result; - { - Poset poset; - poset.addVertex(1000); - for (int i = 0; i < 20; i++) - poset.addRelationship(i,i+1); - result = ""; - for (int i : poset.getTopoSort()) - result += intToString(i) + " "; - //std::cout << result << std::endl; - assert(result == "20 1000 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 "); //Note that sets do not have a set order, so this could change - //This is why the 1000 is in an odd, yet valid, position - } - { - Poset poset; - for (int i = 0; i < 20; i+=2) - poset.addRelationship(i,i+1); - result = ""; - for (int i : poset.getTopoSort()) - result += intToString(i) + " "; - //std::cout << result << std::endl; - assert(result == "1 3 5 7 9 11 13 15 17 19 0 2 4 6 8 10 12 14 16 18 "); - } - - std::cout << "Poset tests passed" << std::endl; -} - -#endif \ No newline at end of file diff --git a/deprecated_compiler/include/RNGLRParser.h b/deprecated_compiler/include/RNGLRParser.h deleted file mode 100644 index 5c8c756..0000000 --- a/deprecated_compiler/include/RNGLRParser.h +++ /dev/null @@ -1,68 +0,0 @@ -#ifndef RNGLRPARSER_H -#define RNGLRPARSER_H - -#include -#include -#include -#include -#include -#include -#include -#include "Parser.h" -#include "Symbol.h" -#include "GraphStructuredStack.h" -#include "util.h" - -class RNGLRParser: public Parser { - public: - RNGLRParser(); - ~RNGLRParser(); - NodeTree* parseInput(std::string inputString, std::string filename, bool highlight_errors); // filename for error reporting - void printReconstructedFrontier(int frontier); - - private: - void reducer(int i); - void shifter(int i); - void addChildren(NodeTree* parent, std::vector*>* children, NodeTree* nullableParts); - - void addStates(std::vector< State* >* stateSets, State* state, std::queue* toDo); - void addStateReductionsToTable(State* state); - bool fullyReducesToNull(ParseRule* rule); - bool reducesToNull(ParseRule* rule); - bool reducesToNull(ParseRule* rule, std::vector avoidList); - - bool belongsToFamily(NodeTree* node, std::vector*>* nodes); - bool arePacked(std::vector*> nodes); - bool isPacked(NodeTree* node); - void setPacked(NodeTree* node, bool isPacked); - - NodeTree* getNullableParts(ParseRule* rule); - NodeTree* getNullableParts(ParseRule* rule, std::vector*> avoidList); - NodeTree* getNullableParts(Symbol symbol); - - std::vector*> getPathEdges(std::vector*> path); - - int findLine(int tokenNum); //Get the line number for a token, used for error reporting - - std::vector input; - GraphStructuredStack gss; - //start node, lefthand side of the reduction, reduction length - struct Reduction { - NodeTree* from; - Symbol symbol; - int length; - NodeTree* nullableParts; - NodeTree* label; - } ; - std::queue toReduce; - //Node coming from, state going to - std::queue< std::pair*, int> > toShift; - std::vector*, int> > SPPFStepNodes; - - std::vector*> nullableParts; - std::map, bool> packedMap; - - std::map reduceToNullMap; -}; - -#endif diff --git a/deprecated_compiler/include/RegEx.h b/deprecated_compiler/include/RegEx.h deleted file mode 100644 index 2e18c35..0000000 --- a/deprecated_compiler/include/RegEx.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef REGEX_H -#define REGEX_H - -#include "util.h" -#include "RegExState.h" -#include "Symbol.h" - -#include -#include -#include -#include - -class RegEx { - public: - RegEx(); - RegEx(std::string inPattern); - ~RegEx(); - - RegExState* construct(std::vector* ending, std::string pattern); - int longMatch(std::string stringToMatch); - std::string getPattern(); - std::string toString(); - static void test(); - private: - std::string pattern; - RegExState* begin; - std::vector currentStates; -}; -#endif diff --git a/deprecated_compiler/include/RegExState.h b/deprecated_compiler/include/RegExState.h deleted file mode 100644 index 9423229..0000000 --- a/deprecated_compiler/include/RegExState.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef REGEXSTATE_H -#define REGEXSTATE_H - -#include "util.h" -#include "Symbol.h" - -#include -#include - -class RegExState { - public: - RegExState(char inCharacter); - RegExState(); - ~RegExState(); - - void addNext(RegExState* nextState); - bool characterIs(char inCharacter); - std::vector advance(char advanceCharacter); - std::vector getNextStates(); - - bool isGoal(); - std::string toString(); - std::string toString(RegExState* avoid); - std::string toString(std::vector* avoid); - - char getCharacter(); - - private: - std::vector nextStates; - char character; -}; -#endif diff --git a/deprecated_compiler/include/RemovalTransformation.h b/deprecated_compiler/include/RemovalTransformation.h deleted file mode 100644 index 8667e6b..0000000 --- a/deprecated_compiler/include/RemovalTransformation.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef REMOVALTRANSFORMATION_H -#define REMOVALTRANSFORMATION_H - -#include -#include - -#include "NodeTransformation.h" - -template -class RemovalTransformation: public NodeTransformation { - public: - RemovalTransformation(T toRemove); - ~RemovalTransformation(); - virtual NodeTree* transform(NodeTree* from); - - private: - T toRemove; -}; - -#endif - -template -RemovalTransformation::RemovalTransformation(T toRemove) { - this->toRemove = toRemove; -} - -template -RemovalTransformation::~RemovalTransformation() { - // -} - -template -NodeTree* RemovalTransformation::transform(NodeTree* from) { - std::queue*> toProcess; - toProcess.push(from); - while(!toProcess.empty()) { - NodeTree* node = toProcess.front(); - toProcess.pop(); - if (!node) - continue; - std::vector*> children = node->getChildren(); - for (int i = 0; i < children.size(); i++) { - if (children[i]->getData() == toRemove) - node->removeChild(children[i]); - else if (children[i]) - toProcess.push(children[i]); - } - } - return from; -} diff --git a/deprecated_compiler/include/State.h b/deprecated_compiler/include/State.h deleted file mode 100644 index d07d1a8..0000000 --- a/deprecated_compiler/include/State.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef STATE_H -#define STATE_H - -#ifndef NULL -#define NULL ((void*)0) -#endif - -#include "util.h" -#include "ParseRule.h" - -#include -#include -#include -#include - -class State { - public: - State(int number, ParseRule* basis); - State(int number, ParseRule* basis, State* parent); - ~State(); - bool const operator==(const State &other); - bool const basisEquals(const State &other); - bool const basisEqualsExceptLookahead(const State &other); - bool const operator!=(const State &other); - std::vector* getBasis(); - std::vector* getRemaining(); - std::vector getTotal(); - bool containsRule(ParseRule* rule); - void addRuleCombineLookahead(ParseRule* rule); - std::string toString(); - - void combineStates(State &other); - void addParents(std::vector* parents); - std::vector* getParents(); - std::vector* getDeepParents(int depth); - int getNumber(); - - - std::vector basis; - std::vector remaining; - private: - std::vector parents; - int number; -}; - -#endif diff --git a/deprecated_compiler/include/StringReader.h b/deprecated_compiler/include/StringReader.h deleted file mode 100644 index 52d2358..0000000 --- a/deprecated_compiler/include/StringReader.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef StringReader_H -#define StringReader_H - -#include -#include -#include - -class StringReader -{ - public: - StringReader(); - StringReader(std::string inputString); - virtual ~StringReader(); - void setString(std::string inputString); - std::string word(bool truncateEnd = true); - std::string line(bool truncateEnd = true); - std::string getTokens(const char *get_chars, bool truncateEnd = true); - std::string truncateEnd(std::string to_truncate); - - static void test(); - protected: - private: - std::string rd_string; - int str_pos; - bool end_reached; -}; - -#endif diff --git a/deprecated_compiler/include/Symbol.h b/deprecated_compiler/include/Symbol.h deleted file mode 100644 index 34e07dc..0000000 --- a/deprecated_compiler/include/Symbol.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef SYMBOL_H -#define SYMBOL_H - -#ifndef NULL -#define NULL ((void*)0) -#endif - -#include "NodeTree.h" - -#include -#include - -class Symbol { - public: - Symbol(); - Symbol(std::string name, bool isTerminal); - Symbol(std::string name, bool isTerminal, std::string value); - Symbol(std::string name, bool isTerminal, NodeTree* tree); - ~Symbol(); - bool const operator==(const Symbol &other)const; - bool const operator!=(const Symbol &other)const; - bool const operator<(const Symbol &other)const; - - std::string getName() const; - std::string getValue() const; - std::string toString() const; - Symbol clone(); - void setSubTree(NodeTree* tree); - NodeTree* getSubTree(); - bool isTerminal(); - private: - std::string name; - std::string value; - bool terminal; -}; - -#endif diff --git a/deprecated_compiler/include/Table.h b/deprecated_compiler/include/Table.h deleted file mode 100644 index ca2ace9..0000000 --- a/deprecated_compiler/include/Table.h +++ /dev/null @@ -1,37 +0,0 @@ -#include - -#include -#include - -#include "util.h" -#include "ParseRule.h" -#include "ParseAction.h" -#include "Symbol.h" -#include "State.h" - -#ifndef TABLE_H -#define TABLE_H - -class Table { - public: - Table(); - ~Table(); - void exportTable(std::ofstream &file); - void importTable(char* tableData); - void setSymbols(Symbol EOFSymbol, Symbol nullSymbol); - void add(int stateNum, Symbol tranSymbol, ParseAction* action); - void remove(int stateNum, Symbol tranSymbol); - std::vector* get(int state, Symbol token); - ParseAction* getShift(int state, Symbol token); - std::vector> stateAsParseActionVector(int state); - std::string toString(); - private: - std::vector< std::vector< std::vector* >* > table; - std::vector symbolIndexVec; - //The EOFSymbol, a pointer because of use in table, etc - Symbol EOFSymbol; - //The nullSymbol, ditto with above. Also used in comparisons - Symbol nullSymbol; -}; - -#endif diff --git a/deprecated_compiler/include/Tester.h b/deprecated_compiler/include/Tester.h deleted file mode 100644 index 188cbb6..0000000 --- a/deprecated_compiler/include/Tester.h +++ /dev/null @@ -1,32 +0,0 @@ -#include -#include - -#include - -#include "util.h" - -#ifndef TESTER_H -#define TESTER_H - -class Tester { - public: - Tester(std::string krakenInvocation, std::string krakenGrammerLocation); - ~Tester(); - bool run(std::string fileName); - bool compareFiles(std::string file1Path, std::string file2Path); - void cleanExtras(std::string path); - - private: - std::string krakenInvocation; - std::string krakenGrammerLocation; - std::string removeCmd; - std::string resultsExtention; - std::string expectedExtention; - std::string krakenExtention; - std::string shell; - std::string changePermissions; - std::string redirect; - std::string sep; - std::string cd; -}; -#endif diff --git a/deprecated_compiler/include/Type.h b/deprecated_compiler/include/Type.h deleted file mode 100644 index 74876cd..0000000 --- a/deprecated_compiler/include/Type.h +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef TYPE_H -#define TYPE_H - -#ifndef NULL -#define NULL ((void*)0) -#endif - -#include -#include -#include - -//Circular dependency -class ASTData; -#include "ASTData.h" -#include "util.h" - -enum ValueType {none, template_type, template_type_type, void_type, boolean, character, integer, floating, double_percision, function_type }; - - -class Type { - public: - Type(); - Type(ValueType typeIn, int indirectionIn = 0); - Type(ValueType typeIn, std::set traitsIn); //Mostly for template type type's - Type(NodeTree* typeDefinitionIn, int indirectionIn = 0); - Type(NodeTree* typeDefinitionIn, std::set traitsIn); - Type(ValueType typeIn, NodeTree* typeDefinitionIn, int indirectionIn, bool referenceIn, std::set traitsIn); - Type(ValueType typeIn, NodeTree* typeDefinitionIn, int indirectionIn, bool referenceIn, std::set traitsIn, std::vector parameterTypesIn, Type* returnTypeIn); - Type(std::vector parameterTypesIn, Type* returnTypeIn, bool referenceIn = false); - Type(ValueType typeIn, NodeTree* templateDefinitionIn, std::set traitsIn = std::set()); - ~Type(); - const bool test_equality(const Type &other, bool care_about_references) const; - bool const operator==(const Type &other)const; - bool const operator!=(const Type &other)const; - bool const operator<(const Type &other)const; - Type* clone(); - std::string toString(bool showTraits = true); - int getIndirection(); - void setIndirection(int indirectionIn); - void increaseIndirection(); - void decreaseIndirection(); - void modifyIndirection(int mod); - Type withIncreasedIndirection(); - Type withReference(); - Type *withReferencePtr(); - Type *withIncreasedIndirectionPtr(); - Type withDecreasedIndirection(); - - Type* withoutReference(); - - ValueType baseType; - NodeTree* typeDefinition; - NodeTree* templateDefinition; - std::map templateTypeReplacement; - bool templateInstantiated; - std::set traits; - std::vector parameterTypes; - Type *returnType; - bool is_reference; - private: - int indirection; -}; - -#endif diff --git a/deprecated_compiler/include/util.h b/deprecated_compiler/include/util.h deleted file mode 100644 index 242cbd6..0000000 --- a/deprecated_compiler/include/util.h +++ /dev/null @@ -1,92 +0,0 @@ -#ifndef UTIL_H -#define UTIL_H - -#ifndef NULL -#define NULL ((void*)0) -#endif - -#include -#include -#include -#include -#include -#include -#include - -int ssystem(std::string command); -std::string intToString(int theInt); -std::string replaceExEscape(std::string first, std::string search, std::string replace); -std::string strSlice(std::string str, int begin, int end); -int findPerenEnd(std::string str, int i); -std::vector split(const std::string &str, char delim); -std::string join(const std::vector &strVec, std::string joinStr); -std::string readFile(std::istream &file); -std::string padWithSpaces(std::string str, int padTo); - -template -class triple { - public: - T first; - U second; - V third; -}; -template -triple make_triple(T f, U s, V t) { - triple out; - out.first = f; - out.second = s; - out.third = t; - return out; -} - -template -bool contains(std::vector vec, T item) { - for (auto i : vec) - if (i == item) - return true; - return false; -} - -template -std::vector flatten(std::vector> vec) { - std::vector flat; - for (auto i : vec) - flat.insert(flat.end(), i.begin(), i.end()); - return flat; -} - -template -std::vector reverse(std::vector vec) { - std::vector flat; - flat.insert(flat.end(), vec.rbegin(), vec.rend()); - return flat; -} - -template -std::vector dereferenced(std::vector vec) { - std::vector de; - for (T* i:vec) - de.push_back(*i); - return de; -} - -template -std::vector slice(std::vector vec, int begin, int end, int step = 1) { - std::vector toReturn; - if (begin < 0) - begin += vec.size()+1; - if (end < 0) - end += vec.size()+1; - for (int i = begin; i < end; i += step) - toReturn.push_back(vec[i]); - return toReturn; -} - -template -bool subset(std::set a, std::set b) { - for (auto i : a) - if (b.find(i) == b.end()) - return false; - return true; -} -#endif diff --git a/deprecated_compiler/main.cpp b/deprecated_compiler/main.cpp deleted file mode 100644 index 1504d51..0000000 --- a/deprecated_compiler/main.cpp +++ /dev/null @@ -1,190 +0,0 @@ -#include -#include -#include -#include - -#include - -#include "NodeTree.h" -#include "Symbol.h" -#include "Lexer.h" -#include "RNGLRParser.h" - -#include "Importer.h" -#include "ASTData.h" -#include "CGenerator.h" -#include "Poset.h" - -#include "util.h" -#include "Tester.h" - - -int main(int argc, char* argv[]) { - std::vector includePaths; - includePaths.push_back(""); //Local - - if (argc <= 1) { - std::cerr << "Kraken invocation: kraken sourceFile.krak" << std::endl; - std::cerr << "Kraken invocation: kraken sourceFile.krak outputName" << std::endl; - std::cerr << "Kraken invocation: kraken grammerFile.kgm sourceFile.krak outputName" << std::endl; - std::cerr << "Or for testing do: kraken --test [optional list of names of file (.krak .expected_results) without extentions to run]" << std::endl; - return 0; - } - std::string grammerFileString = "../krakenGrammer.kgm"; - - if (argc >= 2 && std::string(argv[1]) == "--test") { - StringReader::test(); - RegEx::test(); - Lexer::test(); - //std::cout << strSlice("123", 0, -1) << std::endl; - Poset::test(); - - if (argc >= 3) { - std::string testResults, line; - int passed = 0, failed = 0; - Tester test(argv[0], grammerFileString); - // find the max length so we can pad the string and align the results - unsigned int maxLineLength = 0; - for (int i = 2; i < argc; i++) { - int strLen = std::string(argv[i]).length(); - maxLineLength = maxLineLength < strLen ? strLen : maxLineLength; - } - for (int i = 2; i < argc; i++) { - bool result = test.run(argv[i]); - if (result) - line = padWithSpaces(std::string(argv[i]), maxLineLength) + "\t\tpassed!\n", passed++; - else - line = padWithSpaces(std::string(argv[i]), maxLineLength) + "\t\tFAILED!!!!\n", failed++; - std::cout << line << std::endl; - testResults += line; - } - std::cout << "===========Done Testing===========" << std::endl; - std::cout << testResults << std::endl; - std::cout << "Test results: " << passed << "/" << passed+failed << std::endl; - } - return 0; - } - std::string krakenDir = argv[0]; - krakenDir = strSlice(krakenDir, 0, -(std::string("kraken").length()+1)); - includePaths.push_back(krakenDir + "stdlib/"); //Add the stdlib directory that exists in the same directory as the kraken executable to the path - - std::string programName; - std::string outputName; - bool parse_only = false; - //std::cout << "argv[1] == " << argv[1] << std::endl; - if (std::string(argv[1]) == "--parse-only") { - parse_only = true; - grammerFileString = argv[2]; - programName = argv[3]; - //outputName = argv[3]; - } else if (argc > 3) { - grammerFileString = argv[1]; - programName = argv[2]; - outputName = argv[3]; - } else if (argc == 3) { - programName = argv[1]; - outputName = argv[2]; - } else { - programName = argv[1]; - outputName = join(slice(split(programName, '.'), 0, -2), "."); // without extension - } - - std::ifstream grammerInFile, compiledGrammerInFile; - std::ofstream compiledGrammerOutFile; - - grammerInFile.open(grammerFileString); - if (!grammerInFile.is_open()) { - std::cerr << "Problem opening grammerInFile " << grammerFileString << "\n"; - return(1); - } - - compiledGrammerInFile.open(grammerFileString + ".comp", std::ios::binary | std::ios::ate); - if (!compiledGrammerInFile.is_open()) - std::cerr << "Problem opening compiledGrammerInFile " << grammerFileString + ".comp" << "\n"; - - //Read the input file into a string - std::string grammerInputFileString; - std::string line; - while(grammerInFile.good()) { - getline(grammerInFile, line); - grammerInputFileString.append(line+"\n"); - } - grammerInFile.close(); - - RNGLRParser parser; - parser.loadGrammer(grammerInputFileString); - - //Start binary stuff - bool compGramGood = false; - if (compiledGrammerInFile.is_open()) { - //std::cout << "Compiled grammer file exists, reading it in" << std::endl; - std::streampos compGramSize = compiledGrammerInFile.tellg(); - char* binaryTablePointer = new char [compGramSize]; - compiledGrammerInFile.seekg(0, std::ios::beg); - compiledGrammerInFile.read(binaryTablePointer, compGramSize); - compiledGrammerInFile.close(); - //Check magic number - if (binaryTablePointer[0] == 'K' && binaryTablePointer[1] == 'R' && binaryTablePointer[2] == 'A' && binaryTablePointer[3] == 'K') { - //std::cout << "Valid Kraken Compiled Grammer File" << std::endl; - int gramStringLength = *((int*)(binaryTablePointer+4)); - //std::cout << "The grammer string is stored to be " << gramStringLength << " characters long, gramString is " - //<< grammerInputFileString.length() << " long. Remember 1 extra for null terminator!" << std::endl; - if (grammerInputFileString.length() != gramStringLength-1 || - (strncmp(grammerInputFileString.c_str(), (binaryTablePointer+4+sizeof(int)), gramStringLength) != 0)) { - //(one less for null terminator that is stored) - std::cout << "The Grammer has been changed, will re-create" << std::endl; - } else { - compGramGood = true; - //std::cout << "Grammer file is up to date." << std::endl; - parser.importTable(binaryTablePointer + 4 + sizeof(int) + gramStringLength); //Load table starting at the table section - } - } else { - std::cerr << grammerFileString << ".comp is NOT A Valid Kraken Compiled Grammer File, aborting" << std::endl; - return -1; - } - delete [] binaryTablePointer; - } - - if (!compGramGood) { - //The load failed because either the file does not exist or it is not up-to-date. - std::cout << "Compiled grammer file does not exist or is not up-to-date, generating table and writing it out" << std::endl; - compiledGrammerOutFile.open(grammerFileString + ".comp", std::ios::binary); - if (!compiledGrammerOutFile.is_open()) - std::cerr << "Could not open compiled file to write either!" << std::endl; - compiledGrammerOutFile.write("KRAK", sizeof(char)*4); //Let us know when we load it that this is a kraken grammer file, but don't write out - compiledGrammerOutFile.flush(); // the grammer txt until we create the set, so that if we fail creating it it won't look valid - parser.createStateSet(); - int* intBuffer = new int; - *intBuffer = grammerInputFileString.length()+1; - compiledGrammerOutFile.write((char*)intBuffer, sizeof(int)); - delete intBuffer; - compiledGrammerOutFile.write(grammerInputFileString.c_str(), grammerInputFileString.length()+1); //Don't forget null terminator - - parser.exportTable(compiledGrammerOutFile); - compiledGrammerOutFile.close(); - } - //End binary stuff - - //std::cout << "\nParsing" << std::endl; - //std::cout << "\toutput name: " << outputName << std::endl; - //std::cout << "\tprogram name: " << programName << std::endl; - Importer importer(&parser, includePaths, outputName, parse_only); // Output name for directory to put stuff in - - //for (auto i : includePaths) - //std::cout << i << std::endl; - - importer.import(programName); - std::map*> ASTs = importer.getASTMap(); - if (parse_only) - return 0; - - //Do optimization, etc. here. - //None at this time, instead going straight to C in this first (more naive) version - - //Code generation - //For right now, just C - - // return code from calling C compiler - return CGenerator().generateCompSet(ASTs, outputName); -} - diff --git a/deprecated_compiler/src/ASTData.cpp b/deprecated_compiler/src/ASTData.cpp deleted file mode 100644 index c244ae0..0000000 --- a/deprecated_compiler/src/ASTData.cpp +++ /dev/null @@ -1,88 +0,0 @@ -#include "ASTData.h" - -ASTData::ASTData() { - this->type = undef; - this->valueType = NULL; -} - -ASTData::ASTData(ASTType type, Type *valueType) { - this->type = type; - this->valueType = valueType; -} - -ASTData::ASTData(ASTType type, Symbol symbol, Type *valueType) { - this->type = type; - this->valueType = valueType; - this->symbol = symbol; -} - - -ASTData::~ASTData() { -} - -std::string ASTData::toString() { - return ASTTypeToString(type) + " " + - (symbol.isTerminal() ? " " + symbol.toString() : "") + " " + - (valueType ? valueType->toString() : "no_type"); -} - -std::string ASTData::ASTTypeToString(ASTType type) { - switch (type) { - case translation_unit: - return "translation_unit"; - case identifier: - return "identifier"; - case import: - return "import"; - case function: - return "function"; - case type_def: - return "type_def"; - case code_block: - return "code_block"; - case typed_parameter: - return "typed_parameter"; - case expression: - return "expression"; - case boolean_expression: - return "boolean_expression"; - case statement: - return "statement"; - case if_statement: - return "if_statement"; - case while_loop: - return "while_loop"; - case for_loop: - return "for_loop"; - case return_statement: - return "return_statement"; - case break_statement: - return "break_statement"; - case continue_statement: - return "continue_statement"; - case defer_statement: - return "defer_statement"; - case assignment_statement: - return "assignment_statement"; - case declaration_statement: - return "declaration_statement"; - case if_comp: - return "if_comp"; - case simple_passthrough: - return "simple_passthrough"; - case passthrough_params: - return "passthrough_params"; - case in_passthrough_params: - return "out_passthrough_params"; - case param_assign: - return "param_assign"; - case opt_string: - return "opt_string"; - case function_call: - return "function_call"; - case value: - return "value"; - default: - return "unknown_ASTType"; - } -} diff --git a/deprecated_compiler/src/ASTTransformation.cpp b/deprecated_compiler/src/ASTTransformation.cpp deleted file mode 100644 index 885ba0c..0000000 --- a/deprecated_compiler/src/ASTTransformation.cpp +++ /dev/null @@ -1,1903 +0,0 @@ -#include "ASTTransformation.h" - -ASTTransformation::ASTTransformation(Importer *importerIn) { - importer = importerIn; - topScope = NULL; - - builtin_trans_unit = new NodeTree("translation_unit", ASTData(translation_unit, Symbol("builtin", false))); - - //Set up language level reserved identifier scope (only this, right now) - languageLevelReservedWords["this"].push_back(new NodeTree("identifier", ASTData(identifier, Symbol("this", true), NULL))); - - //Set up language level special scope. (the final scope checked) - //Note the NULL type - languageLevelOperators["+"].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree("function", ASTData(function, Symbol("+", true), NULL)))); - languageLevelOperators["-"].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree("function", ASTData(function, Symbol("-", true), NULL)))); - languageLevelOperators["*"].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree("function", ASTData(function, Symbol("*", true), NULL)))); - languageLevelOperators["/"].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree("function", ASTData(function, Symbol("/", true), NULL)))); - languageLevelOperators["%"].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree("function", ASTData(function, Symbol("%", true), NULL)))); - languageLevelOperators["&"].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree("function", ASTData(function, Symbol("&", true), NULL)))); - languageLevelOperators["--"].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree("function", ASTData(function, Symbol("--", true), NULL)))); - languageLevelOperators["++"].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree("function", ASTData(function, Symbol("++", true), NULL)))); - languageLevelOperators["=="].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree("function", ASTData(function, Symbol("==", true), new Type(std::vector(), new Type(boolean)))))); - languageLevelOperators["!="].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree("function", ASTData(function, Symbol("!=", true), new Type(std::vector(), new Type(boolean)))))); - languageLevelOperators["<="].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree("function", ASTData(function, Symbol("<=", true), new Type(std::vector(), new Type(boolean)))))); - languageLevelOperators[">="].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree("function", ASTData(function, Symbol(">=", true), new Type(std::vector(), new Type(boolean)))))); - languageLevelOperators["<"].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree("function", ASTData(function, Symbol("<", true), new Type(std::vector(), new Type(boolean)))))); - languageLevelOperators[">"].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree("function", ASTData(function, Symbol(">", true), new Type(std::vector(), new Type(boolean)))))); - languageLevelOperators["&&"].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree("function", ASTData(function, Symbol("&&", true), new Type(std::vector(), new Type(boolean)))))); - languageLevelOperators["||"].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree("function", ASTData(function, Symbol("||", true), new Type(std::vector(), new Type(boolean)))))); - languageLevelOperators["!"].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree("function", ASTData(function, Symbol("!", true), new Type(std::vector(), new Type(boolean)))))); - languageLevelOperators["*="].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree("function", ASTData(function, Symbol("*=", true), NULL)))); - languageLevelOperators["="].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree("function", ASTData(function, Symbol("=", true), NULL)))); - languageLevelOperators["+="].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree("function", ASTData(function, Symbol("+=", true), NULL)))); - languageLevelOperators["-="].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree("function", ASTData(function, Symbol("-=", true), NULL)))); - languageLevelOperators["."].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree("function", ASTData(function, Symbol(".", true), NULL)))); - languageLevelOperators["->"].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree("function", ASTData(function, Symbol("->", true), NULL)))); - languageLevelOperators["[]"].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree("function", ASTData(function, Symbol("[]", true), NULL)))); - languageLevelOperators["[]="].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree("function", ASTData(function, Symbol("[]=", true), NULL)))); -} - -ASTTransformation::~ASTTransformation() { -} - -NodeTree* ASTTransformation::getNode(std::string lookup, NodeTree* parent) { - auto results = getNodes(lookup, parent); - if (results.size() > 1) - throw "too many results"; - if (results.size()) - return results[0]; - return nullptr; -} -NodeTree* ASTTransformation::getNode(std::string lookup, std::vector*> nodes) { - auto results = getNodes(lookup, nodes); - if (results.size() > 1) - throw "too many results"; - if (results.size()) - return results[0]; - return nullptr; -} -std::vector*> ASTTransformation::getNodes(std::string lookup, NodeTree* parent) { - return getNodes(lookup, parent->getChildren()); -} -std::vector*> ASTTransformation::getNodes(std::string lookup, std::vector*> nodes) { - std::vector*> results; - for (auto i : nodes) - if (i->getDataRef()->getName() == lookup) - results.push_back(i); - return results; -} - -//First pass defines all type_defs (objects and ailises), ADTs, and if_comp/simple_passthrough -NodeTree* ASTTransformation::firstPass(std::string fileName, NodeTree* parseTree) { - NodeTree* translationUnit = new NodeTree("translation_unit", ASTData(translation_unit, Symbol(fileName, false))); - std::vector*> children = parseTree->getChildren(); - importer->registerAST(fileName, translationUnit, parseTree); //Register ourselves with the importer. - //This puts us in the scope and the list of ASTs that go through all the passes - - //Go through and define all types (type_defs whether they are classes or ailises, as well as including non-instantiated templates) - for (NodeTree* i : children) { - if (i->getDataRef()->getName() == "type_def") { - std::string name = concatSymbolTree(i->getChildren()[0]); - NodeTree* firstDec = addToScope("~enclosing_scope", translationUnit, new NodeTree("type_def", ASTData(type_def, Symbol(name, true, name)))); - addToScope(name, firstDec, translationUnit); - translationUnit->addChild(firstDec); - //If this is a template, go ahead and set it up. Pass 2 needs templates set up so it can (partially) instantiate them. - //So we give this typedef its name without any template types and make its type template_type, and point to this from node. - //Then, when this template is instantiated, it will run transform on from with the types filled in. - auto typedefChildren = i->getChildren(); - if (typedefChildren.size()>1 && typedefChildren[1]->getData().getName() == "template_dec") { - if (typedefChildren.size() > 2 && typedefChildren[2]->getData().getName() == "traits") - firstDec->getDataRef()->valueType = new Type(template_type, i, parseTraits(i->getChildren()[2])); - else - firstDec->getDataRef()->valueType = new Type(template_type, i); - } else if (typedefChildren.size() > 1 && typedefChildren[1]->getData().getName() == "traits") { - firstDec->getDataRef()->valueType = new Type(firstDec, parseTraits(i->getChildren()[1])); - } else if (typedefChildren.size() == 1 || typedefChildren[1]->getData().getName() != "type") { //We don't make the type for alises, because the second pass will assign it the type it points to - firstDec->getDataRef()->valueType = new Type(firstDec); - } - - } else if (i->getDataRef()->getName() == "adt_def") { - std::string name = concatSymbolTree(getNode("identifier", i)); - NodeTree* adt_dec = addToScope("~enclosing_scope", translationUnit, new NodeTree("adt_def", ASTData(adt_def, Symbol(name, true, name)))); - addToScope(name, adt_dec, translationUnit); - translationUnit->addChild(adt_dec); - adt_dec->getDataRef()->valueType = new Type(adt_dec); - } else if (i->getDataRef()->getName() == "if_comp") { - //std::cout << "IF COMP" << std::endl; - NodeTree* newNode = addToScope("~enclosing_scope", translationUnit, new NodeTree(i->getDataRef()->getName(), ASTData(if_comp))); - newNode->addChild(addToScope("~enclosing_scope", newNode, new NodeTree("identifier", ASTData(identifier, Symbol(concatSymbolTree(i->getChildren()[0]),true))))); - std::set skipChildren; - skipChildren.insert(0); //Don't do the identifier. The identifier lookup will fail. That's why we do it here. - newNode->addChildren(transformChildren(i->getChildren(), skipChildren, translationUnit, std::vector(), false, std::map())); - translationUnit->addChild(newNode); - } - } - - //Now go through and do all imports - //We do this second so that if an import also imports us, all of our stuff has already been defined - for (NodeTree* i : children) { - if (i->getDataRef()->getName() == "import") { - auto importChildren = i->getChildren(); - std::string toImport = concatSymbolTree(importChildren[1]); - auto importNode = addToScope("~enclosing_scope", translationUnit, new NodeTree("import", ASTData(import, Symbol(toImport, true)))); - translationUnit->addChild(importNode); - //Do the imported file too - NodeTree* outsideTranslationUnit = importer->importFirstPass(toImport + ".krak"); - translationUnit->getDataRef()->scope[toImport].push_back(outsideTranslationUnit); //Put this transation_unit in the scope as it's files name - // Now go through and handle anything like import asdf: a; or import asdf: a,b; or import asdf: *; - // We do this by looping through the children and adding links to them as the scope in the import node. If it's *, we add the entire translationUnit link. - // Note that import affects scope in two ways: - // (1) The other file's translationUnit is added to our translationUnit's scope under it's name - // (2) The import node's scope contains the nodes indicated by the qualifiers after the import (i.e. the import a:b; or import a:*;) - for (auto importQualifer : slice(importChildren, 2, -1)) { // Not the first child, import, or the second that's the name of the file - auto name = concatSymbolTree(importQualifer); - if (name == "*") { - std::vector*> tmp; - tmp.push_back(outsideTranslationUnit); - importNode->getDataRef()->scope["*"] = tmp; - } else { - bool found = false; - for (auto outsideScopeEntry : outsideTranslationUnit->getDataRef()->scope) { - if (name == outsideScopeEntry.first) { - importNode->getDataRef()->scope[outsideScopeEntry.first] = outsideScopeEntry.second; - found = true; - } - } - // If it's not found yet, put it in as a empty vector for pass 3. - // This makes sure that it does appear in the scope map, which is what we iterate through later. - if (!found) - importNode->getDataRef()->scope[name] = std::vector*>(); - } - } - } - } - - return translationUnit; -} - -std::set ASTTransformation::parseTraits(NodeTree* traitsNode) { - std::set traits; - //Every other one b/c comma separated - for (auto i : slice(traitsNode->getChildren(), 0, -1, 2)) - traits.insert(concatSymbolTree(i)); - return traits; -} - -//Second pass defines data inside objects + ADTs, outside declaration statements, and function prototypes (since we have type_defs+ADTs now) -void ASTTransformation::secondPass(NodeTree* ast, NodeTree* parseTree) { - topScope = ast; //Top scope is maintained for templates, which need to add themselves to the top scope from where ever they are instantiated - std::vector*> children = parseTree->getChildren(); - - //Go through and declare data internal to objects as well as all function prototypes (methods and otherwise) - //Note that this pass can instantiate class templates - for (NodeTree* i : children) { - if (i->getDataRef()->getName() == "type_def") { - if (i->getChildren().size()>1 && i->getChildren()[1]->getData().getName() == "template_dec") // It's a template - continue; //We've already set upt the class templates - std::vector*> typedefChildren = i->getChildren(); - std::string name = concatSymbolTree(typedefChildren[0]); - NodeTree* typeDef = ast->getDataRef()->scope[name][0]; //No overloaded types (besides uninstantiated templates, which can have multiple versions based on types or specilizations) - - //It's an alias. Note that if typedefChildren.size() == 1 it's because its a regular class with no body, i.e. {} - if (typedefChildren.size() > 1 && typedefChildren[1]->getData().getName() == "type") { - Type* aliasedType = typeFromTypeNode(typedefChildren[1], ast, std::map()); - typeDef->getDataRef()->valueType = aliasedType; - // only put in scope if it has a definition, that is it is not an aliased primitive - if (aliasedType->typeDefinition) - typeDef->getDataRef()->scope["~enclosing_scope"][0] = aliasedType->typeDefinition; //So that object lookups find the right member. Note that this overrides translation_unit as a parent scope - // std::cout << name << " alias's to " << aliasedType->typeDefinition << std::endl; - // std::cout << "that is " << aliasedType->typeDefinition->getDataRef()->toString() << std::endl; - continue; - } - //Do the inside of classes here - secondPassDoClassInsides(typeDef, typedefChildren, std::map()); - } else if (i->getDataRef()->getName() == "adt_def") { - std::cout << "ADT DEF" << std::endl; - std::cout << "there are " << getNodes("adt_option", i).size() << " adt_options" << std::endl; - std::string name = concatSymbolTree(getNode("identifier", i)); - NodeTree* adtDef = ast->getDataRef()->scope[name][0]; //No overloaded types (besides uninstantiated templates, which can have multiple versions based on types or specilizations) - - // Let's make an equality function prototype - Type *thisADTType = adtDef->getDataRef()->valueType; - NodeTree* equalityFunc = new NodeTree("function", ASTData(function, Symbol("operator==", true), new Type(std::vector{thisADTType->withReferencePtr()}, new Type(boolean)))); - adtDef->addChild(equalityFunc); - addToScope("operator==", equalityFunc, adtDef); - addToScope("~enclosing_scope", adtDef, equalityFunc); - - NodeTree* inequalityFunc = new NodeTree("function", ASTData(function, Symbol("operator!=", true), new Type(std::vector{thisADTType->withReferencePtr()}, new Type(boolean)))); - adtDef->addChild(inequalityFunc); - addToScope("operator!=", inequalityFunc, adtDef); - addToScope("~enclosing_scope", adtDef, inequalityFunc); - - NodeTree* copy_constructFunc = new NodeTree("function", ASTData(function, Symbol("copy_construct", true), new Type(std::vector{thisADTType->withIncreasedIndirectionPtr()}, new Type(void_type)))); - adtDef->addChild(copy_constructFunc); - addToScope("copy_construct", copy_constructFunc, adtDef); - addToScope("~enclosing_scope", adtDef, copy_constructFunc); - - NodeTree* assignmentFunc = new NodeTree("function", ASTData(function, Symbol("operator=", true), new Type(std::vector{thisADTType->withReferencePtr()}, new Type(void_type)))); - adtDef->addChild(assignmentFunc); - addToScope("operator=", assignmentFunc, adtDef); - addToScope("~enclosing_scope", adtDef, assignmentFunc); - - NodeTree* destructFunc = new NodeTree("function", ASTData(function, Symbol("destruct", true), new Type(std::vector(), new Type(void_type)))); - adtDef->addChild(destructFunc); - addToScope("destruct", destructFunc, adtDef); - addToScope("~enclosing_scope", adtDef, destructFunc); - - for (NodeTree* j : getNodes("adt_option", i)) { - std::string ident_name = concatSymbolTree(getNode("identifier", j)); - std::cout << "add ing " << ident_name << " to " << name << " for ADT" << std::endl; - NodeTree* enum_variant_identifier; - NodeTree* possibleType = getNode("type", j); - NodeTree* enum_variant_function = nullptr; - if (possibleType) { - Type* actual_type = typeFromTypeNode(possibleType, adtDef, std::map()); - enum_variant_identifier = new NodeTree("identifier", ASTData(identifier, Symbol(ident_name, true), actual_type)); - - // also make a function prototype for a function that returns an instance of this type. If we don't contain a type, it's just the literal - //enum_variant_function = new NodeTree("function", ASTData(function, Symbol("fun_"+ident_name, true), new Type(std::vector{actual_type}, adtDef->getDataRef()->valueType))); - enum_variant_function = new NodeTree("function", ASTData(function, Symbol(ident_name, true), new Type(std::vector{actual_type}, thisADTType))); - } else { - enum_variant_identifier = new NodeTree("identifier", ASTData(identifier, Symbol(ident_name, true), adtDef->getDataRef()->valueType)); - // now a function in both cases... - enum_variant_function = new NodeTree("function", ASTData(function, Symbol(ident_name, true), new Type(std::vector(), thisADTType))); - } - adtDef->addChild(enum_variant_identifier); - addToScope(ident_name, enum_variant_identifier, adtDef); - addToScope("~enclosing_scope", adtDef, enum_variant_identifier); - // this comes second so it is added to the enclosing scope second so that the function is found last on identifer lookup so we can still access members that are not functions - // as their names alias each other - if (enum_variant_function) { - adtDef->addChild(enum_variant_function); - addToScope(ident_name, enum_variant_function, adtDef); - addToScope("~enclosing_scope", adtDef, enum_variant_function); - } - } - } else if (i->getDataRef()->getName() == "function") { - //Do prototypes of functions - ast->addChild(secondPassFunction(i, ast, std::map())); - } else if (i->getDataRef()->getName() == "declaration_statement") { - //Do declaration statements - ast->addChild(secondPassDeclaration(i, ast, std::map())); - } - } -} - -void ASTTransformation::secondPassDoClassInsides(NodeTree* typeDef, std::vector*> typedefChildren, std::map templateTypeReplacements) { - //We pull out this functionality into a new function because this is used in typeFromTypeNode to partially instantiate templates - for (NodeTree* j : typedefChildren) { - if (j->getDataRef()->getName() == "declaration_statement") { - //do declaration - typeDef->addChild(secondPassDeclaration(j, typeDef, templateTypeReplacements)); - } else if (j->getDataRef()->getName() == "function") { - //do member method - typeDef->addChild(secondPassFunction(j, typeDef, templateTypeReplacements)); - } - } -} - -//This function may need to partially instantiate a class template -NodeTree* ASTTransformation::secondPassDeclaration(NodeTree* from, NodeTree* scope, std::map templateTypeReplacements) { - return transform(from, scope, std::vector(), false, templateTypeReplacements); -} - -//This function may need to partially instantiate a class template -NodeTree* ASTTransformation::secondPassFunction(NodeTree* from, NodeTree* scope, std::map templateTypeReplacements) { - //If this is a function template - std::vector*> children = from->getChildren(); - NodeTree* functionDef = NULL; - std::string functionName = concatSymbolTree(children[0]); - if (children[1]->getData().getName() == "template_dec") { - functionDef = new NodeTree("function", ASTData(function, Symbol(functionName, true), new Type(template_type, from))); - addToScope("~enclosing_scope", scope, functionDef); - addToScope(functionName, functionDef, scope); - std::map yetToBeInstantiatedTemplateTypes; //So that template types (like T) that have not been placed yet are found and given - //a special Type() - baseType = template_type_type - for (auto i : slice(children[1]->getChildren(), 1, -1, 2)) {//skip commas - if (i->getChildren().size() == 1) - yetToBeInstantiatedTemplateTypes[concatSymbolTree(i)] = new Type(template_type_type); //This may have to be combined with templateTypeReplacements if we do templated member functions inside of templated classes - else //has traits - yetToBeInstantiatedTemplateTypes[concatSymbolTree(i->getChildren()[0])] = new Type(template_type_type, parseTraits(i->getChildren()[1])); //This may have to be combined with templateTypeReplacements if we do templated member functions inside of templated classes - } - //std::cout << "Finished Non-Instantiated Template function " << functionName << std::endl; - return functionDef; - } - auto returnTypeNode = getNode("type", getNode("typed_return", children)); // if null, the typed_return had no children and we're supposed to automatically do a void type - auto returnType = returnTypeNode ? typeFromTypeNode(returnTypeNode, scope, templateTypeReplacements): new Type(void_type); - if (!returnType) - throw "freakout"; - functionDef = new NodeTree("function", ASTData(function, Symbol(functionName, true), returnType)); - addToScope("~enclosing_scope", scope, functionDef); - addToScope(functionName, functionDef, scope); - //We only do the parameter nodes. We don't do the body yet, as this is the secondPass - //auto transChildren = transformChildren(slice(children,1,-3, 2), std::set(), functionDef, std::vector(), false, templateTypeReplacements); - auto transChildren = transformChildren(getNodes("typed_parameter", children), std::set(), functionDef, std::vector(), false, templateTypeReplacements); - - functionDef->addChildren(transChildren); - // Swap the function type over to be the correct type (a function with parameter and return types, etc) - functionDef->getDataRef()->valueType = new Type(mapNodesToTypePointers(transChildren), functionDef->getDataRef()->valueType); - return functionDef; -} - -//The third pass finishes up by doing all function bodies -void ASTTransformation::thirdPass(NodeTree* ast, NodeTree* parseTree) { - topScope = ast; //Top scope is maintained for templates, which need to add themselves to the top scope from where ever they are instantiated - std::vector*> children = parseTree->getChildren(); - - //Go through and finish both regular functions and class methods - //Note that this pass can instantiate class AND function templates - for (NodeTree* i : children) { - if (i->getDataRef()->getName() == "type_def") { - if (i->getChildren().size() > 1 && i->getChildren()[1]->getData().getName() == "template_dec") // It's a template - continue; //We've already set up the class templates - std::vector*> typedefChildren = i->getChildren(); - std::string name = concatSymbolTree(typedefChildren[0]); - NodeTree* typeDef = ast->getDataRef()->scope[name][0]; //No overloaded types - - //It's an alias. Note that typedefChildren.size() can equal one when it's a regular class with an empty body, i.e. {} - if (typedefChildren.size() > 1 && typedefChildren[1]->getData().getName() == "type") - continue; //We're done with aliases too - - //Do the inside of classes here - for (NodeTree* j : typedefChildren) { - // skip templated member functions - if (j->getDataRef()->getName() == "function" && j->getChildren()[1]->getDataRef()->getName() != "template_dec") { - thirdPassFunction(j, searchScopeForFunctionDef(typeDef, j, std::map()), std::map()); //do member method - } - } - } else if (i->getDataRef()->getName() == "adt_def") { - // nothing to do here yet, but eventually we will set up our internal objs, etc - } else if (i->getDataRef()->getName() == "function") { - //Do prototypes of functions - if (i->getChildren()[1]->getData().getName() == "template_dec") - continue; //We've already set up function templates - thirdPassFunction(i, searchScopeForFunctionDef(ast, i, std::map()), std::map()); - } - } -} -bool ASTTransformation::fourthPass(NodeTree* ast, NodeTree* parseTree) { - topScope = ast; //Top scope is maintained for templates, which need to add themselves to the top scope from where ever they are instantiated - - bool changed = false; - // We do these here, in a loop, so that we can do mututally recursive definitions - // even inside of class templates. As its methods may cause partial instantiation of - // other class templates, we need to do this until the size no longer changes. - std::vector*> classTemplates; - int lastSize = 0; - while (lastSize != ast->getDataRef()->scope.size()) { - lastSize = ast->getDataRef()->scope.size(); - classTemplates.clear(); - for (auto i : ast->getDataRef()->scope) { - // we actually keep track of the template type replacements now, and need them after they're instantiated, so we use a set to check if we've done it now - if (i.second[0]->getDataRef()->type == type_def && i.second[0]->getDataRef()->valueType->templateTypeReplacement.size() - && !i.second[0]->getDataRef()->valueType->templateInstantiated) { - classTemplates.push_back(i.second[0]); - //std::cout << "Saving " << i.second[0]->getDataRef()->toString() << " to instantiate." << std::endl; - changed = true; - } - } - for (auto i : classTemplates) { - Type* classTemplateType = i->getDataRef()->valueType; - //std::cout << "Instantiating template " << i->getDataRef()->toString() << std::endl; - for (NodeTree* j : classTemplateType->templateDefinition->getChildren()) - if (j->getDataRef()->getName() == "function" && j->getChildren()[1]->getDataRef()->getName() != "template_dec") - thirdPassFunction(j, searchScopeForFunctionDef(i, j, classTemplateType->templateTypeReplacement), classTemplateType->templateTypeReplacement); //do member method - classTemplateType->templateInstantiated = true; - } - } - return changed; -} - -//This function finds the right AST definition in a scope given its parseTree -NodeTree* ASTTransformation::searchScopeForFunctionDef(NodeTree* scope, NodeTree* parseTree, std::map templateTypeReplacements) { - std::string functionName = concatSymbolTree(parseTree->getChildren()[0]); - std::vector types; - std::vector*> children = parseTree->getChildren(); - //Skipping the initial return type and identifier as well as the final code block - //std::cout << "\n Searching scope for function def, function is: " << concatSymbolTree(children[0]) << ", children size is " << children.size() << std::endl; - for (auto param: getNodes("typed_parameter", children)) { //Skip over commas - //std::cout << "Making type for lookup ||" << concatSymbolTree(param) << "||" << std::endl; - Type type = *typeFromTypeNode(param->getChildren().back(), scope, templateTypeReplacements); - //std::cout << "Type made: " << type.toString() << std::endl; - types.push_back(type); - } - //std::cout << "About to search scope about " << concatSymbolTree(children[0]) << std::endl; - NodeTree* result = functionLookup(scope, functionName, types); - //std::cout << "Done searching scope about " << concatSymbolTree(children[0]) << std::endl; - return result; -} - -//This function does the function bodies given its start (the prototype) -//It is used in the third pass to finish things up -//Note that it may instantiate class OR function templates, which need to be fully instantiated -void ASTTransformation::thirdPassFunction(NodeTree* from, NodeTree* functionDef, std::map templateTypeReplacements) { - NodeTree* codeBlock = from->getChildren().back(); - functionDef->addChild(transform(codeBlock, functionDef, std::vector(), false, templateTypeReplacements)); -} - -NodeTree* ASTTransformation::transform(NodeTree* from) { - //Set up top scope - return transform(from, NULL, std::vector(), false, std::map()); -} - -NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree* scope, std::vector types, bool limitToFunction, std::map templateTypeReplacements) { - Symbol current = from->getData(); - std::string name = current.getName(); - NodeTree* newNode = NULL; - std::vector*> children = from->getChildren(); - std::set skipChildren; - - if (name == "identifier" || name == "scoped_identifier") { - //Make sure we get the entire name - std::string lookupName = concatSymbolTree(from); - //std::cout << "Looking up: " << lookupName << std::endl; - if (limitToFunction) { - newNode = functionLookup(scope, lookupName, types); - if (newNode == NULL) { - std::cout << "scope lookup failed! Could not find " << lookupName << " in identifier (functionLookup)" << std::endl; - std::cout << "(maybe this is supposted to happen because the function is a template and we're infrencing), or this is a operator() call" << std::endl; - // Ok, now we try the case where the lookupName is an object, and we'll try to look for operator() - // in its scope - for (auto possibleObj : scopeLookup(scope, lookupName)) { - NodeTree *typeDefinition = possibleObj->getDataRef()->valueType->typeDefinition; - if (typeDefinition) { - // ugly for now, it's just operator because the ( and ) have been removed by a removal - // pass - NodeTree* perenOp = functionLookup(typeDefinition, "operator", types); - if (perenOp) { - NodeTree* dotFunctionCall = new NodeTree(".", ASTData(function_call, Symbol(".", true), perenOp->getDataRef()->valueType)); - dotFunctionCall->addChild(languageLevelOperators["."][0]); //function definition - dotFunctionCall->addChild(possibleObj); // The object whose method we're calling - dotFunctionCall->addChild(perenOp); //The method we're calling - return dotFunctionCall; - } - } - } - return nullptr; - } - } else { - auto possibleMatches = scopeLookup(scope, lookupName); - if (!possibleMatches.size()) { - std::cerr << std::endl; - std::cerr << "scope lookup error! Could not find " << lookupName << " in identifier (scopeLookup)" << std::endl; - std::cerr << "lookup failedin file " << getUpperTranslationUnit(scope)->getDataRef()->symbol.getName() << std::endl; - std::cerr << "note that this might not be the file where the error is" << std::endl; - std::cerr << "obj.non_existant_member would fail in the file that defines obj's type, for instance" << std::endl; - std::cerr << std::endl; - throw "LOOKUP ERROR: " + lookupName; - } - // can't cull out functiokns b/c we might want them as values - newNode = possibleMatches[0]; - //newNode = nullptr; - //for (auto i : possibleMatches) { - //if (i->getDataRef()->valueType->baseType != function_type) { - //newNode = i; - //break; - //} - //} - //if (!newNode) { - //std::cerr << "scope lookup error! only found functions for " << lookupName << " in identifier (scopeLookup)" << std::endl; - //throw "LOOKUP ERROR: " + lookupName; - //} - } - return newNode; - } else if (name == "type_def") { - //If it is an alisis of a type - std::string typeAlias; - //std::cout << "The scope here at type_def is " << scope->getDataRef()->toString() << std::endl; - if (children[1]->getData().getName() == "type") { - typeAlias = concatSymbolTree(children[0]); - newNode = scope->getDataRef()->scope[typeAlias][0]; //The node for this type_def has already been made by translation_unit. - //This is done so that types that reference each other can be declared in any order - - newNode->getDataRef()->valueType = typeFromTypeNode(children[1], scope, templateTypeReplacements); - skipChildren.insert(0); //Don't want any children, it's unnecessary for ailising - skipChildren.insert(1); - } else { //Is a struct or class - Type* objectType = NULL; - if (children[1]->getData().getName() == "template_dec") { - typeAlias = concatSymbolTree(children[0]); - //std::cout << "Template Type!"<getDataRef()->scope[typeAlias][0]; //The node for this type_def has already been made by translation_unit. - //This is done so that types that reference each other can be declared in any order - // std::cout << "typeAlias is " << typeAlias << " and newNode is " << newNode << std::endl; - - //So we give this typedef its name without any template types and make its type template_type, and point to this from node. - //Then, when this template is instantiated, it will run transform on from with the types filled in. - objectType = new Type(template_type, from); - } else { - typeAlias = concatSymbolTree(children[0]); - - newNode = scope->getDataRef()->scope[typeAlias][0]; //The node for this type_def has already been made by translation_unit. - //This is done so that types that reference each other can be declared in any order - - objectType = new Type(newNode); - skipChildren.insert(0); //Identifier lookup will be ourselves, as we just added ourselves to the scope - } - newNode->getDataRef()->valueType = objectType; //Type is self-referential since this is the definition - } - addToScope("~enclosing_scope", scope, newNode); - - - //Templates are done here. No need to go farther - if (children[1]->getData().getName() == "template_dec") - return newNode; - scope = newNode; - } else if (name == "function" || name == "lambda") { - std::string functionName; - //If this is a function template - if (children[1]->getData().getName() == "template_dec") { - functionName = concatSymbolTree(children[0]); - newNode = new NodeTree(name, ASTData(function, Symbol(functionName, true), new Type(template_type, from))); - addToScope(functionName, newNode, scope); - addToScope("~enclosing_scope", scope, newNode); - std::map yetToBeInstantiatedTemplateTypes; //So that template types (like T) that have not been placed yet are found and given - //a special Type() - baseType = template_type_type - for (auto i : slice(children[1]->getChildren(), 1, -1, 2)) //skip commas - yetToBeInstantiatedTemplateTypes[concatSymbolTree(i)] = new Type(template_type_type); //This may have to be combined with templateTypeReplacements if we do templated member functions inside of templated classes - - auto transChildren = transformChildren(slice(children,3,-2), std::set(), newNode, types, limitToFunction, yetToBeInstantiatedTemplateTypes); - //std::cout << "Template function " << functionName << " has these parameters: "; - //for (auto i : transChildren) - //std::cout << "||" << i->getDataRef()->toString() << "|| "; - //std::cout << "??||" << std::endl; - newNode->addChildren(transChildren); - - //std::cout << "Finished Non-Instantiated Template function " << functionName << std::endl; - return newNode; - } - if (name == "lambda") - functionName = "lambda" + intToString(lambdaID++); - else - functionName = concatSymbolTree(children[0]); - auto returnTypeNode = getNode("type", getNode("typed_return", children)); // if null, the typed_return had no children and we're supposed to automatically do a void type - auto returnType = returnTypeNode ? typeFromTypeNode(returnTypeNode, scope, templateTypeReplacements): new Type(void_type); - newNode = new NodeTree(name, ASTData(function, Symbol(functionName, true), returnType)); - addToScope(functionName, newNode, scope); - addToScope("~enclosing_scope", scope, newNode); - scope = newNode; - // If lambda, add to top scope so it gets emitted - if (name == "lambda") - addToScope(functionName, newNode, topScope); - - auto parameters = transformChildren(getNodes("typed_parameter", children), skipChildren, scope, types, limitToFunction, templateTypeReplacements); - newNode->addChildren(parameters); - // update type with actual type - newNode->getDataRef()->valueType = new Type(mapNodesToTypePointers(parameters), newNode->getDataRef()->valueType); - auto statement = transform(getNode("statement", children), scope, types, false, templateTypeReplacements); // definitly do not limit this statement to functions - if (name == "lambda") - newNode->getDataRef()->closedVariables = findVariablesToClose(newNode, statement, scope); - //for (auto i : newNode->getDataRef()->closedVariables) - //std::cout << "OK, CLOSED: " << i->getDataRef()->toString() << std::endl; - newNode->addChild(statement); - //std::cout << "finished function" << functionName << std::endl; - return newNode; - - } else if (name == "code_block") { - newNode = new NodeTree(name, ASTData(code_block)); - addToScope("~enclosing_scope", scope, newNode); - scope = newNode; - } else if (name == "typed_parameter") { - //newNode = transform(children[1]); //Transform to get the identifier - std::string parameterName = concatSymbolTree(children[0]); - //std::cout << "Doing typed parameter " << parameterName << std::endl; - //std::string typeString = concatSymbolTree(children[0]);//Get the type (left child) and set our new identifer to be that type - newNode = new NodeTree("identifier", ASTData(identifier, Symbol(parameterName, true), typeFromTypeNode(children[2], scope, templateTypeReplacements))); - addToScope(parameterName, newNode, scope); - addToScope("~enclosing_scope", scope, newNode); - //std::cout << "Done doing typed_parameter " << parameterName << std::endl; - return newNode; - } else if (name == "boolean_expression" || name == "and_boolean_expression" || name == "bool_exp") { - //If this is an actual part of an expression, not just a premoted term - if (children.size() > 1) { - //We do children first so we can do appropriate scope searching with types (yay operator overloading!) - skipChildren.insert(1); - std::vector*> transformedChildren = transformChildren(children, skipChildren, scope, types, limitToFunction, templateTypeReplacements); - std::string functionCallString = concatSymbolTree(children[1]); - NodeTree* function = doFunction(scope, functionCallString, transformedChildren, templateTypeReplacements); - if (function == NULL) { - std::cerr << "scope lookup error! Could not find " << functionCallString << " in boolean stuff " << std::endl; - throw "LOOKUP ERROR: " + functionCallString; - } - return function; - } else { - // XXX What the heck is this - if (children.size() == 0) - return new NodeTree(); - return transform(children[0], scope, types, limitToFunction, templateTypeReplacements); //Just a promoted term, so do child - } - //Here's the order of ops stuff - } else if (name == "expression" || name == "shiftand" || name == "term" || name == "unarad" || name == "access_operation") { - //If this is an actual part of an expression, not just a premoted child - if (children.size() > 2) { - NodeTree* lhs = transform(children[0], scope, std::vector(),false, templateTypeReplacements); //LHS does not inherit types, or limittofunction - NodeTree* rhs; - if (name == "access_operation") { - //std::cout << "lhs is: " << lhs->getDataRef()->toString() << std::endl; - rhs = transform(children[2], lhs->getDataRef()->valueType->typeDefinition, types, limitToFunction, templateTypeReplacements); //If an access operation, then the right side will be in the lhs's type's scope - // this might be a template member function, so do like below would do, but make it our rhs - if (rhs == nullptr) - rhs = findOrInstantiateFunctionTemplate(slice(children,2,-1), lhs->getDataRef()->valueType->typeDefinition, types, templateTypeReplacements); - } else - rhs = transform(children[2], scope, types, limitToFunction, templateTypeReplacements); - - std::string functionCallName = concatSymbolTree(children[1]); - if (functionCallName == "[") - functionCallName = "[]"; //fudge the lookup of brackets because only one is at children[1] (the other is at children[3]) - //std::cout << "scope lookup from expression or similar" << std::endl; - std::vector*> transformedChildren; transformedChildren.push_back(lhs); transformedChildren.push_back(rhs); - newNode = doFunction(scope, functionCallName, transformedChildren, templateTypeReplacements); - if (newNode == NULL) { - std::cerr << "scope lookup error! Could not find " << functionCallName << " in expression " << std::endl; - throw "LOOKUP ERROR: " + functionCallName; - } - return newNode; - } - if (children.size() == 1) { - newNode = transform(children[0], scope, types, limitToFunction, templateTypeReplacements); //Just a promoted child, so do it instead - if (newNode) - return newNode; - } - // So if children.size() != 1, or that returned null because the function lookup failed, - // we try to do a template instatiation. If it had 2 children, it's an instantion, if it has 1 - // maybe it's a template instantiation we're supposed to infer the types for. Either way, we let - // findorinstantiatefunctiontemplate take care of it. - return findOrInstantiateFunctionTemplate(children, scope, types, templateTypeReplacements); - } else if (name == "factor") { //Do factor here, as it has all the weird unary operators - //If this is an actual part of an expression, not just a premoted child - //NO SUPPORT FOR CASTING YET - std::string funcName; - if (children.size() == 2) { - funcName = concatSymbolTree(children[0]); - NodeTree* param; - // I think this is where we look at pre vs post operators - if (funcName == "*" || funcName == "&" || funcName == "++" || funcName == "--" || funcName == "+" || funcName == "-" || funcName == "!" || funcName == "~") - param = transform(children[1], scope, types, limitToFunction, templateTypeReplacements); - else - funcName = concatSymbolTree(children[1]), param = transform(children[0], scope, types, limitToFunction, templateTypeReplacements); - - //std::cout << "\t\t\t funcName= " << funcName << " param: " << param->getDataRef()->symbol.getName() << std::endl; - //std::cout << "scope lookup from factor" << std::endl; - std::vector*> transformedChildren; transformedChildren.push_back(param); - NodeTree* function = doFunction(scope, funcName, transformedChildren, templateTypeReplacements); - //std::cout << "\t\t\t AFTER dofunction= " << std::endl; - if (function == NULL) { - std::cerr << "scope lookup error! Could not find " << funcName << " in factor " << std::endl; - throw "LOOKUP ERROR: " + funcName; - } - - return function; - } else { - return transform(children[0], scope, types, limitToFunction, templateTypeReplacements); //Just a promoted child, so do it instead - } - } else if (name == "statement") { - newNode = new NodeTree(name, ASTData(statement)); - } else if (name == "if_statement") { - newNode = new NodeTree(name, ASTData(if_statement)); - } else if (name == "match_statement") { - newNode = new NodeTree(name, ASTData(match_statement)); - } else if (name == "case_statement") { - newNode = new NodeTree(name, ASTData(case_statement)); - std::string adtOptionStr = concatSymbolTree(getNodes("scoped_identifier", children)[0]); - auto optionDefPoss = scopeLookup(scope, adtOptionStr); - auto optionDef = optionDefPoss[0]; - //auto adtDef = optionDef->getDataRef()->scope["~enclosing_scope"][0]; - - addToScope("~enclosing_scope", scope, newNode); - newNode->addChild(optionDef); - - // we have a destructure - auto newIdentifierSymbolNodes = getNodes("identifier", children); - if (newIdentifierSymbolNodes.size()) { - std::string newIdentifierStr = concatSymbolTree(newIdentifierSymbolNodes[0]); - NodeTree* newIdentifier = new NodeTree("identifier", ASTData(identifier, Symbol(newIdentifierStr, true), optionDef->getDataRef()->valueType)); - addToScope(newIdentifierStr, newIdentifier, newNode); - addToScope("~enclosing_scope", newNode, newIdentifier); - newNode->addChild(newIdentifier); - } - - newNode->addChild(transform(getNode("statement",children), newNode, types, limitToFunction, templateTypeReplacements)); - return newNode; - } else if (name == "while_loop") { - newNode = new NodeTree(name, ASTData(while_loop)); - } else if (name == "for_loop") { - newNode = new NodeTree(name, ASTData(for_loop)); - } else if (name == "return_statement") { - newNode = new NodeTree(name, ASTData(return_statement)); - } else if (name == "break_statement") { - newNode = new NodeTree(name, ASTData(break_statement)); - } else if (name == "continue_statement") { - newNode = new NodeTree(name, ASTData(continue_statement)); - } else if (name == "defer_statement") { - newNode = new NodeTree(name, ASTData(defer_statement)); - } else if (name == "assignment_statement") { - std::string assignFuncName = concatSymbolTree(children[1]); - // but first check to see if the lefthand side is a factor which is a unarad with "[" in order to first check for operator []=? - // checking for this very specific case - // ok, assuming the left side is a factor, we grab the unarad - auto unarad = getNode("unarad", children[0]); - if (unarad && getNode("[", unarad)) { - // allrightly, check to see if we have []= - NodeTree* lhs = transform(getNode("unarad", unarad), scope, types, limitToFunction, templateTypeReplacements); - NodeTree* indexArg = transform(getNode("expression", unarad), scope, types, limitToFunction, templateTypeReplacements); - NodeTree* rhs = transform(children[2], scope, types, limitToFunction, templateTypeReplacements); - std::vector*> transformedChildren; transformedChildren.push_back(lhs); transformedChildren.push_back(indexArg); transformedChildren.push_back(rhs); - // doFunction special cases []= to return null if it's not found as a method - NodeTree* function = doFunction(scope, "[]=", transformedChildren, templateTypeReplacements); - if (function) - return function; - // otherwise, screw it and do it regularly - } - NodeTree* lhs = transform(children[0], scope, types, limitToFunction, templateTypeReplacements); - NodeTree* rhs = transform(children[2], scope, types, limitToFunction, templateTypeReplacements); - std::vector*> transformedChildren; transformedChildren.push_back(lhs); transformedChildren.push_back(rhs); - - // see if this is an overloaded assignment - NodeTree* function = doFunction(scope, assignFuncName, transformedChildren, templateTypeReplacements); - if (function) - return function; - - newNode = new NodeTree(name, ASTData(assignment_statement)); - if (assignFuncName == "=") { - newNode->addChildren(transformedChildren); - } else { - //For assignments like += or *=, expand the syntatic sugar. - std::string functionName = assignFuncName.substr(0,1); - NodeTree* operatorCall = doFunction(scope, functionName, transformedChildren, templateTypeReplacements); - if (operatorCall == NULL) { - std::cerr << "scope lookup error! Could not find " << functionName << " in assignment_statement " << std::endl; - throw "LOOKUP ERROR: " + functionName; - } - newNode->addChild(lhs); - newNode->addChild(operatorCall); - } - return newNode; - } else if (name == "declaration_statement") { - newNode = new NodeTree(name, ASTData(declaration_statement)); - std::string newIdentifierStr = concatSymbolTree(children[0]); - NodeTree* typeSyntaxNode = getNode("type", children); - Type* identifierType = typeSyntaxNode ? typeFromTypeNode(typeSyntaxNode, scope, templateTypeReplacements) : nullptr; - - //if (identifierType) - //std::cout << "Declaring an identifier " << newIdentifierStr << " to be of type " << identifierType->toString() << std::endl; - //else - //std::cout << "Declaring an identifier " << newIdentifierStr << " with type to be type-inferenced " << std::endl; - - if (children.size() > 1 && concatSymbolTree(children[1]) == ".") { - NodeTree* newIdentifier = new NodeTree("identifier", ASTData(identifier, Symbol(newIdentifierStr, true), identifierType)); - addToScope(newIdentifierStr, newIdentifier, scope); - addToScope("~enclosing_scope", scope, newNode); - addToScope("~enclosing_scope", newNode, newIdentifier); - newNode->addChild(newIdentifier); - //A bit of a special case for declarations - if there's anything after just the normal 1 node declaration, it's either - //an expression that is assigned to the declaration (int a = 4;) or a member call (Object a.constructAThing()) - //This code is a simplified version of the code in function_call with respect to access_operation. - //Note that in this case, what is lhs there is our newIdentifier here (the declaration of the left side of the access operation) - auto sliced = slice(children, 3, -3); - std::vector*> initPositionFuncParams = transformChildren(sliced, std::set(), scope, types, limitToFunction, templateTypeReplacements); - NodeTree* rhs = transform(children[2], identifierType->typeDefinition, mapNodesToTypes(initPositionFuncParams), true, templateTypeReplacements); //If an access operation, then the right side will be in the lhs's type's scope - std::vector*> transformedChildren; transformedChildren.push_back(newIdentifier); transformedChildren.push_back(rhs); - NodeTree* accessFuncCall = doFunction(scope, ".", transformedChildren, templateTypeReplacements); - accessFuncCall->getDataRef()->valueType = rhs->getDataRef()->valueType; - //Now we borrow a bit of code from function_call below to actually use our new accessFuncCall to setup a "initPosition" function call - //that will follow the identifier in this declaration node - std::string initPosFuncName = newIdentifierStr + "." + concatSymbolTree(children[2]); - NodeTree* initPositionFuncCall = new NodeTree(initPosFuncName, ASTData(function_call, Symbol(initPosFuncName, true))); - initPositionFuncCall->addChild(accessFuncCall); - initPositionFuncCall->getDataRef()->valueType = accessFuncCall->getDataRef()->valueType; - initPositionFuncCall->addChildren(initPositionFuncParams); - newNode->addChild(initPositionFuncCall); - return newNode; - } - - NodeTree* newIdentifier = new NodeTree("identifier", ASTData(identifier, Symbol(newIdentifierStr, true), identifierType)); - addToScope(newIdentifierStr, newIdentifier, scope); - addToScope("~enclosing_scope", scope, newNode); - addToScope("~enclosing_scope", newNode, newIdentifier); - - auto boolExp = getNode("boolean_expression", children); - NodeTree* toAssign = boolExp ? transform(boolExp, scope, types, limitToFunction, templateTypeReplacements) : nullptr; - // for type inferencing - if (!identifierType) { - if (toAssign) { - // no reference variables - identifierType = toAssign->getDataRef()->valueType->withoutReference(); - newIdentifier->getDataRef()->valueType = identifierType; - } else - throw "have to inference but no expression"; - } - - - newNode->addChild(newIdentifier); - if (toAssign) - newNode->addChild(toAssign); - return newNode; - } else if (name == "if_comp") { - newNode = new NodeTree(name, ASTData(if_comp)); - newNode->addChild(addToScope("~enclosing_scope", scope, new NodeTree("identifier", ASTData(identifier, Symbol(concatSymbolTree(children[0]),true))))); - addToScope("~enclosing_scope", scope, newNode); - skipChildren.insert(0); //Don't do the identifier. The identifier lookup will fail. That's why we do it here. - } else if (name == "simple_passthrough") { - newNode = new NodeTree(name, ASTData(simple_passthrough)); - addToScope("~enclosing_scope", scope, newNode); - skipChildren.insert(0); //Don't do the identifier. The identifier lookup will fail. That's why we do it here. - } else if (name == "passthrough_params") { - newNode = new NodeTree(name, ASTData(passthrough_params)); - addToScope("~enclosing_scope", scope, newNode); - } else if (name == "in_passthrough_params") { - newNode = new NodeTree(name, ASTData(in_passthrough_params)); - addToScope("~enclosing_scope", scope, newNode); - } else if (name == "out_passthrough_params") { - newNode = new NodeTree(name, ASTData(out_passthrough_params)); - addToScope("~enclosing_scope", scope, newNode); - } else if (name == "opt_string") { - newNode = new NodeTree(name, ASTData(opt_string)); - addToScope("~enclosing_scope", scope, newNode); - } else if (name == "param_assign") { - newNode = new NodeTree(name, ASTData(param_assign)); - addToScope("~enclosing_scope", scope, newNode); - } else if (name == "function_call") { - std::string functionCallName = concatSymbolTree(children[0]); - newNode = new NodeTree(functionCallName, ASTData(function_call, Symbol(functionCallName, true))); - - skipChildren.insert(0); - std::vector*> transformedChildren = transformChildren(children, skipChildren, scope, types, limitToFunction, templateTypeReplacements); - //std::cout << "scope lookup from function_call: " << functionCallName << std::endl; - //for (auto i : children) - //std::cout << i << " : " << i->getName() << " : " << i->getDataRef()->getName() << std::endl; - - NodeTree* function = transform(children[0], scope, mapNodesToTypes(transformedChildren), true, templateTypeReplacements); - //std::cout << "The thing: " << function << " : " << function->getName() << std::endl; - //for (auto i : function->getChildren()) - //std::cout << i->getName() << " "; - //std::cout << std::endl; - newNode->addChild(function); - // note that we now get the return type from the function call's type - newNode->getDataRef()->valueType = function->getDataRef()->valueType->returnType; - newNode->addChildren(transformedChildren); - return newNode; - } else if (name == "parameter") { - return transform(children[0], scope, types, limitToFunction, templateTypeReplacements); //Don't need a parameter node, just the value - } else if (name == "type") { - std::string theConcat = concatSymbolTree(from); //We have no symbol, so this will concat our children - newNode = new NodeTree(name, ASTData(value, Symbol(theConcat, true), typeFromTypeNode(from, scope, templateTypeReplacements))); - addToScope("~enclosing_scope", scope, newNode); - } else if (name == "number") { - return transform(children[0], scope, types, limitToFunction, templateTypeReplacements); - } else if (name == "integer") { - newNode = new NodeTree(name, ASTData(value, Symbol(concatSymbolTree(from), true), new Type(integer))); - } else if (name == "floating_literal") { - std::string literal = concatSymbolTree(from); - ValueType type = double_percision; - if (literal.back() == 'f') { - literal = literal.substr(0, literal.length()-1); - type = floating; - } else if (literal.back() == 'd') { - literal = literal.substr(0, literal.length()-1); - type = double_percision; - } - newNode = new NodeTree(name, ASTData(value, Symbol(literal, true), new Type(type))); - } else if (name == "char") { //Is this correct? This might be a useless old thing - newNode = new NodeTree(name, ASTData(value, Symbol(concatSymbolTree(children[0]), true), new Type(character, 1))); //Indirection of 1 for array - } else if (name == "string" || name == "triple_quoted_string") { - newNode = new NodeTree(name, ASTData(value, Symbol(concatSymbolTree(children[0]), true), new Type(character, 1))); //Indirection of 1 for array - } else if (name == "character") { - newNode = new NodeTree(name, ASTData(value, Symbol(concatSymbolTree(children[0]), true), new Type(character, 0))); //Indirection of 0 for character - } else if (name == "bool") { - newNode = new NodeTree(name, ASTData(value, Symbol(concatSymbolTree(children[0]), true), new Type(boolean, 0))); //Indirection of 0 for character - } else if (name == "AmbiguityPackOuter" || name == "AmbiguityPackInner") { - std::cerr << "///////////////////////////////////////////////////////////////////////////////" << std::endl; - std::cerr << "Ambigious program when parsed by this grammer! This is a bug, please report it." << std::endl; - std::cerr << "///////////////////////////////////////////////////////////////////////////////" << std::endl; - std::cerr << concatSymbolTree(from) << std::endl; - throw "Ambigious parse!"; - } else { - // Should get rid of this eventually. Right now it handles cases like sign, alpha, a comma, etc - //std::cout << "Unhandled syntax node: " << name << std::endl; - return new NodeTree(); - } - - //Do all children but the ones we skip - newNode->addChildren(transformChildren(children, skipChildren, scope, types, limitToFunction, templateTypeReplacements)); - return newNode; -} - -//We use this functionality a lot at different places -std::vector*> ASTTransformation::transformChildren(std::vector*> children, std::set skipChildren, NodeTree* scope, std::vector types, bool limitToFunction, std::map templateTypeReplacements) { - std::vector*> transformedChildren; - // In general, iterate through children and do them. Might not do this for all children. - for (int i = 0; i < children.size(); i++) { - if (skipChildren.find(i) == skipChildren.end()) { - NodeTree* transChild = transform(children[i], scope, types, limitToFunction, templateTypeReplacements); - if (transChild->getDataRef()->type) //Only add the children that have a real ASTData::ASTType, that is, legit ASTData. - transformedChildren.push_back(transChild); - else - delete transChild; - } - } - return transformedChildren; -} - -//Simple way to extract strings from syntax trees. Used often for identifiers, strings, types -std::string ASTTransformation::concatSymbolTree(NodeTree* root) { - std::string concatString; - std::string ourValue = root->getDataRef()->getValue(); - if (ourValue != "NoValue") - concatString += ourValue; - std::vector*> children = root->getChildren(); - for (int i = 0; i < children.size(); i++) { - concatString += concatSymbolTree(children[i]); - } - return concatString; -} - -//We pass in the actual children (parameters) to allow us to handle overloaded operator methods (where a parameter is actually the scope of the method) -NodeTree* ASTTransformation::doFunction(NodeTree* scope, std::string lookup, std::vector*> nodes, std::map templateTypeReplacements) { - auto LLElementIterator = languageLevelOperators.find(lookup); - NodeTree* newNode; - if (LLElementIterator != languageLevelOperators.end()) { - //std::cout << "Checking for early method level operator overload" << std::endl; - std::string lookupOp = "operator" + lookup; - //for (auto i : nodes) - //std::cout << i->getDataRef()->toString() << " "; - //std::cout << std::endl; - NodeTree* operatorMethod = NULL; - - // make sure this isn't a pointer, also. Silly vector bug - if (nodes[0]->getDataRef()->valueType && !nodes[0]->getDataRef()->valueType->getIndirection() && nodes[0]->getDataRef()->valueType->typeDefinition) { - operatorMethod = functionLookup(nodes[0]->getDataRef()->valueType->typeDefinition, lookupOp, mapNodesToTypes(slice(nodes,1,-1))); - // we're also gonna check to see if this is an operator template method - if (!operatorMethod) - operatorMethod = tryToFindOrInstantiateFunctionTemplate(lookupOp, nodes[0]->getDataRef()->valueType->typeDefinition, mapNodesToTypes(slice(nodes,1,-1)), templateTypeReplacements); - } - if (operatorMethod) { - //Ok, so we construct - //std::cout << "Early method level operator was found" << std::endl; - //return operatorMethod; - NodeTree* newNode = new NodeTree(lookupOp, ASTData(function_call, Symbol(lookupOp, true))); - NodeTree* dotFunctionCall = new NodeTree(".", ASTData(function_call, Symbol(".", true), operatorMethod->getDataRef()->valueType)); - dotFunctionCall->addChild(languageLevelOperators["."][0]); //function definition - dotFunctionCall->addChild(nodes[0]); // The object whose method we're calling - dotFunctionCall->addChild(operatorMethod); //The method we're calling - newNode->addChild(dotFunctionCall); // First child of function call is a link to the function definition - newNode->addChildren(slice(nodes, 1, -1)); //The rest of the parameters to the operator - - - //Set the value of this function call - newNode->getDataRef()->valueType = operatorMethod->getDataRef()->valueType->returnType; - return newNode; - } - //std::cout << "Early method level operator was NOT found" << std::endl; - if (lookup == "[]=") { - //std::cout << "as the operator was []= we're returning nullptr now and gonna let our above handle it as seperate ones" << std::endl; - return nullptr; - } - } - - newNode = new NodeTree(lookup, ASTData(function_call, Symbol(lookup, true))); - NodeTree* function = functionLookup(scope, lookup, mapNodesToTypes(nodes)); - //std::cout << "Num of newNode children " << newNode->getChildren().size() << std::endl; - newNode->addChild(function); - //std::cout << "Num of newNode children " << newNode->getChildren().size() << std::endl; - newNode->addChildren(nodes); - //std::cout << "Num of newNode children " << newNode->getChildren().size() << std::endl; - //std::cout << "nodes " << nodes.size() << std::endl; - - //Specially handle dereference and address of to assign the correct type - //We need some significant other type corrections here, maybe to the point of being their own function. (int + float, etc.) - //std::cout << "the passed in nodes" << std::endl; - //for (auto i : nodes) - //std::cout << i->getDataRef()->toString() << " "; - //std::cout< oldTypes = mapNodesToTypes(nodes); - //std::cout << "the oldtypes size" << oldTypes.size() << std::endl; - if ((nodes.size() != 2 && lookup == "*") || lookup == "&" || lookup == "[]") { - Type* newType = oldTypes[0].clone(); - if (lookup == "*" || lookup == "[]") - newType->decreaseIndirection(); - else - newType->increaseIndirection(); - - newNode->getDataRef()->valueType = newType; //, std::cout << "Operator " + lookup << " is altering indirection from " << oldTypes[0].toString() << " to " << newType->toString() << std::endl; - } else { - //std::cout << "Some other ||" << lookup << "||" << std::endl; - if (function->getDataRef()->valueType) - newNode->getDataRef()->valueType = function->getDataRef()->valueType->returnType; - } - - // Set the value of this function call if it has not already been set - // It's important that it's the last parameter, the rhs if it has one - // because of the . operator, etc - if (newNode->getDataRef()->valueType == NULL) { - //std::cout << "The value type from doFunction was null! (for " << lookup << ")" << std::endl; - Type* newType = nullptr; - if (lookup == "->") - newType = oldTypes.back().clone(); - else if (oldTypes.front().getIndirection()) - newType = oldTypes.front().clone(); - else if (oldTypes.back().getIndirection()) - newType = oldTypes.back().clone(); - else - newType = (oldTypes.front().baseType > oldTypes.back().baseType) ? oldTypes.front().clone() : oldTypes.back().clone(); - //if (!newType) - //newType = oldTypes.back().clone(); - - newNode->getDataRef()->valueType = newType; - //std::cout << "function call to " << lookup << " - " << newNode->getName() << " is now " << newNode->getDataRef()->valueType << std::endl; - } - return newNode; -} -// checks to see if scope is in node's parent scope chain -bool ASTTransformation::inScopeChain(NodeTree* node, NodeTree* scope) { - auto nodeScope = node->getDataRef()->scope; - auto enclosingItr = nodeScope.find("~enclosing_scope"); - if (enclosingItr == nodeScope.end()) - return false; - if (enclosingItr->second[0] == scope) - return true; - return inScopeChain(enclosingItr->second[0], scope); -} -// We return a set of all identifers used in the children of stat that are not declared somewhere below stat -// used to calculate the closedvariables for closures -std::set*> ASTTransformation::findVariablesToClose(NodeTree* func, NodeTree* stat, NodeTree* scope) { - std::set*> closed; -//enum ASTType {undef, translation_unit, interpreter_directive, import, identifier, type_def, - //function, code_block, typed_parameter, expression, boolean_expression, statement, - //if_statement, while_loop, for_loop, return_statement, break_statement, continue_statement, defer_statement, - //assignment_statement, declaration_statement, if_comp, simple_passthrough, passthrough_params, - //in_passthrough_params, out_passthrough_params, opt_string, param_assign, function_call, value}; - if (stat->getDataRef()->type == function || stat->getDataRef()->type == translation_unit - || stat->getDataRef()->type == type_def || stat->getDataRef()->type == value - ) { - // if this is a method we know that it is a method of our current enclosing object (as we already know that we're not on the right side of . or ->, see below) - // we should add our enclosing object, this, to our closed over variables - // also, if this is a lambda, we should close over what it needs to close over too... - if (stat->getDataRef()->type == function) { - auto statEnclosingScope = stat->getDataRef()->scope["~enclosing_scope"][0]; - if (statEnclosingScope && statEnclosingScope->getDataRef()->valueType && statEnclosingScope->getDataRef()->valueType->typeDefinition) - closed.insert(generateThis(scope)); - if (stat->getDataRef()->closedVariables.size()) { - for (auto item : stat->getDataRef()->closedVariables) { - auto recClosed = findVariablesToClose(func, item, scope); - closed.insert(recClosed.begin(), recClosed.end()); - } - } - } - return closed; - } - if (stat->getDataRef()->type == case_statement) { - // don't try to close over the variant specifier itself, only its statement child - auto recClosed = findVariablesToClose(func, stat->getChildren().back(), scope); - closed.insert(recClosed.begin(), recClosed.end()); - return closed; - } - if (stat->getDataRef()->type == function_call && (stat->getDataRef()->symbol.getName() == "." || stat->getDataRef()->symbol.getName() == "->")) { - // only search on the left side of access operators like . and -> - auto recClosed = findVariablesToClose(func, stat->getChildren()[1], scope); - closed.insert(recClosed.begin(), recClosed.end()); - return closed; - } - // if it's an identifier and not in the scope chain, and isn't an enum name - if (stat->getDataRef()->type == identifier && !inScopeChain(stat, func)) - // used to be this because C style enums, but now those are functions and we should definitly close over variables of type adt... - //if (stat->getDataRef()->type == identifier && !inScopeChain(stat, func) - // && (!stat->getDataRef()->valueType->typeDefinition || - //stat->getDataRef()->valueType->typeDefinition->getDataRef()->type != adt_def) ) - closed.insert(stat); - for (auto child: stat->getChildren()) { - auto recClosed = findVariablesToClose(func, child, scope); - closed.insert(recClosed.begin(), recClosed.end()); - } - return closed; -} - -//Lookup a function that takes in parameters matching the types passed in -NodeTree* ASTTransformation::functionLookup(NodeTree* scope, std::string lookup, std::vector types) { - //We first check to see if it's one of the special reserved identifiers (only this, for now) and return early if it is. - auto LLElementIterator = languageLevelReservedWords.find(lookup); - if (LLElementIterator != languageLevelReservedWords.end()) { - //std::cout << "found it at language level as reserved word." << std::endl; - return LLElementIterator->second[0]; - } - //We search the languageLevelOperators to see if it's an operator. If so, we modifiy the lookup with a preceding "operator" - LLElementIterator = languageLevelOperators.find(lookup); - if (LLElementIterator != languageLevelOperators.end()) - lookup = "operator" + lookup; - - //Look up the name - std::vector*> possibleMatches = scopeLookup(scope, lookup); - std::cout << "Function lookup of " << lookup << " has " << possibleMatches.size() << " possible matches." << std::endl; - if (possibleMatches.size()) { - for (auto i : possibleMatches) { - //We're not looking for types - //if (i->getDataRef()->type == type_def || i->getDataRef()->type == adt_def) - // actually, lets make it we're only looking for things with type function - if (i->getDataRef()->valueType->baseType != function_type) - continue; - Type* functionType = i->getDataRef()->valueType; - - int numTypes = functionType->parameterTypes.size(); - if (types.size() != numTypes) { - std::cout << "Type sizes do not match between two " << lookup << "(" << types.size() << "," << numTypes << "), types are: "; - for (auto j : types) - std::cout << j.toString() << " "; - std::cout << std::endl; - std::cout << "Versus" << std::endl; - for (int j = 0; j < numTypes; j++) - std::cout << functionType->parameterTypes[j]->toString() << " "; - std::cout << std::endl; - continue; - } - bool typesMatch = true; - for (int j = 0; j < types.size(); j++) { - Type* tmpType = functionType->parameterTypes[j]; - //Don't worry if types don't match if it's a template type - //if (types[j] != *tmpType && tmpType->baseType != template_type_type) { - // WE DO WORRY NOW B/C template type infrence is ugly and we need this to fail - // for regular function lookups so that we know to retry with a template - // - // we use test_equality so that we can pass in a false to not care about references - if (!types[j].test_equality(*tmpType, false)) { - typesMatch = false; - std::cout << "Types do not match between two " << lookup << " " << types[j].toString(); - std::cout << " vs " << tmpType->toString() << std::endl; - break; - } - } - if (typesMatch) - return i; - } - } - - //std::cout << "could not find " << lookup << " in standard scopes, checking for operator" << std::endl; - //Note that we don't check for types. At some point we should, as we don't know how to add objects/structs without overloaded operators, etc - //Also, we've already searched for the element because this is also how we keep track of operator overloading - if (LLElementIterator != languageLevelOperators.end()) { - //std::cout << "found it at language level as operator." << std::endl; - return LLElementIterator->second[0]; - } - std::cout << "Did not find, returning NULL" << std::endl; - return NULL; -} - -//Lookup class templates. It evaluates possible matches on traits -NodeTree* ASTTransformation::templateClassLookup(NodeTree* scope, std::string lookup, std::vector templateInstantiationTypes) { - std::set*> mostFittingTemplates; - int bestNumTraitsSatisfied = -1; - auto possibleMatches = scopeLookup(scope, lookup); - //std::cout << "Template Class instantiation has " << possibleMatches.size() << " possible matches." << std::endl; - for (auto i : possibleMatches) { - if (i->getDataRef()->type != type_def) - continue; - NodeTree* templateSyntaxTree = i->getDataRef()->valueType->templateDefinition; - - auto nameTraitsPairs = makeTemplateNameTraitPairs(templateSyntaxTree->getChildren()[1]); - //Check if sizes match between the placeholder and actual template types - if (nameTraitsPairs.size() != templateInstantiationTypes.size()) - continue; - - bool traitsEqual = true; - int typeIndex = 0; - int currentTraitsSatisfied = 0; - for (auto j : nameTraitsPairs) { - // error out if not subset, or if we're a pointer but should have traits - if (!subset(j.second, templateInstantiationTypes[typeIndex]->traits) || (templateInstantiationTypes[typeIndex]->getIndirection() && j.second.size())) { - traitsEqual = false; - //std::cout << "Traits not subset for " << j.first << " and " << templateInstantiationTypes[typeIndex]->toString() << ": "; - //std::cout << baseType << " " << indirection << " " << typeDefinition << " " << templateDefinition << " " << traits << ; - //std::copy(j.second.begin(), j.second.end(), std::ostream_iterator(std::cout, " ")); - //std::cout << " vs "; - //std::copy(templateInstantiationTypes[typeIndex]->traits.begin(), templateInstantiationTypes[typeIndex]->traits.end(), std::ostream_iterator(std::cout, " ")); - //std::cout << std::endl; - break; - } else { - //std::cout << "Traits ARE subset for " << j.first << " and " << templateInstantiationTypes[typeIndex]->toString() << ": "; - //std::cout << baseType << " " << indirection << " " << typeDefinition << " " << templateDefinition << " " << traits << ; - //std::copy(j.second.begin(), j.second.end(), std::ostream_iterator(std::cout, " ")); - //std::cout << " vs "; - //std::copy(templateInstantiationTypes[typeIndex]->traits.begin(), templateInstantiationTypes[typeIndex]->traits.end(), std::ostream_iterator(std::cout, " ")); - //std::cout << std::endl; - } - currentTraitsSatisfied += j.second.size(); - typeIndex++; - } - if (!traitsEqual) - continue; - - //See if this is a better match than the current best - if (currentTraitsSatisfied > bestNumTraitsSatisfied) { - mostFittingTemplates.clear(); - //std::cout << "Class satisfying " << currentTraitsSatisfied << " beats previous " << bestNumTraitsSatisfied << std::endl; - bestNumTraitsSatisfied = currentTraitsSatisfied; - } else if (currentTraitsSatisfied < bestNumTraitsSatisfied) - continue; - mostFittingTemplates.insert(i); - //std::cout << "Current class fits, satisfying " << currentTraitsSatisfied << " traits" << std::endl; - } - if (!mostFittingTemplates.size()) { - std::cout << "No template classes fit for " << lookup << "!" << std::endl; - std::cerr << "in file " << getUpperTranslationUnit(scope)->getDataRef()->symbol.getName() << std::endl; - throw "No matching template classes"; - } else if (mostFittingTemplates.size() > 1) { - std::cout << "Multiple template classes fit with equal number of traits satisfied for " << lookup << "!" << std::endl; - throw "Multiple matching template classes"; - } - return *mostFittingTemplates.begin(); -} - -void ASTTransformation::unifyType(NodeTree *syntaxType, Type type, std::map* templateTypeMap, std::map typeMap) { - // First, get rid of the reference part - we don't care for unification - syntaxType = syntaxType->getChildren().back(); - - // Ok, 3 options for syntaxType here. - // 1) This a basic type. (int, or object, etc) - // THIS ONE will fall through and get put in the map, but it - // doesn't matter b/c it'll get filterd out in unifyTemplateFunction - // I also kina feel like maybe I need to worry about typeMap, which is why - // I passed it in... It would contain the typemap from our scope if we are - // doing a template member function of a templated object - // 2) This is a template type type (i.e. T) - // match! set up templateTypeMap[T] -> type - // 3) This some sort of instantiated template - // a) instantiated with some other type (i.e. vector) - // THIS ONE will fall through and get put in the map, but it - // doesn't matter b/c it'll get filterd out in unifyTemplateFunction - // b) instantiated with a template type type (i.e. vector) - // this will be a bit of a pain too - // 4) This is a pointer type, go down a pointer level - // 5) This is a function type, unify on parameter types and return type - - auto children = syntaxType->getChildren(); - - if (children.back()->getDataRef()->getName() == "function_type") { - if (!type.returnType) - return; - auto childrenTypes = getNodes("type", children.back()->getChildren()); - // unify params - for (int i = 0; i < childrenTypes.size()-1; i++) - unifyType(childrenTypes[i], *type.parameterTypes[i], templateTypeMap, typeMap); - unifyType(childrenTypes.back(), *type.returnType, templateTypeMap, typeMap); - return; - } - - if (children.size() == 1) { - (*templateTypeMap)[concatSymbolTree(children.front())] = type; - // I also kina feel like maybe I need to worry about typeMap, which is why - // I passed it in... It would contain the typemap from our scope if we are - // doing a template member function of a templated object - } else { - // go down one in our pointer - if (children.front()->getDataRef()->getValue() == "*") { - // gotta be a better way to do this - Type* clonedType = type.clone(); - clonedType->decreaseIndirection(); - unifyType(children.back(), *clonedType, templateTypeMap, typeMap); - delete clonedType; - return; - } - - if (type.typeDefinition) { - // ok, what happens here is that we get the origional type from our type. This is - // the same as the type we have now but it still has extra data from when it was instantiated - // like the templateTypeReplacement map, which we'll use. - // We get the etc part from the template we're matching against and unify it with the - // actual types the type we're unifying with used by passing it's through the templateTypeReplacement - // to get the type it was instantiated with. - auto origionalType = type.typeDefinition->getDataRef()->valueType; - auto typeTemplateDefinition = origionalType->templateDefinition; - // we have to get rid of the scope partion of the scoped_identifier so we can compare properly with the typeTemplateDefinition's identifier - auto scoped = getNode("scoped_identifier", children); - NodeTree* ident = nullptr; - while(scoped && !ident) { - ident = getNode("identifier", scoped); - scoped = getNode("scoped_identifier", scoped); - } - //if (typeTemplateDefinition) { - //std::cout << concatSymbolTree(ident) << std::endl; - //std::cout << concatSymbolTree(getNode("identifier", typeTemplateDefinition->getChildren())) << std::endl; - //} - if (typeTemplateDefinition && concatSymbolTree(ident) == concatSymbolTree(getNode("identifier", typeTemplateDefinition->getChildren()))) { - std::vector*> uninTypeInstTypes = getNodes("type", getNode("template_inst", children)); - std::vector*> typeInstTypes = getNodes("template_param", getNode("template_dec", typeTemplateDefinition->getChildren())); - for (int i = 0; i < uninTypeInstTypes.size(); i++) { - //std::cout << concatSymbolTree(uninTypeInstTypes[i]) << " : " << origionalType->toString() << " : " << concatSymbolTree(typeInstTypes[i]) << std::endl; - //std::cout << "which is " << origionalType->templateTypeReplacement[concatSymbolTree(typeInstTypes[i])]->toString() << std::endl; - //std::cout << "which is " << *origionalType->templateTypeReplacement[concatSymbolTree(typeInstTypes[i])] << std::endl; - unifyType(uninTypeInstTypes[i], *origionalType->templateTypeReplacement[concatSymbolTree(typeInstTypes[i])], templateTypeMap, typeMap); - } - - return; - } - throw "the inference just isn't good enough"; - } - throw "the inference just isn't good enough"; - } -} - -void ASTTransformation::unifyTemplateFunction(NodeTree* templateFunction, std::vector types, std::vector* templateInstantiationTypes, std::map typeMap) { - NodeTree* templateSyntaxTree = templateFunction->getDataRef()->valueType->templateDefinition; - std::vector*> templateParameters = getNodes("typed_parameter", templateSyntaxTree); - if (templateParameters.size() != types.size()) - return; - std::map templateTypeMap; - for (int i = 0; i < types.size(); i++) - unifyType(getNode("type", templateParameters[i]), types[i], &templateTypeMap, typeMap); - for (auto instantiationParam : getNodes("template_param", getNode("template_dec", templateSyntaxTree))) { - templateInstantiationTypes->push_back(templateTypeMap[concatSymbolTree(getNode("identifier", instantiationParam))].clone()); // gotta be careful of catching the traits in the concat - } -} - -//Lookup function for template functions. It has some extra concerns compared to function lookup, namely traits -NodeTree* ASTTransformation::templateFunctionLookup(NodeTree* scope, std::string lookup, std::vector* templateInstantiationTypes, std::vector types, std::map scopeTypeMap) { - std::map*, std::vector> templateInstantiationTypesPerFunction; - std::set*> mostFittingTemplates; - int bestNumTraitsSatisfied = -1; - auto possibleMatches = scopeLookup(scope, lookup); - std::cout << "Template Function instantiation has " << possibleMatches.size() << " possible matches." << std::endl; - int index = 1; - for (auto i : possibleMatches) { - if (i->getDataRef()->type != function) - continue; - //std::cout << "Possibility " << index++ << std::endl; - NodeTree* templateSyntaxTree = i->getDataRef()->valueType->templateDefinition; - if (!templateSyntaxTree) { - std::cout << "Not a template, skipping" << std::endl; - continue; - } - // We have the type map here because we might want to augment it with the typeMap from - // the current scope, which would happen if we're trying to instantiate a template member function - std::map typeMap = scopeTypeMap; - // If template instantiation was explicit, use those types. Otherwise, unify to find them - if (templateInstantiationTypes->size()) { - templateInstantiationTypesPerFunction[i] = *templateInstantiationTypes; - //std::cout << "passed in types" << std::endl; - }else{ - unifyTemplateFunction(i, types, &templateInstantiationTypesPerFunction[i], typeMap); - //std::cout << "unified types" << std::endl; - } - //std::cout << "TYPES ARE: "; - //for (Type *a : templateInstantiationTypesPerFunction[i]) - //std::cout << a->toString() << " : "; - //std::cout << std::endl; - auto nameTraitsPairs = makeTemplateNameTraitPairs(templateSyntaxTree->getChildren()[1]); - //Check if sizes match between the placeholder and actual template types - if (nameTraitsPairs.size() != templateInstantiationTypesPerFunction[i].size()) - continue; - - bool traitsEqual = true; - int typeIndex = 0; - int currentTraitsSatisfied = 0; - for (auto j : nameTraitsPairs) { - // error out if not subset, or if we're a pointer but should have traits - if (!subset(j.second, templateInstantiationTypesPerFunction[i][typeIndex]->traits) || (templateInstantiationTypesPerFunction[i][typeIndex]->getIndirection() && j.second.size())) { - traitsEqual = false; - std::cout << "Traits not a subset for " << j.first << " and " << templateInstantiationTypesPerFunction[i][typeIndex]->toString() << ": |"; - std::copy(j.second.begin(), j.second.end(), std::ostream_iterator(std::cout, " ")); - std::cout << "| vs |"; - std::copy(templateInstantiationTypesPerFunction[i][typeIndex]->traits.begin(), templateInstantiationTypesPerFunction[i][typeIndex]->traits.end(), std::ostream_iterator(std::cout, " ")); - std::cout << "|" << std::endl; - break; - } else { - //std::cout << "Traits ARE a subset for " << j.first << " and " << templateInstantiationTypesPerFunction[i][typeIndex]->toString() << ": "; - //std::copy(j.second.begin(), j.second.end(), std::ostream_iterator(std::cout, " ")); - //std::cout << " vs "; - //std::copy(templateInstantiationTypesPerFunction[i][typeIndex]->traits.begin(), templateInstantiationTypesPerFunction[i][typeIndex]->traits.end(), std::ostream_iterator(std::cout, " ")); - //std::cout << std::endl; - } - //As we go, build up the typeMap for when we transform the parameters for parameter checking - typeMap[j.first] = templateInstantiationTypesPerFunction[i][typeIndex]; - currentTraitsSatisfied += j.second.size(); - typeIndex++; - } - if (!traitsEqual) - continue; - - //std::vector*> functionParameters = slice(templateSyntaxTree->getChildren(), 2, -4, 2); //skip name, intervening commas, return type, and the code block - std::vector*> functionParameters = getNodes("typed_parameter", templateSyntaxTree->getChildren()); - std::cout << functionParameters.size() << " " << types.size() << std::endl; - if (functionParameters.size() != types.size()) - continue; - - bool parameterTypesMatch = true; - for (int j = 0; j < functionParameters.size(); j++) { - auto paramType = typeFromTypeNode(functionParameters[j]->getChildren()[2], scope, typeMap); - //std::cout << "Template param type: " << paramType->toString() << " : Needed Type: " << types[j].toString() << std::endl; - // use test_equality so we can pass false and not care about references - if (!paramType->test_equality(types[j], false)) { - parameterTypesMatch = false; - std::cout << "Not equal template param: " << paramType->toString() << " : Needed Type actual param: " << types[j].toString() << std::endl; - break; - } - } - if (!parameterTypesMatch) - continue; - //See if this is a better match than the current best - if (currentTraitsSatisfied > bestNumTraitsSatisfied) { - mostFittingTemplates.clear(); - //std::cout << "Function satisfying " << currentTraitsSatisfied << " beats previous " << bestNumTraitsSatisfied << std::endl; - bestNumTraitsSatisfied = currentTraitsSatisfied; - } else if (currentTraitsSatisfied < bestNumTraitsSatisfied) - continue; - mostFittingTemplates.insert(i); - //std::cout << "Current function fits, satisfying " << currentTraitsSatisfied << " traits" << std::endl; - } - if (!mostFittingTemplates.size()) { - std::cout << "No template functions fit for " << lookup << "("; - for (auto t : types) - std::cout << t.toString() + ", "; - std::cout << ")!" << std::endl; - std::cout << "in file " << getUpperTranslationUnit(scope)->getDataRef()->symbol.getName() << std::endl; - throw "No matching template functions"; - } else if (mostFittingTemplates.size() > 1) { - std::cout << "Multiple template functions fit with equal number of traits satisfied for " << lookup << "!" << std::endl; - throw "Multiple matching template functions"; - } - // Assign our most fitting instantiation types to what we were passed in - // if it was empty - if (templateInstantiationTypes->size() == 0) - *templateInstantiationTypes = templateInstantiationTypesPerFunction[*mostFittingTemplates.begin()]; - std::cout << *mostFittingTemplates.begin() << std::endl; - return *mostFittingTemplates.begin(); -} - -//Extract pairs of type names and traits -std::vector>> ASTTransformation::makeTemplateNameTraitPairs(NodeTree* templateNode) { - std::vector*> templateParams = slice(templateNode->getChildren(), 1, -2, 2); //Skip <, >, and interveaning commas - std::vector>> typePairs; - for (auto i : templateParams) { - if (i->getChildren().size() > 1) - typePairs.push_back(std::make_pair(concatSymbolTree(i->getChildren()[0]), parseTraits(i->getChildren()[1]))); - else - typePairs.push_back(std::make_pair(concatSymbolTree(i->getChildren()[0]), std::set())); - } - return typePairs; -} - -std::map ASTTransformation::makeTemplateFunctionTypeMap(NodeTree* templateNode, std::vector types, std::map scopeTypeMap) { - auto typePairs = makeTemplateNameTraitPairs(templateNode); - // we start with the scopeTypeMap because we want to combine - // them (this is for templated member functions of templated objects) - std::map typeMap = scopeTypeMap; - int typeIndex = 0; - std::cout << typePairs.size() << " " << types.size() << std::endl; - for (auto i : typePairs) { - typeMap[i.first] = types[typeIndex]; - //std::cout << "Mapping " << i.first << " to " << types[typeIndex]->toString() << std::endl; - typeIndex++; - } - return typeMap; -} - -NodeTree* ASTTransformation::generateThis(NodeTree* scope) { - // if we're looking for this, traverse up until we find the declaration of this object and assign it's type to this - NodeTree* trans; - for (trans = scope; trans->getDataRef()->type != type_def; trans = trans->getDataRef()->scope["~enclosing_scope"][0]); - auto possible_this = this_map.find(trans); // check to see if we've generated this this before - if (possible_this != this_map.end()) - return possible_this->second; - NodeTree* identifier = languageLevelReservedWords["this"][0]; - identifier = new NodeTree("identifier", identifier->getData()); - identifier->getDataRef()->valueType = trans->getDataRef()->valueType->clone(); - identifier->getDataRef()->valueType->increaseIndirection(); - identifier->getDataRef()->scope = trans->getDataRef()->scope; - this_map[trans] = identifier; - return identifier; -} - -// We need recursion protection -std::vector*> ASTTransformation::scopeLookup(NodeTree* scope, std::string lookup, bool includeModules) { - return scopeLookup(scope, lookup, includeModules, std::set*>()); -} - -std::vector*> ASTTransformation::scopeLookup(NodeTree* scope, std::string lookup, bool includeModules, std::set*> visited) { - //std::cout << "Scp]|[e looking up " << lookup << std::endl; - //std::cout << "current: " << scope->getDataRef()->toString() << std::endl; - //for (auto i : scope->getDataRef()->scope) - //std::cout << "\t" << i.first << std::endl; - //std::cout << i.first << " : " << i.second->toString() << std::endl; - // Don't visit this node again when looking for the smae lookup. Note that we don't prevent coming back for the scope operator, as that should be able to come back. - if (visited.find(scope) != visited.end()) - return std::vector*>(); - visited.insert(scope); - //We first check to see if it's one of the special reserved identifiers (only this, for now) and return early if it is. - auto LLElementIterator = languageLevelReservedWords.find(lookup); - if (LLElementIterator != languageLevelReservedWords.end()) { - //std::cout << "found it at language level as reserved word." << std::endl; - NodeTree* identifier = LLElementIterator->second[0]; - if (lookup == "this") { - identifier = generateThis(scope); - } - std::vector*> thingy; thingy.push_back(identifier); - return thingy; - } - std::vector*> matches; - // First, we check for scope operator (::) but only if occurs before a "<" as this would signal the beginning of a template instatiation inside type - // If we find it, we look up the left side of the :: and then use the resuts as the scope for looking up the right side, recursively. - size_t scopeOpPos = lookup.find("::"); - size_t angleBrktPos = lookup.find("<"); - if (scopeOpPos != std::string::npos && (angleBrktPos == std::string::npos || scopeOpPos < angleBrktPos)) { - //std::cout << "Has :: operator, doing left then right" << std::endl; - for (auto scopeMatch : scopeLookup(scope, strSlice(lookup, 0, scopeOpPos), true)) { - //std::cout << "Trying right side with found left side " << scopeMatch->getDataRef()->toString() << std::endl; - auto addMatches = scopeLookup(scopeMatch, strSlice(lookup, scopeOpPos+2, -1), includeModules); - matches.insert(matches.end(), addMatches.begin(), addMatches.end()); - } - return matches; - } - - std::map*>> scopeMap = scope->getDataRef()->scope; - auto possibleMatches = scopeMap.find(lookup); - if (possibleMatches != scopeMap.end()) { - for (auto i : possibleMatches->second) - if (includeModules || i->getName() != "translation_unit") - matches.push_back(i); - //std::cout << "Found " << possibleMatches->second.size() << " match(s) at " << scope->getDataRef()->toString() << std::endl; - } - // Add results from our enclosing scope, if it exists. - // If it doesn't we should be at the top of a translation unit, and we should check the scope of import statements. - auto enclosingIterator = scopeMap.find("~enclosing_scope"); - if (enclosingIterator != scopeMap.end()) { - std::vector*> upperResult = scopeLookup(enclosingIterator->second[0], lookup, includeModules, visited); - matches.insert(matches.end(), upperResult.begin(), upperResult.end()); - } else { - // Ok, let's iterate through and check for imports - for (auto child : scope->getChildren()) { - if (child->getDataRef()->type == import) { - auto importScope = child->getDataRef()->scope; - // Check if there is a match named explicily in the import's scope (i.e. looking for a and the import is import somefile: a;) - // If so, add it's members to our matches - auto importLookupItr = importScope.find(lookup); - if (importLookupItr != importScope.end()) { - auto addMatches = importLookupItr->second; - matches.insert(matches.end(), addMatches.begin(), addMatches.end()); - } - // Check if there is an uncionditional import to follow (i.e. import somefile: *;) - // If so, continue the search in that scope - auto importStarItr = importScope.find("*"); - if (importStarItr != importScope.end()) { - auto addMatches = scopeLookup(importStarItr->second[0], lookup, includeModules, visited); - matches.insert(matches.end(), addMatches.begin(), addMatches.end()); - } - } - } - } - return matches; -} - -// Find the translation unit that is the top of the passed in node -NodeTree* ASTTransformation::getUpperTranslationUnit(NodeTree* node) { - auto scope = node->getDataRef()->scope; - auto iter = scope.find("~enclosing_scope"); - while(iter != scope.end()) { - node = iter->second[0]; - scope = node->getDataRef()->scope; - iter = scope.find("~enclosing_scope"); - } - return node; -} - -//Create a type from a syntax tree. This can get complicated with templates -Type* ASTTransformation::typeFromTypeNode(NodeTree* typeNode, NodeTree* scope, std::map templateTypeReplacements) { - - int indirection = 0; - bool is_reference = false; - ValueType baseType; - NodeTree* typeDefinition = NULL; - std::set traits; - // if this is a reference, we also have to step down a level - if (typeNode->getChildren().size() && typeNode->getChildren().front()->getDataRef()->getValue() == "ref") { - is_reference = true; - } - // always step down below the ref level - typeNode = typeNode->getChildren().back(); - - std::string typeIn = concatSymbolTree(typeNode); - - // To counter this, for every indirection we step down a level - //while (typeIn[indirection] == '*') { - //since fun(*T):int gets transformed to *T:int, the text based way doesn't work anymore - while (typeNode->getChildren().size() && typeNode->getChildren().front()->getDataRef()->getValue() == "*") { - indirection++; - typeNode = typeNode->getChildren().back(); - } - std::string edited = strSlice(typeIn, indirection, -1); - if (edited == "void") - baseType = void_type; - else if (edited == "bool") - baseType = boolean; - else if (edited == "int") - baseType = integer; - else if (edited == "float") - baseType = floating; - else if (edited == "double") - baseType = double_percision; - else if (edited == "char") - baseType = character; - else if (typeNode->getChildren().size() && typeNode->getChildren()[0]->getDataRef()->getName() == "function_type") { - baseType = function_type; - std::vector types; - for (auto typeSyntaxNode : getNodes("type", typeNode->getChildren()[0]->getChildren())) - types.push_back(typeFromTypeNode(typeSyntaxNode, scope, templateTypeReplacements)); - return new Type(slice(types, 0, -2),types.back(), is_reference); - } else { - baseType = none; - - auto possibleMatches = scopeLookup(scope, edited); - if (possibleMatches.size()) { - // so the scope lookup can find things that aren't types. We could have an entirely differnt lookup function for them, - // but at this point (deep in the self-hosting process) I think it's better that I just prune out the ones that aren't types - // here - for (auto definition : possibleMatches) { - if (definition->getDataRef()->type == type_def || definition->getDataRef()->type == adt_def) { - typeDefinition = definition; - break; - } - } - traits = typeDefinition->getDataRef()->valueType->traits; - } - //So either this is an uninstatiated template class type, or this is literally a template type T, and we should get it from our - //templateTypeReplacements map. We try this first - if (templateTypeReplacements.find(edited) != templateTypeReplacements.end()) { - //std::cout << "Template type! (" << edited << ")" << std::endl; - Type* templateTypeReplacement = templateTypeReplacements[edited]->clone(); - templateTypeReplacement->modifyIndirection(indirection); - templateTypeReplacement->is_reference = is_reference; - return templateTypeReplacement; - } - //std::cout << edited << " was not found in templateTypeReplacements" << std::endl; - //std::cout << "templateTypeReplacements consists of : "; - //for (auto i : templateTypeReplacements) - //std::cout << i.first << " "; - //std::cout << std::endl; - - //std::cout << possibleMatches.size() << " " << typeNode->getChildren().size() << std::endl; - //if (typeNode->getChildren().size() > 1) - //std::cout << typeNode->getChildren()[1]->getDataRef()->getName() << std::endl; - //If not, we better instantiate it and then add it to the highest (not current) scope - if (possibleMatches.size() == 0 && typeNode->getChildren().size() > 1 && typeNode->getChildren()[1]->getData().getName() == "template_inst") { - //std::cout << "Template type: " << edited << " not yet instantiated" << std::endl; - - //We pull out the replacement types first so that we can choose the correct possibly overloaded template - std::vector*> templateParamInstantiationNodes = slice(typeNode->getChildren()[1]->getChildren(), 1, -2, 2); //same - std::vector templateParamInstantiationTypes; - std::string instTypeString = ""; - for (int i = 0; i < templateParamInstantiationNodes.size(); i++) { - Type* instType = typeFromTypeNode(templateParamInstantiationNodes[i], scope, templateTypeReplacements); - /******************************************************************************* - * WE RETURN EARLY IF ONE OF OUR REPLACEMENT INST TYPES IS TEMPLATE_TYPE_TYPE - * WE DO THIS BECAUSE WE CAN'T ACTUALLY INSTATNTIATE WITH THIS. - * THIS CAN HAPPEN IN THE FOLLOWING SITUATIONS. - * fun example(a:vec):T { return a.at(0); } - * etc - *******************************************************************************/ - if (instType->baseType == template_type_type) - return instType; - templateParamInstantiationTypes.push_back(instType); - instTypeString += (instTypeString == "") ? instType->toString(false) : "," + instType->toString(false); - } - - //Finish creating the new name for this instantiation - std::string classNameWithoutTemplate = concatSymbolTree(typeNode->getChildren()[0]); - std::string templateLookupName = classNameWithoutTemplate + "<" + instTypeString + ">"; - - // Recheck for prior definition here, now that we have the true name. - possibleMatches = scopeLookup(scope, templateLookupName); - if (possibleMatches.size()) { - typeDefinition = possibleMatches[0]; - traits = typeDefinition->getDataRef()->valueType->traits; - //std::cout << "Found already instantiated template of " << templateLookupName << " at second check" << std::endl; - } else { - //std::cout << "Did not find already instantiated template of " << templateLookupName << " at second check" << std::endl; - //Look up this template's plain definition. It's type has the syntax tree that we need to parse - NodeTree* templateDefinition = templateClassLookup(scope, concatSymbolTree(typeNode->getChildren()[0]), templateParamInstantiationTypes); - - std::string fullyInstantiatedName = templateDefinition->getDataRef()->symbol.getName() + "<" + instTypeString + ">"; - - NodeTree* templateSyntaxTree = templateDefinition->getDataRef()->valueType->templateDefinition; - //Create a new map of template type names to actual types. - std::vector*> templateParamPlaceholderNodes = slice(templateSyntaxTree->getChildren()[1]->getChildren(), 1, -2, 2); //Don't get beginning or end for < or >, skip commas in the middle - std::map newTemplateTypeReplacement; - for (int i = 0; i < templateParamInstantiationTypes.size(); i++) - newTemplateTypeReplacement[concatSymbolTree(templateParamPlaceholderNodes[i])] = templateParamInstantiationTypes[i]; - - typeDefinition = new NodeTree("type_def", ASTData(type_def, Symbol(fullyInstantiatedName, true, fullyInstantiatedName))); - traits = templateDefinition->getDataRef()->valueType->traits; // We have the same traits as the template definition - Type* selfType = new Type(typeDefinition, traits); // Type is self-referential since this is the definition. - typeDefinition->getDataRef()->valueType = selfType; - - //Note that we're adding to the current top scope. This makes it more efficient by preventing multiple instantiation and should not cause any problems - //It also makes sure it gets generated in the right place - //std::cout << "Adding to top scope and template's origional scope with fullyInstantiatedName " << fullyInstantiatedName << std::endl; - //topScope->getDataRef()->scope[fullyInstantiatedName].push_back(typeDefinition); - //topScope->addChild(typeDefinition); Add this object the the highest scope's - - // Actually, let's just put it in the scope of the origional template, which should work just fine under the new scoping rules and will ACTUALLY prevent multiple instantiation. - // At least, hopefully it will if we also check it's scope for it. Which I think it should be anyway. Yeah, I think it should work. - //std::cout << "Adding to template top scope and template's origional scope with fullyInstantiatedName " << fullyInstantiatedName << std::endl; - auto templateTopScope = getUpperTranslationUnit(templateDefinition); - //std::cout << "UPPER TRANS for " << fullyInstantiatedName << " " << templateTopScope->getDataRef()->toString() << std::endl; - templateTopScope->getDataRef()->scope[fullyInstantiatedName].push_back(typeDefinition); - templateTopScope->addChild(typeDefinition); // Add this object the the highest scope's - - //NodeTree* templateHighScope = templateDefinition->getDataRef()->scope["~enclosing_scope"][0]; - //if (topScope != templateHighScope) - //templateHighScope->getDataRef()->scope[fullyInstantiatedName].push_back(typeDefinition); - // We put it in the scope of the template so that it can find itself (as it's scope is its template definition) - addToScope(fullyInstantiatedName, typeDefinition, templateDefinition); - //Note that the instantiated template's scope is the template's definition. - addToScope("~enclosing_scope", templateDefinition, typeDefinition); - - // We only partially instantiate templates no matter what now - // They are all fully instantiated in the loop at the end of the 4th pass - // This is done for code simplicity and so that that loop can do template class methods - // that instantiate other templates that instantiate other templates while still retaining the - // deferred method allowing us to correctly instantiate multiple levels of mututally recursive definitions. - selfType->templateDefinition = templateSyntaxTree; //We're going to still need this when we finish instantiating - selfType->templateTypeReplacement = newTemplateTypeReplacement; //Save the types for use when this is fully instantiated in pass 4 - //for (auto daPair : selfType->templateTypeReplacement) { - //std::cout << " BREAK HERE " << daPair.first << " : " << daPair.second->toString() << std::endl; - //if (daPair.second == NULL) - //std::cout << " BREAK HERE " << std::endl; - //} - secondPassDoClassInsides(typeDefinition, templateSyntaxTree->getChildren(), newTemplateTypeReplacement); //Use these types when instantiating data members - } - } else if (possibleMatches.size() == 0) { - std::cout << "Could not find type " << edited << ", returning NULL" << std::endl; - return NULL; - } else { - //std::cout << "Type: " << edited << " already instantiated with " << typeDefinition << ", will be " << Type(baseType, typeDefinition, indirection, is_reference, traits).toString() << std::endl; - } - } - Type* toReturn = new Type(baseType, typeDefinition, indirection, is_reference, traits); - //std::cout << "Returning type " << toReturn->toString() << std::endl; - return toReturn; -} - -// So we want to be able to call this with either the children which is one name and one template thingy (func), or just the name (func), or even with just -// a string as the name if, for example, we're generating the name from an operator overload (which we do) (operator+) -NodeTree* ASTTransformation::tryToFindOrInstantiateFunctionTemplate(std::string functionName, NodeTree* scope, std::vector types, std::map templateTypeReplacements) { - try { - return findOrInstantiateFunctionTemplate(functionName, std::vector*>(), scope, types, templateTypeReplacements); - } catch (const char *ex) { - return nullptr; - } -} -NodeTree* ASTTransformation::findOrInstantiateFunctionTemplate(std::vector*> children, NodeTree* scope, std::vector types, std::map templateTypeReplacements) { - return findOrInstantiateFunctionTemplate("", children, scope, types, templateTypeReplacements); -} -NodeTree* ASTTransformation::findOrInstantiateFunctionTemplate(std::string functionName, NodeTree* scope, std::vector types, std::map templateTypeReplacements) { - return findOrInstantiateFunctionTemplate(functionName, std::vector*>(), scope, types, templateTypeReplacements); -} -NodeTree* ASTTransformation::findOrInstantiateFunctionTemplate(std::string functionName, std::vector*> children, NodeTree* scope, std::vector types, std::map templateTypeReplacements) { - //First look to see if we can find this already instantiated - //std::cout << "\n\nFinding or instantiating templated function\n\n" << std::endl; - if (children.size()) - functionName = concatSymbolTree(children[0]); - std::string fullyInstantiatedName; - std::string scopelessFullyInstantiatedName; - std::vector templateActualTypes; - NodeTree* templateDefinition = NULL; - - // If this is a templated member function, we should also add this function to the object - NodeTree* objectForTemplateMethod = NULL; - // Ok, our scope might have a typeMap if we are inside a templated object and are looking - // for a templated member function - std::map scopeTypeMap; - if (scope->getDataRef()->valueType && scope->getDataRef()->valueType->typeDefinition - && scope->getDataRef()->valueType->typeDefinition->getDataRef()->valueType) { - objectForTemplateMethod = scope->getDataRef()->valueType->typeDefinition; - scopeTypeMap = objectForTemplateMethod->getDataRef()->valueType->templateTypeReplacement; - } - - // Are we supposed to infer our instantiation, or not? If we have only one child we're inferring as we don't - // have the actual instantiation part. If do have the instantiation part, then we'll use that. - // Note that as a part o finferring the instantiation we already find the template, so we make that - // condtitional too (templateDefinition) - std::string instTypeString = ""; - if (children.size() <= 1) { - // templateFunctionLookup adds the actual types to templateActualTypes if it's currently empty - templateDefinition = templateFunctionLookup(scope, functionName, &templateActualTypes, types, scopeTypeMap); - for (auto instType : templateActualTypes) - instTypeString += (instTypeString == "" ? instType->toString() : "," + instType->toString()); - } else { - auto unsliced = children[1]->getChildren(); - std::vector*> templateParamInstantiationNodes = slice(unsliced, 1 , -2, 2);//skip <, >, and commas - for (int i = 0; i < templateParamInstantiationNodes.size(); i++) { - Type* instType = typeFromTypeNode(templateParamInstantiationNodes[i], scope, templateTypeReplacements); - instTypeString += (instTypeString == "" ? instType->toString() : "," + instType->toString()); - templateActualTypes.push_back(instType); - } - //std::cout << "Size: " << templateParamInstantiationNodes.size() << std::endl; - } - fullyInstantiatedName = functionName + "<" + instTypeString + ">"; - //std::cout << "Looking for " << fullyInstantiatedName << std::endl; - //std::cout << "Types are : "; - //for (auto i : types) - //std::cout << " " << i.toString(); - //std::cout << std::endl; - - NodeTree* instantiatedFunction = functionLookup(scope, fullyInstantiatedName, types); - //If it already exists, return it - if (instantiatedFunction) { - //std::cout << fullyInstantiatedName << " already exists! Returning" << std::endl; - return instantiatedFunction; - } else { - instantiatedFunction = functionLookup(topScope, fullyInstantiatedName, types); - if (instantiatedFunction) { - //std::cout << fullyInstantiatedName << "already exists! Found in TopScope" << std::endl; - return instantiatedFunction; - } - //std::cout << fullyInstantiatedName << " does NOT exist" << std::endl; - } - - //Otherwise, we're going to instantiate it - //Find the template definitions - // templateFunctionLookup adds the actual types to templateActualTypes if it's currently empty - // by here, it's not as either we had the instantiation already or we figured out out before - // and are not actually doing this call - if (!templateDefinition) - templateDefinition = templateFunctionLookup(scope, functionName, &templateActualTypes, types, scopeTypeMap); - if (templateDefinition == NULL) { - //std::cout << functionName << " search turned up null, returing null" << std::endl; - return NULL; - } - scopelessFullyInstantiatedName = templateDefinition->getDataRef()->symbol.getName() + "<" + instTypeString + ">"; - - NodeTree* templateSyntaxTree = templateDefinition->getDataRef()->valueType->templateDefinition; - // Makes a map between the names of the template placeholder parameters and the provided types - std::map newTemplateTypeReplacement = makeTemplateFunctionTypeMap(templateSyntaxTree->getChildren()[1], templateActualTypes, scopeTypeMap); - - std::vector*> templateChildren = templateSyntaxTree->getChildren(); - //for (int i = 0; i < templateChildren.size(); i++) - //std::cout << ", " << i << " : " << templateChildren[i]->getDataRef()->getName(); - //std::cout << std::endl; - - // return type should be looked up in template's scope - auto returnTypeNode = getNode("type", getNode("typed_return", templateChildren)); // if null, the typed_return had no children and we're supposed to automatically do a void type - auto returnType = returnTypeNode ? typeFromTypeNode(returnTypeNode, templateDefinition, newTemplateTypeReplacement): new Type(void_type); - instantiatedFunction = new NodeTree("function", ASTData(function, Symbol(scopelessFullyInstantiatedName, true), returnType)); - addToScope("~enclosing_scope", templateDefinition->getDataRef()->scope["~enclosing_scope"][0], instantiatedFunction); - addToScope(scopelessFullyInstantiatedName, instantiatedFunction, templateDefinition->getDataRef()->scope["~enclosing_scope"][0]); - templateDefinition->getDataRef()->scope["~enclosing_scope"][0]->addChild(instantiatedFunction); // Add this object the the highest scope's - - //std::cout << "About to do children of " << functionName << " to " << fullyInstantiatedName << std::endl; - - std::set skipChildren; - auto parameters = transformChildren(getNodes("typed_parameter", templateSyntaxTree->getChildren()), skipChildren, instantiatedFunction, std::vector(), false, newTemplateTypeReplacement); - instantiatedFunction->addChildren(parameters); - // update type with actual type - instantiatedFunction->getDataRef()->valueType = new Type(mapNodesToTypePointers(parameters), instantiatedFunction->getDataRef()->valueType); - instantiatedFunction->addChild(transform(getNode("statement", templateSyntaxTree->getChildren()), instantiatedFunction, std::vector(), false, newTemplateTypeReplacement)); - - //std::cout << "Fully Instantiated function " << functionName << " to " << fullyInstantiatedName << std::endl; - return instantiatedFunction; -} - -NodeTree* ASTTransformation::addToScope(std::string name, NodeTree* toAdd, NodeTree* addTo) { - addTo->getDataRef()->scope[name].push_back(toAdd); - return addTo; -} - - -//Extract types from already transformed nodes -std::vector mapNodesToTypePointers(std::vector*> nodes) { - std::vector types; - for (auto i : nodes) { - //std::cout << i->getDataRef()->toString() << std::endl; - types.push_back((i->getDataRef()->valueType)); - } - return types; -} - -//Extract types from already transformed nodes -std::vector mapNodesToTypes(std::vector*> nodes) { - std::vector types; - for (auto i : nodes) { - //std::cout << i->getDataRef()->toString() << std::endl; - types.push_back(*(i->getDataRef()->valueType)); - } - return types; -} diff --git a/deprecated_compiler/src/CCodeTriple.cpp b/deprecated_compiler/src/CCodeTriple.cpp deleted file mode 100644 index c73066e..0000000 --- a/deprecated_compiler/src/CCodeTriple.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include "CCodeTriple.h" - -CCodeTriple::CCodeTriple(std::string pre, std::string val, std::string post) { - preValue = pre; - value = val; - postValue = post; -} - -CCodeTriple::CCodeTriple(std::string val) { - value = val; -} -CCodeTriple::CCodeTriple(const char* val) { - value = val; -} - -CCodeTriple::CCodeTriple() { -} - -CCodeTriple::~CCodeTriple() { -} - -std::string CCodeTriple::oneString(bool endValue) { - return preValue + value + (endValue ? ";" : "") + postValue; -} - -CCodeTriple & CCodeTriple::operator=(const CCodeTriple &rhs) { - preValue = rhs.preValue; - value = rhs.value; - postValue = rhs.postValue; - return *this; -} - -CCodeTriple & CCodeTriple::operator+=(const CCodeTriple &rhs) { - preValue += rhs.preValue; - //preValue = rhs.preValue + preValue; - value += rhs.value; - postValue = rhs.postValue + postValue; - return *this; -} - -CCodeTriple operator+(const CCodeTriple &a, const CCodeTriple &b) { - return CCodeTriple(a.preValue + b.preValue, a.value + b.value, b.postValue + a.postValue); - //return CCodeTriple(b.preValue + a.preValue, a.value + b.value, b.postValue + a.postValue); -} - diff --git a/deprecated_compiler/src/CGenerator.cpp b/deprecated_compiler/src/CGenerator.cpp deleted file mode 100644 index 928f6f4..0000000 --- a/deprecated_compiler/src/CGenerator.cpp +++ /dev/null @@ -1,1390 +0,0 @@ -#include "CGenerator.h" - -#define CLEAR_SCREEN "\033[2J\033[1;1H" -#define BOLD_GREEN "\033[1m\033[32m" -#define RESET_TXT "\033[0m" - -CGenerator::CGenerator() : generatorString("__C__") { - tabLevel = 0; - id = 0; - function_header = "fun_"; - functionTypedefString = ""; - functionTypedefStringPre = ""; -} -CGenerator::~CGenerator() { -} - -// Note the use of std::pair to hold two strings - the running string for the header file and the running string for the c file. -int CGenerator::generateCompSet(std::map*> ASTs, std::string outputName) { - //Generate an entire set of files - std::string buildString = "#!/bin/sh\ncc -g -O3 -std=c99 "; - std::cout << "\n\n =====GENERATE PASS===== \n\n" << std::endl; - std::cout << "\n\nGenerate pass for: " << outputName << std::endl; - buildString += outputName + ".c "; - //std::ofstream outputCFile, outputHFile; - std::ofstream outputCFile; - outputCFile.open(outputName + "/" + outputName + ".c"); - //outputHFile.open(outputName + "/" + outputName + ".h"); - //if (outputCFile.is_open() || outputHFile.is_open()) { - if (outputCFile.is_open()) { - // Prequel common to all files - auto chPair = generateTranslationUnit(outputName, ASTs); - //outputHFile << "#include \n#include \n#include \n" << chPair.first; - //outputCFile << "#include \"" + outputName + ".h\"\n\n" << chPair.second; - outputCFile << "#include \n#include \n#include \n" << chPair.first << "\n\n// C FILE BEGIN\n\n" << chPair.second; - } else { - std::cerr << "Cannot open file " << outputName << ".c/h" << std::endl; - } - outputCFile.close(); - //outputHFile.close(); - - buildString += linkerString; - buildString += "-o " + outputName; - std::ofstream outputBuild; - std::string scriptName = split(outputName, '/').back() + ".sh"; - outputBuild.open(outputName + "/" + scriptName); - outputBuild << buildString; - outputBuild.close(); - std::cout << CLEAR_SCREEN; - std::cout << BOLD_GREEN << "KRAKEN COMPILER DONE, CALLING C COMPILER" << RESET_TXT << std::endl; - return ssystem("cd " + outputName + "/; sh " + scriptName); -} - -std::string CGenerator::tabs() { - std::string returnTabs; - for (int i = 0; i < tabLevel; i++) - returnTabs += "\t"; - return returnTabs; -} - -std::string CGenerator::getID() { - return intToString(id++); -} - -std::string CGenerator::generateTypeStruct(NodeTree* from) { - auto data = from->getData(); - auto children = from->getChildren(); - //std::string structString, enumString, functionString; - std::string structString, enumString; - std::string enumName = "__enum_dummy_" + prefixIfNeeded(scopePrefix(from), CifyName(data.symbol.getName())+"__"); - enumString = "enum " + enumName + " {\n"; - structString = "struct __struct_dummy_"; - structString += prefixIfNeeded(scopePrefix(from), CifyName(data.symbol.getName())+"__") + " {\n"; - if (data.type == adt_def) { - structString = structString + " enum " + enumName + " flag;\n union { \n"; - tabLevel++; - } - tabLevel++; - - for (auto child : children) { - //std::cout << children[i]->getName() << std::endl; - if (child->getName() != "function") { - if (data.type == adt_def) { - // if this is not a plain no-data adt member (so if it is a primitive or doesn't have a reference back to) - // wait a sec, this is easier - if ( child->getDataRef()->valueType->typeDefinition != from) - structString += tabs() + ValueTypeToCType(child->getDataRef()->valueType, prefixIfNeeded(scopePrefix(child), child->getDataRef()->symbol.getName())) + "; /* adt data member */\n"; - } else { - structString += tabs() + generate(child, nullptr).oneString() + "\n"; - } - //enumString += tabs() + data.symbol.getName() + "__" + generate(child, nullptr).oneString() + (data.type == adt_def ? ",\n" : "\n"); - // this was prefixing when it shouldn't have, since we prefix with the name of the adt anyway. Probs the entire thing should be prefixed, but we'll cross that bridge when we come to it - enumString += tabs() + data.symbol.getName() + "__" + child->getDataRef()->symbol.getName() + (data.type == adt_def ? ",\n" : "\n"); - } - } - tabLevel--; - if (data.type == adt_def) { - //structString += "} data; /*end union*/ \n"; - tabLevel--; - structString += " }; /*end union*/\n};"; - } else { - structString += "};"; - } - enumString += "};\n"; - if (data.type == adt_def) - return enumString + structString; - return structString; -} - -// This method recurseivly generates all aliases of some definition -std::string CGenerator::generateAliasChains(std::map*> ASTs, NodeTree* definition) { - std::string output; - for (auto trans : ASTs) { - for (auto i = trans.second->getDataRef()->scope.begin(); i != trans.second->getDataRef()->scope.end(); i++) { - for (auto declaration : i->second) { - auto declarationData = declaration->getDataRef(); - if (declarationData->type == type_def - && declarationData->valueType->typeDefinition != declaration - && declarationData->valueType->typeDefinition == definition) { - output += "typedef " + - prefixIfNeeded(scopePrefix(definition), CifyName(definition->getDataRef()->symbol.getName())) + " " + - prefixIfNeeded(scopePrefix(declaration), CifyName(declarationData->symbol.getName())) + ";\n"; - // Recursively add the ones that depend on this one - output += generateAliasChains(ASTs, declaration); - } - } - } - } - return output; -} - -bool CGenerator::isUnderNodeWithType(NodeTree* from, ASTType type) { - auto scope = from->getDataRef()->scope; - auto upper = scope.find("~enclosing_scope"); - if (upper != scope.end()) { - if (upper->second[0]->getDataRef()->type == type) - return true; - return isUnderNodeWithType(upper->second[0], type); - } - return false; -} - -bool CGenerator::isUnderTranslationUnit(NodeTree* from, NodeTree* node) { - auto scope = from->getDataRef()->scope; - for (auto i : scope) - for (auto j : i.second) - if (j == node) - return true; - - auto upper = scope.find("~enclosing_scope"); - if (upper != scope.end()) - return isUnderTranslationUnit(upper->second[0], node); - return false; -} - -NodeTree* CGenerator::highestScope(NodeTree* node) { - auto it = node->getDataRef()->scope.find("~enclosing_scope"); - while (it != node->getDataRef()->scope.end()) { - node = it->second[0]; - it = node->getDataRef()->scope.find("~enclosing_scope"); - } - return node; -} - -// We do translation units in their own function so they can do the pariwise h/c stuff and regualr in function body generation does not -std::pair CGenerator::generateTranslationUnit(std::string name, std::map*> ASTs) { - // We now pass in the entire map of ASTs and loop through them so that we generate out into a single file - std::string cOutput, hOutput; - // Ok, so we've got to do this in passes to preserve mututally recursive definitions. - // - // First Pass: All classes get "struct dummy_thing; typedef struct dummy_thing thing;". - // Also, other typedefs follow after their naming. - // Second Pass: All top level variable declarations - // Third Pass: Define all actual structs of a class, in correct order (done with posets) - // Fourth Pass: Declare all function prototypes (as functions may be mutually recursive too). - // (this includes object methods) - // Fifth Pass: Define all functions (including object methods). - - // However, most of these do not actually have to be done as separate passes. First, second, fourth, and fifth - // are done simultanously, but append to different strings that are then concatinated properly, in order. - - std::string importIncludes = "/**\n * Import Includes\n */\n\n"; - std::string topLevelCPassthrough = "/**\n * Top Level C Passthrough\n */\n\n"; - std::string variableExternDeclarations = "/**\n * Extern Variable Declarations \n */\n\n"; - std::string plainTypedefs = "/**\n * Plain Typedefs\n */\n\n"; - std::string variableDeclarations = "/**\n * Variable Declarations \n */\n\n"; - std::string classStructs = "/**\n * Class Structs\n */\n\n"; - std::string functionPrototypes = "/**\n * Function Prototypes\n */\n\n"; - std::string functionDefinitions = "/**\n * Function Definitions\n */\n\n"; - // There also exists functionTypedefString which is a member variable that keeps - // track of utility typedefs that allow our C type generation to be more sane - // it is emitted in the h file right before functionPrototypes - - - Poset*> typedefPoset; - for (auto trans : ASTs) { - auto children = trans.second->getChildren(); - for (int i = 0; i < children.size(); i++) { - if (children[i]->getDataRef()->type == type_def) { - // If we're an alias type, continue. We handle those differently - if (children[i]->getDataRef()->valueType->typeDefinition != children[i]) - continue; - - typedefPoset.addVertex(children[i]); // We add this definition by itself just in case there are no dependencies. - // If it has dependencies, there's no harm in adding it here - // Go through every child in the class looking for declaration statements. For each of these that is not a primitive type - // we will add a dependency from this definition to that definition in the poset. - std::vector*> classChildren = children[i]->getChildren(); - for (auto j : classChildren) { - if (j->getDataRef()->type == declaration_statement) { - Type* decType = j->getChildren()[0]->getDataRef()->valueType; // Type of the declaration - if (decType->typeDefinition && decType->getIndirection() == 0) // If this is a custom type and not a pointer - typedefPoset.addRelationship(children[i], decType->typeDefinition); // Add a dependency - } - } - } else if (children[i]->getDataRef()->type == adt_def) { - typedefPoset.addVertex(children[i]); // We add this definition by itself just in case there are no dependencies. - std::vector*> adtChildren = children[i]->getChildren(); - for (auto j : adtChildren) { - if (j->getDataRef()->type == identifier) { - Type* decType = j->getDataRef()->valueType; // Type of the declaration - if (decType->typeDefinition == children[i]) - continue; - if (decType->typeDefinition && decType->getIndirection() == 0) // If this is a custom type and not a pointer - typedefPoset.addRelationship(children[i], decType->typeDefinition); // Add a dependency - } - } - } - } - } - //Now generate the typedef's in the correct, topological order - for (NodeTree* i : typedefPoset.getTopoSort()) - classStructs += generateTypeStruct(i) + "\n"; - - // Declare everything in translation unit scope here (now for ALL translation units). (allows stuff from other files, automatic forward declarations) - // Also, everything in all of the import's scopes - // Also c passthrough - for (auto trans : ASTs) { - // First go through and emit all the passthroughs, etc - for (auto i : trans.second->getChildren()) { - if (i->getDataRef()->type == if_comp) - topLevelCPassthrough += generate(i, nullptr).oneString(); - } - - for (auto i = trans.second->getDataRef()->scope.begin(); i != trans.second->getDataRef()->scope.end(); i++) { - for (auto declaration : i->second) { - std::vector*> decChildren = declaration->getChildren(); - ASTData declarationData = declaration->getData(); - switch(declarationData.type) { - case identifier: - { - auto parent = declaration->getDataRef()->scope["~enclosing_scope"][0]; - if (parent->getChildren().size() == 1) - variableDeclarations += ValueTypeToCType(declarationData.valueType, prefixIfNeeded(scopePrefix(declaration), declarationData.symbol.getName())) + "; /*identifier*/\n"; - else - variableDeclarations += ValueTypeToCType(declarationData.valueType, generate(parent->getChildren()[0], nullptr, true, nullptr).oneString()) + " = " + generate(parent->getChildren()[1], nullptr, true, nullptr).oneString() + ";"; - variableExternDeclarations += "extern " + ValueTypeToCType(declarationData.valueType, declarationData.symbol.getName()) + "; /*extern identifier*/\n"; - break; - } - case function: - { - if (declarationData.valueType->baseType == template_type) - functionPrototypes += "/* template function " + declarationData.symbol.toString() + " */\n"; - else if (decChildren.size() == 0) //Not a real function, must be a built in passthrough - functionPrototypes += "/* built in function: " + declarationData.symbol.toString() + " */\n"; - else { - std::string nameDecoration, parameters; - if (declarationData.closedVariables.size()) - parameters += closureStructType(declarationData.closedVariables) + "*"; - for (int j = 0; j < decChildren.size()-1; j++) { - if (j > 0 || declarationData.closedVariables.size() ) - parameters += ", "; - parameters += ValueTypeToCType(decChildren[j]->getData().valueType, generate(decChildren[j], nullptr).oneString()); - nameDecoration += "_" + ValueTypeToCTypeDecoration(decChildren[j]->getData().valueType); - } - std::string funName = (declarationData.symbol.getName() == "main") ? "main" : - function_header + prefixIfNeeded(scopePrefix(declaration), CifyName(declarationData.symbol.getName() + nameDecoration)); - functionPrototypes += "\n" + ValueTypeToCType(declarationData.valueType->returnType, funName) + "(" + parameters + "); /*func*/\n"; - // generate function - //std::cout << "Generating " << prefixIfNeeded(scopePrefix(declaration), CifyName(declarationData.symbol.getName())) << std::endl; - functionDefinitions += generate(declaration, nullptr).oneString(); - } - } - break; - case type_def: - //type - plainTypedefs += "/*typedef " + declarationData.symbol.getName() + " */\n"; - - if (declarationData.valueType->baseType == template_type) { - plainTypedefs += "/* non instantiated template " + declarationData.symbol.getName() + " */"; - } else if (declarationData.valueType->typeDefinition != declaration) { - if (declarationData.valueType->typeDefinition) - continue; // Aliases of objects are done with the thing it alises - // Otherwise, we're actually a renaming of a primitive, can generate here - plainTypedefs += "typedef " + ValueTypeToCType(declarationData.valueType, - prefixIfNeeded(scopePrefix(declaration), CifyName(declarationData.symbol.getName()))) + ";\n"; - plainTypedefs += generateAliasChains(ASTs, declaration); - } else { - plainTypedefs += "typedef struct __struct_dummy_" + - prefixIfNeeded(scopePrefix(declaration), CifyName(declarationData.symbol.getName()) + "__") + " " + - prefixIfNeeded(scopePrefix(declaration), CifyName(declarationData.symbol.getName())) + ";\n"; - functionPrototypes += "/* Method Prototypes for " + declarationData.symbol.getName() + " */\n"; - // We use a seperate string for this because we only include it if this is the file we're defined in - std::string objectFunctionDefinitions = "/* Method Definitions for " + declarationData.symbol.getName() + " */\n"; - for (int j = 0; j < decChildren.size(); j++) { - //std::cout << decChildren[j]->getName() << std::endl; - if (decChildren[j]->getName() == "function" - && decChildren[j]->getDataRef()->valueType->baseType != template_type) //If object method and not template - objectFunctionDefinitions += generateObjectMethod(declaration, decChildren[j], &functionPrototypes) + "\n"; - } - // Add all aliases to the plain typedefs. This will add any alias that aliases to this object, and any alias that aliases to that, and so on - plainTypedefs += generateAliasChains(ASTs, declaration); - functionPrototypes += "/* Done with " + declarationData.symbol.getName() + " */\n"; - // include methods - functionDefinitions += objectFunctionDefinitions + "/* Done with " + declarationData.symbol.getName() + " */\n"; - } - break; - case adt_def: - { - plainTypedefs += "typedef struct __struct_dummy_" + - prefixIfNeeded(scopePrefix(declaration), CifyName(declarationData.symbol.getName()) + "__") + " " + - prefixIfNeeded(scopePrefix(declaration), CifyName(declarationData.symbol.getName())) + ";\n"; - for (auto child : decChildren) { - if (child->getName() == "function") { - std::string orig_fun_name = child->getDataRef()->symbol.getName(); - std::string nameDecoration; - for (Type *paramType : child->getDataRef()->valueType->parameterTypes) - nameDecoration += "_" + ValueTypeToCTypeDecoration(paramType); - std::string fun_name = "fun_" + declarationData.symbol.getName() + "__" + CifyName(orig_fun_name + nameDecoration); - std::string first_param; - if (orig_fun_name == "operator==" || orig_fun_name == "operator!=" || orig_fun_name == "copy_construct" || orig_fun_name == "operator=" - || orig_fun_name == "destruct") { - first_param = ValueTypeToCType(declarationData.valueType->withIncreasedIndirectionPtr(), "this"); - } - bool has_param = child->getDataRef()->valueType->parameterTypes.size(); - std::string first_part = "\n" + ValueTypeToCType(child->getDataRef()->valueType->returnType, fun_name) + "(" + first_param + - (has_param ? (first_param != "" ? ", " : "") + ValueTypeToCType(child->getDataRef()->valueType->parameterTypes[0], "in") : "") + ")"; - functionPrototypes += first_part + "; /*adt func*/\n"; - functionDefinitions += first_part + "{ /*adt func*/\n"; - if (orig_fun_name == "operator==") { - functionDefinitions += " /* equality woop woop */\n"; - functionDefinitions += " bool equal = true;\n"; - functionDefinitions += " if (this->flag != in->flag) equal = false;\n"; - - for (auto child : decChildren) { - if (child->getName() != "function" && child->getDataRef()->valueType->typeDefinition != declaration) { - std::string option_name = child->getDataRef()->symbol.getName(); - std::string prefixed_option_name = prefixIfNeeded(scopePrefix(declaration),option_name); - functionDefinitions += " else if (this->flag == " + declarationData.symbol.getName() + "__" + option_name + ") {\n"; - NodeTree* method = nullptr; - if ((method = getMethod(child->getDataRef()->valueType, "operator==", std::vector{*child->getDataRef()->valueType}))) { - bool is_reference = method->getDataRef()->valueType->parameterTypes[0]->is_reference; - - auto itemTypeVector = std::vector{child->getDataRef()->valueType->withIncreasedIndirection()}; - bool need_temporary = !is_reference && getMethod(child->getDataRef()->valueType, "copy_construct", itemTypeVector); - if (need_temporary) { - functionDefinitions += " " + ValueTypeToCType(child->getDataRef()->valueType, "copy_constructTemporary") + ";\n"; - functionDefinitions += " " + generateMethodIfExists(child->getDataRef()->valueType, "copy_construct", - "©_constructTemporary, &in->" + prefixed_option_name, itemTypeVector) + ";\n"; - } - - std::string otherValue = (is_reference ? "&" : "") + (need_temporary ? "copy_constructTemporary" : "in->" + prefixed_option_name); - functionDefinitions += " equal = " + generateMethodIfExists(child->getDataRef()->valueType, "operator==", - "&this->" + prefixed_option_name + ", " + otherValue, - std::vector{*child->getDataRef()->valueType}) + ";\n"; - // Remember, we don't destruct copy_constructTemporary because the function will do that - functionDefinitions += "}\n"; - } else { - // if we're an object type but don't define an equality function (or, as is a current bug, that function is a template) - // we just say always false/unequal - if (child->getDataRef()->valueType->typeDefinition) - functionDefinitions += " equal = false;\n}\n"; - else - functionDefinitions += " equal = this->" + prefixed_option_name + " == in->" + prefixed_option_name + ";\n}\n"; - } - } - } - functionDefinitions += " return equal;\n"; - } else if (orig_fun_name == "operator!=") { - functionDefinitions += " /* inequality woop woop */\n"; - std::string adtName = declarationData.symbol.getName(); - - functionDefinitions += " bool equal = !fun_" + adtName + "__" + CifyName("operator==") + "_" + adtName + "_space__div__star_ref_star__div__space__star_(this, in);\n"; - functionDefinitions += " return equal;\n"; - } else if (orig_fun_name == "operator=") { - functionDefinitions += "/* wopo assignment */\n"; - auto adtType = declaration->getDataRef()->valueType; - functionDefinitions += " " + generateMethodIfExists(adtType, "destruct", - "this", std::vector()) + ";\n"; - functionDefinitions += " " + generateMethodIfExists(adtType, "copy_construct", - "this, in", std::vector{adtType->withIncreasedIndirection()}) + ";\n"; - } else if (orig_fun_name == "copy_construct") { - functionDefinitions += " /* copy_construct woop woop */\n"; - functionDefinitions += " this->flag = in->flag;\n"; - std::string elsePrefix = ""; - for (auto child : decChildren) { - if (child->getName() != "function" && child->getDataRef()->valueType->typeDefinition != declaration) { - std::string option_name = child->getDataRef()->symbol.getName(); - std::string prefixed_option_name = prefixIfNeeded(scopePrefix(declaration),option_name); - functionDefinitions += " " + elsePrefix + " if (in->flag == " + declarationData.symbol.getName() + "__" + option_name + ") {\n"; - elsePrefix = "else"; - NodeTree* method = nullptr; - auto itemTypeVector = std::vector{child->getDataRef()->valueType->withIncreasedIndirection()}; - if ((method = getMethod(child->getDataRef()->valueType, "copy_construct", itemTypeVector))) { - functionDefinitions += " " + generateMethodIfExists(child->getDataRef()->valueType, "copy_construct", - "&this->" + prefixed_option_name + ", &in->" + prefixed_option_name, itemTypeVector) + ";\n"; - } else { - functionDefinitions += "this->" + prefixed_option_name + " = in->" + prefixed_option_name + ";\n"; - } - functionDefinitions += " }\n"; - } - } - } else if (orig_fun_name == "destruct") { - functionDefinitions += " /* destruct woop woop */\n"; - std::string elsePrefix = ""; - for (auto child : decChildren) { - if (child->getName() != "function" && child->getDataRef()->valueType->typeDefinition != declaration) { - std::string option_name = child->getDataRef()->symbol.getName(); - std::string prefixed_option_name = prefixIfNeeded(scopePrefix(child),option_name); - functionDefinitions += " " + elsePrefix + " if (this->flag == " + declarationData.symbol.getName() + "__" + option_name + ") {\n"; - elsePrefix = "else"; - NodeTree* method = nullptr; - if ((method = getMethod(child->getDataRef()->valueType, "destruct", std::vector()))) { - functionDefinitions += " " + generateMethodIfExists(child->getDataRef()->valueType, "destruct", - "&this->" + prefixed_option_name, std::vector()) + ";\n"; - //"&this->" + option_name, std::vector()) + ";\n"; - } - functionDefinitions += " }\n"; - } - } - } else { - // ok, is a constructor function - functionDefinitions += " /* constructor woop woop */\n"; - functionDefinitions += " " + declarationData.symbol.getName() + " toRet;\n"; - functionDefinitions += " toRet.flag = " + declarationData.symbol.getName() + "__" + orig_fun_name + ";\n"; - if (has_param) { - NodeTree* method = nullptr; - auto paramType = child->getDataRef()->valueType->parameterTypes[0]; - auto itemTypeVector = std::vector{paramType->withIncreasedIndirection()}; - functionDefinitions += "/*" + ValueTypeToCType(paramType, "") + "*/\n"; - if ((method = getMethod(paramType, "copy_construct", itemTypeVector))) { - functionDefinitions += " " + generateMethodIfExists(paramType, "copy_construct", - "&toRet." + prefixIfNeeded(scopePrefix(declaration),orig_fun_name) + ", &in", itemTypeVector) + ";\n"; - } else { - functionDefinitions += " toRet." + prefixIfNeeded(scopePrefix(declaration),orig_fun_name) + " = in;\n"; - } - - if ((method = getMethod(paramType, "destruct", std::vector()))) { - functionDefinitions += " " + generateMethodIfExists(paramType, "destruct", - "&in", std::vector()) + ";\n"; - } } - functionDefinitions += " return toRet;\n"; - } - functionDefinitions += "}\n"; - } - } - break; - } - default: - //std::cout << "Declaration? named " << declaration->getName() << " of unknown type " << ASTData::ASTTypeToString(declarationData.type) << " in translation unit scope" << std::endl; - cOutput += "/*unknown declaration named " + declaration->getName() + "*/\n"; - hOutput += "/*unknown declaration named " + declaration->getName() + "*/\n"; - } - } - } - } - hOutput += plainTypedefs + importIncludes + topLevelCPassthrough + functionTypedefStringPre + variableExternDeclarations + classStructs + functionTypedefString + functionPrototypes; - cOutput += variableDeclarations + functionDefinitions; - return std::make_pair(hOutput, cOutput); -} - -//The enclosing object is for when we're generating the inside of object methods. They allow us to check scope lookups against the object we're in -CCodeTriple CGenerator::generate(NodeTree* from, NodeTree* enclosingObject, bool justFuncName, NodeTree* enclosingFunction) { - ASTData data = from->getData(); - std::vector*> children = from->getChildren(); - //std::string output; - CCodeTriple output; - switch (data.type) { - case translation_unit: - { - // Should not happen! We do this in it's own function now! - std::cerr << "Trying to normal generate a translation unit! That's a nono! (" << from->getDataRef()->toString() << ")" << std::endl; - throw "That's not gonna work"; - } - break; - case import: - return CCodeTriple("/* never reached import? */\n"); - case identifier: - { - std::string preName = ""; - std::string postName = ""; - bool closed = false; - // check for this being a closed over variable - // first, get declaring function, if it exists - if (enclosingFunction) { - if (enclosingFunction->getDataRef()->closedVariables.size()) { - //std::cout << "WHOH IS A CLOSER" << std::endl; - if (enclosingFunction->getDataRef()->closedVariables.find(from) != enclosingFunction->getDataRef()->closedVariables.end()) { - preName += "(*closed_variables->"; - postName += ")"; - closed = true; - } - } - } - // enclosing function comes first now, we might have a double closure that both close over the this pointer of an object - //but first, if we're this, we should just emit. (assuming enclosing object) (note that technically this would fall through, but for errors) - if (data.symbol.getName() == "this") { - if (enclosingObject || enclosingFunction) - return CCodeTriple(preName + "this" + postName); - std::cerr << "Error: this used in non-object scope" << std::endl; - throw "Error: this used in non-object scope"; - } - //If we're in an object method, and our enclosing scope is that object, we're a member of the object and should use the this reference. - //if (enclosingObject && enclosingObject->getDataRef()->scope.find(data.symbol.getName()) != enclosingObject->getDataRef()->scope.end()) - // the old one would actually activate if the object even had one of the same name - if (enclosingObject) { - auto containing = enclosingObject->getDataRef()->scope.find(data.symbol.getName()); - if (containing != enclosingObject->getDataRef()->scope.end() && std::find(containing->second.begin(), containing->second.end(), from) != containing->second.end()) - preName = "(" + preName + "this)->"; // incase this is a closed over this that is referencing another thing (I think this happens for a.b when a is supposed to be closed over but isn't) - } - // dereference references, but only if inside a function and not if this is a closed over variable - if (enclosingFunction && data.valueType->is_reference && !closed) { - preName += "(*"; - postName += ")"; - } - // we're scope prefixing EVERYTHING, but only if needed - return preName + prefixIfNeeded(scopePrefix(from), CifyName(data.symbol.getName())) + postName; //Cifying does nothing if not an operator overload - } - case function: - { - if (data.valueType->baseType == template_type) - return "/* template function: " + data.symbol.getName() + " */"; - - // we push on a new vector to hold parameters that might need a destructor call - distructDoubleStack.push_back(std::vector*>()); - - std::string nameDecoration, parameters; - if (data.closedVariables.size()) - parameters += closureStructType(data.closedVariables) + " *closed_variables"; - for (int j = 0; j < children.size()-1; j++) { - if (j > 0 || data.closedVariables.size()) - parameters += ", "; - parameters += ValueTypeToCType(children[j]->getData().valueType, generate(children[j], enclosingObject, justFuncName, enclosingFunction).oneString()); - //nameDecoration += "_" + ValueTypeToCTypeDecoration(children[j]->getData().valueType); - // add parameters to distructDoubleStack so that their destructors will be called at return (if they exist) - distructDoubleStack.back().push_back(children[j]); - } - for (Type *paramType : from->getDataRef()->valueType->parameterTypes) - nameDecoration += "_" + ValueTypeToCTypeDecoration(paramType); - // this is for using functions as values - if (justFuncName) { - std::string funcName; - if (data.symbol.getName() != "main") { - funcName += function_header + prefixIfNeeded(scopePrefix(from), CifyName(data.symbol.getName() + nameDecoration)); - } else { - funcName += CifyName(data.symbol.getName() + nameDecoration); - } - if (from->getDataRef()->closedVariables.size()) { - std::string tmpStruct = "closureStruct" + getID(); - output.preValue += closureStructType(data.closedVariables) + " " + tmpStruct + " = {"; - bool notFirst = false; - for (auto var : data.closedVariables) { - if (notFirst) - output.preValue += ", "; - notFirst = true; - std::string varName = var->getDataRef()->symbol.getName(); - std::string preName; - if (enclosingObject && enclosingObject->getDataRef()->scope.find(varName) != enclosingObject->getDataRef()->scope.end()) - preName += "this->"; - varName = (varName == "this") ? varName : prefixIfNeeded(scopePrefix(var), varName); - // so that we can close over things that have been closed over by an enclosing closure - output.preValue += "." + varName + " = &/*woo*/" + generate(var, enclosingObject, justFuncName, enclosingFunction).oneString() + "/*woo*/"; - //output.preValue += "." + varName + " = &" + preName + varName; - } - output.preValue += "};\n"; - output += "("+ ValueTypeToCType(data.valueType, "") +"){(void*)" + funcName + ", &" + tmpStruct + "}"; - } else { - output += "("+ ValueTypeToCType(data.valueType, "") +"){" + funcName + ", NULL}"; - } - } else { - // Note that we always wrap out child in {}, as we now allow one statement functions without a codeblock - std::string funName = (data.symbol.getName() == "main") ? "main" : function_header + prefixIfNeeded(scopePrefix(from), CifyName(data.symbol.getName() + nameDecoration)); - output = "\n" + ValueTypeToCType(data.valueType->returnType, funName) + "(" + parameters + ") {\n" + - generate(children[children.size()-1], enclosingObject, justFuncName, from).oneString(); - output += emitDestructors(reverse(distructDoubleStack.back()), enclosingObject); - output += "}\n"; - } - - distructDoubleStack.pop_back(); - return output; - } - case code_block: - { - output += "{\n"; - tabLevel++; - - // we push on a new vector to hold parameters that might need a destructor call - distructDoubleStack.push_back(std::vector*>()); - // we push on a new vector to hold deferred statements - deferDoubleStack.push_back(std::vector*>()); - for (int i = 0; i < children.size(); i++) - output += generate(children[i], enclosingObject, justFuncName, enclosingFunction).oneString(); - // we pop off the vector and go through them in reverse emitting them - for (auto iter = deferDoubleStack.back().rbegin(); iter != deferDoubleStack.back().rend(); iter++) - output += generate(*iter, enclosingObject, justFuncName, enclosingFunction).oneString(); - deferDoubleStack.pop_back(); - output += emitDestructors(reverse(distructDoubleStack.back()), enclosingObject); - distructDoubleStack.pop_back(); - - tabLevel--; - output += tabs() + "}"; - - return output; - } - case expression: - output += " " + data.symbol.getName() + ", "; - case boolean_expression: - output += " " + data.symbol.getName() + " "; - case statement: - { - CCodeTriple stat = generate(children[0], enclosingObject, justFuncName, enclosingFunction); - return tabs() + stat.preValue + stat.value + ";\n" + stat.postValue ; - } - case if_statement: - output += "if (" + generate(children[0], enclosingObject, true, enclosingFunction) + ")\n\t"; - // We have to see if the then statement is a regular single statement or a block. - // If it's a block, because it's also a statement a semicolon will be emitted even though - // we don't want it to be, as if (a) {b}; else {c}; is not legal C, but if (a) {b} else {c}; is. - if (children[1]->getChildren()[0]->getDataRef()->type == code_block) { - output += generate(children[1]->getChildren()[0], enclosingObject, justFuncName, enclosingFunction).oneString(); - } else { - // ALSO we always emit blocks now, to handle cases like defer when several statements need to be - // run in C even though it is a single Kraken statement - output += "{ " + generate(children[1], enclosingObject, justFuncName, enclosingFunction).oneString() + " }"; - } - // Always emit blocks here too - if (children.size() > 2) - output += " else { " + generate(children[2], enclosingObject, justFuncName, enclosingFunction).oneString() + " }"; - return output; - case match_statement: - { - output += "/* match_statement */\n"; - CCodeTriple thingToMatch = generate(children[0], enclosingObject, false, enclosingFunction); - output.preValue += thingToMatch.preValue; - output.postValue += thingToMatch.postValue; - for (auto case_stmt : slice(children, 1, -1)) { - auto case_children = case_stmt->getChildren(); - // was accidntally adding in prefix when it shouldn't, though maybe it should when both option and ADT name are identical, deal with this later - //std::string option = generate(case_children[0], enclosingObject, false, enclosingFunction).oneString(); - std::string option = case_children[0]->getDataRef()->symbol.getName(); - std::string prefixed_option = prefixIfNeeded(scopePrefix(case_children[0]),option); - std::string parentName = case_children[0]->getDataRef()->scope["~enclosing_scope"][0]->getDataRef()->symbol.getName(); - output += "/* case " + option + " if " + thingToMatch.value + " */\n"; - output += tabs() + "if ((" + thingToMatch.value + ").flag == " + parentName + "__" + option + ") {\n"; - tabLevel++; - if (case_children.size() > 2) { - output += tabs() + ValueTypeToCType(case_children[1]->getData().valueType, generate(case_children[1], enclosingObject, false, enclosingFunction).oneString()) - + " = (" + thingToMatch.value + ")." + prefixed_option + ";\n"; - //+ " = (" + thingToMatch.value + ")." + option + ";\n"; - output += generate(case_children[2], enclosingObject, false, enclosingFunction).oneString(); - } else { - output += generate(case_children[1], enclosingObject, false, enclosingFunction).oneString(); - } - tabLevel--; - output += "}\n"; - } - return output; - } - break; - case case_statement: - output += "/* case_statement */"; - throw "case statement isn't actually used, but is generated in match"; - break; - case while_loop: - { - // we push on a new vector to hold while stuff that might need a destructor call - loopDistructStackDepth.push(distructDoubleStack.size()); - distructDoubleStack.push_back(std::vector*>()); - // keep track of the current size of the deferDoubleStack so that statements that - // break or continue inside this loop can correctly emit all of the defers through - // all of the inbetween scopes - loopDeferStackDepth.push(deferDoubleStack.size()); - // gotta do like this so that the preconditions can happen every loop - output += "while (1) {\n"; - CCodeTriple condtition = generate(children[0], enclosingObject, true, enclosingFunction); - output += condtition.preValue; - output += "if (!( " + condtition.value + ")) break;\n"; - output += condtition.postValue; - output += generate(children[1], enclosingObject, justFuncName, enclosingFunction).oneString(); - output += emitDestructors(reverse(distructDoubleStack.back()),enclosingObject); - output += + "}"; - - distructDoubleStack.pop_back(); - loopDistructStackDepth.pop(); - // and pop it off again - loopDeferStackDepth.pop(); - return output; - } - case for_loop: - { - // we push on a new vector to hold for stuff that might need a destructor call - loopDistructStackDepth.push(distructDoubleStack.size()); - distructDoubleStack.push_back(std::vector*>()); - // keep track of the current size of the deferDoubleStack so that statements that - // break or continue inside this loop can correctly emit all of the defers through - // all of the inbetween scopes - loopDeferStackDepth.push(deferDoubleStack.size()); - //The strSlice's are there to get ride of an unwanted return and an unwanted semicolon(s) - - std::string doUpdateName = "do_update" + getID(); - // INITIALIZER - output += "{"; - output += generate(children[0], enclosingObject, true, enclosingFunction).oneString(); - output += "bool " + doUpdateName + " = false;\n"; - output += "for (;;) {"; - // UPDATE - output += "if (" + doUpdateName + ") {"; - output += generate(children[2], enclosingObject, true, enclosingFunction).oneString(); - output += "}\n"; - output += doUpdateName + " = true;\n"; - // CONDITION - // note that the postValue happens whether or not we break - CCodeTriple condition = generate(children[1], enclosingObject, true, enclosingFunction); - output += condition.preValue; - output += "if (!(" + condition.value + ")) {\n"; - output += condition.postValue; - output += "break;\n}"; - output += condition.postValue; - // BODY - output += generate(children[3], enclosingObject, justFuncName, enclosingFunction).oneString(); - output += emitDestructors(reverse(distructDoubleStack.back()),enclosingObject); - output += "}"; - output += "}"; - distructDoubleStack.pop_back(); - loopDistructStackDepth.pop(); - // and pop it off again - loopDeferStackDepth.pop(); - return output; - } - case return_statement: - { - // we pop off the vector and go through them in reverse emitting them, going - // through all of both arrays, as return will go through all scopes - for (auto topItr = deferDoubleStack.rbegin(); topItr != deferDoubleStack.rend(); topItr++) - for (auto iter = (*topItr).rbegin(); iter != (*topItr).rend(); iter++) - output += generate(*iter, enclosingObject, justFuncName, enclosingFunction).oneString(); - - std::string destructors = emitDestructors(reverse(flatten(distructDoubleStack)),enclosingObject); - if (children.size()) { - CCodeTriple expr = generate(children[0], enclosingObject, true, enclosingFunction); - output.preValue += expr.preValue; - std::string retTemp = "ret_temp" + getID(); - // use the function's return value so we do the right thing with references - output.preValue += ValueTypeToCType(enclosingFunction->getDataRef()->valueType->returnType, retTemp) + ";\n"; - if (enclosingFunction->getDataRef()->valueType->returnType->is_reference) - output.preValue += retTemp + " = &" + expr.value + ";\n"; - else if (methodExists(children[0]->getDataRef()->valueType, "copy_construct", std::vector{children[0]->getDataRef()->valueType->withIncreasedIndirection()})) - output.preValue += generateMethodIfExists(children[0]->getDataRef()->valueType, "copy_construct", "&"+retTemp + ", &" + expr.value, std::vector{children[0]->getDataRef()->valueType->withIncreasedIndirection()}); - else - output.preValue += retTemp + " = " + expr.value + ";\n"; - // move expr post to before return - output.value += expr.postValue; - output.value += destructors; - output.value += "return " + retTemp; - } else { - output.value += destructors; - output += "return"; - } - return output; - } - case break_statement: - // handle everything that's been deferred all the way back to the loop's scope - for (int i = deferDoubleStack.size()-1; i >= loopDeferStackDepth.top(); i--) - for (auto iter = deferDoubleStack[i].rbegin(); iter != deferDoubleStack[i].rend(); iter++) - output += generate(*iter, enclosingObject, justFuncName, enclosingFunction).oneString(); - // ok, emit destructors to where the loop ends - output += emitDestructors(reverse(flatten(slice(distructDoubleStack,loopDistructStackDepth.top(),-1))),enclosingObject); - return output + "break"; - case continue_statement: - // handle everything that's been deferred all the way back to the loop's scope - for (int i = deferDoubleStack.size()-1; i >= loopDeferStackDepth.top(); i--) - for (auto iter = deferDoubleStack[i].rbegin(); iter != deferDoubleStack[i].rend(); iter++) - output += generate(*iter, enclosingObject, justFuncName, enclosingFunction).oneString(); - // ok, emit destructors to where the loop ends - output += emitDestructors(reverse(flatten(slice(distructDoubleStack,loopDistructStackDepth.top(),-1))),enclosingObject); - return output + "continue"; - case defer_statement: - deferDoubleStack.back().push_back(children[0]); - return CCodeTriple("/*defer " + generate(children[0], enclosingObject, justFuncName, enclosingFunction).oneString() + "*/"); - case assignment_statement: - return generate(children[0], enclosingObject, justFuncName, enclosingFunction).oneString() + " = " + generate(children[1], enclosingObject, true, enclosingFunction); - case declaration_statement: - // adding declaration to the distructDoubleStack so that we can call their destructors when leaving scope (}, return, break, continue) - // but only if we're inside an actual doublestack - if ((distructDoubleStack.size())) - distructDoubleStack.back().push_back(children[0]); - - if (children.size() == 1) - return ValueTypeToCType(children[0]->getData().valueType, generate(children[0], enclosingObject, justFuncName, enclosingFunction).oneString()) + ";"; - else if (children[1]->getChildren().size() && children[1]->getChildren()[0]->getChildren().size() > 1 - && children[1]->getChildren()[0]->getChildren()[1] == children[0]) { - //That is, if we're a declaration with an init position call (Object a.construct()) - //We can tell if our function call (children[1])'s access operation([0])'s lhs ([1]) is the thing we just declared (children[0]) - // be sure to end value by passing oneString true - return ValueTypeToCType(children[0]->getData().valueType, generate(children[0], enclosingObject, justFuncName, enclosingFunction).oneString()) + "; " + generate(children[1], enclosingObject, true, enclosingFunction).oneString(true) + "/*Init Position Call*/"; - } else { - // copy constructor if exists (even for non same types) - if (methodExists(children[0]->getDataRef()->valueType, "copy_construct", std::vector{children[1]->getDataRef()->valueType->withIncreasedIndirection()})) { - CCodeTriple toAssign = generate(children[1], enclosingObject, true, enclosingFunction); - std::string assignedTo = generate(children[0], enclosingObject, justFuncName, enclosingFunction).oneString(); - output.value = toAssign.preValue; - output.value += ValueTypeToCType(children[0]->getData().valueType, assignedTo) + ";\n"; - // we put the thing about to be copy constructed in a variable so we can for sure take its address - std::string toAssignTemp = "copy_construct_param" + getID(); - output.value += ValueTypeToCType(children[1]->getData().valueType->withoutReference(), toAssignTemp) + " = " + toAssign.value + ";\n"; - - output.value += generateMethodIfExists(children[0]->getDataRef()->valueType, "copy_construct", "&" + assignedTo + ", &" + toAssignTemp, std::vector{children[1]->getDataRef()->valueType->withIncreasedIndirection()}) + ";\n" + output.postValue; - output.value += toAssign.postValue; - return output; - } else { - // we might use this address in the right hand side (recursive closures), so split it up - std::string assignTo = generate(children[0], enclosingObject, justFuncName, enclosingFunction).oneString(); - output.preValue = ValueTypeToCType(children[0]->getData().valueType, assignTo) + ";\n"; - output += assignTo + " = " + generate(children[1], enclosingObject, true, enclosingFunction) + ";"; - return output; - } - } - case if_comp: - // Lol, this doesn't work because the string gets prefixed now - //if (generate(children[0], enclosingObject, enclosingFunction) == generatorString) - if (children[0]->getDataRef()->symbol.getName() == generatorString) - return generate(children[1], enclosingObject, justFuncName, enclosingFunction); - return CCodeTriple(""); - case simple_passthrough: - { - std::string pre_end_dec, end_assign; - // Stuff is bit more interesting now! XXX - std::string pre_passthrough, post_passthrough; - // Handle input/output parameters - if (children.front()->getDataRef()->type == passthrough_params) { - auto optParamAssignLists = children.front()->getChildren(); - for (auto in_or_out : optParamAssignLists) { - for (auto assign : in_or_out->getChildren()) { - auto assignChildren = assign->getChildren(); - if (in_or_out->getDataRef()->type == in_passthrough_params) { - std::string currentName = generate(assignChildren[0], enclosingObject, enclosingFunction).oneString(); - std::string toName; - if (assignChildren.size() == 2) - toName = assignChildren[1]->getDataRef()->symbol.getName(); - else - toName = assignChildren[0]->getDataRef()->symbol.getName(); - if (currentName != toName) - pre_passthrough += ValueTypeToCType(assignChildren[0]->getDataRef()->valueType, toName) + " = " + currentName + ";\n"; - } else if (in_or_out->getDataRef()->type == out_passthrough_params) { - std::string currentName = generate(assignChildren[0], enclosingObject, justFuncName, enclosingFunction).oneString(); - std::string toName; - if (assignChildren.size() == 2) - toName = assignChildren[1]->getDataRef()->symbol.getName(); - else - toName += assignChildren[0]->getDataRef()->symbol.getName(); - std::string trans_dec_name = currentName + "_end_assign"; - pre_end_dec += ValueTypeToCType(assignChildren[0]->getDataRef()->valueType, trans_dec_name) + ";\n"; - post_passthrough += trans_dec_name + " = " + toName + ";\n"; - end_assign += currentName + " = " + trans_dec_name + ";\n"; - } else - linkerString += " " + strSlice(generate(in_or_out, enclosingObject, justFuncName, enclosingFunction).oneString(), 1, -2) + " "; - } - } - } - // The actual passthrough string is the last child now, as we might - // have passthrough_params be the first child - // we don't generate, as that will escape the returns and we don't want that. We'll just grab the string - // we don't want the scope stuff if we're at top level for an include, etc.... - if (isUnderNodeWithType(from,function)) - return pre_end_dec + "{" + pre_passthrough + strSlice(children.back()->getDataRef()->symbol.getName(), 3, -4) + post_passthrough + "}\n" + end_assign; - else - return strSlice(children.back()->getDataRef()->symbol.getName(), 3, -4); - } - case function_call: - { - //NOTE: The first (0th) child of a function call node is the declaration of the function - - //Handle operators specially for now. Will later replace with - //Inlined functions in the standard library - // std::string name = data.symbol.getName(); - // std::cout << name << " == " << children[0]->getData().symbol.getName() << std::endl; - std::string name = children[0]->getDataRef()->symbol.getName(); - ASTType funcType = children[0]->getDataRef()->type; - - // UGLLLLYYYY - // But we have these here because some stuff has to be moved out of the giant nested blocks below and this is the way to do it - CCodeTriple functionCallSource; - bool doClosureInstead = false; - - //std::cout << "Doing function: " << name << std::endl; - //Test for special functions only if what we're testing is, indeed, the definition, not a function call that returns a callable function pointer - if (funcType == function) { - if (name == "++" || name == "--") - return generate(children[1], enclosingObject, true, enclosingFunction) + name; - if ( (name == "*" || name == "&" || name == "!" || name == "-" || name == "+" ) && children.size() == 2) //Is dereference, not multiplication, address-of, or other unary operator - return name + "(" + generate(children[1], enclosingObject, true, enclosingFunction) + ")"; - if (name == "[]") - return "(" + generate(children[1], enclosingObject, true, enclosingFunction) + ")[" + generate(children[2],enclosingObject, true, enclosingFunction) + "]"; - if (name == "+" || name == "-" || name == "*" || name == "/" || name == "==" || name == ">=" || name == "<=" || name == "!=" - || name == "<" || name == ">" || name == "%" || name == "=" || name == "+=" || name == "-=" || name == "*=" || name == "/=") { - return "((" + generate(children[1], enclosingObject, true, enclosingFunction) + ")" + name + "(" + generate(children[2], enclosingObject, true, enclosingFunction) + "))"; - } else if (name == "&&" || name == "||") { - // b/c short circuiting, these have to be done seperately - CCodeTriple lhs = generate(children[1], enclosingObject, true, enclosingFunction); - CCodeTriple rhs = generate(children[2], enclosingObject, true, enclosingFunction); - output.preValue = lhs.preValue; - std::string shortcircuit_result = "shortcircuit_result" + getID(); - output.preValue += "bool " + shortcircuit_result + " = " + lhs.value + ";\n"; - output.preValue += lhs.postValue; - output.preValue += "if (" + std::string(name == "||" ? "!":"") + shortcircuit_result + ") { \n"; - output.preValue += rhs.preValue; - output.preValue += shortcircuit_result + " = " + rhs.value + ";\n"; - output.preValue += rhs.postValue; - output.preValue += "}\n"; - output.value = shortcircuit_result; - return output; - } else if (name == "." || name == "->") { - if (children.size() == 1) - return "/*dot operation with one child*/" + generate(children[0], enclosingObject, true, enclosingFunction).oneString() + "/*end one child*/"; - //If this is accessing an actual function, find the function in scope and take the appropriate action. Probabally an object method - if (children[2]->getDataRef()->type == function) { - std::string functionName = children[2]->getDataRef()->symbol.getName(); - NodeTree* possibleObjectType = children[1]->getDataRef()->valueType->typeDefinition; - //If is an object method, generate it like one. Needs extension/modification for inheritence - if (possibleObjectType) { - NodeTree* unaliasedTypeDef = getMethodsObjectType(possibleObjectType, functionName); - if (unaliasedTypeDef) { //Test to see if the function's a member of this type_def, or if this is an alias, of the original type. Get this original type if it exists. - std::string nameDecoration; - NodeTree* functionDef = children[2]; //The function def is the rhs of the access operation - //std::vector*> functionDefChildren = children[2]->getChildren(); //The function def is the rhs of the access operation - //std::cout << "Decorating (in access-should be object) " << name << " " << functionDefChildren.size() << std::endl; - for (Type *paramType : functionDef->getDataRef()->valueType->parameterTypes) - nameDecoration += "_" + ValueTypeToCTypeDecoration(paramType); - //for (int i = 0; i < (functionDefChildren.size() > 0 ? functionDefChildren.size()-1 : 0); i++) - //nameDecoration += "_" + ValueTypeToCTypeDecoration(functionDefChildren[i]->getData().valueType); - // Note that we only add scoping to the object, as this specifies our member function too - return function_header + prefixIfNeeded(scopePrefix(unaliasedTypeDef), CifyName(unaliasedTypeDef->getDataRef()->symbol.getName())) +"__" + - CifyName(functionName + nameDecoration) + "(" + (name == "." ? "&" : "") + generate(children[1], enclosingObject, true, enclosingFunction) + ","; - //The comma lets the upper function call know we already started the param list - //Note that we got here from a function call. We just pass up this special case and let them finish with the perentheses - } else { - //std::cout << "Is not in scope or not type" << std::endl; - return "((" + generate(children[1], enclosingObject, true, enclosingFunction) + ")" + name + functionName + ")"; - } - } else { - //std::cout << "Is not in scope or not type" << std::endl; - return "((" + generate(children[1], enclosingObject, true, enclosingFunction) + ")" + name + functionName + ")"; - } - } else { - //return "((" + generate(children[1], enclosingObject, enclosingFunction) + ")" + name + generate(children[2], enclosingObject, enclosingFunction) + ")"; - return "((" + generate(children[1], enclosingObject, true, enclosingFunction) + ")" + name + generate(children[2], nullptr, true, enclosingFunction) + ")"; - } - } else { - // this could a closure literal. sigh, I know. - if (children[0]->getDataRef()->closedVariables.size()) { - functionCallSource = generate(children[0], enclosingObject, true, enclosingFunction); - doClosureInstead = true; - } else { - //It's a normal function call, not a special one or a method or anything. Name decorate. - std::vector*> functionDefChildren = children[0]->getChildren(); - //std::cout << "Decorating (none-special)" << name << " " << functionDefChildren.size() << std::endl; - std::string nameDecoration; - for (Type *paramType : children[0]->getDataRef()->valueType->parameterTypes) - nameDecoration += "_" + ValueTypeToCTypeDecoration(paramType); - //for (int i = 0; i < (functionDefChildren.size() > 0 ? functionDefChildren.size()-1 : 0); i++) - //nameDecoration += "_" + ValueTypeToCTypeDecoration(functionDefChildren[i]->getData().valueType); - // it is possible that this is an object method from inside a closure - // in which case, recover the enclosing object from this - bool addClosedOver = false; - if (enclosingFunction && enclosingFunction->getDataRef()->closedVariables.size()) { - for (auto closedVar : enclosingFunction->getDataRef()->closedVariables) { - if (closedVar->getDataRef()->symbol.getName() == "this") { - enclosingObject = closedVar->getDataRef()->valueType->typeDefinition; - addClosedOver = true; - } - } - } - //Check to see if we're inside of an object and this is a method call - bool isSelfObjectMethod = enclosingObject && contains(enclosingObject->getChildren(), children[0]); - if (isSelfObjectMethod) { - output += function_header + prefixIfNeeded(scopePrefix(children[0]), CifyName(enclosingObject->getDataRef()->symbol.getName())) +"__"; - output += CifyName(name + nameDecoration) + "("; - output += std::string(addClosedOver ? "(*closed_variables->this)" : "this") + (children.size() > 1 ? "," : ""); - } else { - // ha, I think this is the normal function call one. Had a little trouble finding it - // darned if we don't have to special case ADT psudo-constructors - auto possibleParentADTVector = children[0]->getDataRef()->scope["~enclosing_scope"]; - NodeTree* possibleParentADT = possibleParentADTVector.size() ? possibleParentADTVector[0] : nullptr; - std::string adtAdditional = ""; - if (possibleParentADT && possibleParentADT->getDataRef()->type == adt_def) - adtAdditional = possibleParentADT->getDataRef()->symbol.getName() + "__"; - output += function_header + prefixIfNeeded(scopePrefix(children[0]), CifyName(adtAdditional + name + nameDecoration)) + "("; - } - } - } - } else { - //This part handles cases where our definition isn't the function definition (that is, it is probabally the return from another function) - //It's probabally the result of an access function call (. or ->) to access an object method. - //OR a function value! - // - //THIS IS UUUUUGLLYYY too. We moved the closure part out to after the generation of the params becuase it needs to use them twice - functionCallSource = generate(children[0], enclosingObject, true, enclosingFunction); - if (functionCallSource.value[functionCallSource.value.size()-1] == ',') //If it's a member method, it's already started the parameter list. - output += children.size() > 1 ? functionCallSource : CCodeTriple(functionCallSource.preValue, functionCallSource.value.substr(0, functionCallSource.value.size()-1), functionCallSource.postValue); - else { - doClosureInstead = true; - } - } - CCodeTriple parameters; - // see if we should copy_construct / referencize all the parameters - for (int i = 1; i < children.size(); i++) { //children[0] is the declaration - Type* func_param_type = children[0]->getDataRef()->valueType->parameterTypes[i-1]; - // ok, if our param is a reference returned by another function, we don't actually want this type to be a reference if it is now. - Type *param_type = children[i]->getDataRef()->valueType->withoutReference(); - // don't copy_construct references - if (func_param_type->is_reference) { - parameters += "&" + generate(children[i], enclosingObject, true, enclosingFunction); - } else if (methodExists(children[i]->getDataRef()->valueType, "copy_construct", std::vector{param_type->withIncreasedIndirection()})) { - std::string tmpParamName = "param" + getID(); - CCodeTriple paramValue = generate(children[i], enclosingObject, true, enclosingFunction); - parameters.preValue += paramValue.preValue; - parameters.preValue += ValueTypeToCType(param_type, tmpParamName) + ";\n"; - parameters.preValue += generateMethodIfExists(param_type, "copy_construct", "&"+tmpParamName + ", &" + paramValue.value, std::vector{children[i]->getDataRef()->valueType->withIncreasedIndirection()}); - parameters.value += tmpParamName; - parameters.postValue += paramValue.postValue; - } else { - parameters += generate(children[i], enclosingObject, true, enclosingFunction); - } - if (i < children.size()-1) - parameters += ", "; - } - if (doClosureInstead) { - Type* funcType = children[0]->getDataRef()->valueType; - Type* retType = funcType->returnType; - bool doRet = retType->baseType != void_type || retType->getIndirection(); - std::string tmpName = "functionValueTmp" + getID(); - std::string retTmpName = "closureRetTemp" + getID(); - output += CCodeTriple(parameters.preValue + functionCallSource.preValue + ValueTypeToCType(funcType, tmpName) + " = " + functionCallSource.value + ";\n" - + (doRet ? ValueTypeToCType(retType, retTmpName) + ";\n" : "") - + "if (" + tmpName + ".data) { " + (doRet ? (retTmpName + " =") : "") + " (("+ ValueTypeToCTypeDecoration(funcType,ClosureFunctionPointerTypeWithClosedParam) +") (" + tmpName + ".func))(" + tmpName + ".data" + (children.size() > 1 ? ", " : "") + parameters.value + "); }\n" - + "else { " + (doRet ? (retTmpName + " = ") : "") + " (("+ ValueTypeToCTypeDecoration(funcType,ClosureFunctionPointerTypeWithoutClosedParam) +") (" + tmpName + ".func))(" + parameters.value + "); }\n", - (doRet ? retTmpName : ""), - parameters.postValue + functionCallSource.postValue); - } else { - output += parameters + ") "; - } - // see if we should add a destructer call to this postValue - Type* retType = children[0]->getDataRef()->valueType->returnType; - if (retType->baseType != void_type) { - // we always use return temps now :( (for psudo-pod objects that still have methods called on them, like range(1,3).for_each(...) - std::string retTempName = "return_temp" + getID(); - output.preValue += ValueTypeToCType(retType, retTempName) + " = " + output.value + ";\n"; - output.value = retTempName; - if (retType->is_reference) - output.value = "(*" + output.value + ")"; - else if (methodExists(retType, "destruct", std::vector())) { - output.postValue = generateMethodIfExists(retType, "destruct", "&"+retTempName, std::vector()) + ";\n" + output.postValue; - } - } - return output; - } - case value: - { - // ok, we now check for it being a multiline string and escape all returns if it is (so that multiline strings work) - if (data.symbol.getName()[0] == '"') { - std::string innerString = strSlice(data.symbol.getName(), 1, -2); - bool triple = strSlice(data.symbol.getName(), 0, 3) == "\"\"\""; - if (triple) - innerString = strSlice(data.symbol.getName(), 3, -4); - std::string newStr; - for (auto character: innerString) - if (character == '\n') - newStr += "\\n"; - else if (triple && character == '"') - newStr += "\\\""; - else - newStr += character; - return "\"" + newStr + "\""; - } - return data.symbol.getName(); - } - - default: - std::cout << "Nothing!" << std::endl; - } - for (int i = 0; i < children.size(); i++) - output += generate(children[i], enclosingObject, justFuncName, enclosingFunction).oneString(); - - return output; -} -NodeTree* CGenerator::getMethodsObjectType(NodeTree* scope, std::string functionName) { - //check the thing - while (scope != scope->getDataRef()->valueType->typeDefinition) //type is an alias, follow it to the definition - scope = scope->getDataRef()->valueType->typeDefinition; - return (scope->getDataRef()->scope.find(functionName) != scope->getDataRef()->scope.end()) ? scope : NULL; -} - -// Returns the function prototype in the out param and the full definition normally -std::string CGenerator::generateObjectMethod(NodeTree* enclosingObject, NodeTree* from, std::string *functionPrototype) { - distructDoubleStack.push_back(std::vector*>()); - - ASTData data = from->getData(); - Type enclosingObjectType = *(enclosingObject->getDataRef()->valueType); //Copy a new type so we can turn it into a pointer if we need to - enclosingObjectType.increaseIndirection(); - std::vector*> children = from->getChildren(); - std::string nameDecoration, parameters; - if (!children.size()) { - //problem - std::cerr << " no children " << std::endl; - } - for (int i = 0; i < children.size()-1; i++) { - parameters += ", " + ValueTypeToCType(children[i]->getData().valueType, generate(children[i]).oneString()); - nameDecoration += "_" + ValueTypeToCTypeDecoration(children[i]->getData().valueType); - - distructDoubleStack.back().push_back(children[i]); - } - std::string functionSignature = "\n" + ValueTypeToCType(data.valueType->returnType, function_header + - prefixIfNeeded(scopePrefix(from), CifyName(enclosingObject->getDataRef()->symbol.getName())) + "__" + - CifyName(data.symbol.getName()) + nameDecoration) + "(" + ValueTypeToCType(&enclosingObjectType, "this") + parameters + ")"; - *functionPrototype += functionSignature + ";\n"; - // Note that we always wrap out child in {}, as we now allow one statement functions without a codeblock - // - std::string output; - output += functionSignature + " {\n" + generate(children.back(), enclosingObject, false, from).oneString(); - output += emitDestructors(reverse(distructDoubleStack.back()), enclosingObject); - output += "}\n"; //Pass in the object so we can properly handle access to member stuff - distructDoubleStack.pop_back(); - return output; -} - -NodeTree* CGenerator::getMethod(Type* type, std::string method, std::vector types) { - if (type->getIndirection()) - return nullptr; - NodeTree *typeDefinition = type->typeDefinition; - if (typeDefinition) { - auto definitionItr = typeDefinition->getDataRef()->scope.find(method); - if (definitionItr != typeDefinition->getDataRef()->scope.end()) { - for (auto method : definitionItr->second) { - bool methodFits = true; - std::vector methodTypes = dereferenced(method->getDataRef()->valueType->parameterTypes); - if (types.size() != methodTypes.size()) - continue; - for (int i = 0; i < types.size(); i++) { - // don't care about references - if (!types[i].test_equality(methodTypes[i], false)) { - methodFits = false; - break; - } - } - if (methodFits) - return method; - } - } - } - return nullptr; -} - -bool CGenerator::methodExists(Type* type, std::string method, std::vector types) { - return getMethod(type, method, types) != nullptr; -} - -std::string CGenerator::generateMethodIfExists(Type* type, std::string method, std::string parameter, std::vector methodTypes) { - NodeTree *methodDef = getMethod(type, method, methodTypes); - if (methodDef) { - NodeTree *typeDefinition = type->typeDefinition; - std::string nameDecoration; - for (Type *paramType : methodDef->getDataRef()->valueType->parameterTypes) - nameDecoration += "_" + ValueTypeToCTypeDecoration(paramType); - return function_header + prefixIfNeeded(scopePrefix(typeDefinition), CifyName(typeDefinition->getDataRef()->symbol.getName())) + "__" + CifyName(method) + nameDecoration + "(" + parameter + ");\n"; - } - return ""; -} - -std::string CGenerator::emitDestructors(std::vector*> identifiers, NodeTree* enclosingObject) { - std::string destructorString = ""; - for (auto identifier : identifiers) - if (!identifier->getDataRef()->valueType->is_reference) - destructorString += tabs() + generateMethodIfExists(identifier->getDataRef()->valueType, "destruct", "&" + generate(identifier, enclosingObject).oneString(), std::vector()); - return destructorString; -} - -std::string CGenerator::closureStructType(std::set*> closedVariables) { - auto it = closureStructMap.find(closedVariables); - if (it != closureStructMap.end()) - return it->second; - std::string typedefString = "typedef struct { "; - // note the increased indirection b/c we're using references to what we closed over - for (auto var : closedVariables) { - // unfortunatly we can't just do it with increased indirection b/c closing over function values - // will actually change the underlying function's type. We cheat and just add a * - //auto tmp = var->getDataRef()->valueType->withIncreasedIndirection(); - std::string varName = var->getDataRef()->symbol.getName(); - varName = (varName == "this") ? varName : prefixIfNeeded(scopePrefix(var), varName); - typedefString += ValueTypeToCType(var->getDataRef()->valueType->withoutReference(), "*"+varName) + ";"; - } - std::string structName = "closureStructType" + getID(); - typedefString += " } " + structName + ";\n"; - functionTypedefString += typedefString; - closureStructMap[closedVariables] = structName; - return structName; -} - -std::string CGenerator::ValueTypeToCType(Type *type, std::string declaration, ClosureTypeSpecialType closureSpecial) { return ValueTypeToCTypeThingHelper(type, " " + declaration, closureSpecial); } -std::string CGenerator::ValueTypeToCTypeDecoration(Type *type, ClosureTypeSpecialType closureSpecial) { return CifyName(ValueTypeToCTypeThingHelper(type, "", closureSpecial)); } -std::string CGenerator::ValueTypeToCTypeThingHelper(Type *type, std::string declaration, ClosureTypeSpecialType closureSpecial) { - std::string return_type; - bool do_ending = true; - switch (type->baseType) { - case none: - if (type->typeDefinition) - return_type = prefixIfNeeded(scopePrefix(type->typeDefinition), CifyName(type->typeDefinition->getDataRef()->symbol.getName())); - else - return_type = "none"; - break; - case function_type: - { - std::string indr_str; - for (int i = 0; i < type->getIndirection(); i++) - indr_str += "*"; - - auto it = functionTypedefMap.find(*type); - if (it != functionTypedefMap.end()) { - if (closureSpecial == ClosureFunctionPointerTypeWithClosedParam) - return_type = it->second.second + declaration; - else if (closureSpecial == ClosureFunctionPointerTypeWithoutClosedParam) - return_type = it->second.third + declaration; - else - return_type = it->second.first + declaration; - } else { - std::string typedefWithoutVoidStr = "typedef "; - std::string typedefWithVoidStr = "typedef "; - std::string typedefWithoutVoidID = "ID_novoid_" + CifyName(type->toString(false)); - std::string typedefWithVoidID = "ID_withvoid_" + CifyName(type->toString(false)); - std::string typedefStructID = "ID_struct_" + CifyName(type->toString(false)); - - // How I wish the world were this kind. Because of C name resolution not looking ahead, this definition needs to be BEFORE - // the object definitions. So to prevent circular dependencies, I'm making this take in a void pointer and we'll simply - // cast in both cases, whether or not there's a data pointer. Sigh. - //std::string typedefStructStr = "typedef struct {" + typedefWithoutVoidID + " func; void* val; } " + typedefStructID + ";\n"; - std::string typedefStructStr = "typedef struct { void* func; void* data; } " + typedefStructID + ";\n"; - - typedefWithoutVoidStr += ValueTypeToCTypeThingHelper(type->returnType, "", closureSpecial); - typedefWithVoidStr += ValueTypeToCTypeThingHelper(type->returnType, "", closureSpecial); - typedefWithoutVoidStr += " (*" + typedefWithoutVoidID + ")("; - typedefWithVoidStr += " (*" + typedefWithVoidID + ")("; - - typedefWithVoidStr += "void*"; - if (type->parameterTypes.size() == 0) - typedefWithoutVoidStr += "void"; - else - for (int i = 0; i < type->parameterTypes.size(); i++) { - typedefWithoutVoidStr += (i != 0 ? ", " : "") + ValueTypeToCTypeThingHelper(type->parameterTypes[i], "", closureSpecial); - typedefWithVoidStr += ", " + ValueTypeToCTypeThingHelper(type->parameterTypes[i], "", closureSpecial); - } - typedefWithoutVoidStr += ");\n"; - typedefWithVoidStr += ");\n"; - // again, sigh - functionTypedefString += typedefWithoutVoidStr; - functionTypedefString += typedefWithVoidStr; - functionTypedefStringPre += typedefStructStr; - //functionTypedefString += typedefStructStr; - if (closureSpecial == ClosureFunctionPointerTypeWithClosedParam) - return_type = typedefWithVoidID + indr_str + declaration; - else - return_type = typedefStructID + indr_str + declaration; - - functionTypedefMap[*type] = make_triple(typedefStructID, typedefWithVoidID, typedefWithoutVoidID); - } - do_ending = false; - } - break; - case void_type: - return_type = "void"; - break; - case boolean: - return_type = "bool"; - break; - case integer: - return_type = "int"; - break; - case floating: - return_type = "float"; - break; - case double_percision: - return_type = "double"; - break; - case character: - return_type = "char"; - break; - default: - return_type = "unknown_ValueType"; - break; - } - if (!do_ending) - return return_type; - for (int i = 0; i < type->getIndirection(); i++) - return_type += "*"; - if (type->is_reference) { - return_type += " /*ref*/ *"; - } - return return_type + declaration; -} - -std::string CGenerator::CifyName(std::string name) { - std::string operatorsToReplace[] = { "+", "plus", - "-", "minus", - "*", "star", - "/", "div", - "%", "mod", - "^", "carat", - "&", "amprsd", - "|", "pipe", - "~", "tilde", - "!", "exlmtnpt", - ",", "comma", - "=", "eq", - "++", "dbplus", - "--", "dbminus", - "<<", "dbleft", - ">>", "dbright", - "::", "scopeop", - ":", "colon", - "==", "dbq", - "!=", "notequals", - "&&", "doubleamprsnd", - "||", "doublepipe", - "+=", "plusequals", - "-=", "minusequals", - "/=", "divequals", - "%=", "modequals", - "^=", "caratequals", - "&=", "amprsdequals", - "|=", "pipeequals", - "*=", "starequals", - "<<=", "doublerightequals", - "<", "lt", - ">", "gt", - ">>=", "doubleleftequals", - "(", "openparen", - ")", "closeparen", - "[", "obk", - "]", "cbk", - " ", "space", - ".", "dot", - "->", "arrow" }; - int length = sizeof(operatorsToReplace)/sizeof(std::string); - //std::cout << "Length is " << length << std::endl; - for (int i = 0; i < length; i+= 2) { - size_t foundPos = name.find(operatorsToReplace[i]); - while(foundPos != std::string::npos) { - name = strSlice(name, 0, foundPos) + "_" + operatorsToReplace[i+1] + "_" + strSlice(name, foundPos+operatorsToReplace[i].length(), -1); - foundPos = name.find(operatorsToReplace[i]); - } - } - return name; -} -// Generate the scope prefix, that is "file_class_" for a method, etc -// What do we still need to handle? Packages! But we don't have thoes yet.... -std::string CGenerator::scopePrefix(NodeTree* from) { - //return ""; - std::string suffix = "_scp_"; - ASTData data = from->getData(); - if (data.type == translation_unit) - return CifyName(data.symbol.getName()) + suffix; - // so we do prefixing for stuff that c doesn't already scope: - // different files. That's it for now. Methods are already lowered correctly with their parent object, - // that parent object will get scoped. When we add a package system, we'll have to then add their scoping here - return scopePrefix(from->getDataRef()->scope["~enclosing_scope"][0]); -} -std::string CGenerator::prefixIfNeeded(std::string prefix, std::string name) { - return simpleComplexName(name, prefix + name); -} -std::string CGenerator::simpleComplexName(std::string simpleName, std::string complexName) { - auto already = simpleComplexNameMap.find(complexName); - if (already != simpleComplexNameMap.end()) - return already->second; - if (usedNameSet.find(simpleName) == usedNameSet.end()) { - usedNameSet.insert(simpleName); - simpleComplexNameMap[complexName] = simpleName; - return simpleName; - } - usedNameSet.insert(complexName); - simpleComplexNameMap[complexName] = complexName; - return complexName; -} - diff --git a/deprecated_compiler/src/GraphStructuredStack.cpp b/deprecated_compiler/src/GraphStructuredStack.cpp deleted file mode 100644 index 9246b77..0000000 --- a/deprecated_compiler/src/GraphStructuredStack.cpp +++ /dev/null @@ -1,145 +0,0 @@ -#include "GraphStructuredStack.h" - -GraphStructuredStack::GraphStructuredStack() { - // -} - -GraphStructuredStack::~GraphStructuredStack() { - // -} - -NodeTree* GraphStructuredStack::newNode(int stateNum) { - return new NodeTree("gssNode", stateNum); -} - -void GraphStructuredStack::addToFrontier(int frontier, NodeTree* node) { - //First, make sure our vector has this and lesser frontiers. If not, add it and up to it - while (gss.size() <= frontier) { - gss.push_back(new std::vector*>()); - } - gss[frontier]->push_back(node); - containing_frontier_map[node] = frontier; -} - -NodeTree* GraphStructuredStack::inFrontier(int frontier, int state) { - if (frontierIsEmpty(frontier)) - return NULL; - for (std::vector*>::size_type i = 0; i < gss[frontier]->size(); i++) { - if ((*(gss[frontier]))[i]->getData() == state) - return (*(gss[frontier]))[i]; - } - return NULL; -} - -int GraphStructuredStack::getContainingFrontier(NodeTree* node) { - auto iter = containing_frontier_map.find(node); - if (iter != containing_frontier_map.end()) - return iter->second; - return -1; - //for (std::vector*>*>::size_type i = 0; i < gss.size(); i++) { - //if (frontierIsEmpty(i)) - //continue; - //for (std::vector*>::size_type j = 0; j < gss[i]->size(); j++) { - //if ((*(gss[i]))[j] == node) - //return i; - //} - //} - //return -1; -} - -bool GraphStructuredStack::frontierIsEmpty(int frontier) { - return frontier >= gss.size() || gss[frontier]->size() == 0; -} - -NodeTree* GraphStructuredStack::frontierGetAccState(int frontier) { - //The acc state is always state 1, for now - return inFrontier(frontier, 1); -} - -std::vector*>* GraphStructuredStack::getReachable(NodeTree* start, int length) { - std::vector*>* reachableList = new std::vector*>(); - std::queue*> currentNodes; - std::queue*> nextNodes; - currentNodes.push(start); - for (int i = 0; i < length; i++) { - while (!currentNodes.empty()) { - NodeTree* currentNode = currentNodes.front(); - currentNodes.pop(); - std::vector*> children = currentNode->getChildren(); - //std::cout << currentNode->getData() << " has children "; - for (std::vector*>::size_type j = 0; j < children.size(); j++) { - std::cout << children[j]->getData() << " "; - nextNodes.push(children[j]); - } - std::cout << std::endl; - } - currentNodes = nextNodes; - //No clear function, so go through and remove - while(!nextNodes.empty()) - nextNodes.pop(); - } - while (!currentNodes.empty()) { - reachableList->push_back(currentNodes.front()); - //std::cout << currentNodes.front()->getData() << " is reachable from " << start->getData() << " by length " << length << std::endl; - currentNodes.pop(); - } - return reachableList; -} - -std::vector*> >* GraphStructuredStack::getReachablePaths(NodeTree* start, int length) { - std::vector*> >* paths = new std::vector*> >(); - std::vector*> currentPath; - recursivePathFind(start, length, currentPath, paths); - return paths; -} - -void GraphStructuredStack::recursivePathFind(NodeTree* start, int length, std::vector*> currentPath, std::vector*> >* paths) { - currentPath.push_back(start); - if (length == 0) { - paths->push_back(currentPath); - return; - } - std::vector*> children = start->getChildren(); - for (std::vector*>::size_type i = 0; i < children.size(); i++) { - recursivePathFind(children[i], length-1, currentPath, paths); - } -} - -bool GraphStructuredStack::hasEdge(NodeTree* start, NodeTree* end) { - //Really, either testing for parent or child should work. - return start->findChild(end) != -1; -} - -NodeTree* GraphStructuredStack::getEdge(NodeTree* start, NodeTree* end) { - return edges[std::make_pair(start, end)]; -} - -void GraphStructuredStack::addEdge(NodeTree* start, NodeTree* end, NodeTree* edge) { - start->addChild(end); - end->addParent(start); - edges[std::make_pair(start, end)] = edge; -} - -std::vector GraphStructuredStack::getFrontier(int frontier) { - std::vector toReturn; - for (int i = 0; i < gss[frontier]->size(); i++) - toReturn.push_back((*(gss[frontier]))[i]->getData()); - return toReturn; -} - -std::string GraphStructuredStack::toString() { - std::string tostring = ""; - for (std::vector*>*>::size_type i = 0; i < gss.size(); i++) { - tostring += "Frontier: " + intToString(i) + "\n"; - for (std::vector*>::size_type j = 0; j < gss[i]->size(); j++) { - tostring += "|" + intToString((*(gss[i]))[j]->getData()) + "| "; - } - tostring += "\n"; - } - return tostring; -} - -void GraphStructuredStack::clear() { - gss.clear(); - edges.clear(); -} diff --git a/deprecated_compiler/src/Importer.cpp b/deprecated_compiler/src/Importer.cpp deleted file mode 100644 index ecfd3b5..0000000 --- a/deprecated_compiler/src/Importer.cpp +++ /dev/null @@ -1,238 +0,0 @@ -#include "Importer.h" - -#ifdef _WIN32 - #include - #define mkdir( A, B ) mkdir(A) -#endif -Importer::Importer(Parser* parserIn, std::vector includePaths, std::string outputNameIn, bool only_parseIn) { - only_parse = only_parseIn; - //constructor - outputName = outputNameIn; - - if (!only_parse) { - if (mkdir(("./" + outputName).c_str(), 0755)) { - //std::cerr << "\n\n =====IMPORTER===== \n\n" << std::endl; - //std::cerr << "Could not make directory " << outputName << std::endl; - } - } - - parser = parserIn; - this->includePaths = includePaths; - ASTTransformer = new ASTTransformation(this); - - removeSymbols.push_back(Symbol("$NULL$", true)); - removeSymbols.push_back(Symbol("WS", false)); - removeSymbols.push_back(Symbol("\\(", true)); - removeSymbols.push_back(Symbol("\\)", true)); - removeSymbols.push_back(Symbol("var", true)); - removeSymbols.push_back(Symbol("fun", true)); - - removeSymbols.push_back(Symbol(";", true)); - removeSymbols.push_back(Symbol("line_end", false)); - removeSymbols.push_back(Symbol("{", true)); - removeSymbols.push_back(Symbol("}", true)); - removeSymbols.push_back(Symbol("(", true)); - removeSymbols.push_back(Symbol(")", true)); - //removeSymbols.push_back(Symbol("import", true)); - removeSymbols.push_back(Symbol("if", true)); - removeSymbols.push_back(Symbol("while", true)); - removeSymbols.push_back(Symbol("__if_comp__", true)); - //removeSymbols.push_back(Symbol("simple_passthrough", true)); - removeSymbols.push_back(Symbol("comp_simple_passthrough", true)); - removeSymbols.push_back(Symbol("def_nonterm", false)); - removeSymbols.push_back(Symbol("obj_nonterm", false)); - removeSymbols.push_back(Symbol("adt_nonterm", false)); - removeSymbols.push_back(Symbol("template", true)); - removeSymbols.push_back(Symbol("\\|", true)); - //removeSymbols.push_back(Symbol("match", true)); - collapseSymbols.push_back(Symbol("case_statement_list", false)); - collapseSymbols.push_back(Symbol("opt_param_assign_list", false)); - collapseSymbols.push_back(Symbol("param_assign_list", false)); - collapseSymbols.push_back(Symbol("opt_typed_parameter_list", false)); - collapseSymbols.push_back(Symbol("opt_parameter_list", false)); - collapseSymbols.push_back(Symbol("identifier_list", false)); - collapseSymbols.push_back(Symbol("adt_option_list", false)); - collapseSymbols.push_back(Symbol("statement_list", false)); - collapseSymbols.push_back(Symbol("parameter_list", false)); - collapseSymbols.push_back(Symbol("typed_parameter_list", false)); - collapseSymbols.push_back(Symbol("unorderd_list_part", false)); - collapseSymbols.push_back(Symbol("if_comp_pred", false)); - collapseSymbols.push_back(Symbol("declaration_block", false)); - collapseSymbols.push_back(Symbol("type_list", false)); - collapseSymbols.push_back(Symbol("opt_type_list", false)); - collapseSymbols.push_back(Symbol("template_param_list", false)); - collapseSymbols.push_back(Symbol("trait_list", false)); - collapseSymbols.push_back(Symbol("dec_type", false)); - //collapseSymbols.push_back(Symbol("pre_reffed", false)); -} - -Importer::~Importer() { - //destructor - delete ASTTransformer; -} - -void Importer::registerAST(std::string name, NodeTree* ast, NodeTree* syntaxTree) { - imported[name] = ast; - importedTrips.push_back({name, ast, syntaxTree}); - std::cout << "REGISTERD " << name << std::endl; -} - -NodeTree* Importer::getUnit(std::string fileName) { - //std::cout << "\n\nImporting " << fileName << " "; - //Check to see if we've already done it - if (imported.find(fileName) != imported.end()) { - //std::cout << "Already Imported!" << std::endl; - return imported[fileName]; - } - //std::cout << "Not yet imported" << std::endl; - - return NULL; -} - -NodeTree* Importer::importFirstPass(std::string fileName) { - NodeTree* ast = getUnit(fileName); - if (ast == NULL) { - NodeTree* parseTree = parseAndTrim(fileName); - if (!parseTree) - return NULL; - //Call with ourself to allow the transformation to call us to import files that it needs - if (!only_parse) - ast = ASTTransformer->firstPass(fileName, parseTree); //This firstPass will register itself - } - return ast; -} - -void Importer::import(std::string fileName) { - - //Start the ball rolling by importing and running the first pass on the first file. - //This will import, first pass and register all the other files too. - - //std::cout << "\n\n =====FIRST PASS===== \n\n" << std::endl; - importFirstPass(fileName); //First pass defines all objects - if (only_parse) - return; - - std::cout << "\n\n =====SECOND PASS===== \n\n" << std::endl; - for (importTriplet i : importedTrips) //Second pass defines data inside objects, outside declaration statements, - std::cout << "\n\nSecond pass for: " << i.name << std::endl, ASTTransformer->secondPass(i.ast, i.syntaxTree); //function prototypes, and identifiers (as we now have all type defs) - - std::cout << "\n\n =====THIRD PASS===== \n\n" << std::endl; - for (importTriplet i : importedTrips) //Third pass does all function bodies - std::cout << "\n\nThird pass for: " << i.name << std::endl, ASTTransformer->thirdPass(i.ast, i.syntaxTree); - - std::cout << "\n\n =====FOURTH PASS===== \n\n" << std::endl; - bool changed = true; - while (changed) { - changed = false; - for (importTriplet i : importedTrips) { //Fourth pass finishes up by doing all template classes - std::cout << "\n\nFourth pass for: " << i.name << std::endl; - changed = changed ? changed : ASTTransformer->fourthPass(i.ast, i.syntaxTree); - } - } - - //Note that class template instantiation can happen in the second or third passes and that function template instantion - //can happen in the third pass. - - std::ofstream outFileAST; - for (importTriplet i : importedTrips) { - std::string outputFileName = outputName + "/" + i.name + "out"; - outFileAST.open((outputFileName + ".AST.dot").c_str()); - if (!outFileAST.is_open()) { - std::cout << "Problem opening second output file " << outputFileName + ".AST.dot" << "\n"; - return; - } - if (i.ast) { - //outFileAST << i.ast->DOTGraphString() << std::endl; - } else { - std::cout << "Tree returned from ASTTransformation for " << fileName << " is NULL!" << std::endl; - } - outFileAST.close(); - } -} - -NodeTree* Importer::parseAndTrim(std::string fileName) { - - std::ifstream programInFile; - //std::ofstream outFile, outFileTransformed; - - //std::cout << "outputName " << outputName << std::endl; - //std::cout << "fileName " << fileName << std::endl; - - auto pathPieces = split(fileName, '/'); - std::string outputFileName = outputName + "/" + pathPieces[pathPieces.size()-1] + "out"; - //std::cout << "outputFileName " << outputFileName << std::endl; - - std::string inputFileName; - for (auto i : includePaths) { - programInFile.open(i+fileName); - if (programInFile.is_open()) { - inputFileName = i+fileName; - break; - } else { - std::cout << i+fileName << " is no good" << std::endl; - } - } - if (!programInFile.is_open()) { - std::cout << "Problem opening programInFile " << fileName << "\n"; - return NULL; - } - - //outFile.open(outputFileName); - //if (!outFile.is_open()) { - //std::cout << "Probelm opening output file " << outputFileName << "\n"; - //return NULL; - //} - - //outFileTransformed.open((outputFileName + ".transformed.dot").c_str()); - //if (!outFileTransformed.is_open()) { - //std::cout << "Probelm opening second output file " << outputFileName + ".transformed.dot" << "\n"; - //return NULL; - //} - - std::string programInputFileString, line; - while(programInFile.good()) { - getline(programInFile, line); - programInputFileString.append(line+"\n"); - } - programInFile.close(); - - //std::cout << programInputFileString << std::endl; - NodeTree* parseTree = parser->parseInput(programInputFileString, inputFileName, !only_parse); - - if (parseTree) { - //std::cout << parseTree->DOTGraphString() << std::endl; - //outFile << parseTree->DOTGraphString() << std::endl; - } else { - std::cout << "ParseTree returned from parser for " << fileName << " is NULL!" << std::endl; - //outFile.close(); outFileTransformed.close(); - throw "unexceptablblllll"; - return NULL; - } - if (only_parse) - return parseTree; - //outFile.close(); - - //Remove Transformations - - for (int i = 0; i < removeSymbols.size(); i++) - parseTree = RemovalTransformation(removeSymbols[i]).transform(parseTree); - - //Collapse Transformations - - for (int i = 0; i < collapseSymbols.size(); i++) - parseTree = CollapseTransformation(collapseSymbols[i]).transform(parseTree); - - if (parseTree) { - //outFileTransformed << parseTree->DOTGraphString() << std::endl; - } else { - std::cout << "Tree returned from transformation is NULL!" << std::endl; - } - //outFileTransformed.close(); - - std::cout << "Returning parse tree" << std::endl; - return parseTree; -} - -std::map*> Importer::getASTMap() { - return imported; -} diff --git a/deprecated_compiler/src/Lexer.cpp b/deprecated_compiler/src/Lexer.cpp deleted file mode 100644 index e65f4ae..0000000 --- a/deprecated_compiler/src/Lexer.cpp +++ /dev/null @@ -1,120 +0,0 @@ -#include "Lexer.h" -#include - -Lexer::Lexer() { - //Do nothing - currentPosition = 0; -} - -Lexer::Lexer(std::string inputString) { - input = inputString; - currentPosition = 0; -} - -Lexer::~Lexer() { - //No cleanup necessary -} - -void Lexer::setInput(std::string inputString) { - input = inputString; -} - -void Lexer::addRegEx(std::string regExString) { - regExs.push_back(new RegEx(regExString)); -} - -Symbol Lexer::next() { - //std::cout << "Current at is \"" << input.substr(currentPosition) << "\" currentPos is " << currentPosition << " out of " << input.length() <= input.length()) - return Symbol("$EOF$", true); - int longestMatch = -1; - RegEx* longestRegEx = NULL; - std::string remainingString = input.substr(currentPosition); - for (std::vector::size_type i = 0; i < regExs.size(); i++) { - //std::cout << "Trying regex " << regExs[i]->getPattern() << std::endl; - int currentMatch = regExs[i]->longMatch(remainingString); - if (currentMatch > longestMatch) { - longestMatch = currentMatch; - longestRegEx = regExs[i]; - } - } - if (longestRegEx != NULL) { - std::string eatenString = input.substr(currentPosition, longestMatch); - currentPosition += longestMatch; - //std::cout << "Current at is \"" << input.substr(currentPosition) << "\" currentPos is " << currentPosition <getPattern(), true, eatenString); - } else { - // std::cout << "Found no applicable regex" << std::endl; - // std::cout << "Remaining is ||" << input.substr(currentPosition) << "||" << std::endl; - return Symbol("$INVALID$", true); - } -} - -void Lexer::test() { - Symbol s; - { - Lexer lex; - lex.addRegEx("b"); - lex.setInput("bb"); - s = lex.next(); - assert(s.getName() == "b" && s.getValue() == "b"); - s = lex.next(); - assert(s.getName() == "b" && s.getValue() == "b"); - assert(lex.next() == Symbol("$EOF$", true)); - } - - { - Lexer lex; - lex.addRegEx("a*"); - lex.addRegEx("b"); - lex.setInput("aaabaabb"); - s = lex.next(); - assert(s.getName() == "a*" && s.getValue() == "aaa"); - s = lex.next(); - assert(s.getName() == "b" && s.getValue() == "b"); - s = lex.next(); - assert(s.getName() == "a*" && s.getValue() == "aa"); - s = lex.next(); - assert(s.getName() == "b" && s.getValue() == "b"); - s = lex.next(); - assert(s.getName() == "b" && s.getValue() == "b"); - assert(lex.next() == Symbol("$EOF$", true)); - } - - // Test a lexer error condition. - { - Lexer lex; - lex.addRegEx("a|b"); - lex.setInput("blah"); - s = lex.next(); - assert(s.getName() == "a|b" && s.getValue() == "b"); - assert(lex.next() == Symbol("$INVALID$", true)); - } - - // Lexer can consume all the input at once. - { - Lexer lex; - lex.addRegEx("xyzzy"); - lex.setInput("xyzzy"); - s = lex.next(); - assert(s.getName() == "xyzzy" && s.getValue() == "xyzzy"); - assert(lex.next() == Symbol("$EOF$", true)); - } - - // Lexer produces the longest match, not the first. - { - Lexer lex; - lex.addRegEx("int"); - lex.addRegEx("(i|n|t|e)+"); - lex.setInput("intent"); - s = lex.next(); - assert(s.getName() == "(i|n|t|e)+" && s.getValue() == "intent"); - } - - std::cout << "Lexer tests passed\n"; -} - -void Lexer::reset() { - currentPosition = 0; -} diff --git a/deprecated_compiler/src/ParseAction.cpp b/deprecated_compiler/src/ParseAction.cpp deleted file mode 100644 index 1e21714..0000000 --- a/deprecated_compiler/src/ParseAction.cpp +++ /dev/null @@ -1,79 +0,0 @@ -#include "ParseAction.h" - -ParseAction::ParseAction(ActionType action) { - this->action = action; - this->reduceRule = NULL; - this->shiftState = -1; -} - -ParseAction::ParseAction(ActionType action, ParseRule* reduceRule) { - this->action = action; - this->reduceRule = reduceRule; - this->shiftState = -1; -} - -ParseAction::ParseAction(ActionType action, int shiftState) { - this->action = action; - this->reduceRule = NULL; - this->shiftState = shiftState; -} - -ParseAction::~ParseAction() { - -} - -const bool ParseAction::equalsExceptLookahead(const ParseAction &other) const { - return( action == other.action && ( reduceRule == other.reduceRule || reduceRule->equalsExceptLookahead(*(other.reduceRule)) ) && shiftState == other.shiftState); -} - -const bool ParseAction::operator==(const ParseAction &other) const { - return( action == other.action && ( reduceRule == other.reduceRule || *reduceRule == *(other.reduceRule) ) && shiftState == other.shiftState); -} - -const bool ParseAction::operator!=(const ParseAction &other) const { - return !(this->operator==(other)); -} - -//Exists so we can put ParseActions into sets -const bool ParseAction::operator<(const ParseAction &other) const { - if (action != other.action) - return action < other.action; - if (reduceRule != other.reduceRule) { - if (! (reduceRule && other.reduceRule)) { - return reduceRule < other.reduceRule; - } else { - return *reduceRule < *(other.reduceRule); - } - } - - return shiftState < other.shiftState; -} - -std::string ParseAction::actionToString(ActionType action) { - switch (action) { - case REDUCE: - return "reduce"; - break; - case SHIFT: - return "shift"; - break; - case ACCEPT: - return "accept"; - break; - case REJECT: - return "reject"; - break; - default: - return "INVALID PARSE ACTION"; - } -} - -std::string ParseAction::toString(bool printRuleLookahead) { - std::string outputString = ""; - outputString += actionToString(action); - if (reduceRule != NULL) - outputString += " " + reduceRule->toString(printRuleLookahead); - if (shiftState != -1) - outputString += " " + intToString(shiftState); - return(outputString); -} diff --git a/deprecated_compiler/src/ParseRule.cpp b/deprecated_compiler/src/ParseRule.cpp deleted file mode 100644 index a8bc130..0000000 --- a/deprecated_compiler/src/ParseRule.cpp +++ /dev/null @@ -1,145 +0,0 @@ -#include "ParseRule.h" - -ParseRule::ParseRule() { - pointerIndex = 0; -} - -ParseRule::ParseRule(Symbol leftHandle, int pointerIndex, std::vector &rightSide, std::vector lookahead) { - this->leftHandle = leftHandle; - this->pointerIndex = pointerIndex; - this->rightSide = rightSide; - this->lookahead = lookahead; -} - -ParseRule::~ParseRule() { - -} - -const bool ParseRule::equalsExceptLookahead(const ParseRule &other) const { - return(leftHandle == other.leftHandle && rightSide == other.rightSide && pointerIndex == other.pointerIndex); -} - -const bool ParseRule::operator==(const ParseRule &other) const { - return(equalsExceptLookahead(other) && (lookahead == other.lookahead)); -} - -const bool ParseRule::operator!=(const ParseRule &other) const { - return !(this->operator==(other)); -} - -const bool ParseRule::operator<(const ParseRule &other) const { - //Used for ordering so we can put ParseRule's in sets, and also so that ParseActions will have an ordering - if (leftHandle != other.leftHandle) - return leftHandle < other.leftHandle; - if (rightSide != other.rightSide) - return rightSide < other.rightSide; - if (lookahead != other.lookahead) { - return lookahead < other.lookahead; - } - return false; -} - -ParseRule* ParseRule::clone() { - return( new ParseRule(leftHandle, pointerIndex, rightSide, lookahead) ); -} - -void ParseRule::setLeftHandle(Symbol leftHandle) { - this->leftHandle = leftHandle; -} - -void ParseRule::appendToRight(Symbol appendee) { - rightSide.push_back(appendee); -} - -Symbol ParseRule::getLeftSide() { - return leftHandle; -} - -void ParseRule::setRightSide(std::vector rightSide) { - this->rightSide = rightSide; -} - -std::vector ParseRule::getRightSide() { - return rightSide; -} - -Symbol ParseRule::getAtNextIndex() { - if (pointerIndex >= rightSide.size()) - return Symbol(); - return rightSide[pointerIndex]; -} - -Symbol ParseRule::getAtIndex() { - if (pointerIndex < 1) - return Symbol(); - return rightSide[pointerIndex-1]; -} - -int ParseRule::getRightSize() { - return rightSide.size(); -} - -int ParseRule::getIndex() { - return pointerIndex; -} - -bool ParseRule::advancePointer() { - if (pointerIndex < rightSide.size()) { - pointerIndex++; - return true; - } - return false; -} - -bool ParseRule::isAtEnd() { - return pointerIndex == rightSide.size(); -} - -void ParseRule::setLookahead(std::vector lookahead) { - this->lookahead = lookahead; -} - -void ParseRule::addLookahead(std::vector lookahead) { - for (std::vector::size_type i = 0; i < lookahead.size(); i++) { - bool alreadyIn = false; - for (std::vector::size_type j = 0; j < this->lookahead.size(); j++) { - if (lookahead[i] == this->lookahead[j]) { - alreadyIn = true; - break; - } - } - if (!alreadyIn) - this->lookahead.push_back(lookahead[i]); - } -} - -std::vector ParseRule::getLookahead() { - return lookahead; -} - -std::string ParseRule::toString(bool printLookahead) { - std::string concat = leftHandle.toString() + " -> "; - for (int i = 0; i < rightSide.size(); i++) { - if (i == pointerIndex) - concat += "(*) "; - concat += rightSide[i].toString() + " "; - } - if (pointerIndex >= rightSide.size()) - concat += "(*)"; - if (printLookahead && lookahead.size()) { - concat += "**"; - for (std::vector::size_type i = 0; i < lookahead.size(); i++) - concat += lookahead[i].toString(); - concat += "**"; - } - return(concat); -} - -std::string ParseRule::toDOT() { - std::string concat = ""; - for (int i = 0; i < rightSide.size(); i++) { - concat += leftHandle.toString() + " -> " + rightSide[i].toString() + ";\n"; - } - return(concat); -} - diff --git a/deprecated_compiler/src/Parser.cpp b/deprecated_compiler/src/Parser.cpp deleted file mode 100644 index 2298b17..0000000 --- a/deprecated_compiler/src/Parser.cpp +++ /dev/null @@ -1,407 +0,0 @@ -#include "Parser.h" - -Parser::Parser() : EOFSymbol("$EOF$", true), nullSymbol("$NULL$", true), invalidSymbol("$INVALID$", true){ - table.setSymbols(EOFSymbol, nullSymbol); -} - -Parser::~Parser() { -} - -void Parser::exportTable(std::ofstream &file) { - //Do table - table.exportTable(file); -} -void Parser::importTable(char* tableData) { - //Do table - table.importTable(tableData); - return; -} - -Symbol Parser::getOrAddSymbol(std::string symbolString, bool isTerminal) { - Symbol symbol; - std::pair entry = std::make_pair(symbolString, isTerminal); - if (symbols.find(entry) == symbols.end()) { - symbol = Symbol(symbolString, isTerminal); - symbols[entry] = symbol; - } else { - symbol = symbols[entry]; - } - return(symbol); -} - -void Parser::loadGrammer(std::string grammerInputString) { - reader.setString(grammerInputString); - - std::string currToken = reader.word(false); //Don't truncate so we can find the newline correctly (needed for comments) - - while(currToken != "") { - //First, if this starts with a '#', skip this - if (currToken.front() == '#') { - //If this line is more than one token long, eat it - //std::cout << "Ate: " << currToken << std::endl; - if (currToken.back() != '\n') { - std::string ate = reader.line(); - //std::cout << "Eating " << ate << " b/c grammer comment" << std::endl; - } - currToken = reader.word(false); - continue; - } - if (currToken.back() == '\n' || currToken.back() == ' ' || currToken.back() == '\t') - currToken.erase(currToken.size()-1); - - //Load the left of the rule - ParseRule* currentRule = new ParseRule(); - Symbol leftSide = getOrAddSymbol(currToken, false); //Left handle is never a terminal - currentRule->setLeftHandle(leftSide); - reader.word(); //Remove the = - //Add the right side, adding Symbols to symbol map. - currToken = reader.word(); - while (currToken != ";") { - - //If there are multiple endings to this rule, finish this rule and start a new one with same left handle - while (currToken == "|") { - //If we haven't added anything, that means that this is a null rule - if (currentRule->getRightSide().size() == 0) - currentRule->appendToRight(nullSymbol); - - loadedGrammer.push_back(currentRule); - currentRule = new ParseRule(); - currentRule->setLeftHandle(leftSide); - currToken = reader.word(); - } - - if (currToken == ";") - break; - - if (currToken[0] == '\"') { - //Remove the quotes - currToken = currToken.substr(1,currToken.length()-2); - lexer.addRegEx(currToken); - currentRule->appendToRight(getOrAddSymbol(currToken, true)); //If first character is a ", then is a terminal - } else { - currentRule->appendToRight(getOrAddSymbol(currToken, false)); - } - currToken = reader.word(); - } - //Add new rule to grammer - //If we haven't added anything, that means that this is a null rule - if (currentRule->getRightSide().size() == 0) - currentRule->appendToRight(nullSymbol); - - loadedGrammer.push_back(currentRule); - //Get next token - currToken = reader.word(false); - } - //std::cout << "Parsed!\n"; - - // for (std::vector::size_type i = 0; i < loadedGrammer.size(); i++) - // std::cout << loadedGrammer[i]->toString() << std::endl; -} - -void Parser::createStateSet() { - std::cout << "Begining creation of stateSet" << std::endl; - //First state has no parents - - //Set the first state's basis to be the goal rule with lookahead EOF - ParseRule* goalRule = loadedGrammer[0]->clone(); - std::vector goalRuleLookahead; - goalRuleLookahead.push_back(EOFSymbol); - goalRule->setLookahead(goalRuleLookahead); - State* zeroState = new State(0, goalRule); - stateSets.push_back(zeroState); - std::queue toDo; - toDo.push(zeroState); - //std::cout << "Begining for main set for loop" << std::endl; - int count = 0; - while (toDo.size()) { - if (count % 200 == 0) - std::cout << "while count: " << count << std::endl; - count++; - //closure - closure(toDo.front()); - //Add the new states - addStates(&stateSets, toDo.front(), &toDo); - toDo.pop(); - } - table.remove(1, EOFSymbol); -} - -int Parser::stateNum(State* state) { - for (std::vector::size_type i = 0; i < stateSets.size(); i++) { - if (*(stateSets[i]) == *state) { - return i; - } - } - return -1; -} - -std::vector Parser::firstSet(Symbol token, std::vector avoidList, bool addNewTokens) { - if (tokenFirstSet.find(token) != tokenFirstSet.end()) - return tokenFirstSet[token]; - //If we've already done this token, don't do it again - for (std::vector::size_type i = 0; i < avoidList.size(); i++) - if (avoidList[i] == token) - return std::vector(); - avoidList.push_back(token); - - std::vector first; - //First, if the symbol is a terminal, than it's first set is just itself. - if (token.isTerminal()) { - first.push_back(token); - return(first); - } - //Otherwise.... - //Ok, to make a first set, go through the grammer, if the token it's left side, add it's production's first token's first set. - //If that one includes mull, do the next one too (if it exists). - Symbol rightToken; - std::vector recursiveFirstSet; - for (std::vector::size_type i = 0; i < loadedGrammer.size(); i++) { - if (token == loadedGrammer[i]->getLeftSide()) { - //Loop through the rule adding first sets for each token if the previous token contained NULL - int j = 0; - do { - rightToken = loadedGrammer[i]->getRightSide()[j]; //Get token of the right side of this rule - if (rightToken.isTerminal()) { - recursiveFirstSet.push_back(rightToken); - } else { - //Add the entire set - recursiveFirstSet = firstSet(rightToken, avoidList, false);//Don't add children to cache, as early termination may cause them to be incomplete - } - first.insert(first.end(), recursiveFirstSet.begin(), recursiveFirstSet.end()); - j++; - } while (isNullable(rightToken) && loadedGrammer[i]->getRightSide().size() > j); - } - } - if (addNewTokens) - tokenFirstSet[token] = first; - return(first); -} - -bool Parser::isNullable(Symbol token) { - if (tokenNullable.find(token) != tokenNullable.end()) - return tokenNullable[token]; - bool nullable = isNullableHelper(token, std::set()); - tokenNullable[token] = nullable; - return nullable; -} -//We use this helper function to recurse because it is possible to wind up with loops, and if so we want -//early termination. However, this means that nullable determinations in the middle of the loop are inaccurate -//(since we terminated early), so we don't want to save them. Thus, for simplicity, only the main method will -//add to the cache. This is somewhat unfortunate for preformance, but the necessary additions to keep track of -//invalidated state are more complicated than it's worth. -bool Parser::isNullableHelper(Symbol token, std::set done) { - if (token.isTerminal()) - return token == nullSymbol; - if (done.find(token) != done.end()) - return false; - done.insert(token); - if (tokenNullable.find(token) != tokenNullable.end()) - return tokenNullable[token]; - - for (std::vector::size_type i = 0; i < loadedGrammer.size(); i++) { - if (token == loadedGrammer[i]->getLeftSide()) { - auto rightSide = loadedGrammer[i]->getRightSide(); - bool ruleNullable = true; - for (int j = 0; j < rightSide.size(); j++) { - if (!isNullableHelper(rightSide[j], done)) { - ruleNullable = false; - break; - } - } - if (ruleNullable) - return true; - } - } - return false; -} - -//Return the correct lookahead. This followSet is built based on the current rule's lookahead if at end, or the next Symbol's first set. -std::vector Parser::incrementiveFollowSet(ParseRule* rule) { - //Advance the pointer past the current Symbol (the one we want the followset for) to the next symbol (which might be in our follow set, or might be the end) - rule = rule->clone(); - rule->advancePointer(); - - //Get the first set of the next Symbol. If it contains nullSymbol, keep doing for the next one - std::vector followSet; - std::vector symbolFirstSet; - bool symbolFirstSetHasNull = true; - while (symbolFirstSetHasNull && !rule->isAtEnd()) { - symbolFirstSetHasNull = false; - symbolFirstSet = firstSet(rule->getAtNextIndex()); - for (std::vector::size_type i = 0; i < symbolFirstSet.size(); i++) { - if (symbolFirstSet[i] == nullSymbol) { - symbolFirstSetHasNull = true; - symbolFirstSet.erase(symbolFirstSet.begin()+i); - break; - } - } - followSet.insert(followSet.end(), symbolFirstSet.begin(), symbolFirstSet.end()); - rule->advancePointer(); - } - if (rule->isAtEnd()) { - symbolFirstSet = rule->getLookahead(); - followSet.insert(followSet.end(), symbolFirstSet.begin(), symbolFirstSet.end()); - } - std::vector followSetReturn; - for (std::vector::size_type i = 0; i < followSet.size(); i++) { - bool alreadyIn = false; - for (std::vector::size_type j = 0; j < followSetReturn.size(); j++) - if (followSet[i] == followSetReturn[j]) { - alreadyIn = true; - break; - } - if (!alreadyIn) - followSetReturn.push_back(followSet[i]); - } - delete rule; - return followSetReturn; -} - -void Parser::closure(State* state) { - //Add all the applicable rules. - //std::cout << "Closure on " << state->toString() << " is" << std::endl; - std::vector stateTotal = state->getTotal(); - for (std::vector::size_type i = 0; i < stateTotal.size(); i++) { - ParseRule* currentStateRule = stateTotal[i]; - //If it's at it's end, move on. We can't advance it. - if(currentStateRule->isAtEnd()) - continue; - for (std::vector::size_type j = 0; j < loadedGrammer.size(); j++) { - //If the current symbol in the rule is not null (rule completed) and it equals a grammer's left side - ParseRule* currentGramRule = loadedGrammer[j]->clone(); - if (currentStateRule->getAtNextIndex() == currentGramRule->getLeftSide()) { - //std::cout << (*stateTotal)[i]->getAtNextIndex()->toString() << " has an applicable production " << loadedGrammer[j]->toString() << std::endl; - //Now, add the correct lookahead. This followSet is built based on the current rule's lookahead if at end, or the next Symbol's first set. - //std::cout << "Setting lookahead for " << currentGramRule->toString() << " in state " << state->toString() << std::endl; - currentGramRule->setLookahead(incrementiveFollowSet(currentStateRule)); - - //Check to make sure not already in - bool isAlreadyInState = false; - for (std::vector::size_type k = 0; k < stateTotal.size(); k++) { - if (stateTotal[k]->equalsExceptLookahead(*currentGramRule)) { - //std::cout << (*stateTotal)[k]->toString() << std::endl; - stateTotal[k]->addLookahead(currentGramRule->getLookahead()); - isAlreadyInState = true; - delete currentGramRule; - break; - } - } - if (!isAlreadyInState) { - state->remaining.push_back(currentGramRule); - stateTotal = state->getTotal(); - } - } else { - delete currentGramRule; - } - } - } - //std::cout << state->toString() << std::endl; -} - -//Adds state if it doesn't already exist. -void Parser::addStates(std::vector< State* >* stateSets, State* state, std::queue* toDo) { - std::vector< State* > newStates; - //For each rule in the state we already have - std::vector currStateTotal = state->getTotal(); - for (std::vector::size_type i = 0; i < currStateTotal.size(); i++) { - //Clone the current rule - ParseRule* advancedRule = currStateTotal[i]->clone(); - //Try to advance the pointer, if sucessful see if it is the correct next symbol - if (advancedRule->advancePointer()) { - //Technically, it should be the set of rules sharing this symbol advanced past in the basis for new state - - //So search our new states to see if any of them use this advanced symbol as a base. - //If so, add this rule to them. - //If not, create it. - bool symbolAlreadyInState = false; - for (std::vector< State* >::size_type j = 0; j < newStates.size(); j++) { - if (newStates[j]->basis[0]->getAtIndex() == advancedRule->getAtIndex()) { - symbolAlreadyInState = true; - //So now check to see if this exact rule is in this state - if (!newStates[j]->containsRule(advancedRule)) - newStates[j]->basis.push_back(advancedRule); - //We found a state with the same symbol, so stop searching - break; - } - } - if (!symbolAlreadyInState) { - State* newState = new State(stateSets->size()+newStates.size(),advancedRule, state); - newStates.push_back(newState); - } - } else { - delete advancedRule; - } - //Also add any completed rules as reduces in the action table - //See if reduce - //Also, this really only needs to be done for the state's basis, but we're already iterating through, so... - std::vector lookahead = currStateTotal[i]->getLookahead(); - if (currStateTotal[i]->isAtEnd()) { - for (std::vector::size_type j = 0; j < lookahead.size(); j++) - table.add(stateNum(state), lookahead[j], new ParseAction(ParseAction::REDUCE, currStateTotal[i])); - } else if (currStateTotal[i]->getAtNextIndex() == nullSymbol) { - //If is a rule that produces only NULL, add in the approprite reduction, but use a new rule with a right side of length 0. (so we don't pop off stack) - ParseRule* nullRule = currStateTotal[i]->clone(); - nullRule->setRightSide(std::vector()); - for (std::vector::size_type j = 0; j < lookahead.size(); j++) - table.add(stateNum(state), lookahead[j], new ParseAction(ParseAction::REDUCE, nullRule)); - } - } - //Put all our new states in the set of states only if they're not already there. - bool stateAlreadyInAllStates = false; - Symbol currStateSymbol; - for (std::vector< State * >::size_type i = 0; i < newStates.size(); i++) { - stateAlreadyInAllStates = false; - currStateSymbol = (*(newStates[i]->getBasis()))[0]->getAtIndex(); - for (std::vector< State * >::size_type j = 0; j < stateSets->size(); j++) { - if (newStates[i]->basisEquals(*((*stateSets)[j]))) { - stateAlreadyInAllStates = true; - //If it does exist, we should add it as the shift/goto in the action table - (*stateSets)[j]->addParents(newStates[i]->getParents()); - table.add(stateNum(state), currStateSymbol, new ParseAction(ParseAction::SHIFT, j)); - break; - } - } - if (!stateAlreadyInAllStates) { - //If the state does not already exist, add it and add it as the shift/goto in the action table - stateSets->push_back(newStates[i]); - toDo->push(newStates[i]); - table.add(stateNum(state), currStateSymbol, new ParseAction(ParseAction::SHIFT, stateSets->size()-1)); - } - } -} - -std::string Parser::stateSetToString() { - std::string concat = ""; - for (std::vector< State *>::size_type i = 0; i < stateSets.size(); i++) { - concat += intToString(i) + " is " + stateSets[i]->toString(); - } - return concat; -} - - -std::string Parser::tableToString() { - return table.toString(); -} - -//parseInput is now pure virtual - -std::string Parser::grammerToString() { - //Iterate through the vector, adding string representation of each grammer rule - std::cout << "About to toString\n"; - std::string concat = ""; - for (int i = 0; i < loadedGrammer.size(); i++) { - concat += loadedGrammer[i]->toString() + "\n"; - } - return(concat); -} - -std::string Parser::grammerToDOT() { - //Iterate through the vector, adding DOT representation of each grammer rule - //std::cout << "About to DOT export\n"; - std::string concat = ""; - for (int i = 0; i < loadedGrammer.size(); i++) { - concat += loadedGrammer[i]->toDOT(); - } - return("digraph Kraken_Grammer { \n" + concat + "}"); -} - diff --git a/deprecated_compiler/src/RNGLRParser.cpp b/deprecated_compiler/src/RNGLRParser.cpp deleted file mode 100644 index 006856a..0000000 --- a/deprecated_compiler/src/RNGLRParser.cpp +++ /dev/null @@ -1,565 +0,0 @@ -#include "RNGLRParser.h" -#include - -//sorry about the macros -#define RESET "\033[0m" -#define BOLDRED "\033[1m\033[31m" -#define BOLDWHITE "\033[1m\033[37m" -#define BOLDGREEN "\033[1m\033[32m" -#define BOLDYELLOW "\033[1m\033[33m" -#define BOLDBLUE "\033[1m\033[34m" -#define BOLDMAGENTA "\033[1m\033[35m" -#define BOLDCYAN "\033[1m\033[36m" - -RNGLRParser::RNGLRParser() { - // -} - -RNGLRParser::~RNGLRParser() { - // -} - -void RNGLRParser::printReconstructedFrontier(int frontier) { - std::vector lastFrontier = gss.getFrontier(frontier); - for (int j = 0; j < lastFrontier.size(); j++) { - std::cout << "State: " << lastFrontier[j] << std::endl; - std::vector> stateParseActions = table.stateAsParseActionVector(lastFrontier[j]); - std::set> noRepeats; - for (auto k : stateParseActions) - noRepeats.insert(k); - for (auto k : noRepeats) - std::cout << k.first << " " << k.second.toString(false) << std::endl; - std::cout << std::endl; - } -} - -NodeTree* RNGLRParser::parseInput(std::string inputString, std::string filename, bool highlight_errors) { - input.clear(); - gss.clear(); - while(!toReduce.empty()) toReduce.pop(); - while(!toShift.empty()) toReduce.pop(); - SPPFStepNodes.clear(); - nullableParts.clear(); - packedMap.clear(); - bool errord = false; - - //Check for no tokens - bool accepting = false; - if (inputString == "") { - std::vector* zeroStateActions = table.get(0,EOFSymbol); - for (int i = 0; i < zeroStateActions->size(); i++) { - if ((*zeroStateActions)[i]->action == ParseAction::REDUCE) - accepting = true; - } - if (accepting) { - std::cout << "Accepted!" << std::endl; - return getNullableParts((*(stateSets[0]->getBasis()))[0]->getLeftSide()); - } else { - std::cerr << "Rejected, no input (with no accepting state)" << std::endl; - } - return new NodeTree(); - } - - lexer.reset(); - lexer.setInput(inputString); - //Now fully lex our input because this algorithm was designed in that manner and simplifies this first implementation. - //It could be converted to on-line later. - int tokenNum = 1; - Symbol currentToken = lexer.next(); - input.push_back(currentToken); - while (currentToken != EOFSymbol) { - currentToken = lexer.next(); - //std::cout << "CurrentToken is " << currentToken.toString() << std::endl; - if (currentToken == invalidSymbol) { - std::cerr << filename << ":" << findLine(tokenNum) << std::endl; - errord = true; - std::cerr << "lex error" << std::endl; - std::cerr << "Invalid Symbol!" << std::endl; - throw "Invalid Symbol, cannot lex"; - } - input.push_back(currentToken); - tokenNum++; - } - - // std::cout << "\nDone with Lexing, length:" << input.size() << std::endl; - // std::cout << input[0].toString() << std::endl; - - - // for (int i = 0; i < input.size(); i++) - // std::cout << "|" << input[i]->toString() << "|"; - // std::cout << std::endl; - - - //std::cout << "Setting up 0th frontier, first actions, toShift, toReduce" << std::endl; - - //Frontier 0, new node with state 0 - NodeTree* v0 = gss.newNode(0); - gss.addToFrontier(0,v0); - - //std::cout << "Done setting up new frontier" << std::endl; - - std::vector firstActions = *(table.get(0, input[0])); - for (std::vector::size_type i = 0; i < firstActions.size(); i++) { - if (firstActions[i]->action == ParseAction::SHIFT) - toShift.push(std::make_pair(v0,firstActions[i]->shiftState)); - else if (firstActions[i]->action == ParseAction::REDUCE && fullyReducesToNull(firstActions[i]->reduceRule)) { - Reduction newReduction = {v0, firstActions[i]->reduceRule->getLeftSide(), 0, getNullableParts(firstActions[i]->reduceRule), NULL}; - toReduce.push(newReduction); - } - } - - // std::cout << "GSS:\n" << gss.toString() << std::endl; - - //std::cout << "Starting parse loop" << std::endl; - - for (int i = 0; i < input.size(); i++) { - // std::cout << "Checking if frontier " << i << " is empty" << std::endl; - if (gss.frontierIsEmpty(i)) { - //std::cout << "Frontier " << i << " is empty." << std::endl; - //std::cerr << "Parsing failed on " << input[i].toString() << std::endl; - //std::cerr << "Problem is on line: " << findLine(i) << std::endl; - // std::cerr << filename << ":" << findLine(i) << std::endl; - errord = true; - if (highlight_errors) - std::cout << BOLDBLUE; - std::cout << filename << ":" << findLine(i) << std::endl; - if (highlight_errors) - std::cout << BOLDMAGENTA; - std::cout << ": parse error" << std::endl; - - std::ifstream infile(filename); - std::string line; - int linecount = 0; - while(std::getline(infile,line)) - { - if(linecount == findLine(i) - 1) { - if (highlight_errors) - std::cout << BOLDRED; - std::cout << line << std::endl; - } - linecount++; - } - if (highlight_errors) - std::cout << RESET << std::endl; - - break; - } - - //Clear the vector of SPPF nodes created every step - SPPFStepNodes.clear(); - - while (toReduce.size() != 0) { - //std::cout << "Reducing for " << i << std::endl; - //std::cout << "GSS:\n" << gss.toString() << std::endl; - reducer(i); - } - // std::cout << "Shifting for " << i << std::endl; - shifter(i); - //std::cout << "GSS:\n" << gss.toString() << std::endl; - } - //std::cout << "Done with parsing loop, checking for acceptance" << std::endl; - NodeTree* accState = gss.frontierGetAccState(input.size()-1); - if (accState) { - std::cout << "Accepted!" << std::endl; - return gss.getEdge(accState, v0); - } - - if (!errord) { - std::cerr << filename << ":" << findLine(input.size())-2 << std::endl; - std::cerr << "parse error" << std::endl; - std::cerr << "Nearby is:" << std::endl; - } - - std::cerr << "Rejected!" << std::endl; - // std::cout << "GSS:\n" << gss.toString() << std::endl; - return NULL; -} - -void RNGLRParser::reducer(int i) { - Reduction reduction = toReduce.front(); - toReduce.pop(); - //std::cout << "Doing reduction of length " << reduction.length << " from state " << reduction.from->getData() << " to symbol " << reduction.symbol->toString() << std::endl; - int pathLength = reduction.length > 0 ? reduction.length -1 : 0; - //Get every reachable path - std::vector*> >* paths = gss.getReachablePaths(reduction.from, pathLength); - - for (std::vector*> >::size_type j = 0; j < paths->size(); j++) { - - std::vector*> currentPath = (*paths)[j]; - - //Get the edges for the current path - std::vector*> pathEdges = getPathEdges(currentPath); - std::reverse(pathEdges.begin(), pathEdges.end()); - //If the reduction length is 0, label as passed in is null - if (reduction.length != 0) - pathEdges.push_back(reduction.label); - //The end of the current path - NodeTree* currentReached = currentPath[currentPath.size()-1]; - - //std::cout << "Getting the shift state for state " << currentReached->getData() << " and symbol " << reduction.symbol.toString() << std::endl; - int toState = table.getShift(currentReached->getData(), reduction.symbol)->shiftState; - - //If reduction length is 0, then we make the new label the appropriate nullable parts - NodeTree* newLabel = NULL; - if (reduction.length == 0) { - newLabel = reduction.nullableParts; - } else { - //Otherwise, we create the new label if we haven't already - int reachedFrontier = gss.getContainingFrontier(currentReached); - for (std::vector*, int> >::size_type k = 0; k < SPPFStepNodes.size(); k++) { - if ( SPPFStepNodes[k].second == reachedFrontier && SPPFStepNodes[k].first->getData() == reduction.symbol) { - newLabel = SPPFStepNodes[k].first; - break; - } - } - if (!newLabel) { - newLabel = new NodeTree("frontier: " + intToString(reachedFrontier), reduction.symbol); - SPPFStepNodes.push_back(std::make_pair(newLabel, reachedFrontier)); - } - } - - NodeTree* toStateNode = gss.inFrontier(i, toState); - if (toStateNode) { - if (!gss.hasEdge(toStateNode, currentReached)) { - gss.addEdge(toStateNode, currentReached, newLabel); - if (reduction.length != 0) { - //Do all non null reduction - //std::cout << "Checking for non-null reductions in states that already existed" << std::endl; - std::vector actions = *(table.get(toState, input[i])); - for (std::vector::size_type k = 0; k < actions.size(); k++) { - if (actions[k]->action == ParseAction::REDUCE && !fullyReducesToNull(actions[k]->reduceRule)) { - Reduction newReduction = {currentReached, actions[k]->reduceRule->getLeftSide(), actions[k]->reduceRule->getIndex(), getNullableParts(actions[k]->reduceRule), newLabel}; - toReduce.push(newReduction); - } - } - } - } - } else { - toStateNode = gss.newNode(toState); - gss.addToFrontier(i, toStateNode); - gss.addEdge(toStateNode, currentReached, newLabel); - - //std::cout << "Adding shifts and reductions for a state that did not exist" << std::endl; - std::vector actions = *(table.get(toState, input[i])); - for (std::vector::size_type k = 0; k < actions.size(); k++) { - //std::cout << "Action is " << actions[k]->toString() << std::endl; - if (actions[k]->action == ParseAction::SHIFT) { - toShift.push(std::make_pair(toStateNode, actions[k]->shiftState)); - } else if (actions[k]->action == ParseAction::REDUCE && fullyReducesToNull(actions[k]->reduceRule)) { - Reduction newReduction = {toStateNode, actions[k]->reduceRule->getLeftSide(), 0, getNullableParts(actions[k]->reduceRule), NULL}; - toReduce.push(newReduction); - } else if (reduction.length != 0 && actions[k]->action == ParseAction::REDUCE && !fullyReducesToNull(actions[k]->reduceRule)) { - Reduction newReduction = {currentReached, actions[k]->reduceRule->getLeftSide(), actions[k]->reduceRule->getIndex(), getNullableParts(actions[k]->reduceRule), newLabel}; - toReduce.push(newReduction); - } - } - } - if (reduction.length != 0) - addChildren(newLabel, &pathEdges, reduction.nullableParts); - } -} - -void RNGLRParser::shifter(int i) { - if (i != input.size()-1) { - std::queue< std::pair*, int> > nextShifts; - NodeTree* newLabel = new NodeTree("frontier: " + intToString(i), input[i]); - while (!toShift.empty()) { - std::pair*, int> shift = toShift.front(); - toShift.pop(); - //std::cout << "Current potential shift from " << shift.first->getData() << " to " << shift.second << std::endl; - NodeTree* shiftTo = gss.inFrontier(i+1, shift.second); - if (shiftTo) { - //std::cout << "State already existed, just adding edge" << std::endl; - gss.addEdge(shiftTo, shift.first, newLabel); - std::vector actions = *(table.get(shift.second, input[i+1])); - for (std::vector::size_type j = 0; j < actions.size(); j++) { - if (actions[j]->action == ParseAction::REDUCE && !fullyReducesToNull(actions[j]->reduceRule)) { - Reduction newReduction = {shift.first, actions[j]->reduceRule->getLeftSide(), actions[j]->reduceRule->getIndex(), getNullableParts(actions[j]->reduceRule), newLabel}; - toReduce.push(newReduction); - } - } - } else { - //std::cout << "State did not already exist, adding" << std::endl; - shiftTo = gss.newNode(shift.second); - gss.addToFrontier(i+1, shiftTo); - gss.addEdge(shiftTo, shift.first, newLabel); - std::vector actions = *(table.get(shift.second, input[i+1])); - for (std::vector::size_type j = 0; j < actions.size(); j++) { - //std::cout << "Adding action " << actions[j]->toString() << " to either nextShifts or toReduce" << std::endl; - //Shift - if (actions[j]->action == ParseAction::SHIFT) { - nextShifts.push(std::make_pair(shiftTo, actions[j]->shiftState)); - } else if (actions[j]->action == ParseAction::REDUCE && !fullyReducesToNull(actions[j]->reduceRule)) { - Reduction newReduction = {shift.first, actions[j]->reduceRule->getLeftSide(), actions[j]->reduceRule->getIndex(), getNullableParts(actions[j]->reduceRule), newLabel}; - toReduce.push(newReduction); - } else if (actions[j]->action == ParseAction::REDUCE && fullyReducesToNull(actions[j]->reduceRule)) { - Reduction newReduction = {shiftTo, actions[j]->reduceRule->getLeftSide(), 0, getNullableParts(actions[j]->reduceRule), NULL}; - toReduce.push(newReduction); - } - } - } - } - toShift = nextShifts; - } -} - -void RNGLRParser::addChildren(NodeTree* parent, std::vector*>* children, NodeTree* nullableParts) { - if (nullableParts) - children->push_back(nullableParts); - - if (!belongsToFamily(parent, children)) { - if (parent->getChildren().size() == 0) { - parent->addChildren(children); - } else { - if (!arePacked(parent->getChildren())) { - NodeTree* subParent = new NodeTree("AmbiguityPackInner", Symbol("AmbiguityPackInner", true)); - setPacked(subParent, true); - std::vector*> tmp = parent->getChildren(); - subParent->addChildren(&tmp); - parent->clearChildren(); - parent->addChild(subParent); - } - NodeTree* t = new NodeTree("AmbiguityPackOuter", Symbol("AmbiguityPackInner", true)); - setPacked(t, true); - parent->addChild(t); - t->addChildren(children); - } - } -} - -bool RNGLRParser::belongsToFamily(NodeTree* node, std::vector*>* nodes) { - //std::cout << "Checking " << node->getData()->toString() << "'s family" << std::endl; - std::vector*> children = node->getChildren(); - for (std::vector*>::size_type i = 0; i < nodes->size(); i++) { - bool containsOne = false; - for (std::vector*>::size_type j = 0; j < children.size(); j++) { - //Not sure where null comes from. For right now, just check to be sure we don't segfault - if ((*nodes)[i] == children[j] || ( (*nodes)[i] != NULL && children[j] != NULL && (*(*nodes)[i]) == *(children[j]) )) { - containsOne = true; - break; - } - } - if (!containsOne) { - return false; - } - } - return true; -} - -bool RNGLRParser::arePacked(std::vector*> nodes) { - bool packed = true; - for (std::vector*>::size_type i = 0; i < nodes.size(); i++) - packed &= packedMap[*(nodes[i])]; - return packed; -} - -bool RNGLRParser::isPacked(NodeTree* node) { - return packedMap[*node]; -} - -void RNGLRParser::setPacked(NodeTree* node, bool isPacked) { - packedMap[*node] = isPacked; -} - - -//Have to use own add states function in order to construct RN table instead of LALR table -void RNGLRParser::addStates(std::vector< State* >* stateSets, State* state, std::queue* toDo) { - std::vector< State* > newStates; - //For each rule in the state we already have - std::vector currStateTotal = state->getTotal(); - for (std::vector::size_type i = 0; i < currStateTotal.size(); i++) { - //Clone the current rule - ParseRule* advancedRule = currStateTotal[i]->clone(); - //Try to advance the pointer, if sucessful see if it is the correct next symbol - if (advancedRule->advancePointer()) { - //Technically, it should be the set of rules sharing this symbol advanced past in the basis for new state - - //So search our new states to see if any of them use this advanced symbol as a base. - //If so, add this rule to them. - //If not, create it. - bool symbolAlreadyInState = false; - for (std::vector< State* >::size_type j = 0; j < newStates.size(); j++) { - if (newStates[j]->basis[0]->getAtIndex() == advancedRule->getAtIndex()) { - symbolAlreadyInState = true; - //Add rule to state, combining with idenical rule except lookahead if exists - newStates[j]->addRuleCombineLookahead(advancedRule); - //We found a state with the same symbol, so stop searching - break; - } - } - if (!symbolAlreadyInState) { - State* newState = new State(stateSets->size()+newStates.size(),advancedRule, state); - newStates.push_back(newState); - } - } else { - delete advancedRule; - } - } - //Put all our new states in the set of states only if they're not already there. - bool stateAlreadyInAllStates = false; - Symbol currStateSymbol; - for (std::vector< State * >::size_type i = 0; i < newStates.size(); i++) { - stateAlreadyInAllStates = false; - currStateSymbol = (*(newStates[i]->getBasis()))[0]->getAtIndex(); - for (std::vector< State * >::size_type j = 0; j < stateSets->size(); j++) { - if (newStates[i]->basisEqualsExceptLookahead(*((*stateSets)[j]))) { - //if (newStates[i]->basisEquals(*((*stateSets)[j]))) { - stateAlreadyInAllStates = true; - //If it does exist, we should add it as the shift/goto in the action table - //std::cout << "newStates[" << i << "] == stateSets[" << j << "]" << std::endl; - - if (!((*stateSets)[j]->basisEquals(*(newStates[i])))) - toDo->push((*stateSets)[j]); - - (*stateSets)[j]->combineStates(*(newStates[i])); - //std::cout << j << "\t Hay, doing an inside loop state reductions!" << std::endl; - addStateReductionsToTable((*stateSets)[j]); - table.add(stateNum(state), currStateSymbol, new ParseAction(ParseAction::SHIFT, j)); - - break; - } - } - if (!stateAlreadyInAllStates) { - //If the state does not already exist, add it and add it as the shift/goto in the action table - stateSets->push_back(newStates[i]); - toDo->push(newStates[i]); - table.add(stateNum(state), currStateSymbol, new ParseAction(ParseAction::SHIFT, stateSets->size()-1)); - } - } - addStateReductionsToTable(state); -} - - -void RNGLRParser::addStateReductionsToTable(State* state) { - std::vector currStateTotal = state->getTotal(); - //std::cout << currStateTotal->size() << "::" << state->getNumber() << std::endl; - for (std::vector::size_type i = 0; i < currStateTotal.size(); i++) { - //See if reduce - //Also, this really only needs to be done for the state's basis, but we're already iterating through, so... - std::vector lookahead = currStateTotal[i]->getLookahead(); - if (currStateTotal[i]->isAtEnd()) { - for (std::vector::size_type j = 0; j < lookahead.size(); j++) { - table.add(stateNum(state), lookahead[j], new ParseAction(ParseAction::REDUCE, currStateTotal[i])); - } - //If this has an appropriate ruduction to null, get the reduce trees out - } else if (reducesToNull(currStateTotal[i])) { - //std::cout << (*currStateTotal)[i]->toString() << " REDUCES TO NULL" << std::endl; - //It used to be that if is a rule that produces only NULL, add in the approprite reduction, but use a new rule with a right side that is equal to - //the part that we've already gone through in the rule. (so we don't pop extra off stack) - //Now we use the same rule and make sure that the index location is used - for (std::vector::size_type j = 0; j < lookahead.size(); j++) - table.add(stateNum(state), lookahead[j], new ParseAction(ParseAction::REDUCE, currStateTotal[i])); - } - } -} - -bool RNGLRParser::fullyReducesToNull(ParseRule* rule) { - return rule->getIndex() == 0 && reducesToNull(rule); -} - -bool RNGLRParser::reducesToNull(ParseRule* rule) { - auto itr = reduceToNullMap.find(rule); - if (itr != reduceToNullMap.end()) - return itr->second; - std::vector avoidList; - auto val = reducesToNull(rule, avoidList); - reduceToNullMap[rule] = val; - return val; -} - -bool RNGLRParser::reducesToNull(ParseRule* rule, std::vector avoidList) { - //If the rule is completed and not null, it doesn't reduce to null, it's just completed. - if (rule->isAtEnd() && rule->getRightSize() != 0) - return false; - - for (std::vector::size_type i = 0; i < avoidList.size(); i++) - if (rule->getLeftSide() == avoidList[i]) - return false; - - avoidList.push_back(rule->getLeftSide()); - - std::vector rightSide = rule->getRightSide(); - bool reduces = true; - for (std::vector::size_type i = rule->getIndex(); i < rightSide.size(); i++) { - if (rightSide[i] == nullSymbol) - continue; - if (rightSide[i].isTerminal()) { - reduces = false; - break; - } - bool subSymbolReduces = false; - for (std::vector::size_type j = 0; j < loadedGrammer.size(); j++) { - if (loadedGrammer[j]->getLeftSide() == rightSide[i]) { - if(reducesToNull(loadedGrammer[j], avoidList)) { - subSymbolReduces = true; - break; - } - } - } - if (!subSymbolReduces) { - reduces = false; - break; - } - } - return reduces; -} - -NodeTree* RNGLRParser::getNullableParts(ParseRule* rule) { - return getNullableParts(rule, std::vector*>()); -} - -NodeTree* RNGLRParser::getNullableParts(ParseRule* rule, std::vector*> avoidList) { - if (reducesToNull(rule)) { - //std::cout << "Reduces to null so adding parts " << rule->toString() << std::endl; - Symbol symbol = rule->getLeftSide(); - NodeTree* symbolNode = new NodeTree(symbol.getName(), symbol); - if (rule->getAtNextIndex() == nullSymbol) { - symbolNode->addChild(new NodeTree(nullSymbol.getName(), nullSymbol)); - } else { - //Find recursively - ParseRule* iterate = rule->clone(); - while (!iterate->isAtEnd()) { - //Check to see if we've done this symbol already, if so use it - for (std::vector*>::size_type i = 0; i < avoidList.size(); i++) { - if (iterate->getAtNextIndex() == avoidList[i]->getData()) { - symbolNode->addChild(avoidList[i]); - break; - } - } - //We haven't so do it recursively - for (std::vector::size_type i = 0; i < loadedGrammer.size(); i++) { - if (fullyReducesToNull(loadedGrammer[i]) && iterate->getAtNextIndex() == loadedGrammer[i]->getLeftSide()) { - NodeTree* symbolTree = getNullableParts(loadedGrammer[i], avoidList); - avoidList.push_back(symbolTree); - symbolNode->addChild(symbolTree); - } - } - iterate->advancePointer(); - } - } - return symbolNode; - } - return NULL; -} - -NodeTree* RNGLRParser::getNullableParts(Symbol symbol) { - return new NodeTree("CRAZY_SYMBOL", nullSymbol); -} - -std::vector*> RNGLRParser::getPathEdges(std::vector*> path) { - std::vector*> pathEdges; - for (std::vector*>::size_type i = 0; i < path.size()-1; i++) - pathEdges.push_back(gss.getEdge(path[i], path[i+1])); - return pathEdges; -} - -int RNGLRParser::findLine(int tokenNum) { - int lineNo = 1; - for (int i = 0; i < tokenNum; i++) { - std::string tokenString = input[i].getValue(); - for (int j = 0; j < tokenString.size(); j++) - if (tokenString[j] == '\n') - lineNo++; - } - return lineNo; -} diff --git a/deprecated_compiler/src/RegEx.cpp b/deprecated_compiler/src/RegEx.cpp deleted file mode 100644 index b59bbfb..0000000 --- a/deprecated_compiler/src/RegEx.cpp +++ /dev/null @@ -1,225 +0,0 @@ -#include "RegEx.h" -#include - -RegEx::RegEx(std::string inPattern) { - pattern = inPattern; - std::vector ending; - begin = construct(&ending, inPattern); - //last one is goal state, add it to the end of all of these last states - for (std::vector::size_type i = 0; i < ending.size(); i++) - ending[i]->addNext(NULL); -} - -RegExState* RegEx::construct(std::vector* ending, std::string pattern) { - //In the RegEx re-write, instead of doing complicated unperenthesising, we keep track of both the "front" and the "end" of a state. - //(these could be different if the state is perenthesezed) - std::vector previousStatesBegin; - std::vector previousStatesEnd; - std::vector currentStatesBegin; - std::vector currentStatesEnd; - - bool alternating = false; - RegExState* begin = new RegExState(); - currentStatesBegin.push_back(begin); - currentStatesEnd.push_back(begin); - - for (int i = 0; i < pattern.length(); i++) { - switch (pattern[i]) { - case '*': - { - //std::cout << "Star at " << i << " in " << pattern << std::endl; - //NOTE: Because of the re-write, this is necessary again - for (std::vector::size_type j = 0; j < currentStatesEnd.size(); j++) - for (std::vector::size_type k = 0; k < currentStatesBegin.size(); k++) - currentStatesEnd[j]->addNext(currentStatesBegin[k]); //Make the ends point to the beginnings - //add all previous states to current states to enable skipping over the starred item - currentStatesBegin.insert(currentStatesBegin.end(), previousStatesBegin.begin(), previousStatesBegin.end()); - currentStatesEnd.insert(currentStatesEnd.end(), previousStatesEnd.begin(), previousStatesEnd.end()); - } - break; - case '+': - { - //std::cout << "Plus at " << i << " in " << pattern << std::endl; - //NOTE: Because of the re-write, this is necessary again - for (std::vector::size_type j = 0; j < currentStatesEnd.size(); j++) - for (std::vector::size_type k = 0; k < currentStatesBegin.size(); k++) - currentStatesEnd[j]->addNext(currentStatesBegin[k]); //Make the ends point to the beginnings - } - break; - case '?': - { - //std::cout << "Question at " << i << " in " << pattern << std::endl; - //add all previous states to current states to enable skipping over the questioned item - currentStatesBegin.insert(currentStatesBegin.end(), previousStatesBegin.begin(), previousStatesBegin.end()); - currentStatesEnd.insert(currentStatesEnd.end(), previousStatesEnd.begin(), previousStatesEnd.end()); - } - break; - case '|': - { - //std::cout << "Alternation at " << i << " in " << pattern << std::endl; - //alternation - alternating = true; - } - - break; - case '(': - { - //std::cout << "Begin peren at " << i << " in " << pattern << std::endl; - //perentheses - std::vector innerEnds; - int perenEnd = findPerenEnd(pattern, i); - RegExState* innerBegin = construct(&innerEnds, strSlice(pattern, i+1, perenEnd)); - i = perenEnd; - std::vector innerBegins = innerBegin->getNextStates(); - if (alternating) { - for (std::vector::size_type j = 0; j < previousStatesEnd.size(); j++) - for (std::vector::size_type k = 0; k < innerBegins.size(); k++) - previousStatesEnd[j]->addNext(innerBegins[k]); - currentStatesBegin.insert(currentStatesBegin.end(), innerBegins.begin(), innerBegins.end()); - currentStatesEnd.insert(currentStatesEnd.end(), innerEnds.begin(), innerEnds.end()); - } else { - for (std::vector::size_type j = 0; j < currentStatesEnd.size(); j++) - for (std::vector::size_type k = 0; k < innerBegins.size(); k++) - currentStatesEnd[j]->addNext(innerBegins[k]); - previousStatesBegin = currentStatesBegin; - previousStatesEnd = currentStatesEnd; - currentStatesBegin = innerBegins; - currentStatesEnd = innerEnds; - } - alternating = false; - } - break; - - // ) does not need a case as we skip over it after finding it in ('s case - - case '\\': - { - i++; - //std::cout << "Escape! Escaping: " << pattern[i] << std::endl; - //Ahh, it's escaping a special character, so fall through to the default. - } - default: - { - //std::cout << "Regular" << std::endl; - //Ahh, it's regular - RegExState* next = new RegExState(pattern[i]); - //If we're alternating, add next as the next for each previous state, and add self to currentStates - if (alternating) { - for (std::vector::size_type j = 0; j < previousStatesEnd.size(); j++) - previousStatesEnd[j]->addNext(next); - currentStatesBegin.push_back(next); - currentStatesEnd.push_back(next); - alternating = false; - } else { - //If we're not alternating, add next as next for all the current states, make the current states the new - //previous states, and add ourself as the new current state. - for (std::vector::size_type j = 0; j < currentStatesEnd.size(); j++) - currentStatesEnd[j]->addNext(next); - - previousStatesBegin.clear(); - previousStatesEnd.clear(); - previousStatesBegin = currentStatesBegin; - previousStatesEnd = currentStatesEnd; - currentStatesBegin.clear(); - currentStatesEnd.clear(); - currentStatesBegin.push_back(next); - currentStatesEnd.push_back(next); - } - } - } - } - (*ending) = currentStatesEnd; - return(begin); -} - - -RegEx::~RegEx() { - //No cleanup necessary -} - -int RegEx::longMatch(std::string stringToMatch) { - // Start in the begin state (only). - int lastMatch = -1; - currentStates.clear(); - currentStates.push_back(begin); - std::vector nextStates; - - for (int i = 0; i < stringToMatch.size(); i++) { - //Go through every current state. Check to see if it is goal, if so update last goal. - //Also, add each state's advance to nextStates - for (std::vector::size_type j = 0; j < currentStates.size(); j++) { - if (currentStates[j]->isGoal()) - lastMatch = i; - std::vector addStates = currentStates[j]->advance(stringToMatch.at(i)); - nextStates.insert(nextStates.end(), addStates.begin(), addStates.end()); - } - //Now, clear our current states and add eaczh one of our addStates if it is not already in current states - - currentStates.clear(); - for (std::vector::size_type j = 0; j < nextStates.size(); j++) { - bool inCurrStates = false; - for (std::vector::size_type k = 0; k < currentStates.size(); k++) { - if (nextStates[j] == currentStates[k]) - inCurrStates = true; - } - if (!inCurrStates) - currentStates.push_back(nextStates[j]); - } - // if (currentStates.size() != 0) - // std::cout << "Matched " << i << " character: " << stringToMatch[i-1] << std::endl; - - nextStates.clear(); - //If we can't continue matching, just return our last matched - if (currentStates.size() == 0) - break; - } - //Check to see if we match on the last character in the string - for (std::vector::size_type j = 0; j < currentStates.size(); j++) { - if (currentStates[j]->isGoal()) - lastMatch = stringToMatch.size(); - } - return lastMatch; -} - -std::string RegEx::getPattern() { - return pattern; -} - -std::string RegEx::toString() { - return pattern + " -> " + begin->toString(); -} - -void RegEx::test() { - { - RegEx re("a*"); - assert(re.longMatch("a") == 1); - assert(re.longMatch("aa") == 2); - assert(re.longMatch("aaaab") == 4); - assert(re.longMatch("b") == 0); - } - - { - RegEx re("a+"); - assert(re.longMatch("aa") == 2); - assert(re.longMatch("aaaab") == 4); - assert(re.longMatch("b") == -1); - } - - { - RegEx re("a(bc)?"); - assert(re.longMatch("ab") == 1); - } - - { - RegEx re("((ab)|c)*"); - assert(re.longMatch("ababc") == 5); - assert(re.longMatch("ad") == 0); - assert(re.longMatch("ababccd") == 6); - } - { - RegEx re("bbb((bba+)|(ba+))*a*((a+b)|(a+bb)|(a+))*bbb") ; - assert(re.longMatch("bbbababbbaaaaaaaaaaaaaaaaaaabbb") == 9); - } - - std::cout << "RegEx tests pass\n"; -} diff --git a/deprecated_compiler/src/RegExState.cpp b/deprecated_compiler/src/RegExState.cpp deleted file mode 100644 index d8a7544..0000000 --- a/deprecated_compiler/src/RegExState.cpp +++ /dev/null @@ -1,82 +0,0 @@ -#include "RegExState.h" - -RegExState::RegExState(char inCharacter) { - character = inCharacter; -} - -RegExState::RegExState() { - character = 0; -} - -RegExState::~RegExState() { - //No cleanup necessary -} - -void RegExState::addNext(RegExState* nextState) { - nextStates.push_back(nextState); -} - -bool RegExState::characterIs(char inCharacter) { - return character == inCharacter; -} - -std::vector RegExState::advance(char advanceCharacter) { - std::vector advanceStates; - for (std::vector::size_type i = 0; i < nextStates.size(); i++) { - if (nextStates[i] != NULL && nextStates[i]->characterIs(advanceCharacter)) - advanceStates.push_back(nextStates[i]); - } - return advanceStates; -} - -std::vector RegExState::getNextStates() { - return nextStates; -} - -bool RegExState::isGoal() { - for (std::vector::size_type i = 0; i < nextStates.size(); i++) - if (nextStates[i] == NULL) - return true; - return false; -} - -std::string RegExState::toString() { - std::vector avoidList; - return toString(&avoidList); -} - -std::string RegExState::toString(RegExState* avoid) { - std::vector avoidList; - avoidList.push_back(avoid); - return toString(&avoidList); -} - -std::string RegExState::toString(std::vector* avoid) { - avoid->push_back(this); - std::string string = ""; - string += std::string("\"") + character + "\""; - for (std::vector::size_type i = 0; i < nextStates.size(); i++) { - bool inAvoid = false; - for (std::vector::size_type j = 0; j < avoid->size(); j++) { - if (nextStates[i] == (*avoid)[j]) { - inAvoid = true; - } - } - if (inAvoid) { - string += "->loop"; - continue; - } - - if (nextStates[i] != this && nextStates[i] != NULL) - string += "->" + nextStates[i]->toString(avoid) + " EC "; - else if (nextStates[i] == NULL) - string += "-> GOAL "; - else - string += "->this"; - } - return string; -} - -char RegExState::getCharacter() { - return character; -} diff --git a/deprecated_compiler/src/State.cpp b/deprecated_compiler/src/State.cpp deleted file mode 100644 index d6bd453..0000000 --- a/deprecated_compiler/src/State.cpp +++ /dev/null @@ -1,164 +0,0 @@ -#include "State.h" - -State::State(int number, ParseRule* basis) { - this->number = number; - this->basis.push_back(basis); -} - -State::State(int number, ParseRule* basis, State* parent) { - this->number = number; - this->basis.push_back(basis); - parents.push_back(parent); -} - -State::~State() { - -} - -const bool State::operator==(const State &other) { - //return (basis == other.basis && remaining == other.remaining); - if (basis.size() != other.basis.size()) - return false; - - for (std::vector< ParseRule* >::size_type i = 0; i < basis.size(); i++) { - if (*(basis[i]) != *(other.basis[i])) - return false; - } - - if (remaining.size() != other.remaining.size()) - return false; - for (std::vector< ParseRule* >::size_type i = 0; i < remaining.size(); i++) { - if ( *(remaining[i]) != *(other.remaining[i]) ) - return false; - } - return true; -} - -const bool State::operator!=(const State &other) { - return !(this->operator==(other)); -} - -const bool State::basisEquals(const State &other) { - //return (basis == other.basis && remaining == other.remaining); - if (basis.size() != other.basis.size()) - return false; - - for (std::vector< ParseRule* >::size_type i = 0; i < basis.size(); i++) { - if (*(basis[i]) != (*(other.basis[i]))) - return false; - } - return true; -} - -const bool State::basisEqualsExceptLookahead(const State &other) { - //return (basis == other.basis && remaining == other.remaining); - if (basis.size() != other.basis.size()) - return false; - - for (std::vector< ParseRule* >::size_type i = 0; i < basis.size(); i++) { - if (!basis[i]->equalsExceptLookahead(*(other.basis[i]))) - return false; - } - return true; -} - -void State::combineStates(State &other) { - for (std::vector< ParseRule* >::size_type i = 0; i < other.basis.size(); i++) { - bool alreadyIn = false; - for (std::vector< ParseRule* >::size_type j = 0; j < basis.size(); j++) { - if (basis[j]->equalsExceptLookahead(*(other.basis[i]))) { - basis[j]->addLookahead(other.basis[i]->getLookahead()); - alreadyIn = true; - } - } - if (!alreadyIn) - basis.push_back(other.basis[i]); - } - addParents(other.getParents()); -} - -std::vector State::getTotal() { - std::vector total; - total.insert(total.begin(), basis.begin(), basis.end()); - total.insert(total.end(), remaining.begin(), remaining.end()); - return total; -} -std::vector* State::getBasis() { - return &basis; -} -std::vector* State::getRemaining() { - return &remaining; -} - -bool State::containsRule(ParseRule* rule) { - auto total = getTotal(); - for (std::vector::size_type i = 0; i < total.size(); i++) { - if (*rule == *(total[i])) { - return true; - } - } - return false; -} - -void State::addRuleCombineLookahead(ParseRule* rule) { - auto total = getTotal(); - bool alreadyIn = false; - for (std::vector::size_type i = 0; i < total.size(); i++) { - if (rule->equalsExceptLookahead(*(total[i]))) { - total[i]->addLookahead(rule->getLookahead()); - alreadyIn = true; - break; - } - } - if (!alreadyIn) - basis.push_back(rule); -} - -std::string State::toString() { - std::string concat = ""; - concat += "State " + intToString(number) + " with " + intToString(parents.size()) + " parents:\n"; - for (std::vector::size_type j = 0; j < basis.size(); j++) { - concat += "\t" + basis[j]->toString() + "\n"; - } - for (std::vector::size_type j = 0; j < remaining.size(); j++) { - concat += "\t+\t" + remaining[j]->toString() + "\n"; - } - return concat; -} - -void State::addParents(std::vector* parents) { - bool alreadyIn = false; - for (std::vector::size_type i = 0; i < parents->size(); i++) { - alreadyIn = false; - for (std::vector::size_type j = 0; j < this->parents.size(); j++) { - if (this->parents[j]->basisEquals(*((*parents)[i]))) { - alreadyIn = true; - break; - } - } - if (!alreadyIn) - this->parents.push_back((*parents)[i]); - } -} -std::vector* State::getParents() { - return &parents; -} - -std::vector* State::getDeepParents(int depth) { - if (depth <= 0) { - std::vector* returnSelf = new std::vector(); - returnSelf->push_back(this); - return returnSelf; - } - std::vector* recursiveParents = new std::vector(); - std::vector* recursiveParentsToAdd; - for (std::vector::size_type i = 0; i < parents.size(); i++) { - recursiveParentsToAdd = parents[i]->getDeepParents(depth-1); - recursiveParents->insert(recursiveParents->end(), recursiveParentsToAdd->begin(), recursiveParentsToAdd->end()); - } - return recursiveParents; -} - -int State::getNumber() { - return number; -} diff --git a/deprecated_compiler/src/StringReader.cpp b/deprecated_compiler/src/StringReader.cpp deleted file mode 100644 index 029e698..0000000 --- a/deprecated_compiler/src/StringReader.cpp +++ /dev/null @@ -1,166 +0,0 @@ -#include "StringReader.h" -#include - -StringReader::StringReader() -{ - str_pos = 0; -} - -StringReader::StringReader(std::string inputString) -{ - str_pos = 0; - setString(inputString); -} - -StringReader::~StringReader() -{ - //dtor -} - -void StringReader::setString(std::string inputString) -{ - rd_string = inputString; - end_reached = false; -} - -std::string StringReader::word(bool truncateEnd) -{ - std::string result = getTokens(" \n\t", truncateEnd); - while (result == " " || result == "\n" || result == "\t") - { - result = getTokens(" \n\t", truncateEnd); - } - return(result); -} - -std::string StringReader::line(bool truncateEnd) -{ - return getTokens("\n", truncateEnd); -} - -std::string StringReader::getTokens(const char *stop_chars, bool truncateEnd) -{ - if (str_pos >= rd_string.size()) - return ""; - size_t found_pos = rd_string.find_first_of(stop_chars, str_pos); - - if (rd_string[str_pos] == '\"') { - //Find the next quote - found_pos = rd_string.find("\"", str_pos+1); - //Check to see if the quote is escaped - int numBackslashes = 0; - int countBack = 1; - while (found_pos >= countBack && rd_string[found_pos-countBack] == '\\') { - numBackslashes++; - countBack++; - } - //While the quote is escaped - while (numBackslashes % 2 == 1) { - //find the next quote - found_pos = rd_string.find("\"", found_pos+1); - //Check to see if it's escaped - numBackslashes = 0; - countBack = 1; - while (found_pos >= countBack && rd_string[found_pos-countBack] == '\\') { - numBackslashes++; - countBack++; - } - } - } - - if (found_pos == str_pos) //We are at the endline - { - std::string stop_char(1, rd_string[str_pos]); - str_pos++; - return stop_char; - } else if (found_pos == std::string::npos) //We are at the end of the file - { - //End of String - end_reached = true; - //std::cout << "Reached end of file!\n"; - return ""; - } else { - - if (truncateEnd) //If we want to get rid of the delimiting character, which is the default, don't add the last char. Note we have to increase str_pos by one manually later - found_pos -= 1; - - if (rd_string[str_pos] == '\"') - found_pos++; - - std::string string_section = rd_string.substr(str_pos, found_pos - str_pos + 1); - str_pos = found_pos + 1; - - if (truncateEnd) //Ok, we didn't add the last char, but str_pos now points at that char. So we move it one ahead. - str_pos++; - return string_section; - } -} - -void StringReader::test() -{ - { - StringReader reader("\"x\""); - assert(reader.word() == "\"x\""); - assert(reader.word() == ""); - } - - { - StringReader reader("\"y\" ;\n"); - assert(reader.word() == "\"y\""); - assert(reader.word() == ";"); - assert(reader.word() == ""); - } - - { - StringReader reader("Goal = greeting ;\n" - "greeting = \"hello\" | greeting \"world\" ;\n"); - assert(reader.word() == "Goal"); - assert(reader.word() == "="); - assert(reader.word() == "greeting"); - assert(reader.word() == ";"); - assert(reader.word() == "greeting"); - assert(reader.word() == "="); - assert(reader.word() == "\"hello\""); - assert(reader.word() == "|"); - assert(reader.word() == "greeting"); - assert(reader.word() == "\"world\""); - assert(reader.word() == ";"); - assert(reader.word() == ""); - } - - { - StringReader reader("one # pretend this is a comment\n" - " two\n"); - assert(reader.word() == "one"); - assert(reader.word() == "#"); - assert(reader.line() == "pretend this is a comment"); - assert(reader.word() == "two"); - assert(reader.word() == ""); - } - - { - // Quoted strings can span lines. - StringReader reader("x = \"\n \" ;\n"); - assert(reader.word() == "x"); - assert(reader.word() == "="); - assert(reader.word() == "\"\n \""); - assert(reader.word() == ";"); - assert(reader.word() == ""); - } - - { - // Strings may contain backslash-escaped quote characters. - StringReader reader( "\"abc\\\"def\\\\\\\\\\\" \"\n"); - assert(reader.word() == "\"abc\\\"def\\\\\\\\\\\" \""); - assert(reader.word() == ""); - } - - { - // A backslash-escaped backslash can be the last character in a string. - StringReader reader( "\"\\\\\" \n"); - assert(reader.word() == "\"\\\\\""); - assert(reader.word() == ""); - } - - std::cout << "StringReader tests pass\n"; -} diff --git a/deprecated_compiler/src/Symbol.cpp b/deprecated_compiler/src/Symbol.cpp deleted file mode 100644 index 8a1fcec..0000000 --- a/deprecated_compiler/src/Symbol.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include "Symbol.h" - -Symbol::Symbol() { - this->name = "UninitlizedSymbol"; - this->terminal = false; - value = "NoValue"; -} - -Symbol::Symbol(std::string name, bool isTerminal) { - this->name = name; - this->terminal = isTerminal; - value = "NoValue"; -} - -Symbol::Symbol(std::string name, bool isTerminal, std::string value) { - this->name = name; - this->terminal = isTerminal; - this->value = value; -} - -Symbol::~Symbol() { - -} - -const bool Symbol::operator==(const Symbol &other) const { - return( name == other.name && terminal == other.terminal); -} - -const bool Symbol::operator!=(const Symbol &other) const { - return(!this->operator==(other)); -} - -const bool Symbol::operator<(const Symbol &other) const { - return name < other.getName(); -} - -std::string Symbol::getName() const { - return(name); -} - -std::string Symbol::getValue() const { - return(value); -} - -std::string Symbol::toString() const { - return(name + (terminal ? " " + value : "")); -} - -bool Symbol::isTerminal() { - return terminal; -} - diff --git a/deprecated_compiler/src/Table.cpp b/deprecated_compiler/src/Table.cpp deleted file mode 100644 index 7dd548f..0000000 --- a/deprecated_compiler/src/Table.cpp +++ /dev/null @@ -1,388 +0,0 @@ -#include "Table.h" - -Table::Table() { - // -} - -Table::~Table() { - // -} - -void Table::exportTable(std::ofstream &file) { - //Save symbolIndexVec - int size = symbolIndexVec.size(); - file.write((char*)&size, sizeof(int)); - for (int i = 0; i < symbolIndexVec.size(); i++) { - //Save the name - std::string symbolName = symbolIndexVec[i].getName(); //Get the string - size = symbolName.size()+1; - file.write((char*)&size, sizeof(int)); //Save size of string - file.write((char*)(symbolName.c_str()), size); //Save the string - - //Save the value - std::string symbolValue = symbolIndexVec[i].getValue(); //Get the string - size = symbolValue.size()+1; - file.write((char*)&size, sizeof(int)); //Save size of string - file.write((char*)(symbolValue.c_str()), size); //Save the string - - bool isTerminal = symbolIndexVec[i].isTerminal(); - file.write((char*)&isTerminal, sizeof(bool)); //Save the true false - } - - //Save the actual table - size = table.size(); - file.write((char*)&size, sizeof(int)); - for (int i = 0; i < table.size(); i++) { - //each item is a middle vector - //std::vector< std::vector< std::vector* >* > table; - std::vector< std::vector* >* middleVector = table[i]; - int middleVectorSize = middleVector->size(); - file.write((char*)&middleVectorSize, sizeof(int)); - - for (int j = 0; j < middleVectorSize; j++) { - //each item is an inner vector - std::vector* innerVector = (*middleVector)[j]; - int innerVectorSize = 0; - if (innerVector) - innerVectorSize = innerVector->size(); - else - innerVectorSize = 0; - file.write((char*)&innerVectorSize, sizeof(int)); - - for (int k = 0; k < innerVectorSize; k++) { - //Save the type - ParseAction* toSave = (*innerVector)[k]; - ParseAction::ActionType actionType = toSave->action; - file.write((char*)&actionType, sizeof(ParseAction::ActionType)); - //Save the reduce rule if necessary - if (actionType == ParseAction::REDUCE) { - //Save the reduce rule - ParseRule* rule = toSave->reduceRule; - //int pointer index - int ptrIndx = rule->getIndex(); - file.write((char*)&ptrIndx, sizeof(int)); - - //Symbol leftHandle - Symbol leftHandle = rule->getLeftSide(); - //Save the name - std::string symbolName = leftHandle.getName(); //Get the string - size = symbolName.size()+1; - file.write((char*)&size, sizeof(int)); //Save size of string - file.write((char*)(symbolName.c_str()), size); //Save the string - - //Save the value - std::string symbolValue = leftHandle.getValue(); //Get the string - size = symbolValue.size()+1; - file.write((char*)&size, sizeof(int)); //Save size of string - file.write((char*)(symbolValue.c_str()), size); //Save the string - - bool isTerminal = leftHandle.isTerminal(); - file.write((char*)&isTerminal, sizeof(bool)); //Save the true false - - //std::vector* lookahead; - //Should not need - - //std::vector rightSide; - std::vector rightSide = rule->getRightSide(); - size = rightSide.size(); - //std::cout << leftHandle.toString() << std::endl; - file.write((char*)&size, sizeof(int)); - for (int l = 0; l < rightSide.size(); l++) { - //Save the name - symbolName = rightSide[l].getName(); //Get the string - size = symbolName.size()+1; - file.write((char*)&size, sizeof(int)); //Save size of string - file.write((char*)(symbolName.c_str()), size); //Save the string - // - //Save the value - symbolValue = rightSide[l].getValue(); //Get the string - size = symbolValue.size()+1; - file.write((char*)&size, sizeof(int)); //Save size of string - file.write((char*)(symbolValue.c_str()), size); //Save the string - // - isTerminal = rightSide[l].isTerminal(); - file.write((char*)&isTerminal, sizeof(bool)); //Save the true false - } - } - int shiftState = toSave->shiftState; - file.write((char*)&shiftState, sizeof(int)); - } - } - - } -} - -void Table::importTable(char* tableData) { - //Load symbolIndexVec - - int size = *((int*)tableData); - tableData += sizeof(int); - for (int i = 0; i < size; i++) { - int stringLen = *((int*)tableData); - tableData += sizeof(int); - std::string symbolName = std::string(tableData); - tableData += stringLen*sizeof(char); - stringLen = *((int*)tableData); - tableData += sizeof(int); - std::string symbolValue = std::string(tableData); - tableData += stringLen*sizeof(char); - - bool isTerminal = *((bool*)tableData); - tableData += sizeof(bool); - - symbolIndexVec.push_back(Symbol(symbolName, isTerminal, symbolValue)); - } - - //Now for the actual table - int tableSize = *((int*)tableData); - tableData += sizeof(int); - for (int i = 0; i < tableSize; i++) { - //each item is a middle vector - std::vector< std::vector* >* middleVector = new std::vector< std::vector* >(); - table.push_back(middleVector); - - int middleVectorSize = *((int*)tableData); - tableData += sizeof(int); - for (int j = 0; j < middleVectorSize; j++) { - //each item is an inner vector - std::vector* innerVector = new std::vector(); - middleVector->push_back(innerVector); - int innerVectorSize = *((int*)tableData); - tableData += sizeof(int); - for (int k = 0; k < innerVectorSize; k++) { - //each item is a ParseRule - ParseAction::ActionType action = *((ParseAction::ActionType*)tableData); - tableData += sizeof(ParseAction::ActionType); - //If reduce, import the reduce rule - ParseRule* reduceRule = NULL; - if (action == ParseAction::REDUCE) { - int ptrIndx = *((int*)tableData); - tableData += sizeof(int); - - size = *((int*)tableData); - tableData += sizeof(int); - std::string leftHandleName = std::string(tableData); - tableData += size*sizeof(char); - size = *((int*)tableData); - tableData += sizeof(int); - std::string leftHandleValue = std::string(tableData); - tableData += size*sizeof(char); - - bool isTerminal = *((bool*)tableData); - tableData += sizeof(bool); - - //right side - std::vector rightSide; - size = *((int*)tableData); - tableData += sizeof(int); - for (int l = 0; l < size; l++) { - int inStringLen = *((int*)tableData); - tableData += sizeof(int); - std::string inSymbolName = std::string(tableData); - tableData += inStringLen*sizeof(char); - - inStringLen = *((int*)tableData); - tableData += sizeof(int); - std::string inSymbolValue = std::string(tableData); - tableData += inStringLen*sizeof(char); - - bool inIsTerminal = *((bool*)tableData); - tableData += sizeof(bool); - rightSide.push_back(Symbol(inSymbolName, inIsTerminal, inSymbolValue)); - } - reduceRule = new ParseRule(Symbol(leftHandleName, isTerminal, leftHandleValue), ptrIndx, rightSide, std::vector()); - } - int shiftState = *((int*)tableData); - tableData += sizeof(int); - - //And push the new action back - if (reduceRule) - innerVector->push_back(new ParseAction(action, reduceRule)); - else - innerVector->push_back(new ParseAction(action, shiftState)); - } - } - } -} - -void Table::setSymbols(Symbol EOFSymbol, Symbol nullSymbol) { - this->EOFSymbol = EOFSymbol; - this->nullSymbol = nullSymbol; -} - -void Table::add(int stateNum, Symbol tranSymbol, ParseAction* action) { - - //If this is the first time we're adding to the table, add the EOF character - if (symbolIndexVec.size() == 0) - symbolIndexVec.push_back(EOFSymbol); - - //If state not in table, add up to and it. - //std::cout << "table size is " << table.size() <= table.size()) { - //std::cout << "Pushing back table" << std::endl; - table.push_back(new std::vector* >()); - } - - //find out what index this symbol is on - int symbolIndex = -1; - for (std::vector::size_type i = 0; i < symbolIndexVec.size(); i++) { - if ( symbolIndexVec[i] == tranSymbol ) { - //Has been found - symbolIndex = i; - break; - } - } - //std::cout << "symbolIndex is " << symbolIndex << std::endl; - - //If we've never done this symbol, add it - if (symbolIndex < 0) { - // std::cout << "pushing back symbolIndexVec" <toString() << std::endl; - - //std::cout << table[stateNum] << " "; - while (symbolIndex >= table[stateNum]->size()) { - table[stateNum]->push_back(NULL); - } - - //If this table slot is empty - //std::cout << "table[stateNum] is " << table[stateNum] << std::endl; - //std::cout << "blank is " << (*(table[stateNum]))[symbolIndex] << std::endl; - - if ( (*(table[stateNum]))[symbolIndex] == NULL ) { - //std::cout << "Null, adding " << action->toString() << std::endl; - std::vector* actionList = new std::vector(); - actionList->push_back(action); - (*(table[stateNum]))[symbolIndex] = actionList; - } - //If the slot is not empty and does not contain ourself, then it is a conflict - //else if ( !(*(table[stateNum]))[symbolIndex]->equalsExceptLookahead(*action)) { - else { - //std::cout << "not Null!" << std::endl; - //std::cout << "State: " << stateNum << " Conflict between old: " << (*(table[stateNum]))[symbolIndex]->toString() << " and new: " << action->toString() << " on " << tranSymbol->toString() << std::endl; - - //Check to see if this action is already in the list - - //(*(table[stateNum]))[symbolIndex]->push_back(action); - bool alreadyIn = false; - for (std::vector::size_type i = 0; i < (*(table[stateNum]))[symbolIndex]->size(); i++) - if (*((*((*(table[stateNum]))[symbolIndex]))[i]) == *action) - alreadyIn = true; - if (!alreadyIn) - (*(table[stateNum]))[symbolIndex]->push_back(action); - } -} - -void Table::remove(int stateNum, Symbol tranSymbol) { - //find out what index this symbol is on - int symbolIndex = -1; - for (std::vector::size_type i = 0; i < symbolIndexVec.size(); i++) { - if ( symbolIndexVec[i] == tranSymbol ) { - //Has been found - symbolIndex = i; - break; - } - } - (*(table[stateNum]))[symbolIndex] = NULL; -} - -std::vector* Table::get(int state, Symbol token) { - int symbolIndex = -1; - for (std::vector::size_type i = 0; i < symbolIndexVec.size(); i++) { - if ( symbolIndexVec[i] == token) { - symbolIndex = i; - break; - } - } - - if (symbolIndex == -1) { - std::cout << "Unrecognized symbol: " << token.toString() << ", cannot get from table!" << std::endl; - return NULL; - } - - //std::cout << "Get for state: " << state << ", and Symbol: " << token.toString() << std::endl; - if (state < 0 || state >= table.size()) { - std::cout << "State bad: " << state << std::endl; - return NULL; - } - - std::vector* action = NULL; - - if (symbolIndex < 0 || symbolIndex >= table[state]->size()) { - //std::cout << "Symbol bad for this state: " << token.toString() << ". This is a reject." << std::endl; - } else { - action = (*(table[state]))[symbolIndex]; - } - - //This is the accepting state, as it is the 1th's state's reduction on EOF, which is 0 in the symbolIndexVec - //(This assumes singular goal assignment, a simplification for now) - if (state == 1 && symbolIndex == 0) { - if (action == NULL) - action = new std::vector(); - action->push_back(new ParseAction(ParseAction::ACCEPT)); - } - - //If outside the symbol range of this state (same as NULL), reject - if ( symbolIndex >= table[state]->size() ) { - action = new std::vector(); - action->push_back(new ParseAction(ParseAction::REJECT)); - } - - //If null, reject. (this is a space with no other action) - if (action == NULL) { - action = new std::vector(); - action->push_back(new ParseAction(ParseAction::REJECT)); - } - - //Otherwise, we have something, so return it - return action; -} - -ParseAction* Table::getShift(int state, Symbol token) { - std::vector* actions = get(state, token); - ParseAction* shift = NULL; - for (int i = 0; i < actions->size(); i++) { - if ((*actions)[i]->action == ParseAction::SHIFT) { - shift = (*actions)[i]; - break; - } - } - return shift; -} - -std::vector> Table::stateAsParseActionVector(int state) { - std::vector> reconstructedState; - std::vector*>* stateVec = table[state]; - for (int i = 0; i < stateVec->size(); i++) - if (std::vector* forStateAndSymbol = (*stateVec)[i]) - for (int j = 0; j < forStateAndSymbol->size(); j++) - reconstructedState.push_back(std::make_pair(symbolIndexVec[i].toString(),*((*forStateAndSymbol)[j]))); - - return reconstructedState; -} - -std::string Table::toString() { - std::string concat = ""; - for (std::vector::size_type i = 0; i < symbolIndexVec.size(); i++) - concat += "\t" + symbolIndexVec[i].toString(); - concat += "\n"; - - for (std::vector< std::vector< std::vector< ParseRule* >* >* >::size_type i = 0; i < table.size(); i++) { - concat += intToString(i) + " is the state\t"; - for (std::vector< std::vector< ParseRule* >* >::size_type j = 0; j < table[i]->size(); j++) { - concat += "for " + symbolIndexVec[j].toString() + " do "; - if ( (*(table[i]))[j] != NULL) { - for (std::vector< ParseRule* >::size_type k = 0; k < (*(table[i]))[j]->size(); k++) { - concat += (*((*(table[i]))[j]))[k]->toString() + "\t"; - } - } else { - concat += "NULL\t"; - } - } - concat += "\n"; - } - return(concat); -} diff --git a/deprecated_compiler/src/Tester.cpp b/deprecated_compiler/src/Tester.cpp deleted file mode 100644 index 7f5cd37..0000000 --- a/deprecated_compiler/src/Tester.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include "Tester.h" - -Tester::Tester(std::string krakenInvocation, std::string krakenGrammerLocation) : krakenInvocation(krakenInvocation), krakenGrammerLocation(krakenGrammerLocation) { - //initlization list - removeCmd = "rm -r"; - resultsExtention = ".results"; - expectedExtention = ".expected_results"; - krakenExtention = ".krak"; - changePermissions = "chmod 755"; - shell = "sh"; - cd = "cd"; - redirect = ">"; - sep = "/"; -} - -Tester::~Tester() { - //Nothing -} - -void Tester::cleanExtras(std::string fileName) { - ssystem(removeCmd + " " + fileName); -} - -bool Tester::run(std::string path) { - std::string fileName = split(path, *sep.c_str()).back(); - std::cout << "Testing: " << fileName << " with " << krakenInvocation << " and " << krakenGrammerLocation << std::endl; - - cleanExtras(path); - ssystem(krakenInvocation + " " + path + krakenExtention + " " + path); - // done automatically now - //ssystem(changePermissions + " " + path + sep + fileName + ".sh"); - //ssystem(cd + " " + path + "; " + "./" + fileName + ".sh"); - //ssystem(changePermissions + " " + path + sep + fileName); - ssystem(path + sep + fileName + " " + redirect + " " + path + sep + fileName + resultsExtention); - - bool result = compareFiles(fileName + expectedExtention, path + sep + fileName + resultsExtention); - - //If the test was succesful, we don't need all the extra files - if (result) - cleanExtras(path); - - return result; -} - -bool Tester::compareFiles(std::string file1Path, std::string file2Path) { - std::ifstream file1, file2; - file1.open(file1Path); - if (!file1.is_open()) { - std::cout << file1Path << " could not be opened!" << std::endl; - return false; - } - file2.open(file2Path); - if (!file2.is_open()) { - std::cout << file2Path << " could not be opened!" << std::endl; - return false; - } - - std::string file1contents = readFile(file1); - std::string file2contents = readFile(file2); - - return file1contents.compare(file2contents) == 0; -} diff --git a/deprecated_compiler/src/Type.cpp b/deprecated_compiler/src/Type.cpp deleted file mode 100644 index e1750c1..0000000 --- a/deprecated_compiler/src/Type.cpp +++ /dev/null @@ -1,268 +0,0 @@ -#include "Type.h" - -Type::Type() { - indirection = 0; - baseType = none; - typeDefinition = nullptr; - templateDefinition = nullptr; - returnType = nullptr; - templateInstantiated = false; - is_reference = false; -} - -Type::Type(ValueType typeIn, int indirectionIn) { - indirection = indirectionIn; - baseType = typeIn; - typeDefinition = nullptr; - templateDefinition = nullptr; - returnType = nullptr; - templateInstantiated = false; - is_reference = false; -} - -Type::Type(ValueType typeIn, std::set traitsIn) { - indirection = 0; - baseType = typeIn; - traits = traitsIn; - typeDefinition = nullptr; - templateDefinition = nullptr; - returnType = nullptr; - templateInstantiated = false; - is_reference = false; -} - -Type::Type(NodeTree* typeDefinitionIn, int indirectionIn) { - indirection = indirectionIn; - baseType = none; - typeDefinition = typeDefinitionIn; - templateDefinition = nullptr; - returnType = nullptr; - templateInstantiated = false; - is_reference = false; -} - -Type::Type(NodeTree* typeDefinitionIn, std::set traitsIn) { - indirection = 0; - baseType = none; - typeDefinition = typeDefinitionIn; - traits = traitsIn; - templateDefinition = nullptr; - returnType = nullptr; - templateInstantiated = false; - is_reference = false; -} - -Type::Type(ValueType typeIn, NodeTree* typeDefinitionIn, int indirectionIn, bool referenceIn, std::set traitsIn) { - baseType = typeIn; - indirection = indirectionIn; - typeDefinition = typeDefinitionIn; - traits = traitsIn; - templateDefinition = nullptr; - returnType = nullptr; - templateInstantiated = false; - is_reference = referenceIn; -} - -Type::Type(ValueType typeIn, NodeTree* typeDefinitionIn, int indirectionIn, bool referenceIn, std::set traitsIn, std::vector parameterTypesIn, Type* returnTypeIn) { - baseType = typeIn; - indirection = indirectionIn; - typeDefinition = typeDefinitionIn; - traits = traitsIn; - templateDefinition = nullptr; - parameterTypes = parameterTypesIn; - returnType = returnTypeIn; - templateInstantiated = false; - is_reference = referenceIn; -} -Type::Type(std::vector parameterTypesIn, Type* returnTypeIn, bool referenceIn) { - baseType = function_type; - indirection = 0; - typeDefinition = nullptr; - templateDefinition = nullptr; - parameterTypes = parameterTypesIn; - returnType = returnTypeIn; - templateInstantiated = false; - is_reference = referenceIn; -} - -Type::Type(ValueType typeIn, NodeTree* templateDefinitionIn, std::set traitsIn) { - indirection = 0; - baseType = typeIn; - typeDefinition = nullptr; - templateDefinition = templateDefinitionIn; - traits = traitsIn; - returnType = nullptr; - templateInstantiated = false; - is_reference = false; -} - - -Type::~Type() { -} - -const bool Type::operator==(const Type &other) const { - return test_equality(other, true); -} -const bool Type::test_equality(const Type &other, bool care_about_references) const { - bool first_part = ( baseType == other.baseType && indirection == other.indirection && typeDefinition == other.typeDefinition && templateDefinition == other.templateDefinition && other.traits == traits); - if (care_about_references && is_reference != other.is_reference) - return false; - if (!first_part) - return false; - if ((returnType && !other.returnType) || (!returnType && other.returnType)) - return false; - if (returnType && other.returnType) - if (*returnType != *other.returnType) - return false; - if (parameterTypes.size() != other.parameterTypes.size()) - return false; - for (int i = 0; i < parameterTypes.size(); i++) - if (*parameterTypes[i] != *other.parameterTypes[i]) - return false; - return true; -} - -const bool Type::operator!=(const Type &other) const { - return(!this->operator==(other)); -} -const bool Type::operator<(const Type &other) const { - if (baseType != other.baseType) - return baseType < other.baseType; - if (indirection != other.indirection) - return indirection < other.indirection; - if (is_reference != other.is_reference) - return is_reference; - if (typeDefinition != other.typeDefinition) - return typeDefinition < other.typeDefinition; - if (templateDefinition != other.templateDefinition) - return templateDefinition < other.templateDefinition; - if (traits != other.traits) - return traits < other.traits; - if ((returnType && !other.returnType) || (!returnType && other.returnType)) - return returnType < other.returnType; - if (returnType && other.returnType) - if (*returnType != *other.returnType) - return *returnType < *other.returnType; - if (parameterTypes.size() != other.parameterTypes.size()) - return parameterTypes.size() < other.parameterTypes.size(); - for (int i = 0; i < parameterTypes.size(); i++) - if (*parameterTypes[i] != *other.parameterTypes[i]) - return *parameterTypes[i] < *other.parameterTypes[i]; - return false; -} - -std::string Type::toString(bool showTraits) { - std::string typeString; - switch (baseType) { - case none: - if (typeDefinition) - typeString = typeDefinition->getDataRef()->symbol.getName(); - else - typeString = "none"; - break; - case template_type: - typeString = "template: " + templateDefinition->getDataRef()->toString(); - break; - case template_type_type: - typeString = "template_type_type"; - break; - case void_type: - typeString = "void"; - break; - case boolean: - typeString = "bool"; - break; - case integer: - typeString = "int"; - break; - case floating: - typeString = "float"; - break; - case double_percision: - typeString = "double"; - break; - case character: - typeString = "char"; - break; - case function_type: - typeString = "function("; - for (Type *param : parameterTypes) - typeString += param->toString(); - typeString += "): " + returnType->toString(); - break; - default: - if (typeDefinition) - typeString = typeDefinition->getDataRef()->symbol.getName(); - else - typeString = "unknown_type"; - } - if (is_reference) - typeString = "ref " + typeString; - for (int i = 0; i < indirection; i++) - typeString += "*"; - if (indirection < 0) - typeString += "negative indirection: " + intToString(indirection); - if (traits.size() && showTraits) { - typeString += "[ "; - for (auto i : traits) - typeString += i + " "; - typeString += "]"; - } - //std::cout << "Extra components of " << typeString << " are " << indirection << " " << typeDefinition << " " << templateDefinition << std::endl; - return typeString; -} - -Type* Type::clone() { - return new Type(baseType, typeDefinition, indirection, is_reference, traits, parameterTypes, returnType); -} - -int Type::getIndirection() { - return indirection; -} - -void Type::setIndirection(int indirectionIn) { - indirection = indirectionIn; -} - -void Type::increaseIndirection() { - setIndirection(indirection+1); -} -void Type::decreaseIndirection() { - setIndirection(indirection-1); -} - -void Type::modifyIndirection(int mod) { - setIndirection(indirection + mod); -} - -Type Type::withIncreasedIndirection() { - Type *newOne = clone(); - newOne->increaseIndirection(); - return *newOne; -} -Type Type::withReference() { - Type *newOne = clone(); - newOne->is_reference = true; - return *newOne; -} -Type *Type::withReferencePtr() { - Type *newOne = clone(); - newOne->is_reference = true; - return newOne; -} -Type *Type::withIncreasedIndirectionPtr() { - Type *newOne = clone(); - newOne->increaseIndirection(); - return newOne; -} -Type Type::withDecreasedIndirection() { - Type *newOne = clone(); - newOne->decreaseIndirection(); - return *newOne; -} -Type* Type::withoutReference() { - Type *newOne = clone(); - newOne->is_reference = false; - return newOne; -} - diff --git a/deprecated_compiler/src/util.cpp b/deprecated_compiler/src/util.cpp deleted file mode 100644 index 3483fb7..0000000 --- a/deprecated_compiler/src/util.cpp +++ /dev/null @@ -1,92 +0,0 @@ -#include "util.h" - -int ssystem(std::string command) { - return system(command.c_str()); -} -std::string intToString(int theInt) { - std::stringstream converter; - converter << theInt; - return converter.str(); -} - -std::string replaceExEscape(std::string first, std::string search, std::string replace) { - size_t pos = 0; - while (pos <= first.size()-search.size()) { - pos = first.find(search, pos); - if (pos == std::string::npos) - break; - //std::cout << "Position is " << pos << " size of first is " << first.size() << " size of replace is " << replace.size() << std::endl; - //If excaped, don't worry about it. - if (pos > 0) { - int numBackslashes = 0; - int countBack = 1; - while ((int)pos-countBack >= 0 && first[pos-countBack] == '\\') { - numBackslashes++; - countBack++; - } - if (numBackslashes % 2 == 1) { - pos++; - continue; - } - } - first = first.replace(pos, search.size(), replace); - pos += replace.size(); - } - return first; -} - -//String slicing is crazy useful. substr isn't bad, but slicing with negative indicies is wonderful -std::string strSlice(std::string str, int begin, int end) { - if (begin < 0) - begin += str.length()+1; - if (end < 0) - end += str.length()+1; - return str.substr(begin, end-begin); -} - -int findPerenEnd(std::string str, int i) { - int numHangingOpen = 0; - for (; i< str.length(); i++) { - if (str[i] == '(') - numHangingOpen++; - else if (str[i] == ')') - numHangingOpen--; - if (numHangingOpen == 0) - return i; - } - return -1; -} - -std::vector split(const std::string &str, char delim) { - std::stringstream ss(str); - std::string word; - std::vector splitVec; - while (std::getline(ss, word, delim)) - splitVec.push_back(word); - return splitVec; -} - -std::string join(const std::vector &strVec, std::string joinStr) { - if (strVec.size() == 0) - return ""; - std::string joinedStr = strVec[0]; - for (int i = 1; i < strVec.size(); i++) - joinedStr += joinStr + strVec[i]; - return joinedStr; -} - -std::string readFile(std::istream &file) { - std::string line, contents; - while(file.good()) { - getline(file, line); - contents.append(line+"\n"); - } - return contents; -} - -std::string padWithSpaces(std::string str, int padTo) { - while(str.length() < padTo) - str += " "; - return str; -} - diff --git a/doc/.gitignore b/doc/.gitignore new file mode 100644 index 0000000..3cebff8 --- /dev/null +++ b/doc/.gitignore @@ -0,0 +1,9 @@ +*.swp +*.zip +*.aux +*.bbl +*.blg +*.log +*.out +*.pdf + diff --git a/doc/Manual.tex b/doc/Manual.tex deleted file mode 100644 index 8597253..0000000 --- a/doc/Manual.tex +++ /dev/null @@ -1,345 +0,0 @@ -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% Kraken Documentation -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - -%---------------------------------------------------------------------------------------- -% PACKAGES AND DOCUMENT CONFIGURATIONS -%---------------------------------------------------------------------------------------- - -\documentclass{article} - -\usepackage{graphicx} % Required for the inclusion of images -\usepackage{amsmath} % Required for some math elements -\renewcommand{\labelenumi}{\alph{enumi}.} % Make numbering in the enumerate environment by letter rather than number (e.g. section 6) - -\usepackage{times} -\usepackage{listings} -\usepackage{color} -%---------------------------------------------------------------------------------------- -% DOCUMENT INFORMATION -%---------------------------------------------------------------------------------------- - -\title{Kraken Programming Guide v0.0} % Title - -\author{Jack \textsc{Sparrow}} % Author name - -\date{\today} % Date for the report - -\begin{document} - -\maketitle % Insert the title, author and date - -%---------------------------------------------------------------------------------------- -% SECTION Compiling -%---------------------------------------------------------------------------------------- -\section{Compiling} - Kraken compilation currently only supports building the compiler from source. -You can clone the repository from a terminal using: - \begin{lstlisting} - git clone https://github.com/Limvot/kraken.git - \end{lstlisting} -Once you have the repository, run the following commands: - \begin{lstlisting} - mkdir build %Create a build directory - cd build - cmake .. %Requires cmake to build the compiler - make %Create the compiler executable - \end{lstlisting} -This will create a kraken executable, which is how we will call the compiler. -Kraken supports several ways of invoking the compiler. These include: - \begin{lstlisting} - kraken source.krak - kraken source.krak outputExe - kraken grammarFile.kgm source.krak outputExe - \end{lstlisting} -The grammar file is a file specific to the compiler, and should be included -in the github repository. When you run the compile command, a new directory -with the name of the outputExe you specified will be created. In this directory -is a shell script, which will compile the created C file into a binary executable. -This binary exectuable can then be run as a normal C executable. - -%---------------------------------------------------------------------------------------- -% SECTION Variables -%---------------------------------------------------------------------------------------- - -\section{Variables} -\label{sec:var} - Kraken has automatic type deduction. This is sort of like the duck typing of -Python. The difference is that variables cannot change types. In this way, it -is much more like an implicit "auto" keyword in C++. Unlike C++, semicolons are -optional after declarations. - -\subsection{Variable Declaration} - \begin{lstlisting}[language=C++] - var A: int; //A is unitialized int - var B = 1; //B is integer - var C = 2.0; //C is double - var D: double = 3.14 //D is double - - \end{lstlisting} -\subsection{Primitive Types} - The primitive types found in kraken are: - \begin{enumerate} - \item int - \item float - \item double - \item char - \item bool - \item void - \end{enumerate} - -%---------------------------------------------------------------------------------------- -% SECTION 2: Functions -%---------------------------------------------------------------------------------------- -\section{Functions} - \begin{lstlisting}[language=C++] - fun FunctionName(arg1 : arg1_type, arg2 : arg2_type) : returnType { - var result = arg1 + arg2; - return result; - } - \end{lstlisting} - - Functions are declared using the {\bf{fun}} keyword. If you pass in - variables as shown, there will be passed by value, not by reference. - Therefore if you pass a variable in, it will not be modified outside the - function. -%---------------------------------------------------------------------------------------- -% SECTION I/O -%---------------------------------------------------------------------------------------- -\section{Input and Output} - In order to print to a terminal or file, the {\bf{io}} library must be - imported. There are a few different functions you can use to print to the - terminal. - The print() function will print out to the terminal without a newline - character. Like java, there is a println() function that will print whatever - you pass in, as well as a newline. There are also functions that can print - colors in a unix terminal. The color will continue when you print until - you call the function Reset(). - \begin{enumerate} - \item {\color{red}{BoldRed()}} - \item {\color{green}{BoldGreen()}} - \item {\color{yellow}{BoldYellow()}} - \item {\color{blue}{BoldBlue()}} - \item {\color{magenta}{BoldMagneta()}} - \item {\color{cyan}{BoldCyan()}} - \end{enumerate} - - \begin{lstlisting}[language=C++] - io::print(3.2); //print without a newline character - io::println(varA); //print variable A with a newline character - io::BoldRed(); - io::println("This line is printed Red"); - io::Reset(); - io::println("This line is printed black"); - \end{lstlisting} - - You can also use kraken to read and write to files. The functions are as - follows: - \begin{lstlisting}[language=C++] - //returns true if file exists - var ifExists = io::file_exists("/usr/bin/clang"); - - //read file into string - var fileString = io::read_file("~/Documents/file.txt"); - - //write a string to the file - io::write_file("/",SteamString); - - //read file into vector of chars - var charVec = io::read_file_binary("~/Documents/file2.txt"); - - //write a vector of chars to a file - io::write_file_binary("/",md5checkSum); - \end{lstlisting} - -%---------------------------------------------------------------------------------------- -% SECTION Memory Management -%---------------------------------------------------------------------------------------- -\section{Memory Management} - \subsection{Pointers} - Pointers in kraken work like they do in C. The notation is the - {\bf{*}} symbol. This is a dereference operator. This means that it - operates on a pointer, and gives the variable pointed to. For - instance: - \begin{lstlisting}[language=C++] - var B: *int = 4; //B is a pointer to an integer 4 - *B = 3; //B is now equal to 3 - print(B); //would print an address, like "0xFFA3" - \end{lstlisting} - \subsection{References} - References are a way to create "automatic" pointers. If a function - takes in a reference, the variable is passed by reference, instead of by - value. This means that no copy of the variable is made, and any changes - made to the variable in the function will remain after the end of the - function. References also allow left-handed assignment. This means that - an array indexed on the left hand of an equal sign can have its value - changed. - \begin{lstlisting}[language=C++] - fun RefFunction(arg1: ref int): ref int{ - return arg1 + 1; - } - - var a = 6; - var b = RefFunction(a); - println(a); //a is now equal to 6 - println(b); //b is now equal to 6 - RefFunction(b) = 15; - println(b); //b is now equal to 15 - \end{lstlisting} - - \subsection{Dynamic Memory Allocation} - In order to allocate memory on the heap instead of the stack, dynamic - memory allocation must be used. The data must be explicitly allocated with - the {\bf{new}} keyword, and deleted with the {\bf{delete}} keyword. The - size in both instances must be provided. - \begin{lstlisting}[language=C++] - var data = new(8); //Allocate 8 integers on the heap - delete(data,8); //Free the memory when its no longer used. - \end{lstlisting} - -%---------------------------------------------------------------------------------------- -% SECTION Classes -%---------------------------------------------------------------------------------------- - -\section{Classes} - \subsection{Constructors} - As with most of kraken, classes are based on their C++ counterparts, with - a few key differences. Constructors in kraken are not called by default. - You must actually call the constructor function. The constructor must return - a pointer to the object, which is denoted by the {\bf{this}} keyword. - The destructor is automatically called when the object goes out of scope, - and is just called destruct(). An example class is shown below: - \begin{lstlisting}[language=C++] - obj MyObject (Object) { - var variable1: int; - var variable2: vector::vector; - - fun construct(): *MyObject { - variable1 = 42; - variable2.construct(); - return this; - } - - //Could also pass by reference??? - fun copy_construct(old: *MyObject): void { - variable1 = &old->variable1; - variable2.copy_construct(&old->variable2); - } - - fun destruct() { - variable2.destruct(); - } - } - \end{lstlisting} - \subsection{Operator Overloading} - Operator overloading allows you to use operators for syntactic sugar, and - make your code look nicer. This again borrow mostly from C++, and you can - overload most of the operators that you can in C++. An example is shown - below: - \begin{lstlisting} - //Inside a class - - //overload the assignment operator - fun operator=(other: SampleObject): void{ - destruct(); - copy_construct(&other); - } - - //overload the equality operator - fun operator==(other: SampleObject): bool{ - return EqualTest == other.EqualTest; - } - \end{lstlisting} - \subsection{Traits} - Currently, Kraken has no notion of inheritance. Instead, objects can be - intialized with traits. These give special properties to the object. For - instance, if the object is defined with the {\bf{Object}} trait, then its - destructor will be called when the object goes out of scope. The second trait - that kraken has is the {\bf{Serializable}} trait. This allows it to be used - with the {\bf{serialize}} class, which serializes it into a vector of bytes. - This stream of bytes could then be used to send messages over TCP, etc. - \begin{lstlisting} - //Object has both Object and Serializable traits - obj Hermes (Object, Serializable) { - var RedBull: vector::vector; - - fun construct(): *Hermes { - RedBull = "gives you wings"; - } - - fun serialize(): vector::vector { - //String already has a serialize member function - var toReturn = RedBull.serialize(); - return toReturn; - } - - fun unserialize(it: ref vector::vector, pos: int): int { - pos = RedBull.unserialize(it,pos); - return pos; - } - - fun destruct(): void { - io::println("I must return to my people"); - } - - \end{lstlisting} -%---------------------------------------------------------------------------------------- -% SECTION Templates -%---------------------------------------------------------------------------------------- - -\section{Templates} - Templates are a very important part of C++, but are also one of the reasons -people do not like the language. They are extremely useful, but also fairly -hard to use properly. If you make an error while using templates, the bug is -often extremely difficult to find. Kraken templates aim to prevent that problem. -\\ -Templates are a way of writing something once for any type. At compile time, -the compiler will see what types you are using with the template, and substitute -those types in. This is not duck typing, since the types cannot change once they -are assigned. It is more like how you can initialize variables in kraken, with -the use of {\bf{var}}. This is extremely useful for something like a container. -The vector class in kraken uses templates, so you can put any type, including -custom objects, into a vector. \\ -The convention is to use {\bf{T}} for a template, and if there are two, -{\bf{U}}. The following example, taken from the vector implementation, -demonstrates templates. -\begin{lstlisting}[language=C++] - //Can have a vector of any type, with - obj vector (Object, Serializable) { - //data can be an array of any type - var data: *T; - //size and available are just primitive ints - var size: int; - var available: int; - ... - } -\end{lstlisting} - - -%---------------------------------------------------------------------------------------- -% SECTION Standard Library -%---------------------------------------------------------------------------------------- - -\section{Standard Library} - \subsection{Import Statements} - \subsection{Vector} - \subsection{String} - \subsection{Regex} - \subsection{Util} - \subsection{Data Structures} - \subsubsection{Stack} - \subsubsection{Queue} - \subsubsection{Set} - \subsubsection{Map} -%---------------------------------------------------------------------------------------- -% SECTION Understanding Kraken Errors -%---------------------------------------------------------------------------------------- -\section{Understanding Kraken Errors} - Section error -%---------------------------------------------------------------------------------------- -% SECTION C Passthrough -%---------------------------------------------------------------------------------------- -\section{C Passthrough} - -\end{document} diff --git a/doc/cited-paper.bib b/doc/cited-paper.bib new file mode 100644 index 0000000..ed4c8f9 --- /dev/null +++ b/doc/cited-paper.bib @@ -0,0 +1,11 @@ + +@phdthesis{shutt2010fexprs, + title={Fexprs as the basis of Lisp function application or \$vau: the ultimate abstraction}, + author={Shutt, John N}, + year={2010} +} +@article{kearsleyimplementing, + title={Implementing a Vau-based Language With Multiple Evaluation Strategies}, + author={Kearsley, Logan} +} + diff --git a/doc/make_paper.sh b/doc/make_paper.sh new file mode 100755 index 0000000..9acc280 --- /dev/null +++ b/doc/make_paper.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +touch writeup.pdf && rm writeup.aux writeup.bbl writeup.blg writeup.log writeup.out writeup.pdf && pdflatex writeup && bibtex writeup && pdflatex writeup && bibtex writeup && pdflatex writeup && bibtex writeup && evince writeup.pdf diff --git a/doc/nix/sources.json b/doc/nix/sources.json new file mode 100644 index 0000000..0704cd5 --- /dev/null +++ b/doc/nix/sources.json @@ -0,0 +1,38 @@ +{ + "niv": { + "branch": "master", + "description": "Easy dependency management for Nix projects", + "homepage": "https://github.com/nmattia/niv", + "owner": "nmattia", + "repo": "niv", + "rev": "65a61b147f307d24bfd0a5cd56ce7d7b7cc61d2e", + "sha256": "17mirpsx5wyw262fpsd6n6m47jcgw8k2bwcp1iwdnrlzy4dhcgqh", + "type": "tarball", + "url": "https://github.com/nmattia/niv/archive/65a61b147f307d24bfd0a5cd56ce7d7b7cc61d2e.tar.gz", + "url_template": "https://github.com///archive/.tar.gz" + }, + "nixpkgs": { + "branch": "master", + "description": "Nix Packages collection", + "homepage": "", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "2b65a74aba274a06a673dfb6f28b96cbe0b032fb", + "sha256": "0f62z6q00dpxnf4c5ip8362kzzcmnlhx6fbia6dr97a21fzbc8aq", + "type": "tarball", + "url": "https://github.com/NixOS/nixpkgs/archive/2b65a74aba274a06a673dfb6f28b96cbe0b032fb.tar.gz", + "url_template": "https://github.com///archive/.tar.gz" + }, + "nixpkgs-mozilla": { + "branch": "master", + "description": "mozilla related nixpkgs (extends nixos/nixpkgs repo)", + "homepage": "", + "owner": "mozilla", + "repo": "nixpkgs-mozilla", + "rev": "0510159186dd2ef46e5464484fbdf119393afa58", + "sha256": "1c6r5ldkh71v6acsfhni7f9sxvi7xrqzshcwd8w0hl2rrqyzi58w", + "type": "tarball", + "url": "https://github.com/mozilla/nixpkgs-mozilla/archive/0510159186dd2ef46e5464484fbdf119393afa58.tar.gz", + "url_template": "https://github.com///archive/.tar.gz" + } +} diff --git a/doc/nix/sources.nix b/doc/nix/sources.nix new file mode 100644 index 0000000..1938409 --- /dev/null +++ b/doc/nix/sources.nix @@ -0,0 +1,174 @@ +# This file has been generated by Niv. + +let + + # + # The fetchers. fetch_ fetches specs of type . + # + + fetch_file = pkgs: name: spec: + let + name' = sanitizeName name + "-src"; + in + if spec.builtin or true then + builtins_fetchurl { inherit (spec) url sha256; name = name'; } + else + pkgs.fetchurl { inherit (spec) url sha256; name = name'; }; + + fetch_tarball = pkgs: name: spec: + let + name' = sanitizeName name + "-src"; + in + if spec.builtin or true then + builtins_fetchTarball { name = name'; inherit (spec) url sha256; } + else + pkgs.fetchzip { name = name'; inherit (spec) url sha256; }; + + fetch_git = name: spec: + let + ref = + if spec ? ref then spec.ref else + if spec ? branch then "refs/heads/${spec.branch}" else + if spec ? tag then "refs/tags/${spec.tag}" else + abort "In git source '${name}': Please specify `ref`, `tag` or `branch`!"; + in + builtins.fetchGit { url = spec.repo; inherit (spec) rev; inherit ref; }; + + fetch_local = spec: spec.path; + + fetch_builtin-tarball = name: throw + ''[${name}] The niv type "builtin-tarball" is deprecated. You should instead use `builtin = true`. + $ niv modify ${name} -a type=tarball -a builtin=true''; + + fetch_builtin-url = name: throw + ''[${name}] The niv type "builtin-url" will soon be deprecated. You should instead use `builtin = true`. + $ niv modify ${name} -a type=file -a builtin=true''; + + # + # Various helpers + # + + # https://github.com/NixOS/nixpkgs/pull/83241/files#diff-c6f540a4f3bfa4b0e8b6bafd4cd54e8bR695 + sanitizeName = name: + ( + concatMapStrings (s: if builtins.isList s then "-" else s) + ( + builtins.split "[^[:alnum:]+._?=-]+" + ((x: builtins.elemAt (builtins.match "\\.*(.*)" x) 0) name) + ) + ); + + # The set of packages used when specs are fetched using non-builtins. + mkPkgs = sources: system: + let + sourcesNixpkgs = + import (builtins_fetchTarball { inherit (sources.nixpkgs) url sha256; }) { inherit system; }; + hasNixpkgsPath = builtins.any (x: x.prefix == "nixpkgs") builtins.nixPath; + hasThisAsNixpkgsPath = == ./.; + in + if builtins.hasAttr "nixpkgs" sources + then sourcesNixpkgs + else if hasNixpkgsPath && ! hasThisAsNixpkgsPath then + import {} + else + abort + '' + Please specify either (through -I or NIX_PATH=nixpkgs=...) or + add a package called "nixpkgs" to your sources.json. + ''; + + # The actual fetching function. + fetch = pkgs: name: spec: + + if ! builtins.hasAttr "type" spec then + abort "ERROR: niv spec ${name} does not have a 'type' attribute" + else if spec.type == "file" then fetch_file pkgs name spec + else if spec.type == "tarball" then fetch_tarball pkgs name spec + else if spec.type == "git" then fetch_git name spec + else if spec.type == "local" then fetch_local spec + else if spec.type == "builtin-tarball" then fetch_builtin-tarball name + else if spec.type == "builtin-url" then fetch_builtin-url name + else + abort "ERROR: niv spec ${name} has unknown type ${builtins.toJSON spec.type}"; + + # If the environment variable NIV_OVERRIDE_${name} is set, then use + # the path directly as opposed to the fetched source. + replace = name: drv: + let + saneName = stringAsChars (c: if isNull (builtins.match "[a-zA-Z0-9]" c) then "_" else c) name; + ersatz = builtins.getEnv "NIV_OVERRIDE_${saneName}"; + in + if ersatz == "" then drv else + # this turns the string into an actual Nix path (for both absolute and + # relative paths) + if builtins.substring 0 1 ersatz == "/" then /. + ersatz else /. + builtins.getEnv "PWD" + "/${ersatz}"; + + # Ports of functions for older nix versions + + # a Nix version of mapAttrs if the built-in doesn't exist + mapAttrs = builtins.mapAttrs or ( + f: set: with builtins; + listToAttrs (map (attr: { name = attr; value = f attr set.${attr}; }) (attrNames set)) + ); + + # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/lists.nix#L295 + range = first: last: if first > last then [] else builtins.genList (n: first + n) (last - first + 1); + + # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L257 + stringToCharacters = s: map (p: builtins.substring p 1 s) (range 0 (builtins.stringLength s - 1)); + + # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L269 + stringAsChars = f: s: concatStrings (map f (stringToCharacters s)); + concatMapStrings = f: list: concatStrings (map f list); + concatStrings = builtins.concatStringsSep ""; + + # https://github.com/NixOS/nixpkgs/blob/8a9f58a375c401b96da862d969f66429def1d118/lib/attrsets.nix#L331 + optionalAttrs = cond: as: if cond then as else {}; + + # fetchTarball version that is compatible between all the versions of Nix + builtins_fetchTarball = { url, name ? null, sha256 }@attrs: + let + inherit (builtins) lessThan nixVersion fetchTarball; + in + if lessThan nixVersion "1.12" then + fetchTarball ({ inherit url; } // (optionalAttrs (!isNull name) { inherit name; })) + else + fetchTarball attrs; + + # fetchurl version that is compatible between all the versions of Nix + builtins_fetchurl = { url, name ? null, sha256 }@attrs: + let + inherit (builtins) lessThan nixVersion fetchurl; + in + if lessThan nixVersion "1.12" then + fetchurl ({ inherit url; } // (optionalAttrs (!isNull name) { inherit name; })) + else + fetchurl attrs; + + # Create the final "sources" from the config + mkSources = config: + mapAttrs ( + name: spec: + if builtins.hasAttr "outPath" spec + then abort + "The values in sources.json should not have an 'outPath' attribute" + else + spec // { outPath = replace name (fetch config.pkgs name spec); } + ) config.sources; + + # The "config" used by the fetchers + mkConfig = + { sourcesFile ? if builtins.pathExists ./sources.json then ./sources.json else null + , sources ? if isNull sourcesFile then {} else builtins.fromJSON (builtins.readFile sourcesFile) + , system ? builtins.currentSystem + , pkgs ? mkPkgs sources system + }: rec { + # The sources, i.e. the attribute set of spec name to spec + inherit sources; + + # The "pkgs" (evaluated nixpkgs) to use for e.g. non-builtin fetchers + inherit pkgs; + }; + +in +mkSources (mkConfig {}) // { __functor = _: settings: mkSources (mkConfig settings); } diff --git a/doc/shell.nix b/doc/shell.nix new file mode 100644 index 0000000..d5b0c69 --- /dev/null +++ b/doc/shell.nix @@ -0,0 +1,11 @@ +let + sources = import ./nix/sources.nix; + pkgs = import sources.nixpkgs { }; +in +pkgs.mkShell { + buildInputs = with pkgs; [ + texlive.combined.scheme-full + evince + ]; +} + diff --git a/doc/writeup.tex b/doc/writeup.tex new file mode 100644 index 0000000..95c53d5 --- /dev/null +++ b/doc/writeup.tex @@ -0,0 +1,269 @@ +%% +%% This is file `sample-acmsmall.tex', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% samples.dtx (with options: `acmsmall') +%% +%% IMPORTANT NOTICE: +%% +%% For the copyright see the source file. +%% +%% Any modified versions of this file must be renamed +%% with new filenames distinct from sample-acmsmall.tex. +%% +%% For distribution of the original source see the terms +%% for copying and modification in the file samples.dtx. +%% +%% This generated file may be distributed as long as the +%% original source files, as listed above, are part of the +%% same distribution. (The sources need not necessarily be +%% in the same archive or directory.) +%% +%% +%% Commands for TeXCount +%TC:macro \cite [option:text,text] +%TC:macro \citep [option:text,text] +%TC:macro \citet [option:text,text] +%TC:envir table 0 1 +%TC:envir table* 0 1 +%TC:envir tabular [ignore] word +%TC:envir displaymath 0 word +%TC:envir math 0 word +%TC:envir comment 0 0 +%% +%% +%% The first command in your LaTeX source must be the \documentclass command. +\documentclass[acmsmall]{acmart} + +%% +%% \BibTeX command to typeset BibTeX logo in the docs +\AtBeginDocument{% + \providecommand\BibTeX{{% + \normalfont B\kern-0.5em{\scshape i\kern-0.25em b}\kern-0.8em\TeX}}} + +%% Rights management information. This information is sent to you +%% when you complete the rights form. These commands have SAMPLE +%% values in them; it is your responsibility as an author to replace +%% the commands and values with those provided to you when you +%% complete the rights form. +\setcopyright{acmcopyright} +\copyrightyear{2022} +\acmYear{2022} +\acmDOI{10.1145/1122445.1122456} + + +%% +%% These commands are for a JOURNAL article. +\acmJournal{JACM} +\acmVolume{37} +\acmNumber{4} +\acmArticle{111} +\acmMonth{8} + +%% +%% Submission ID. +%% Use this when submitting an article to a sponsored event. You'll +%% receive a unique submission ID from the organizers +%% of the event, and this ID should be used as the parameter to this command. +\acmSubmissionID{123-A56-BU3} + +%% +%% The majority of ACM publications use numbered citations and +%% references. The command \citestyle{authoryear} switches to the +%% "author year" style. +%% +%% If you are preparing content for an event +%% sponsored by ACM SIGGRAPH, you must use the "author year" style of +%% citations and references. +%% Uncommenting +%% the next command will enable that style. +%%\citestyle{acmauthoryear} + +%% +%% end of the preamble, start of the body of the document source. +\begin{document} + +%% +%% The "title" command has an optional parameter, +%% allowing the author to define a "short title" to be used in page headers. +\title{Efficient compilation of a functional Lisp based on Vau calculus} + +%% +%% The "author" command and its associated commands are used to define +%% the authors and their affiliations. +%% Of note is the shared affiliation of the first two authors, and the +%% "authornote" and "authornotemark" commands +%% used to denote shared contribution to the research. +\author{Nathan Braswell} +\email{nathan.braswell@gtri.@gatech.edu} +%%\orcid{1234-5678-9012} +%%\author{G.K.M. Tobin} +%%\authornotemark[1] +%%\email{webmaster@marysville-ohio.com} +\affiliation{% + \institution{Georgia Tech} + %%\streetaddress{P.O. Box 1212} + \city{Atlanta} + \state{GA} + \country{USA} + %%\postcode{43017-6221} +} + +%%\author{Lars Th{\o}rv{\"a}ld} +%%\affiliation{% +%% \institution{The Th{\o}rv{\"a}ld Group} +%% \streetaddress{1 Th{\o}rv{\"a}ld Circle} +%% \city{Hekla} +%% \country{Iceland}} +%%\email{larst@affiliation.org} + +%%\author{Valerie B\'eranger} +%%\affiliation{% +%% \institution{Inria Paris-Rocquencourt} +%% \city{Rocquencourt} +%% \country{France} +%%} + +%%\author{Aparna Patel} +%%\affiliation{% +%% \institution{Rajiv Gandhi University} +%% \streetaddress{Rono-Hills} +%% \city{Doimukh} +%% \state{Arunachal Pradesh} +%% \country{India}} + +%%\author{Huifen Chan} +%%\affiliation{% +%% \institution{Tsinghua University} +%% \streetaddress{30 Shuangqing Rd} +%% \city{Haidian Qu} +%% \state{Beijing Shi} +%% \country{China}} + +%%\author{Charles Palmer} +%%\affiliation{% +%% \institution{Palmer Research Laboratories} +%% \streetaddress{8600 Datapoint Drive} +%% \city{San Antonio} +%% \state{Texas} +%% \country{USA} +%% \postcode{78229}} +%%\email{cpalmer@prl.com} + +%%\author{John Smith} +%%\affiliation{% +%% \institution{The Th{\o}rv{\"a}ld Group} +%% \streetaddress{1 Th{\o}rv{\"a}ld Circle} +%% \city{Hekla} +%% \country{Iceland}} +%%\email{jsmith@affiliation.org} + +%%\author{Julius P. Kumquat} +%%\affiliation{% +%% \institution{The Kumquat Consortium} +%% \city{New York} +%% \country{USA}} +%%\email{jpkumquat@consortium.net} + +%% +%% By default, the full list of authors will be used in the page +%% headers. Often, this list is too long, and will overlap +%% other information printed in the page headers. This command allows +%% the author to define a more concise list +%% of authors' names for this purpose. +%%\renewcommand{\shortauthors}{Trovato and Tobin, et al.} + +%% +%% The abstract is a short summary of the work to be presented in the +%% article. +\begin{abstract} + Naively executing a language using Vau and Fexprs instead of macros + is slow. +\end{abstract} + +%% +%% The code below is generated by the tool at http://dl.acm.org/ccs.cfm. +%% Please copy and paste the code instead of the example below. +%% +%%\begin{CCSXML} +%% +%% +%% 10010520.10010553.10010562 +%% Computer systems organization~Embedded systems +%% 500 +%% +%% +%% 10010520.10010575.10010755 +%% Computer systems organization~Redundancy +%% 300 +%% +%% +%% 10010520.10010553.10010554 +%% Computer systems organization~Robotics +%% 100 +%% +%% +%% 10003033.10003083.10003095 +%% Networks~Network reliability +%% 100 +%% +%% +%%\end{CCSXML} + +%%\ccsdesc[500]{Computer systems organization~Embedded systems} +%%\ccsdesc[300]{Computer systems organization~Redundancy} +%%\ccsdesc{Computer systems organization~Robotics} +%%\ccsdesc[100]{Networks~Network reliability} + +%% +%% Keywords. The author(s) should pick words that accurately describe +%% the work being presented. Separate the keywords with commas. +\keywords{partial evaluation, vau, fexprs, WebAssembly} + + +%% +%% This command processes the author and affiliation and title +%% information and builds the first part of the formatted document. +%%\maketitle + +\section{Introduction and Motivation} + Vaus \cite{shutt2010fexprs} (at \url{https://web.wpi.edu/Pubs/ETD/Available/etd-090110-124904/unrestricted/jshutt.pdf}) + All code available at \url{https://github.com/limvot/kraken} + +\section{Prior Work} +\begin{itemize} + \item{} Axis of Eval rundown of attempted implmentations - \url{https://axisofeval.blogspot.com/2011/09/kernel-underground.html} \\ + \item{} Lambda The Ultimate small discussion of partial eval for Vau/Kernel - \url{http://lambda-the-ultimate.org/node/4346} \\ + \item{} Implementing a Vau-based Language With Multiple Evaluation Strategies - \cite{kearsleyimplementing} \\ + Talks about how partial evaluation could make efficient, doesn't do it. + \item{} Google Groups email thread by Andres Navarro - \url{https://groups.google.com/g/klisp/c/Dva-Le8Hr-g/m/pyl1Ufu-vksJ} \\ + Andres Navarro talks about his experimental fklisp which is a "very simple functional dialect of Kernel" with no mutation or first class continuations. + It doesn't compile anything, but prints out the partially evalauted expression. Was a work in progress, ran into performance problems, seems abandond. +\end{itemize} + +\subsection{Issues} + Slow. +\section{Solution} + Purely functional. + Tricky partial evaluation. + +\begin{verbatim} +((wrap (vau (let1) + +(let1 lambda (vau se (p b1) (wrap (eval (array vau p b1) se))) + (lambda (n) (* n 2)) +) + +; impl of let1 +)) (vau de (s v b) (eval (array (array vau (array s) b) (eval v de)) de))) +\end{verbatim} + +\bibliographystyle{ACM-Reference-Format} +\bibliography{cited-paper} + +\end{document} +\endinput +%% +%% End of file `sample-acmsmall.tex'. diff --git a/fib.c b/fib.c deleted file mode 100644 index 54fea15..0000000 --- a/fib.c +++ /dev/null @@ -1,17 +0,0 @@ -#include - -int fib(int n) { - if (n == 0) { - return 0; - } else if (n == 1) { - return 1; - } else { - return fib(n-1) + fib(n-2); - } -} - -int main(int argc, char** argv) { - int n = 27; - printf("Fib(%d): %d\n", n, fib(n)); - return 0; -} diff --git a/fungll.krak b/fungll.krak deleted file mode 100644 index ea0d1dd..0000000 --- a/fungll.krak +++ /dev/null @@ -1,440 +0,0 @@ -import vec:* -import vec_literals:* -import map:* -import set:* -import hash_set -import util:* -import str:* -import regex:* - -// nonterminals are negative, terminals are positive -obj Grammer (Object) { - var nonterminals: vec>> - var nonterminal_names: vec - var nonterminal_funs: vec): T>>> - var terminals: vec - var terminal_funs: vec> - var start_symbol: int - fun construct(): *Grammer { - nonterminals.construct() - nonterminal_names.construct() - nonterminal_funs.construct() - terminals.construct() - terminal_funs.construct() - start_symbol = 0 - return this - } - fun copy_construct(old: *Grammer): void { - nonterminals.copy_construct(&old->nonterminals) - nonterminal_names.copy_construct(&old->nonterminal_names) - nonterminal_funs.copy_construct(&old->nonterminal_funs) - terminals.copy_construct(&old->terminals) - terminal_funs.copy_construct(&old->terminal_funs) - start_symbol = old->start_symbol - } - fun destruct(): void { - nonterminals.destruct() - nonterminal_names.destruct() - nonterminal_funs.destruct() - terminals.destruct() - terminal_funs.destruct() - } - fun operator=(other:ref Grammer):void { - destruct() - copy_construct(&other) - } - fun add_new_nonterminal(name: *char, rule: ref vec, d: K, f: fun(ref K,ref vec): T): int { - return add_new_nonterminal(str(name), rule, d, f) - } - fun add_new_nonterminal(name: ref str, rule: ref vec, d: K, f: fun(ref K,ref vec): T): int { - nonterminals.add(vec(rule)) - nonterminal_names.add(name) - nonterminal_funs.add(vec(make_pair(d,f))) - return -1*nonterminals.size - } - fun add_to_or_create_nonterminal(name: ref str, rule: ref vec, d: K, f: fun(ref K,ref vec): T): int { - var idx = nonterminal_names.find(name) - if idx >= 0 { - add_to_nonterminal(-1*(idx+1), rule, d, f) - return -1*(idx+1) - } else { - return add_new_nonterminal(name, rule, d, f) - } - } - fun add_to_nonterminal(nonterminal: int, rule: ref vec, d: K, f: fun(ref K,ref vec): T) { - nonterminals[(-1*nonterminal)-1].add(rule) - nonterminal_funs[(-1*nonterminal)-1].add(make_pair(d,f)) - } - fun add_terminal(c: *char, d: K, f: fun(ref K,ref str,int,int): T): int { - return add_terminal(str(c), d, f) - } - fun add_terminal(c: ref str, d: K, f: fun(ref K,ref str,int,int): T): int { - terminals.add(regex(c)) - terminal_funs.add(make_pair(d,f)) - return terminals.size - } - fun get_nonterminal_rules(nonterminal: int): ref vec> { - return nonterminals[(-1*nonterminal)-1] - } - fun match_terminal(terminal: int, input: ref str, start: int): int { - return terminals[terminal-1].long_match(input.getBackingMemory(), start, input.length()) - } - fun is_terminal(x: int): bool { - return x > 0 - } - fun set_start_symbol(x: int) { - start_symbol = x - } - fun to_string(it: BS): str { - var rule_str = str() - for (var i = 0; i < nonterminals[(-1*it.nonterminal)-1][it.rule_idx].size; i++;) { - if i == it.idx_into_rule { - rule_str += "*" - } - var erminal = nonterminals[(-1*it.nonterminal)-1][it.rule_idx][i] - rule_str += to_string(erminal) - if i < nonterminals[(-1*it.nonterminal)-1][it.rule_idx].size-1 { - rule_str += " " - } - } - if it.idx_into_rule == nonterminals[(-1*it.nonterminal)-1][it.rule_idx].size { - rule_str += "*" - } - return str("<") + nonterminal_names[(-1*it.nonterminal)-1] + " ::= " + rule_str + ", " + it.left + ", " + it.pivot + ", " + it.right + ">" - } - fun to_string(erminal: int): str { - if erminal < 0 { - return nonterminal_names[(-1*erminal)-1] - } else { - return terminals[erminal-1].regexString - } - } - fun to_string(): str { - var to_ret = str() - for (var i = 0; i < nonterminals.size; i++;) { - for (var j = 0; j < nonterminals[i].size; j++;) { - to_ret += nonterminal_names[i] + " ::=" - for (var k = 0; k < nonterminals[i][j].size; k++;) { - to_ret += " " + to_string(nonterminals[i][j][k]) - } - to_ret += "\n" - } - } - return "start_symbol: " + to_string(start_symbol) + "\n" + to_ret - } - fun eval_BSR(input: ref str, BSR: ref set): T { - var top = -1 - for (var i = 0; i < BSR.data.size; i++;) { - if BSR.data[i].nonterminal == start_symbol && BSR.data[i].idx_into_rule == nonterminals[(-1*BSR.data[i].nonterminal)-1][BSR.data[i].rule_idx].size && BSR.data[i].left == 0 && BSR.data[i].right == input.length() { - top = i - break - } - } - if top == -1 { - println("Could not find top for input:") - println(input) - println(str("of length ") + input.length()) - for (var i = 0; i < BSR.data.size; i++;) { - println(str() + i + ": " + to_string(BSR.data[i])) - } - error("Could not find top") - } - return eval_BSR(input, BSR, top) - } - fun eval_BSR(input: ref str, BSR: ref set, c: int): T { - var bs = BSR.data[c] - var nonterminal = (-1*bs.nonterminal)-1 - if bs.idx_into_rule != nonterminals[nonterminal][bs.rule_idx].size { - error("Evaluating BSR from not the end!") - } - var params = vec() - for (var i = bs.idx_into_rule-1; i >= 0; i--;) { - var erminal = nonterminals[nonterminal][bs.rule_idx][i] - if is_terminal(erminal) { - var right_value = terminal_funs[erminal-1].second(terminal_funs[erminal-1].first, input, bs.pivot, bs.right) - params.add(right_value) - } else { - /*var right = find_comp(erminal, bs.pivot, bs.right)*/ - var right = -1 - var sub_nonterminal_idx = (-1*erminal)-1 - for (var j = 0; j < BSR.data.size; j++;) { - if BSR.data[j].nonterminal == erminal && BSR.data[j].idx_into_rule == nonterminals[sub_nonterminal_idx][BSR.data[j].rule_idx].size && BSR.data[j].left == bs.pivot && BSR.data[j].right == bs.right { - right = j - break - } - } - var right_value = eval_BSR(input, BSR, right) - params.add(right_value) - } - // get the new left bs - if i != 0 { - /*var new_bs_idx = find_mid(bs.nonterminal, bs.rule_idx, i, bs.left, bs.pivot)*/ - var new_bs_idx = -1 - for (var j = 0; j < BSR.data.size; j++;) { - if BSR.data[j].nonterminal == bs.nonterminal && BSR.data[j].rule_idx == bs.rule_idx && BSR.data[j].idx_into_rule == i && BSR.data[j].left == bs.left && BSR.data[j].right == bs.pivot { - new_bs_idx = j - break - } - } - bs = BSR.data[new_bs_idx] - } - } - var to_ret = nonterminal_funs[nonterminal][bs.rule_idx].second(nonterminal_funs[nonterminal][bs.rule_idx].first, params.reverse()) - return to_ret - } -} -obj Pending (Object) { - var nonterminal: int - var rule_idx: int - var idx_into_rule: int - var left: int - fun construct(): *Pending { - return this->construct(0,0,0,0) - } - fun construct(nonterminal: int, rule_idx: int, idx_into_rule: int, left: int): *Pending { - this->nonterminal = nonterminal; - this->rule_idx = rule_idx; - this->idx_into_rule = idx_into_rule; - this->left = left; - return this - } - fun copy_construct(old: *Pending): void { - this->nonterminal = old->nonterminal; - this->rule_idx = old->rule_idx; - this->idx_into_rule = old->idx_into_rule; - this->left = old->left; - } - fun destruct(): void { } - fun operator=(other:ref Pending):void { - destruct() - copy_construct(&other) - } - fun operator==(rhs: ref Pending): bool { - return nonterminal == rhs.nonterminal && rule_idx == rhs.rule_idx && idx_into_rule == rhs.idx_into_rule && left == rhs.left - } -} -fun pending(nonterminal: int, rule_idx: int, idx_into_rule: int, left: int): Pending { - var to_ret.construct(nonterminal, rule_idx, idx_into_rule, left): Pending - return to_ret -} -obj Descriptor (Object, Hashable) { - var nonterminal: int - var rule_idx: int - var idx_into_rule: int - var left: int - var pivot: int - fun construct(): *Descriptor { - return this->construct(0,0,0,0,0) - } - fun construct(nonterminal: int, rule_idx: int, idx_into_rule: int, left: int, pivot: int): *Descriptor { - this->nonterminal = nonterminal; - this->rule_idx = rule_idx; - this->idx_into_rule = idx_into_rule; - this->left = left; - this->pivot = pivot; - return this - } - fun copy_construct(old: *Descriptor): void { - this->nonterminal = old->nonterminal; - this->rule_idx = old->rule_idx; - this->idx_into_rule = old->idx_into_rule; - this->left = old->left; - this->pivot = old->pivot; - } - fun destruct(): void { } - fun operator=(other:ref Descriptor):void { - destruct() - copy_construct(&other) - } - fun operator==(rhs: ref Descriptor): bool { - return nonterminal == rhs.nonterminal && rule_idx == rhs.rule_idx && idx_into_rule == rhs.idx_into_rule && left == rhs.left && pivot == rhs.pivot - } - fun hash():ulong { - //return hash(nonterminal) ^ hash(rule_idx) ^ hash(idx_into_rule) ^ hash(left) ^ hash(pivot) - return nonterminal*3 + rule_idx*5 + idx_into_rule*7 + left*11 + pivot*13 - } -} -fun descriptor(nonterminal: int, rule_idx: int, idx_into_rule: int, left: int, pivot: int): Descriptor { - var to_ret.construct(nonterminal, rule_idx, idx_into_rule, left, pivot): Descriptor - return to_ret -} -obj BS (Object) { - var nonterminal: int - var rule_idx: int - var idx_into_rule: int - var left: int - var pivot: int - var right: int - fun construct(): *BS { - return this->construct(0,0,0,0,0,0) - } - fun construct(nonterminal: int, rule_idx: int, idx_into_rule: int, left: int, pivot: int, right: int): *BS { - this->nonterminal = nonterminal; - this->rule_idx = rule_idx; - this->idx_into_rule = idx_into_rule; - this->left = left; - this->pivot = pivot; - this->right = right; - return this - } - fun copy_construct(old: *BS): void { - this->nonterminal = old->nonterminal; - this->rule_idx = old->rule_idx; - this->idx_into_rule = old->idx_into_rule; - this->left = old->left; - this->pivot = old->pivot; - this->right = old->right; - } - fun destruct(): void { } - fun operator=(other:ref BS):void { - destruct() - copy_construct(&other) - } - fun to_string(): str { - return str("nonterminal:") + nonterminal + " rule_idx:" + rule_idx + " idx_into_rule:" + idx_into_rule + " l:" + left + " p:" + pivot + " r:" + right - } - fun operator==(rhs: ref BS): bool { - return nonterminal == rhs.nonterminal && rule_idx == rhs.rule_idx && idx_into_rule == rhs.idx_into_rule && left == rhs.left && pivot == rhs.pivot && right == rhs.right - } -} -fun bs(nonterminal: int, rule_idx: int, idx_into_rule: int, left: int, pivot: int, right: int): BS { - var to_ret.construct(nonterminal, rule_idx, idx_into_rule, left, pivot, right): BS - return to_ret -} -/*fun fungll(grammar: ref Grammer, start_symbol: *char, input: ref str): set {*/ - /*return fungll(grammar, str(start_symbol), input)*/ -/*}*/ -/*fun fungll(grammar: ref Grammer, start_symbol: str, input: ref str): set {*/ - /*return fungll(grammar, -1*(grammar.nonterminal_funs.find(start_symbol)+1), input)*/ -/*}*/ -fun fungll(grammar: ref Grammer, start_symbol: int, input: ref str): set { - var R = descend(grammar, start_symbol, 0) - var G = map, set>() - var P = map, set>() - var Y = set() - - R.chaotic_closure(fun(d: Descriptor): set { - var it = process(grammar, input, d, G, P) - //var Yp = it.first.second - Y += it.first.second - var Gp = it.second - var Pp = it.third - - for (var i = 0; i < Gp.keys.size; i++;) { - if G.contains_key(Gp.keys[i]) { - G[Gp.keys[i]].add(Gp.values[i]) - } else { - G[Gp.keys[i]] = Gp.values[i] - } - } - for (var i = 0; i < Pp.keys.size; i++;) { - if P.contains_key(Pp.keys[i]) { - P[Pp.keys[i]].add(Pp.values[i]) - } else { - P[Pp.keys[i]] = Pp.values[i] - } - } - - // Rp - return it.first.first - }) - return Y -} -fun descend(grammar: ref Grammer, symbol: int, l: int): set { - var to_ret = set() - for (var rhs = 0; rhs < grammar.get_nonterminal_rules(symbol).size; rhs++;) - to_ret.add(descriptor(symbol, rhs, 0, l, l)) - return to_ret -} -fun process(grammar: ref Grammer, input: ref str, descript: Descriptor, G: ref map, set>, P: ref map, set>): triple, set>, map, set>, map, set>> { - // if at end / end is emptystr - if descript.idx_into_rule == grammar.get_nonterminal_rules(descript.nonterminal)[descript.rule_idx].size { - return process_e(grammar, descript, G, P) - } else { - return process_symbol(grammar, input, descript, G, P) - } -} -fun process_e(grammar: ref Grammer, descript: Descriptor, G: ref map, set>, P: ref map, set>): triple, set>, map, set>, map, set>> { - var nonterminal: int - var rule_idx: int - var left: int - var pivot: int - var X = descript.nonterminal - var l = descript.left; - var k = descript.pivot; - var K = G.get_with_default(make_pair(X,l), set()) - var it = ascend(l,K,k) - var R = it.first - var Y = it.second - if grammar.get_nonterminal_rules(X)[descript.rule_idx].size == 0 { - Y.add(bs(X,descript.rule_idx, 0, l, l, l)) - } - return make_triple(make_pair(R,Y), map, set>(), map(make_pair(X,l), set(k))) -} -fun process_symbol(grammar: ref Grammer, input: ref str, descript: Descriptor, G: ref map, set>, P: ref map, set>): triple, set>, map, set>, map, set>> { - var s = grammar.get_nonterminal_rules(descript.nonterminal)[descript.rule_idx][descript.idx_into_rule] - var k = descript.pivot - var R = P.get_with_default(make_pair(s,k), set()) - var Gp = map(make_pair(s,k), set(pending(descript.nonterminal, descript.rule_idx, descript.idx_into_rule+1, descript.left))) - if grammar.is_terminal(s) { - return make_triple(matc(grammar,input,descript), map, set>(), map, set>()) - } else if R.size() == 0 { // s in N - return make_triple(make_pair(descend(grammar,s,k), set()), Gp, map, set>()) - } else { // s in N and R != set() - return make_triple(skip(k,pending(descript.nonterminal, descript.rule_idx, descript.idx_into_rule+1, descript.left), R), Gp, map, set>()) - } -} -fun matc(grammar: ref Grammer, input: ref str, descript: Descriptor): pair, set> { - /*println("trying to match " + grammar.to_string(grammar.get_nonterminal_rules(descript.nonterminal)[descript.rule_idx][descript.idx_into_rule]))*/ - var match_length = grammar.match_terminal(grammar.get_nonterminal_rules(descript.nonterminal)[descript.rule_idx][descript.idx_into_rule], input, descript.pivot) - if match_length > 0 { - /*println("matched " + grammar.to_string(grammar.get_nonterminal_rules(descript.nonterminal)[descript.rule_idx][descript.idx_into_rule]))*/ - return make_pair(set(descriptor(descript.nonterminal, descript.rule_idx, descript.idx_into_rule+1, descript.left, descript.pivot+match_length)), set(bs(descript.nonterminal, descript.rule_idx, descript.idx_into_rule+1, descript.left, descript.pivot, descript.pivot+match_length))) - } else { - return make_pair(set(), set()) - } -} -fun skip(k: int, c: Pending, R: ref set): pair, set> { return nmatch(k, set(c), R); } -fun ascend(k:int, K: ref set, r: int): pair, set> { return nmatch(k, K, set(r)); } -fun nmatch(k:int, K: ref set, R: ref set): pair, set> { - var Rp = set() - var Y = set() - for (var i = 0; i < K.data.size; i++;) { - var pending = K.data[i] - for (var j = 0; j < R.data.size; j++;) { - var r = R.data[j] - Rp.add(descriptor(pending.nonterminal, pending.rule_idx, pending.idx_into_rule, pending.left, r)) - Y.add(bs(pending.nonterminal, pending.rule_idx, pending.idx_into_rule, pending.left, k, r)) - } - } - return make_pair(Rp,Y) -} -/*fun main(argc: int, argv: **char): int {*/ - /*var grammar.construct(): Grammer*/ - /*var Number = grammar.add_new_nonterminal("Number", vec(grammar.add_terminal("[0-9]+", fun(input: ref str, l: int, r: int): int { return string_to_num(input.slice(l,r)); })), fun(i: ref vec): int { return i[0]; })*/ - - /*var mult = grammar.add_terminal("\\*", fun(input: ref str, l: int, r: int): int { return 1; })*/ - /*var Factor = grammar.add_new_nonterminal("Factor", vec(Number), fun(i: ref vec): int { return i[0]; })*/ - /*grammar.add_to_nonterminal(Factor, vec(Factor, mult, Number), fun(i: ref vec): int { return i[0]*i[2]; })*/ - - /*var add = grammar.add_terminal("\\+", fun(input: ref str, l: int, r: int): int { return 1; })*/ - /*var Term = grammar.add_new_nonterminal("Term", vec(Factor), fun(i: ref vec): int { return i[0]; })*/ - /*grammar.add_to_nonterminal(Term, vec(Term, add, Factor), fun(i: ref vec): int { return i[0]+i[2]; })*/ - - /*grammar.set_start_symbol(Term)*/ - - /*var input = str("1+23*44")*/ - /*var BSR = fungll(grammar, input)*/ - - - /*println(str("length of BSR is: ") + BSR.size())*/ - /*for (var i = 0; i < BSR.data.size; i++;) {*/ - /*var BS = BSR.data[i]*/ - /*println(str() + i + ": " + grammar.to_string(BSR.data[i]))*/ - /*}*/ - - /*var res = grammar.eval_BSR(input, BSR)*/ - /*println(str("result of grammar.eval_BSR(fungll(grammar, ") + input + ")) = " + res)*/ - - /*return 0*/ -/*}*/ diff --git a/future_features.txt b/future_features.txt deleted file mode 100644 index c93fa0e..0000000 --- a/future_features.txt +++ /dev/null @@ -1,7 +0,0 @@ -correctly importing / running tests is a nightmare with relative paths. - -Namespaces -Imports allow renaming of either entire scope or individual members, and can import from within a scope - -Fix // comment right before top level function declaration. Something to do -with the return as /* comment */ does not have that problem diff --git a/k.krak b/k.krak deleted file mode 100644 index 7a46f02..0000000 --- a/k.krak +++ /dev/null @@ -1,1870 +0,0 @@ -import io:* -import grammer:* -import lexer:* -import parser:* -import str:* -import serialize:* -import os:* -import set:* -import stack:* -import vec:* -import vec_literals:* -import poset:* -import util:* -import ast:* -import type2:* -import tree:* -import symbol:* -import binding:* - -adt OptionVecAst { - Some: vec<*tree>, - None -} - -fun main(argc: int, argv: **char): int { - // delay construction until we either load it or copy construct it - var gram: grammer - var base_dir = str("/").join(str(argv[0]).split('/').slice(0,-2)) - var import_paths = vec(str(), base_dir + "/stdlib/") - var file_name = base_dir + "/krakenGrammer.kgm" - var compiled_name = file_name + str(".comp_new") - var compiled_version = 1 - var file_contents = read_file(file_name) - var loaded_and_valid = false - - if (argc <= 1) { - println("No input file!\n Call with one argument (the input file), or two arguments (input file and output name)") - exit(1) - } else if (str(argv[1]) == "-v" || str(argv[1]) == "--version") { - println("0.0 pre") - exit(0) - } - var opt_str = str("-O2") - var compile_c = true - var positional_args = vec() - for (var i = 1; i < argc; i++;) { - var arg_str = str(argv[i]) - if (arg_str.length() > 2 && arg_str.slice(0,2) == "-O") { - opt_str = arg_str - } else if (arg_str == "--no-c-compile") { - compile_c = false - } else { - positional_args.add(arg_str) - } - } - - if (file_exists(compiled_name)) { - var pos = 0 - var binary = read_file_binary(compiled_name) - var saved_version = 0 - unpack(saved_version, pos) = unserialize(binary, pos) - if (saved_version == compiled_version) { - var cached_contents = str() - unpack(cached_contents, pos) = unserialize(binary, pos) - if (cached_contents == file_contents) { - loaded_and_valid = true - pos = gram.unserialize(binary, pos) - } else println("contents different") - } else println("version number different") - } else { - println("cached file does not exist") - } - if (!loaded_and_valid) { - println("Not loaded_and_valid, re-generating and writing out") - gram.copy_construct(&load_grammer(file_contents)) - println("grammer loaded, calculate_first_set") - gram.calculate_first_set() - println("grammer loaded, calculate_state_automaton") - gram.calculate_state_automaton() - println("calculated, writing out") - write_file_binary(compiled_name, serialize(compiled_version) + serialize(file_contents) + serialize(gram)) - println("done writing") - } - - var lex = lexer(gram.terminals) - var parse.construct(&gram, &lex): parser - - var kraken_file_name = positional_args[0] - var executable_name = str(".").join(kraken_file_name.split('.').slice(0,-2)) - if (positional_args.size > 1) - executable_name = positional_args[1] - - var pass_poset = poset, str>>() - var name_ast_map = map>() - var passes = map): void>() - - var multiple_binding_options = map<*tree, vec<*tree>>() - var primitive_ops.construct(): map>> - - var number_tower = vec(binding_p(type::_char(), binding_epoch::pre_ref()), - binding_p(type::_uchar(), binding_epoch::pre_ref()), - binding_p(type::_short(), binding_epoch::pre_ref()), - binding_p(type::_ushort(), binding_epoch::pre_ref()), - binding_p(type::_int(), binding_epoch::pre_ref()), - binding_p(type::_uint(), binding_epoch::pre_ref()), - binding_p(type::_long(), binding_epoch::pre_ref()), - binding_p(type::_ulong(), binding_epoch::pre_ref()), - binding_p(type::_float(), binding_epoch::pre_ref()), - binding_p(type::_double(), binding_epoch::pre_ref())) - var comparators = vec(str("=="), str("<="), str(">="), str("!="), str("<"), str(">")) - for (var i = 0; i < comparators.size; i++;) { - primitive_ops["op" + comparators[i]] = vec<*tree>() - for (var j = 0; j < number_tower.size; j++;) - for (var k = 0; k < number_tower.size; k++;) - primitive_ops["op" + comparators[i]].add(_compiler_intrinsic(comparators[i], binding_p(type::_fun(make_triple(make_pair(vec( - make_pair(ref_type::_notref(), number_tower[j]), - make_pair(ref_type::_notref(), number_tower[k]) - ), - make_pair(ref_type::_notref(), binding_p(type::_bool(), binding_epoch::pre_ref())) - ), false, false)), binding_epoch::pre_ref()), vec<*binding>())) - } - var math = vec(str("+"), str("-"), str("*"), str("/"), str("&"), str("|"), str("^")) - for (var i = 0; i < math.size; i++;) { - primitive_ops["op" + math[i]] = vec<*tree>() - for (var j = 0; j < number_tower.size; j++;) { - for (var k = 0; k < number_tower.size; k++;) { - var return_type = null>() - if (j > k) { - return_type = number_tower[j] - } else { - return_type = number_tower[k] - } - primitive_ops["op" + math[i]].add(_compiler_intrinsic(math[i], binding_p(type::_fun(make_triple(make_pair(vec( - make_pair(ref_type::_notref(), number_tower[j]), - make_pair(ref_type::_notref(), number_tower[k]) - ), - make_pair(ref_type::_notref(), return_type) - ), false, false)), binding_epoch::pre_ref()), vec<*binding>())) - } - } - } - // cute hack for getting plain = - math.add(str("")) - for (var i = 0; i < math.size; i++;) { - primitive_ops["op" + math[i] + "="] = vec<*tree>() - for (var j = 0; j < number_tower.size; j++;) { - for (var k = 0; k <= j; k++;) { - var return_type = null>() - primitive_ops["op" + math[i] + "="].add(_compiler_intrinsic(math[i] + "=", binding_p(type::_fun(make_triple(make_pair(vec( - make_pair(ref_type::_notref(), number_tower[j]), - make_pair(ref_type::_notref(), number_tower[k]) - ), - make_pair(ref_type::_notref(), binding_p(type::_void(), binding_epoch::pre_ref())) - ), false, false)), binding_epoch::pre_ref()), vec<*binding>())) - } - } - } - math.remove(math.size-1) - - // address of - var template_type = binding_p(type::_template_placeholder(), binding_epoch::pre_ref()) - primitive_ops[str("op&")].add(_template(str("&"), map(str("T"), template_type), vec(_compiler_intrinsic(str("&"), binding_p(type::_fun(make_triple(make_pair(vec( - make_pair(ref_type::_notref(), template_type) - ), - make_pair(ref_type::_notref(), binding_p(type::_ptr(template_type), binding_epoch::pre_ref())) - ), false, false)), binding_epoch::pre_ref()), vec<*binding>())))) - // dereference - var template_type = binding_p(type::_template_placeholder(), binding_epoch::pre_ref()) - primitive_ops[str("op*")].add(_template(str("*"), map(str("T"), template_type), vec(_compiler_intrinsic(str("*"), binding_p(type::_fun(make_triple(make_pair(vec( - make_pair(ref_type::_notref(), binding_p(type::_ptr(template_type), binding_epoch::pre_ref())) - ), - make_pair(ref_type::_notref(), template_type) - ), false, false)), binding_epoch::pre_ref()), vec<*binding>())))) - - for (var i = 0; i < number_tower.size - 2; i++;) { - var template_type = binding_p(type::_template_placeholder(), binding_epoch::pre_ref()) - primitive_ops[str("op+")].add(_template(str("+"), map(str("T"), template_type), vec(_compiler_intrinsic(str("+"), binding_p(type::_fun(make_triple(make_pair(vec( - make_pair(ref_type::_notref(), number_tower[i]), - make_pair(ref_type::_notref(), binding_p(type::_ptr(template_type), binding_epoch::pre_ref())) - ), - make_pair(ref_type::_notref(), binding_p(type::_ptr(template_type), binding_epoch::pre_ref())) - ), false, false)), binding_epoch::pre_ref()), vec<*binding>())))) - primitive_ops[str("op+")].add(_template(str("+"), map(str("T"), template_type), vec(_compiler_intrinsic(str("+"), binding_p(type::_fun(make_triple(make_pair(vec( - make_pair(ref_type::_notref(), binding_p(type::_ptr(template_type), binding_epoch::pre_ref())), - make_pair(ref_type::_notref(), number_tower[i]) - ), - make_pair(ref_type::_notref(), binding_p(type::_ptr(template_type), binding_epoch::pre_ref())) - ), false, false)), binding_epoch::pre_ref()), vec<*binding>())))) - - // note only ptr-1, not 1-ptr to match C... - primitive_ops[str("op-")].add(_template(str("-"), map(str("T"), template_type), vec(_compiler_intrinsic(str("-"), binding_p(type::_fun(make_triple(make_pair(vec( - make_pair(ref_type::_notref(), binding_p(type::_ptr(template_type), binding_epoch::pre_ref())), - make_pair(ref_type::_notref(), number_tower[i]) - ), - make_pair(ref_type::_notref(), binding_p(type::_ptr(template_type), binding_epoch::pre_ref())) - ), false, false)), binding_epoch::pre_ref()), vec<*binding>())))) - } - - var scope_lookup: fun(*tree, str, bool, *tree, str, str): OptionVecAst = fun(scope: *tree, name: str, is_type: bool, item: *tree, pass: str, pass_dep_on: str): OptionVecAst { - /*println("doing a scope lookup for " + name + " starting from " + to_string(scope->data))*/ - var to_ret = vec<*tree>() - for (var i = 0; i < scope->children.size; i++;) { - match(scope->children[i]->data) { - ast::_import(b) if b.second.contains(name) || b.second.contains(str("*")) { - if !ast_bound(b.first) { - // Import / parse file if not already - var file_path = ast_binding_str(b.first) - if (!name_ast_map.contains_key(file_path)) { - printerr(file_path + ", ") - var parse_tree = parse.parse_input(read_file(file_path), file_path) - trim(parse_tree) - name_ast_map[file_path] = syntax_to_ast(file_path, parse_tree, import_paths) - printlnerr("syntax_to_ast " + file_path + ":") - print_tree(name_ast_map[file_path], 1) - } - set_ast_binding(b.first, name_ast_map[file_path], binding_epoch::pre_ref()) - } - var other_top_level = get_ast_binding(b.first, binding_epoch::pre_ref()) - if item != null>() { - if !pass_poset.done(make_pair(other_top_level, str("translation_unit_top_type_resolve"))) { - pass_poset.add_open_dep(make_pair(item, pass), make_pair(other_top_level, pass_dep_on)) - return OptionVecAst::None() - } - } - match (scope_lookup(other_top_level, name, is_type, item, pass, pass_dep_on)) { - OptionVecAst::None() return OptionVecAst::None() - OptionVecAst::Some(v) { - to_ret.add_all_unique(v) - } - } - } - ast::_type_def(b) if (is_type && b == name) - to_ret.add_unique(scope->children[i]) - ast::_adt_def(b) if (is_type && b == name) - to_ret.add_unique(scope->children[i]) - ast::_function(b) if (!is_type && b.first == name) - to_ret.add_unique(scope->children[i]) - ast::_compiler_intrinsic(b) if (!is_type && b.first == name) - to_ret.add_unique(scope->children[i]) - ast::_template(b) if (((!is_type && is_function(scope->children[i]->children[0])) - || (!is_type && is_compiler_intrinsic(scope->children[i]->children[0])) - || ( is_type && is_type_def(scope->children[i]->children[0])) - || ( is_type && is_adt_def( scope->children[i]->children[0]))) && b.first == name) - to_ret.add_unique(scope->children[i]) - ast::_identifier(b) if (!is_type && b.first == name) - to_ret.add_unique(scope->children[i]) - ast::_declaration() if (!is_type && scope->children[i]->children[0]->data._identifier.first == name) - to_ret.add_unique(scope->children[i]->children[0]) - } - } - if (scope->parent != null>()) { - match (scope_lookup(scope->parent, name, is_type, item, pass, pass_dep_on)) { - OptionVecAst::None() return OptionVecAst::None() - OptionVecAst::Some(v) to_ret.add_all_unique(v) - } - } - else if (primitive_ops.contains_key(name)) - to_ret.add_all_unique(primitive_ops[name]) - return OptionVecAst::Some(to_ret) - } - - passes[str("translation_unit_generative")] = fun(item: *tree) { - println("Running translation_unit_generative") - if !is_translation_unit(item) { - error("Running translation_unit_generative on not a translation unit"); - } - for (var i = 0; i < item->children.size; i++;) { - var child = item->children[i] - match (child->data) { - ast::_type_def(name) { - println("Found a type_def! - " + name) - for (var j = 0; j < child->children.size; j++;) { - var grandchild = child->children[j]; - if is_declaration(grandchild) { - var ident = grandchild->children[0] - var ident_name = ident->data._identifier.first - var ident_type = ident->data._identifier.second - var type_def_binding = make_ast_binding(name) - set_ast_binding(type_def_binding, child, binding_epoch::pre_ref()) - item->add_child(_compiler_intrinsic(ident_name, binding_p(type::_fun(make_triple(make_pair(vec( - make_pair(ref_type::_notref(), binding_p(type::_obj(type_def_binding), binding_epoch::pre_ref())) - ), - make_pair(ref_type::_notref(), ident_type) - ), false, false)), binding_epoch::pre_ref()), vec<*binding>())) - println("adding compiler intrinsic to do " + name + "." + ident_name) - } - } - } - ast::_template(name_map_pair) { - if is_type_def(child->children[0]) { - var name = child->children[0]->data._type_def - println("Found a templated type_def! - " + name) - for (var j = 0; j < child->children[0]->children.size; j++;) { - var great_grandchild = child->children[0]->children[j]; - if is_declaration(great_grandchild) { - var ident = great_grandchild->children[0] - var ident_name = ident->data._identifier.first - - // the map retains the order - var new_template_type_map = name_map_pair.second.associate(fun(n: str, t: *binding): pair> return make_pair(n, binding_p(type::_template_placeholder(), binding_epoch::pre_ref()));) - var new_ident_type = inst_temp_type(ident->data._identifier.second, name_map_pair.second.associate(fun(n: str, t: *binding): pair<*binding, *binding> - return make_pair(t, new_template_type_map[n]);), binding_epoch::pre_ref(), binding_epoch::pre_ref()) - - var type_def_binding = make_ast_binding(name, new_template_type_map.values) - // do we need to set the binding to the template? - /*set_ast_binding(type_def_binding, child)*/ - - item->add_child(_template(ident_name, new_template_type_map, vec(_compiler_intrinsic(ident_name, binding_p(type::_fun(make_triple(make_pair(vec( - make_pair(ref_type::_notref(), binding_p(type::_obj(type_def_binding), binding_epoch::pre_ref())) - ), - make_pair(ref_type::_notref(), new_ident_type) - ), false, false)), binding_epoch::pre_ref()), vec<*binding>())))) - println("adding compiler intrinsic to do " + name + "." + ident_name) - } - } - } - } - } - } - - println("post generative") - print_tree(item, 1) - } - - var binding_types = map<*tree, *binding>() - var get_type: fun(*tree, binding_epoch): *binding = fun(a: *tree, epoch: binding_epoch): *binding { - var get_template_type: fun(*tree, vec<*binding>): *binding = fun(a: *tree, inst_with: vec<*binding>): *binding { - var i = 0 - return inst_temp_type(get_type(a->children[0], binding_epoch::pre_ref()), a->data._template.second.associate(fun(k: str, v: *binding): pair<*binding, *binding> { - if (i < inst_with.size) - return make_pair(v, inst_with[i]) - else - return make_pair(v, binding_p(type::_unknown(), epoch)) - }), binding_epoch::pre_ref(), binding_epoch::pre_ref()) - } - match(a->data) { - ast::_identifier(b) return b.second - ast::_binding(b) if (binding_types.contains_key(a)) { - if ast_bound(a) && has_unknown(binding_types[a], epoch) { - var t = null>() - var bound_to = get_ast_binding(a, epoch) - if (is_template(bound_to)) { - t = get_template_type(bound_to, b.second) - unify(binding_types[a], t, epoch) - } else { - t = get_type(bound_to, epoch) - unify(binding_types[a], t, epoch) - } - } - return binding_types[a] - } else { - if (ast_bound(a)) { - var t = null>() - var bound_to = get_ast_binding(a, epoch) - if (is_template(bound_to)) { - t = get_template_type(bound_to, b.second) - } else { - t = get_type(bound_to, epoch) - } - binding_types[a] = t - return t - } else { - var new_type = binding_p(type::_unknown(), epoch) - binding_types[a] = new_type - return new_type - } - } - ast::_function(b) return b.second - ast::_template(b) return get_template_type(a, vec<*binding>()) - ast::_compiler_intrinsic(b) return b.second - ast::_call(add_scope) { - var t = get_type(a->children[0], epoch) - if (is_fun(t->get_bound_to(epoch))) - return t->get_bound_to(epoch)->_fun.first.second.second - if (is_unknown(t->get_bound_to(epoch))) { - var return_type = make_pair(ref_type::_unknown(), binding_p(type::_unknown(), epoch)) - var parameter_types = vec>>() - for (var i = 1; i < a->children.size; i++;) - parameter_types.add(make_pair(ref_type::_unknown(), get_type(a->children[i], epoch))) - t->set(type::_fun(make_triple(make_pair(parameter_types, return_type), false, false)), epoch) - return return_type.second - } - error("Trying to get type of call where type of first child is not function, but " + to_string(t->get_bound_to(epoch))) - } - ast::_cast(b) return b - ast::_value(b) return b.second - } - error("Trying to get type of node without one: " + to_string(a->data)) - } - - passes[str("translation_unit_top_type_resolve")] = fun(item: *tree) { - println("Running translation_unit_top_type_resolve") - if !is_translation_unit(item) { - error("Running translation_unit_top_type_resolve on not a translation unit"); - } - if !pass_poset.done(make_pair(item, str("translation_unit_generative"))) { - pass_poset.add_open_dep(make_pair(item, str("translation_unit_top_type_resolve")), make_pair(item, str("translation_unit_generative"))) - return - } - var quick_bind = fun(binding: *tree, start_scope: *tree, additional_scope: *tree, type_binding: bool): bool { - if !ast_bound(binding) { - match (scope_lookup(start_scope, ast_binding_str(binding), type_binding, item, str("translation_unit_top_type_resolve"), str("translation_unit_generative"))) { - OptionVecAst::None() { - return false; - } - OptionVecAst::Some(options) { - if (options.size < 1) { - error("couldn't find any possibilities for " + ast_binding_str(binding)) - } - println(ast_binding_str(binding) + " resolving at top level to " + to_string(options[0]->data)) - set_ast_binding(binding, options[0], binding_epoch::pre_ref()) - } - } - } - return true; - } - var quick_bind_type: fun(*binding, *tree): bool = fun(t: *binding, n: *tree): bool { - match(*t->get_bound_to(binding_epoch::pre_ref())) { - type::_obj(b) return quick_bind(b, n, null>(), true) - type::_ptr(p) return quick_bind_type(p, n) - type::_fun(b) { - for (var i = 0; i < b.first.first.size; i++;) - if (!quick_bind_type(b.first.first[i].second, n)) - return false - return quick_bind_type(b.first.second.second, n) - } - } - return true - } - for (var i = 0; i < item->children.size; i++;) { - var child = item->children[i] - match (child->data) { - ast::_template(name_map_pair) { - if is_function(child->children[0]) { - quick_bind_type(get_type(child->children[0], binding_epoch::pre_ref()), item) - } - } - ast::_declaration() { - quick_bind_type(get_type(child->children[0], binding_epoch::pre_ref()), item) - } - ast::_function(name_type_ext) { - quick_bind_type(get_type(child, binding_epoch::pre_ref()), item) - } - ast::_compiler_intrinsic(name_type_ext) { - quick_bind_type(get_type(child, binding_epoch::pre_ref()), item) - } - } - } - - println("post translation_unit_top_type_resolve") - print_tree(item, 1) - } - - // resolves all binding possibilities to a single one for one top level item - passes[str("name_type_resolve")] = fun(item: *tree) { - println("name_type resolve for:") - print_tree(item, 1) - - var try_to_find_binding_possibilities = fun(binding: *tree, start_scope: *tree, additional_scope: *tree, type_binding: bool): bool { - if !ast_bound(binding) && !multiple_binding_options.contains_key(binding) { - var all_options = vec<*tree>() - match (scope_lookup(start_scope, ast_binding_str(binding), type_binding, item, str("name_type_resolve"), str("translation_unit_top_type_resolve"))) { - OptionVecAst::None() { - println("OptionVecAst::None for " + ast_binding_str(binding) + " lookup, returning") - return false; - } - OptionVecAst::Some(options) { - println("OptionVecAst::Some for " + ast_binding_str(binding) + " lookup, continuing!") - all_options += options - } - } - if additional_scope != null>() { - println("Additionally looking at scope " + to_string(additional_scope->data) + " for try_to_find_binding_possibilities " + ast_binding_str(binding)) - match (scope_lookup(additional_scope, ast_binding_str(binding), type_binding, item, str("name_type_resolve"), str("translation_unit_top_type_resolve"))) { - OptionVecAst::None() { - println("OptionVecAst::None for " + ast_binding_str(binding) + " lookup, returning") - return false; - } - OptionVecAst::Some(options) { - println("OptionVecAst::Some for " + ast_binding_str(binding) + " lookup, continuing!") - all_options.add_all_unique(options) - } - } - } - if (all_options.size == 0) { - error("Could not find any options for scope lookup of " + ast_binding_str(binding)) - } else if (all_options.size == 1) { - println(ast_binding_str(binding) + " resolved to a single!") - set_ast_binding(binding, all_options[0], binding_epoch::pre_ref()) - } else { - println(ast_binding_str(binding) + " found to have " + all_options.size + " options!") - for (var i = 0; i < all_options.size; i++;) - println("\t" + to_string(all_options[i]->data)) - multiple_binding_options[binding] = all_options - } - } - return true; - } - var handle_type_binding_possibilities: fun(*binding, *tree): bool = fun(t: *binding, n: *tree): bool { - match(*t->get_bound_to(binding_epoch::pre_ref())) { - type::_obj(b) return try_to_find_binding_possibilities(b, n, null>(), true) - type::_ptr(p) return handle_type_binding_possibilities(p, n) - type::_fun(b) { - for (var i = 0; i < b.first.first.size; i++;) - if (!handle_type_binding_possibilities(b.first.first[i].second, n)) - return false - return handle_type_binding_possibilities(b.first.second.second, n) - } - } - return true - } - - var traverse_for_unify: fun(*tree): void = fun(t: *tree) { - t->children.for_each(traverse_for_unify) - match (t->data) { - // even if we have nothing to unify it with, we call get_type on all bindings so that it gets put in the binding map - ast::_binding(b) get_type(t, binding_epoch::pre_ref()) - ast::_declaration() if (t->children.size > 1) - unify(get_type(t->children[0], binding_epoch::pre_ref()), get_type(t->children[1], binding_epoch::pre_ref()), binding_epoch::pre_ref()) - ast::_call(add_scope) { - println("traverse_for_unify call - " + to_string(t->data)) - // we call get type to make sure if it is unknown it is transformed into a function version - get_type(t, binding_epoch::pre_ref()) - println("\tpast first get_type") - var fun_type = get_type(t->children[0], binding_epoch::pre_ref())->get_bound_to(binding_epoch::pre_ref()) - println("\tpast second get_type") - if (!is_fun(fun_type)) - error("trying to call not a function type: " + to_string(fun_type)) - if (fun_type->_fun.first.first.size != (t->children.size - 1)) - error("trying to call function with type wrong number of params (" + to_string(fun_type->_fun.first.first.size) + " vs " + to_string(t->children.size - 1) + "): " + to_string(fun_type)) - println("\titerating through children, matching their type with the param type") - for (var i = 1; i < t->children.size; i++;) - unify(fun_type->_fun.first.first[i-1].second, get_type(t->children[i], binding_epoch::pre_ref()), binding_epoch::pre_ref()) - } - ast::_return() if (t->children.size > 0) - unify(get_type(get_ancestor_satisfying(t, fun(t: *tree): bool return is_function(t);), binding_epoch::pre_ref())->get_bound_to(binding_epoch::pre_ref())->_fun.first.second.second, get_type(t->children[0], binding_epoch::pre_ref()), binding_epoch::pre_ref()) - } - } - traverse_for_unify(item) - - var more_to_do = true - while (more_to_do) { - println("RESOLVE LOOP BEGIN") - more_to_do = false - var work_done = false - var traverse_for_select: fun(*tree): bool = fun(t: *tree): bool { - var children_start_index = 0 - match (t->data) { - ast::_identifier(b) if (!handle_type_binding_possibilities(b.second, t)) - return false; - /*_binding: triple, *tree>,*/ - ast::_function(b) if (!handle_type_binding_possibilities(b.second, t)) - return false; - ast::_compiler_intrinsic(b) { - if (!handle_type_binding_possibilities(b.second, t)) - return false; - for (var i = 0; i < b.third.size; i++;) - if (!handle_type_binding_possibilities(b.third[i], t)) - return false; - /*b.third.for_each(fun(tb: *binding) {*/ - /*handle_type_binding_possibilities(tb, t)*/ - /*})*/ - } - ast::_cast(b) if (!handle_type_binding_possibilities(b, t)) - return false; - ast::_call(add_scope) { - println("call of " + to_string(t->children[0]) + ", that is " + to_string(t->children[0]->data) + " has type " + to_string(get_type(t, binding_epoch::pre_ref())->get_bound_to(binding_epoch::pre_ref())) + ", and the function has type " + to_string(get_type(t->children[0], binding_epoch::pre_ref())->get_bound_to(binding_epoch::pre_ref()))) - /*get_type(t)*/ - if add_scope && is_binding(t->children[0]) && !ast_bound(t->children[0]) && !multiple_binding_options.contains_key(t->children[0]) { - var first_param_type = get_type(t->children[1], binding_epoch::pre_ref()) - if !is_unknown(first_param_type->get_bound_to(binding_epoch::pre_ref())) && (!is_obj(first_param_type->get_bound_to(binding_epoch::pre_ref())) || ast_bound(first_param_type->get_bound_to(binding_epoch::pre_ref())->_obj)) { - if is_obj(first_param_type->get_bound_to(binding_epoch::pre_ref())) { - if (!try_to_find_binding_possibilities(t->children[0], t->children[0], get_ast_binding(first_param_type->get_bound_to(binding_epoch::pre_ref())->_obj, binding_epoch::pre_ref())->parent, false)) - return false; - } else { - if (!try_to_find_binding_possibilities(t->children[0], t->children[0], null>(), false)) - return false - } - work_done = true - println("wok done! generic add posibilities (or down to one) for " + to_string(t->children[0]->data)) - if ast_bound(t->children[0]) { - unify(binding_types[t->children[0]], get_type(get_ast_binding(t->children[0], binding_epoch::pre_ref()), binding_epoch::pre_ref()), binding_epoch::pre_ref()) - } - } else { - children_start_index = 1 - more_to_do = true - } - } - } - - ast::_binding(b) if (!ast_bound(t)) { - println(to_string(t->data) + " - not bound!") - if !multiple_binding_options.contains_key(t) { - if (!try_to_find_binding_possibilities(t, t, null>(), false)) - return false - } - if ast_bound(t) { - unify(binding_types[t], get_type(get_ast_binding(t, binding_epoch::pre_ref()), binding_epoch::pre_ref()), binding_epoch::pre_ref()) - work_done = true - println("wok done! set " + to_string(t->data)) - } else { - // isn't function, by shadowing we just take the first - if !is_fun(binding_types[t]->get_bound_to(binding_epoch::pre_ref())) { - if (!multiple_binding_options[t].size > 0) - error("No possible options for " + to_string(t->data)) - var it = multiple_binding_options[t][0] - set_ast_binding(t, it, binding_epoch::pre_ref()) - unify(binding_types[t], get_type(it, binding_epoch::pre_ref()), binding_epoch::pre_ref()) - work_done = true - } else { - // function type, so we have to get interesting - var filtered_options = multiple_binding_options[t].filter(fun(p: *tree): bool return equality(binding_types[t]->get_bound_to(binding_epoch::pre_ref()), - get_type(p, binding_epoch::pre_ref())->get_bound_to(binding_epoch::pre_ref()), true, binding_epoch::pre_ref());) - if (filtered_options.size == 0) { - println("Attempting to use our inferenced type " + to_string(binding_types[t]->get_bound_to(binding_epoch::pre_ref())) + " to decide what to bind " + to_string(t->data) + " to from options:") - multiple_binding_options[t].for_each(fun(p: *tree) { println("\t" + to_string(p->data) + " of type " + to_string(get_type(p, binding_epoch::pre_ref())->get_bound_to(binding_epoch::pre_ref()))); }) - error("no options remain after filtering overloads by type for " + to_string(t->data)) - } else if (filtered_options.size > 1) { - println("inferenced type " + to_string(binding_types[t]->get_bound_to(binding_epoch::pre_ref())) + " HAD MULTIPLE OPTIONS AFTER FILTER for " + to_string(t) + ", that is "+ to_string(t->data)) - more_to_do = true - } else { - set_ast_binding(t, filtered_options[0], binding_epoch::pre_ref()) - unify(binding_types[t], get_type(filtered_options[0], binding_epoch::pre_ref()), binding_epoch::pre_ref()) - work_done = true - println("wok done! set " + to_string(t->data)) - } - } - } - } - } - for (var i = children_start_index; i < t->children.size; i++;) { - if !traverse_for_select(t->children[i]) { - return false - } - } - return true - } - // early bail if we need more passes - if !traverse_for_select(item) { - println("bailing early b/c select") - return - } - if (!work_done) { - var traverse_for_error: fun(*tree): void = fun(t: *tree) { - match (t->data) { - ast::_binding(b) if (!ast_bound(t)) { - println("Trying to error out because we made no progress") - var filtered_options = multiple_binding_options[t].filter(fun(p: *tree): bool return equality(binding_types[t]->get_bound_to(binding_epoch::pre_ref()), get_type(p, binding_epoch::pre_ref())->get_bound_to(binding_epoch::pre_ref()), true, binding_epoch::pre_ref());) - if (filtered_options.size > 1) { - println("Attempting to use our inferenced type " + to_string(binding_types[t]->get_bound_to(binding_epoch::pre_ref())) + " to decide what to bind " + to_string(t->data) + " to form options:") - multiple_binding_options[t].for_each(fun(p: *tree) { println("\t" + to_string(p->data) + " of type " + to_string(get_type(p, binding_epoch::pre_ref())->get_bound_to(binding_epoch::pre_ref()))); }) - println("current state of this:") - print_tree(item, 1) - println("too many options remain after filtering overloads by type for " + to_string(t->data) + ", they were:") - filtered_options.for_each(fun(p: *tree) { println("\t" + to_string(p->data) + " of type " + to_string(get_type(p, binding_epoch::pre_ref())->get_bound_to(binding_epoch::pre_ref()))); }) - error("cannot resolve") - } - } - } - t->children.for_each(traverse_for_error) - } - traverse_for_error(item) - } - } - println("tree after pass (might have added a dependency though)") - print_tree(item, 1) - } - - - - passes[str("ref_lower")] = fun(item: *tree) { - println("Running ref_lower") - if !pass_poset.done(make_pair(item, str("name_type_resolve"))) { - pass_poset.add_open_dep(make_pair(item, str("ref_lower")), make_pair(item, str("name_type_resolve"))) - return - } - /*var parameter_update_map = map<*tree, *tree>()*/ - var parameter_update_set = set<*tree>() - var traverse_for_ref: fun(*tree): void = fun(t: *tree) { - match (t->data) { - ast::_function(name_type_ext) { - var fun_type = get_type(t, binding_epoch::pre_ref()) - var need_fun_type_replacement = false - println("very before, function is " + to_string(t->data)) - for (var i = 0; i < fun_type->get_bound_to(binding_epoch::pre_ref())->_fun.first.first.size; i++;) { - if fun_type->get_bound_to(binding_epoch::pre_ref())->_fun.first.first[i].first == ref_type::_ref() { - var old_param = t->children[i] - /*get_type(old_param, binding_epoch::post_ref())->set(type::_ptr(binding(get_type(old_param, binding_epoch::post_ref())->get_bound_to(binding_epoch::pre_ref()), binding_epoch::post_ref())), binding_epoch::post_ref())*/ - /*get_type(old_param, binding_epoch::post_ref())->set(type::_ptr(binding(get_type(old_param, binding_epoch::pre_ref())->get_bound_to(binding_epoch::pre_ref()), binding_epoch::post_ref())), binding_epoch::post_ref())*/ - /*get_type(old_param, binding_epoch::post_ref())->set(type::_ptr(binding(get_type(old_param, binding_epoch::post_ref())->get_bound_to(binding_epoch::post_ref()), binding_epoch::post_ref())), binding_epoch::post_ref())*/ - var old_type = get_type(old_param, binding_epoch::post_ref()) - var new_type = type::_ptr(binding(get_type(old_param, binding_epoch::post_ref())->get_bound_to(binding_epoch::post_ref()), binding_epoch::all())) - println("for a param " + to_string(old_param->data) + " setting old_type " + binding_deref_to_string(old_type) + " to " + to_string(&new_type)) - /*old_type->set(new_type, binding_epoch::post_ref())*/ - old_type->set_single(new_type, binding_epoch::post_ref()) - parameter_update_set.add(old_param) - /*println("ok, all together now, old_param is " + to_string(old_param->data))*/ - /*println("note now the type: " + binding_deref_to_string(get_type(old_param, binding_epoch::post_ref())))*/ - /*println("note now the type: " + to_string(get_type(old_param, binding_epoch::post_ref())))*/ - need_fun_type_replacement = true - } - } - /*println("after params, function is " + to_string(t->data))*/ - /*if fun_type->get_bound_to(binding_epoch::pre_ref())->_fun.first.second.first == ref_type::_ref() {*/ - /*fun_type->get_bound_to(binding_epoch::pre_ref())->_fun.first.second.second->set(*/ - /*type::_ptr(binding(fun_type->get_bound_to(binding_epoch::pre_ref())->_fun.first.second.second->get_bound_to(binding_epoch::pre_ref()), binding_epoch::post_ref())),*/ - /*binding_epoch::post_ref())*/ - /*need_fun_type_replacement = true*/ - /*}*/ - println("about to after return") - println("after return, function is " + to_string(t->data)) - if need_fun_type_replacement { - println("before, function is " + to_string(t->data)) - var new_fun_type = type::_fun(fun_type->get_bound_to(binding_epoch::pre_ref())->_fun) - for (var i = 0; i < new_fun_type._fun.first.first.size; i++;) - new_fun_type._fun.first.first[i].first = ref_type::_notref() - new_fun_type._fun.first.second.first = ref_type::_notref() - get_type(t, binding_epoch::post_ref())->set(new_fun_type, binding_epoch::post_ref()) - println("finally, function is " + to_string(t->data)) - } - } - ast::_call(add_scope) { - t->children.for_each(traverse_for_ref) - println("traverse_for_ref call - " + to_string(t->data)) - // we call get type to make sure if it is unknown it is transformed into a function version - var fun_type = get_type(t->children[0], binding_epoch::pre_ref())->get_bound_to(binding_epoch::pre_ref()) - println("\t checking " + to_string(t->children[0]->data) + " for reffed params: " + to_string(fun_type)) - for (var i = 1; i < t->children.size; i++;) { - if fun_type->_fun.first.first[i-1].first == ref_type::_ref() { - println(str("\t\tparam ") + i + " is reffed") - var addr_of_binding = make_ast_binding("op&") - set_single_ast_binding(addr_of_binding, primitive_ops[str("op&")].last(), binding_epoch::post_ref()) - unify(get_type(addr_of_binding, binding_epoch::post_ref())->get_bound_to(binding_epoch::post_ref())->_fun.first.first[0].second, get_type(t->children[i], binding_epoch::post_ref()), binding_epoch::post_ref()) - t->set_child(i, _call(false, vec(addr_of_binding, t->children[i]))) - } - } - if fun_type->_fun.first.second.first == ref_type::_ref() { - println("call's return is reffed!") - var addr_of_binding = make_ast_binding("op*") - set_single_ast_binding(addr_of_binding, primitive_ops[str("op*")].last(), binding_epoch::post_ref()) - /*unify(get_type(addr_of_binding, binding_epoch::pre_ref())->get_bound_to(binding_epoch::pre_ref())->_fun.first.first[0].second, binding_p(type::_ptr(fun_type->_fun.first.second.second), binding_epoch::pre_ref()), binding_epoch::pre_ref())*/ - - - // one intentional pre_ref - we don't know that the function's already had the transformation happen - unify(get_type(addr_of_binding, binding_epoch::post_ref())->get_bound_to(binding_epoch::post_ref())->_fun.first.first[0].second, - binding_p(type::_ptr(binding(fun_type->_fun.first.second.second->get_bound_to(binding_epoch::pre_ref()), binding_epoch::post_ref())), binding_epoch::post_ref()), - binding_epoch::post_ref()) - // BUG IN kraken compiler, or weird part of kraken itself - evaluation order isn't guarenteed, so evaling a param could change lhs - /*t->parent->replace_child(t, _call(false, vec(addr_of_binding, t)))*/ - var parent = t->parent - parent->replace_child(t, _call(false, vec(addr_of_binding, t))) - } - return; - } - ast::_binding(b) { - var bound_to = get_ast_binding(t, binding_epoch::pre_ref()) - if parameter_update_set.contains(bound_to) { - println("param binding is reffed") - println("bound to is " + to_string(bound_to->data)) - println("other bound to is " + to_string(get_ast_binding(t, binding_epoch::post_ref())->data)) - var addr_of_binding = make_ast_binding("op*") - set_single_ast_binding(addr_of_binding, primitive_ops[str("op*")].last(), binding_epoch::post_ref()) - unify( - get_type(addr_of_binding, binding_epoch::post_ref())->get_bound_to(binding_epoch::post_ref())->_fun.first.first[0].second, - get_type(bound_to, binding_epoch::post_ref()), - binding_epoch::post_ref()) - println("param binding is reffed - parent tree is ") - var t_parent = t->parent; - /*t->parent->replace_child(t, _call(false, vec(addr_of_binding, t)))*/ - t_parent->replace_child(t, _call(false, vec(addr_of_binding, t))) - } - } - ast::_return() { - t->children.for_each(traverse_for_ref) - if (t->children.size > 0) { - var ret_is_ref = get_type(get_ancestor_satisfying(t, fun(t: *tree): bool return is_function(t);), binding_epoch::pre_ref())->get_bound_to(binding_epoch::pre_ref())->_fun.first.second.first == ref_type::_ref() - if ret_is_ref { - println("return is reffed") - println("tree is") - print_tree(t, 1) - var addr_of_binding = make_ast_binding("op&") - set_single_ast_binding(addr_of_binding, primitive_ops[str("op&")].last(), binding_epoch::post_ref()) - unify(get_type(addr_of_binding, binding_epoch::post_ref())->get_bound_to(binding_epoch::post_ref())->_fun.first.first[0].second, get_type(t->children[0], binding_epoch::post_ref()), binding_epoch::post_ref()) - t->set_child(0, _call(false, vec(addr_of_binding, t->children[0]))) - } - } - return; - } - } - t->children.for_each(traverse_for_ref) - } - traverse_for_ref(item) - - println("post ref_lower") - print_tree(item, 1) - } - - // has to be set instead of map<> as we need to use type's "equality" - // function instead of type's adt's operator== - var instantiated_map = map<*tree, set, *tree>>>() - passes[str("depend_and_template_resolve")] = fun(item: *tree) { - if !pass_poset.done(make_pair(item, str("ref_lower"))) { - pass_poset.add_open_dep(make_pair(item, str("depend_and_template_resolve")), make_pair(item, str("ref_lower"))) - return - } - - println("what we've got at template resolve time") - print_tree(item, 1) - - var resolve: fun(*tree): void = fun(t: *tree) { - var resolve_type: fun(*binding): void = fun(t: *binding) { - match (*t->get_bound_to(binding_epoch::pre_ref())) { - /*type::_unknown() error("unknown in resolve_type")*/ - type::_unknown() { /* this can happen because we use templates for builtins that we insert in later passes */ } - type::_template_placeholder() error("template_placeholder in resolve_type") - type::_ptr(p) resolve_type(p) - type::_obj(o) { - resolve(o) - pass_poset.add_close_dep(make_pair(item, str("emit_C")), make_pair(get_ast_binding(o, binding_epoch::pre_ref()), str("emit_C"))) - } - type::_fun(t) { - t.first.first.for_each(fun(p: pair>): void { resolve_type(p.second); }) - resolve_type(t.first.second.second) - } - } - } - match (t->data) { - ast::_binding(b) { - var bound_to = get_ast_binding(t, binding_epoch::post_ref()) - if (is_top_level_item(bound_to)) { - if (is_template(bound_to)) { - if (!instantiated_map.contains_key(bound_to)) { - instantiated_map[bound_to] = set, *tree>>() - } - - // grab inst types out of binding, or regen again from unify? Cache from first unify? - var inst_map = map<*binding, *binding>() - if (b.second.size > 0) { - for (var i = 0; i < b.second.size; i++;) { - inst_map[bound_to->data._template.second.values[i]] = b.second[i] - } - } else { - // regenning from unify - inst_map = bound_to->data._template.second.associate(fun(k: str, v: *binding): pair<*binding, *binding> - return make_pair(v, binding_p(type::_unknown(), binding_epoch::pre_ref()));) - } - - // but not in the case where this is a templated type instead of a function - that doesn't make any sense - var binding_type = null>() - if is_function(bound_to->children[0]) || is_compiler_intrinsic(bound_to->children[0]) { - // unify in both cases - we need it in the explicit case to make sure our explicit types propegate back - /*binding_type = get_type(t, binding_epoch::pre_ref())*/ - /*unify(binding_type, inst_temp_type(get_type(bound_to->children[0], binding_epoch::pre_ref()), inst_map, binding_epoch::pre_ref()), binding_epoch::pre_ref())*/ - binding_type = get_type(t, binding_epoch::post_ref()) - unify(binding_type, inst_temp_type(get_type(bound_to->children[0], binding_epoch::post_ref()), inst_map, binding_epoch::post_ref(), binding_epoch::pre_ref()), binding_epoch::post_ref()) - } else { - binding_type = binding_p(type::_obj(t), binding_epoch::pre_ref()) - } - - // shouldn't cache by binding, but by all insted - println("checking for prior instantiations of " + to_string(bound_to->data)) - /*var already_inst = instantiated_map[bound_to].filter(fun(p: pair<*binding, *tree>): bool return equality(binding_type->get_bound_to(binding_epoch::pre_ref()), p.first->get_bound_to(binding_epoch::pre_ref()), false, binding_epoch::pre_ref());)*/ - var already_inst = instantiated_map[bound_to].filter(fun(p: pair<*binding, *tree>): bool return equality(binding_type->get_bound_to(binding_epoch::post_ref()), p.first->get_bound_to(binding_epoch::post_ref()), false, binding_epoch::post_ref());) - if (already_inst.size() > 1) { - error("already inst > 1, should be impossible") - } else if (already_inst.size() == 1) { - println("alreay instantiated template, using (made from):") - print_tree(bound_to->children[0], 1) - println("cached to:") - print_tree(already_inst.single().second, 1) - pass_poset.add_close_dep(make_pair(item, str("emit_C")), make_pair(already_inst.single().second, str("emit_C"))) - /*set_single_ast_binding(t, already_inst.single().second, binding_epoch::pre_ref())*/ - set_single_ast_binding(t, already_inst.single().second, binding_epoch::all()) - } else { - println("Copying tree to instantiate template!" + to_string(bound_to->data)) - println("using inst map:") - inst_map.for_each(fun(k: *binding, v: *binding) { - /*println("\t" + to_string(k->get_bound_to(binding_epoch::pre_ref())) + " -> " + to_string(v->get_bound_to(binding_epoch::pre_ref())))*/ - println("\t" + to_string(k->get_bound_to(binding_epoch::post_ref())) + " -> " + to_string(v->get_bound_to(binding_epoch::post_ref()))) - }) - var inst_copy = bound_to->children[0]->clone(fun(a: ref ast): ast { - match (a) { - /*ast::_identifier(b) return ast::_identifier(make_pair(b.first, inst_temp_type(b.second, inst_map, binding_epoch::pre_ref())))*/ - ast::_identifier(b) return ast::_identifier(make_pair(b.first, inst_temp_type(b.second, inst_map, binding_epoch::post_ref(), binding_epoch::pre_ref()))) - ast::_binding(b) return ast::_binding(make_triple(b.first, - /*b.second.map(fun(bd: *binding): *binding return inst_temp_type(bd, inst_map, binding_epoch::pre_ref());),*/ - b.second.map(fun(bd: *binding): *binding return inst_temp_type(bd, inst_map, binding_epoch::post_ref(), binding_epoch::pre_ref());), - binding>())) - /*ast::_function(b) return ast::_function(make_triple(b.first, inst_temp_type(b.second, inst_map, binding_epoch::pre_ref()), b.third))*/ - ast::_function(b) return ast::_function(make_triple(b.first, inst_temp_type(b.second, inst_map, binding_epoch::post_ref(), binding_epoch::pre_ref()), b.third)) - ast::_compiler_intrinsic(b) return ast::_compiler_intrinsic(make_triple( - b.first, - /*inst_temp_type(b.second, inst_map, binding_epoch::pre_ref()),*/ - inst_temp_type(b.second, inst_map, binding_epoch::post_ref(), binding_epoch::pre_ref()), - /*b.third.map(fun(bd: *binding): *binding return inst_temp_type(bd, inst_map, binding_epoch::pre_ref());)))*/ - b.third.map(fun(bd: *binding): *binding return inst_temp_type(bd, inst_map, binding_epoch::post_ref(), binding_epoch::pre_ref());))) - /*ast::_cast(b) return ast::ast::_cast(inst_temp_type(b, inst_map, binding_epoch::pre_ref()))*/ - ast::_cast(b) return ast::ast::_cast(inst_temp_type(b, inst_map, binding_epoch::post_ref(), binding_epoch::pre_ref())) - /*ast::_value(b) return ast::_value(make_pair(b.first, inst_temp_type(b.second, inst_map, binding_epoch::pre_ref())))*/ - ast::_value(b) return ast::_value(make_pair(b.first, inst_temp_type(b.second, inst_map, binding_epoch::post_ref(), binding_epoch::pre_ref()))) - /*_template: pair>>,*/ - } - return a - }) - // add inst copy as a child of template? - bound_to->add_child(inst_copy) - - println("inst from:") - print_tree(bound_to->children[0], 1) - println("inst to:") - print_tree(inst_copy, 1) - - // save it in our insted map so we don't instantate more than once per types - if is_function(bound_to->children[0]) || is_compiler_intrinsic(bound_to->children[0]) { - /*var binding_type2 = get_type(clone_ast_binding(t), binding_epoch::pre_ref())*/ - var binding_type2 = get_type(clone_ast_binding(t), binding_epoch::post_ref()) - /*unify(binding_type2, inst_temp_type(get_type(bound_to->children[0], binding_epoch::pre_ref()), inst_map, binding_epoch::pre_ref()), binding_epoch::pre_ref())*/ - unify(binding_type2, inst_temp_type(get_type(bound_to->children[0], binding_epoch::post_ref()), inst_map, binding_epoch::post_ref(), binding_epoch::pre_ref()), binding_epoch::post_ref()) - instantiated_map[bound_to].add(make_pair(binding_type2, inst_copy)) - } else { - /*instantiated_map[bound_to].add(make_pair(binding_p(type::_obj(clone_ast_binding(t)), binding_epoch::pre_ref()), inst_copy))*/ - instantiated_map[bound_to].add(make_pair(binding_p(type::_obj(clone_ast_binding(t)), binding_epoch::post_ref()), inst_copy)) - } - pass_poset.add_close_dep(make_pair(item, str("emit_C")), make_pair(inst_copy, str("emit_C"))) - /*set_single_ast_binding(t, inst_copy, binding_epoch::pre_ref())*/ - set_single_ast_binding(t, inst_copy, binding_epoch::all()) - } - } else { - pass_poset.add_close_dep(make_pair(item, str("emit_C")), make_pair(bound_to, str("emit_C"))) - } - // top level var dec - } else if (is_identifier(bound_to) && is_declaration(bound_to->parent) && is_top_level_item(bound_to->parent)) { - pass_poset.add_close_dep(make_pair(item, str("emit_C")), make_pair(bound_to->parent, str("emit_C"))) - } - // bound_to might have changed from binding - } - /*ast::_identifier(p) resolve_type(get_type(t, binding_epoch::pre_ref()))*/ - ast::_identifier(p) resolve_type(get_type(t, binding_epoch::post_ref())) - /*ast::_function(p) resolve_type(get_type(t, binding_epoch::pre_ref()))*/ - ast::_function(p) resolve_type(get_type(t, binding_epoch::post_ref())) - ast::_compiler_intrinsic(p) { - resolve_type(p.second) - p.third.for_each(resolve_type) - } - ast::_cast(p) resolve_type(p) - } - - - t->children.for_each(resolve) - } - resolve(item) - - println("post depend_and_template_resolve") - print_tree(item, 1) - } - - passes[str("defer_lower")] = fun(item: *tree) { - if !pass_poset.done(make_pair(item, str("depend_and_template_resolve"))) { - pass_poset.add_open_dep(make_pair(item, str("defer_lower")), make_pair(item, str("depend_and_template_resolve"))) - return - } - var defer_triple_stack = stack>>>() - var loop_stack = stack(-1) - var traverse_for_defer: fun(*tree): void = fun(t: *tree) { - match (t->data) { - ast::_defer() { - if (is_block(t->parent)) { - t->parent->remove_child(t) - defer_triple_stack.top().top().push(t->children[0]) - } else { - t->parent->replace_child(t, t->children[0]) - } - traverse_for_defer(t->children[0]) - return; - } - ast::_function(name_type_ext) { - defer_triple_stack.push(stack>>()) - t->children.clone().for_each(traverse_for_defer) - defer_triple_stack.pop() - return; - } - ast::_block() { - defer_triple_stack.top().push(stack<*tree>()) - t->children.clone().for_each(traverse_for_defer) - t->children.add_all(defer_triple_stack.top().pop().reverse_vector()) - return; - } - ast::_for() { - loop_stack.push(defer_triple_stack.top().size()) - t->children.clone().for_each(traverse_for_defer) - loop_stack.pop() - return; - } - ast::_while() { - loop_stack.push(defer_triple_stack.top().size()) - t->children.clone().for_each(traverse_for_defer) - loop_stack.pop() - return; - } - ast::_return() { - t->children.clone().for_each(traverse_for_defer) - var our_idx = t->parent->children.find(t) - for (var i = 0; i < defer_triple_stack.top().size(); i++;) { - defer_triple_stack.top().from_top(i).reverse_vector().for_each(fun(c: *tree) { - t->parent->children.add(our_idx, c) - }) - } - return; - } - ast::_break() { - var block = _block() - t->parent->replace_child(t, block) - for (var i = 0; i < defer_triple_stack.top().size() - loop_stack.top(); i++;) - block->add_children(defer_triple_stack.top().from_top(i).reverse_vector()) - block->add_child(t) - return; - } - ast::_continue() { - return; - } - } - t->children.clone().for_each(traverse_for_defer) - } - traverse_for_defer(item) - - println("post defer_lower") - print_tree(item, 1) - } - - var taken_names = map<*tree, str>() - var id = 0 - - var replacement_map.construct() : map - replacement_map[str("+")] = str("plus") - replacement_map[str("-")] = str("minus") - replacement_map[str("*")] = str("star") - replacement_map[str("/")] = str("div") - replacement_map[str("%")] = str("mod") - replacement_map[str("^")] = str("carat") - replacement_map[str("&")] = str("amprsd") - replacement_map[str("|")] = str("pipe") - replacement_map[str("~")] = str("tilde") - replacement_map[str("!")] = str("exlmtnpt") - replacement_map[str(",")] = str("comma") - replacement_map[str("=")] = str("eq") - replacement_map[str("++")] = str("dbplus") - replacement_map[str("--")] = str("dbminus") - replacement_map[str("<<")] = str("dbleft") - replacement_map[str(">>")] = str("dbright") - replacement_map[str("::")] = str("scopeop") - replacement_map[str(":")] = str("colon") - replacement_map[str("==")] = str("dbq") - replacement_map[str("!=")] = str("notequals") - replacement_map[str("&&")] = str("doubleamprsnd") - replacement_map[str("||")] = str("doublepipe") - replacement_map[str("+=")] = str("plusequals") - replacement_map[str("-=")] = str("minusequals") - replacement_map[str("/=")] = str("divequals") - replacement_map[str("%=")] = str("modequals") - replacement_map[str("^=")] = str("caratequals") - replacement_map[str("&=")] = str("amprsdequals") - replacement_map[str("|=")] = str("pipeequals") - replacement_map[str("*=")] = str("starequals") - replacement_map[str("<<=")] = str("doublerightequals") - replacement_map[str("<")] = str("lt") - replacement_map[str(">")] = str("gt") - replacement_map[str(">>=")] = str("doubleleftequals") - replacement_map[str("(")] = str("openparen") - replacement_map[str(")")] = str("closeparen") - replacement_map[str("[")] = str("obk") - replacement_map[str("]")] = str("cbk") - replacement_map[str(" ")] = str("_") - replacement_map[str(".")] = str("dot") - replacement_map[str("->")] = str("arrow") - - var longest_replacement = 0 - replacement_map.for_each(fun(key: str, value: str) { - if (key.length() > longest_replacement) - longest_replacement = key.length() - }) - var cify_name = fun(name: ref str): str { - var to_ret = str() - for (var i = 0; i < name.length(); i++;) { - var replaced = false - for (var j = longest_replacement; j > 0; j--;) { - if (i + j <= name.length() && replacement_map.contains_key(name.slice(i,i+j))) { - to_ret += replacement_map[name.slice(i,i+j)] - replaced = true - i += j-1; - break - } - } - if (!replaced) - to_ret += name[i] - } - return to_ret - } - var get_c_name = fun(x: *tree): str { - if (taken_names.contains_key(x)) - return taken_names[x] - var possible = str() - match(x->data) { - /*ast::_identifier(b) { possible = b.first; }*/ - ast::_identifier(b) { return b.first; } - ast::_type_def(b) { possible = b; } - ast::_function(b) { possible = b.first; } - } - if (possible == "") - error("cannot get_c_name of thing: " + to_string(x->data)) - if (taken_names.contains_value(possible)) { - possible += id++ - } - taken_names[x] = cify_name(possible) - return taken_names[x] - } - - var to_c_type: fun(*binding): str = fun(tb: *binding): str { - match(*tb->get_bound_to(binding_epoch::post_ref())) { - type::_unknown() error("unknown in to_c_type") - /*type::_unknown() return str("unknown")*/ - type::_ptr(p) return to_c_type(p) + "*" - type::_void() return str("void") - type::_obj(b) return get_c_name(get_ast_binding(b, binding_epoch::post_ref())) - type::_fun(b) error("fun in to_c_type unimplemented") - type::_template_placeholder() error("template_placeholder in to_c_type") - type::_bool() return str("bool") - type::_char() return str("char") - type::_uchar() return str("usigned char") - type::_short() return str("short") - type::_ushort() return str("unsigned short") - type::_int() return str("int") - type::_uint() return str("unsigned int") - type::_long() return str("long") - type::_ulong() return str("unsigned long") - type::_float() return str("float") - type::_double() return str("double") - } - error("fell through to_c_type") - } - // emit C - var C_str = str() - var C_type_forward_declaration_str = str() - var C_type_declaration_str_map = map<*tree, str>() - var C_type_declaration_poset = poset<*tree>() - var C_declaration_str = str() - - passes[str("emit_C")] = fun(item: *tree) { - if !pass_poset.done(make_pair(item, str("defer_lower"))) { - pass_poset.add_open_dep(make_pair(item, str("emit_C")), make_pair(item, str("defer_lower"))) - return - } - println("Emitting C for:") - print_tree(item, 1) - - var emit_C: fun(*tree, int): void = fun(t: *tree, level: int) { - var idt = str("\t") * level - match (t->data) { - ast::_translation_unit(b) { - t->children.for_each(fun(c: *tree) { - emit_C(c, 0) - C_str += ";\n" - }) - } - ast::_import(b) { } - ast::_identifier(b) { C_str += idt + get_c_name(t); } - ast::_binding(b) { - C_str += idt + get_c_name(get_ast_binding(t, binding_epoch::post_ref())) - } - ast::_type_def(b) { - C_type_forward_declaration_str += "typedef struct " + get_c_name(t) + " " + get_c_name(t) + ";\n" - C_type_declaration_str_map[t] = "struct " + get_c_name(t) + "{\n" - C_type_declaration_poset.add_job(t) - t->children.for_each(fun(c: *tree) { - C_type_declaration_str_map[t] += "\t" + to_c_type(c->children[0]->data._identifier.second) + " " + get_c_name(c->children[0]) + ";\n" - if is_obj(c->children[0]->data._identifier.second->get_bound_to(binding_epoch::post_ref())) { - C_type_declaration_poset.add_open_dep(t, get_ast_binding(c->children[0]->data._identifier.second->get_bound_to(binding_epoch::post_ref())->_obj, binding_epoch::post_ref())) - } - }) - C_type_declaration_str_map[t] += "};\n" - } - ast::_adt_def(b) { error("no adt_def should remain at C emit"); } - ast::_function(b) { - /*var fun_name = b.first*/ - var fun_name = get_c_name(t) - var fun_type = b.second->get_bound_to(binding_epoch::post_ref()) - var is_ext = b.third - var return_type = fun_type->_fun.first.second - var parameter_types = fun_type->_fun.first.first - var is_variadic = fun_type->_fun.second - var is_raw = fun_type->_fun.third - var is_just_dec = parameter_types.size == t->children.size - // TODO check is_ext for name mangling - // TODO ideally, we wouldn't worry about refs here, but until we have - // per pass trees / bindings and stuff, we can't change the functions - // type to remove ref and add ptr (though we do change the parameters type, - // as that all happens inside the function) - var beginning_str = to_c_type(return_type.second) - /*if (return_type.first == ref_type::_ref())*/ - /*beginning_str += "*"*/ - beginning_str += " " + fun_name + "(" - if (!is_just_dec) - C_str += beginning_str - C_declaration_str += beginning_str - for (var i = 0; i < parameter_types.size; i++;) { - if (i != 0) { - if (!is_just_dec) - C_str += ", " - C_declaration_str += ", " - } - // TODO ditto about ref stuff above - var parameter_type_str = to_c_type(parameter_types[i].second) - /*if (parameter_types[i].first == ref_type::_ref())*/ - /*parameter_type_str += "*"*/ - if (!is_just_dec) - C_str += parameter_type_str + " " - C_declaration_str += parameter_type_str - if (!is_just_dec) - emit_C(t->children[i], 0) - } - if (is_variadic) { - if (parameter_types.size != 0) { - if (!is_just_dec) - C_str += ", " - C_declaration_str += ", " - } - if (!is_just_dec) - C_str += "..." - C_declaration_str += "..." - } - if (!is_just_dec) - C_str += ") {\n" - C_declaration_str += ");\n" - if !is_just_dec { - for (var i = parameter_types.size; i < t->children.size; i++;) { - emit_C(t->children[i], level+1) - C_str += ";\n" - } - C_str += "}\n" - } - } - ast::_template(b) { /* template should be ignored */ } - ast::_declaration() { - C_str += idt + to_c_type(t->children[0]->data._identifier.second) + " " + get_c_name(t->children[0]) - if (t->children.size > 1) { - C_str += " = " - emit_C(t->children[1], 0) - } - if (is_top_level_item(t)) { - C_str += ";\n" - C_declaration_str += idt + to_c_type(t->children[0]->data._identifier.second) + " " + get_c_name(t->children[0]) + ";\n" - } - } - ast::_block() { - C_str += idt + "{\n" - t->children.for_each(fun(c: *tree) { - emit_C(c, level+1) - C_str += ";\n" - }) - C_str += idt + "}" - } - ast::_if() { - C_str += idt + "if (" - emit_C(t->children[0], 0) - C_str += ") {\n" - emit_C(t->children[1], level + 1) - C_str += ";\n" + idt + "}" - if t->children.size > 2 { - C_str += " else {\n" - emit_C(t->children[2], level + 1) - C_str += ";\n" + idt + "}" - } - } - ast::_match() { error("no match should remain at C emit"); } - ast::_case() { error("no case should remain at C emit"); } - ast::_while() { - C_str += idt + "while (" - emit_C(t->children[0], 0) - C_str += ") {\n" - emit_C(t->children[1], level + 1) - C_str += ";\n" + idt + "}" - } - ast::_for() { - C_str += idt + "for (" - emit_C(t->children[0], 0) - C_str += ";" - emit_C(t->children[1], 0) - C_str += ";" - emit_C(t->children[2], 0) - C_str += ") {\n" - emit_C(t->children[3], level+1) - C_str += ";\n" + idt + "}" - } - ast::_return() { - C_str += idt + "return" - if (t->children.size == 1) { - C_str += " " - emit_C(t->children[0], 0) - } - } - ast::_break() { C_str += idt + "break"; } - ast::_continue() { C_str += idt + "continue"; } - ast::_defer() { error("no defer should remain at C emit"); } - ast::_call(add_scope) { - if (is_compiler_intrinsic(get_ast_binding(t->children[0], binding_epoch::post_ref()))) { - if (t->children.size == 2) { - var intrinsic_name = get_ast_binding(t->children[0], binding_epoch::post_ref())->data._compiler_intrinsic.first - if (intrinsic_name == "&" || intrinsic_name == "*") { - C_str += idt + "(" + intrinsic_name + "(" - emit_C(t->children[1], 0) - C_str += "))" - } else { - C_str += idt + "(" - emit_C(t->children[1], 0) - C_str += ")." + intrinsic_name - } - } else if (t->children.size == 3) { - C_str += idt + "((" - emit_C(t->children[1], 0) - C_str += ")" + get_ast_binding(t->children[0], binding_epoch::post_ref())->data._compiler_intrinsic.first + "(" - emit_C(t->children[2], 0) - C_str += "))" - } else error("Calling primitive intrinsic with not 1 or 2 arguments") - } else { - emit_C(t->children[0], level) - C_str += "(" - for (var i = 1; i < t->children.size; i++;) { - if (i != 1) - C_str += ", " - emit_C(t->children[i], 0) - } - C_str += ")" - } - } - ast::_compiler_intrinsic(b) { - if b.first == "sizeof" { - C_str += "sizeof(" + to_c_type(b.third[0]) + ")" - } else { - /* this can happen cuz of templated primitive ops and is_top_level_item includes parentless stuff...*/ - } - } - ast::_cast(b) { - C_str += idt + "((" + to_c_type(b) + ")" - emit_C(t->children[0], 0) - C_str += ")" - } - ast::_value(b) { - if is_ptr(b.second->get_bound_to(binding_epoch::post_ref())) && is_char(b.second->get_bound_to(binding_epoch::post_ref())->_ptr->get_bound_to(binding_epoch::post_ref())) { - C_str += "\"" - b.first.for_each(fun(c: char) { - if (c == '\n') - C_str += "\\n" - else if (c == '\\') - C_str += "\\\\" - else if (c == '"') - C_str += "\\\"" - else - C_str += c - }) - C_str += "\"" - } else { - C_str += idt + b.first; - } - } - } - } - - emit_C(item, 0) - } - - // We construct our real main entry function and add an emit_C pass for it, - // starting generation of the entire program - var real_main = _function( - str("main"), - binding_p(type::_fun(make_triple(make_pair(vec( - make_pair(ref_type::_notref(), binding_p(type::_int(), binding_epoch::pre_ref())), - make_pair(ref_type::_notref(), binding_p(type::_ptr(binding_p(type::_ptr(binding_p(type::_char(), binding_epoch::pre_ref())), binding_epoch::pre_ref())), binding_epoch::pre_ref())) - ), - make_pair(ref_type::_notref(), binding_p(type::_int(), binding_epoch::pre_ref())) - ), false, false)), binding_epoch::pre_ref()), - true, vec( - _identifier(str("argc"), binding_p(type::_int(), binding_epoch::pre_ref())), - _identifier(str("argv"), binding_p(type::_ptr(binding_p(type::_ptr(binding_p(type::_char(), binding_epoch::pre_ref())), binding_epoch::pre_ref())), binding_epoch::pre_ref())), - _return(vec(_call(false, vec(make_ast_binding("fmain"), make_ast_binding("argc"), make_ast_binding("argv"))))) - ) - ) - var top_unit = _translation_unit(str(), vec( - _import(make_ast_binding(kraken_file_name), set(str("*")), vec( - _identifier(kraken_file_name, binding_p(type::_void(), binding_epoch::pre_ref())) - )), - real_main - )) - pass_poset.add_job(make_pair(real_main, str("emit_C"))) - - pass_poset.run(fun(file_pass: pair<*tree, str>) { - printlnerr("doing pass new style " + file_pass.second + " on " + to_string(file_pass.first->data)) - passes[file_pass.second](file_pass.first) - }) - C_str = "#include \n" + C_type_forward_declaration_str + "\n" + - str("\n").join(C_type_declaration_poset.get_sorted().map(fun(type_dec: *tree):str { return C_type_declaration_str_map[type_dec]; })) + - "\n" + C_declaration_str + "\n" + C_str - - println() - println() - println("Finished with trees:") - name_ast_map.for_each(fun(key: str, value: *tree) { - printlnerr(key + ":") - print_tree(value, 1) - printlnerr("done") - }) - - var kraken_c_output_name = kraken_file_name + ".c" - println(C_str) - write_file(kraken_c_output_name, C_str) - - var c_flags = str("") - if (compile_c) { - var compile_string = "cc -g " + opt_str + " -Wno-int-to-pointer-cast -Wno-pointer-to-int-cast -Wno-incompatible-pointer-types -std=c99 " + c_flags + " " + kraken_c_output_name + " -o " + executable_name - printlnerr(compile_string) - system(compile_string) - } - - return 0 -} - -fun parse_type(syntax: *tree, declared_template_types: ref map>): *binding { - return parse_type_helper(get_node("pre_reffed", syntax), declared_template_types) -} - -fun parse_type_helper(syntax: *tree, declared_template_types: ref map>): *binding { - var next = get_node("pre_reffed", syntax) - if (next != null>()) - return binding_p(type::_ptr(parse_type_helper(next, declared_template_types)), binding_epoch::pre_ref()) - - var ident = get_node("scoped_identifier", syntax) - var func = get_node("function_type", syntax) - var first_child_name = syntax->children[0]->data.name - if (ident != null>()) { - var ident_str = concat(ident) - var template_inst = get_node("template_inst", syntax) - if (template_inst != null>()) { - var inst_with = get_nodes("type", template_inst).map(fun(s: *tree): *binding { return parse_type_helper(s, declared_template_types); }) - return binding_p(type::_obj(make_ast_binding(ident_str, inst_with)), binding_epoch::pre_ref()) - } else { - if (declared_template_types.contains_key(ident_str)) - return declared_template_types[ident_str] - else - return binding_p(type::_obj(make_ast_binding(ident_str)), binding_epoch::pre_ref()) - } - } else if (func != null>()) { - error("function type parsing not implemented") - var param_types = vec>>() - var return_type = make_pair(ref_type::_notref(), binding_p(type::_void(), binding_epoch::pre_ref())) - var variadic = false - var raw = false - return binding_p(type::_fun(make_triple(make_pair(param_types, return_type), variadic, raw)), binding_epoch::pre_ref()) - } else if (first_child_name == "\"void\"") { - return binding_p(type::_void(), binding_epoch::pre_ref()) - } else if (first_child_name == "\"bool\"") { - return binding_p(type::_bool(), binding_epoch::pre_ref()) - } else if (first_child_name == "\"char\"") { - return binding_p(type::_char(), binding_epoch::pre_ref()) - } else if (first_child_name == "\"uchar\"") { - return binding_p(type::_uchar(), binding_epoch::pre_ref()) - } else if (first_child_name == "\"short\"") { - return binding_p(type::_short(), binding_epoch::pre_ref()) - } else if (first_child_name == "\"ushort\"") { - return binding_p(type::_ushort(), binding_epoch::pre_ref()) - } else if (first_child_name == "\"int\"") { - return binding_p(type::_int(), binding_epoch::pre_ref()) - } else if (first_child_name == "\"uint\"") { - return binding_p(type::_uint(), binding_epoch::pre_ref()) - } else if (first_child_name == "\"long\"") { - return binding_p(type::_long(), binding_epoch::pre_ref()) - } else if (first_child_name == "\"ulong\"") { - return binding_p(type::_ulong(), binding_epoch::pre_ref()) - } else if (first_child_name == "\"float\"") { - return binding_p(type::_float(), binding_epoch::pre_ref()) - } else if (first_child_name == "\"double\"") { - return binding_p(type::_double(), binding_epoch::pre_ref()) - } - error(syntax, "could not parse type " + first_child_name) -} - -fun syntax_to_ast(file_name: str, syntax: *tree, import_paths: ref vec): *tree { - var resolve_import_file = fun(file_name: str): str { - var file_path = str() - for (var i = 0; i < import_paths.size; i++;) { - if (file_exists(import_paths[i] + file_name)) { - if (file_path != "") - error("File: " + file_name + ", found in multiple import paths - at least two of [" + str(",").join(import_paths) + "]") - file_path = import_paths[i] + file_name - } - } - if (file_path == "") - error("File: " + file_name + ", not found in any import path - none of [" + str(",").join(import_paths) + "]") - return file_path - } - - var syntax_to_ast_helper: fun(*tree, ref map>): *tree = fun(syntax: *tree, declared_template_types: ref map>): *tree { - if (syntax->data.name == "import") { - return _import(make_ast_binding(resolve_import_file(concat(syntax->children[1]) + ".krak")), from_vector(syntax->children.slice(2,-1).filter(fun(s:*tree):bool { - return s->data.name == "identifier" || s->data.data == "*" - }).map(concat)), vec(syntax_to_ast_helper(syntax->children[1], declared_template_types))) - } else if (syntax->data.name == "function") { - - var template = get_node("template_dec", syntax) - var new_template_type_map = map>() - var with_added_declared_template_types = declared_template_types - if (template != null>()) { - get_nodes("template_param", template).for_each(fun(p: *tree) { - var key = concat(p) - var value = binding_p(type::_template_placeholder(), binding_epoch::pre_ref()) - new_template_type_map[key] = value - with_added_declared_template_types[key] = value - }) - } - - var parameters = get_nodes("typed_parameter", syntax).map(fun(x: *tree): pair> { - if get_node("\"ref\"", get_node("type", x)) != null>() { - return make_pair(ref_type::_ref(), syntax_to_ast_helper(x, with_added_declared_template_types)) - } else { - return make_pair(ref_type::_notref(), syntax_to_ast_helper(x, with_added_declared_template_types)) - } - }) - var return_type = make_pair(ref_type::_unknown(), null>()) - var return_type_node = get_node("typed_return", syntax) - if return_type_node != null>() { - if get_node("\"ref\"", get_node("type", return_type_node)) != null>() { - return_type = make_pair(ref_type::_ref(), parse_type(get_node("type", return_type_node), with_added_declared_template_types)) - } else { - return_type = make_pair(ref_type::_notref(), parse_type(get_node("type", return_type_node), with_added_declared_template_types)) - } - } else { - return_type = make_pair(ref_type::_notref(), binding_p(type::_void(), binding_epoch::pre_ref())) - } - var function_type = binding_p(type::_fun(make_triple( - make_pair(parameters.map(fun(i: pair>): pair> return make_pair(i.first, i.second->data._identifier.second);), - return_type), - get_node("\"...\"", syntax) != null>(), - false /*get_node("\"run\"", syntax) != null>()*/)), binding_epoch::pre_ref()) - var body_syntax = get_node("statement", syntax) - var body = vec<*tree>() - if body_syntax != null>() { - body = vec(syntax_to_ast_helper(body_syntax, with_added_declared_template_types)) - } - var n = _function(concat(get_node("func_identifier", syntax)), - function_type, get_node("\"ext\"", syntax) != null>(), - parameters.map(fun(i: pair>): *tree return i.second;) + body) - if (new_template_type_map.size() > 0) { - return _template(n->data._function.first, new_template_type_map, vec(n)) - } else { - return n - } - } else if (syntax->data.name == "typed_parameter") - return _identifier(concat(get_node("identifier", syntax)), parse_type(get_node("type", syntax), declared_template_types)) - else if (syntax->data.name == "type_def") { - - var template = get_node("template_dec", syntax) - var new_template_type_map = map>() - var with_added_declared_template_types = declared_template_types - if (template != null>()) { - get_nodes("template_param", template).for_each(fun(p: *tree) { - var key = concat(p) - var value = binding_p(type::_template_placeholder(), binding_epoch::pre_ref()) - new_template_type_map[key] = value - with_added_declared_template_types[key] = value - }) - } - - var n = _type_def(concat(get_node("identifier", syntax)), - get_nodes("declaration_statement", syntax).map(fun(x: *tree): *tree return syntax_to_ast_helper(x, with_added_declared_template_types);)) - - if (new_template_type_map.size() > 0) { - return _template(n->data._type_def, new_template_type_map, vec(n)) - } else { - return n - } - } else if (syntax->data.name == "adt_def") { - - var template = get_node("template_dec", syntax) - var new_template_type_map = map>() - var with_added_declared_template_types = declared_template_types - if (template != null>()) { - get_nodes("template_param", template).for_each(fun(p: *tree) { - var key = concat(p) - var value = binding_p(type::_template_placeholder(), binding_epoch::pre_ref()) - new_template_type_map[key] = value - with_added_declared_template_types[key] = value - }) - } - - var n = _adt_def(concat(get_node("identifier", syntax)), - get_nodes("adt_option", syntax).map(fun(s: *tree): *tree { - var option_type = get_node("type", s) - if (option_type != null>()) - return _identifier(concat(get_node("identifier", s)), parse_type(option_type, with_added_declared_template_types)) - else - return _identifier(concat(get_node("identifier", s)), binding_p(type::_void(), binding_epoch::pre_ref())) - })) - if (new_template_type_map.size() > 0) { - return _template(n->data._adt_def, new_template_type_map, vec(n)) - } else { - return n - } - } else if (syntax->data.name == "statement") - return syntax_to_ast_helper(syntax->children[0], declared_template_types) - else if (syntax->data.name == "code_block") - return _block(syntax->children.map(fun(x: *tree): *tree return syntax_to_ast_helper(x, declared_template_types);)) - else if (syntax->data.name == "if_statement") - return _if(syntax->children.map(fun(x: *tree): *tree return syntax_to_ast_helper(x, declared_template_types);)) - else if (syntax->data.name == "for_loop") - return _for(syntax->children.map(fun(x: *tree): *tree return syntax_to_ast_helper(x, declared_template_types);)) - else if (syntax->data.name == "while_loop") - return _while(syntax->children.map(fun(x: *tree): *tree return syntax_to_ast_helper(x, declared_template_types);)) - else if (syntax->data.name == "return_statement") - return _return(syntax->children.map(fun(x: *tree): *tree return syntax_to_ast_helper(x, declared_template_types);)) - else if (syntax->data.name == "defer_statement") - return _defer(syntax->children.map(fun(x: *tree): *tree return syntax_to_ast_helper(x, declared_template_types);)) - else if (syntax->data.name == "break_statement") - return _break() - else if (syntax->data.name == "continue_statement") - return _continue() - else if (syntax->data.name == "match_statement") { - return _match(vec(syntax_to_ast_helper(get_node("boolean_expression", syntax), declared_template_types)) + - get_nodes("case_statement", syntax).map(fun(s: *tree): *tree { - return _case(s->children.map(fun(x: *tree): *tree return syntax_to_ast_helper(x, declared_template_types);)) - })) - } else if (syntax->data.name == "declaration_statement") { - var t = binding_p(type::_unknown(), binding_epoch::pre_ref()) - var type_syntax = get_node("type", syntax) - if type_syntax != null>() - t = parse_type(type_syntax, declared_template_types) - var children = vec(_identifier(concat(get_node("identifier", syntax)), t)) - children += get_nodes("boolean_expression", syntax).map(fun(x: *tree): *tree return syntax_to_ast_helper(x, declared_template_types);) - return _declaration(children) - } else if (syntax->data.name == "assignment_statement") { - return _call(false, vec(make_ast_binding("op" + concat(syntax->children[1])), - syntax_to_ast_helper(syntax->children[0], declared_template_types), - syntax_to_ast_helper(syntax->children[2], declared_template_types))) - } else if (syntax->data.name == "function_call") { - // if method, pull out - if syntax->children[0]->data.name == "unarad" && syntax->children[0]->children[0]->data.name == "access_operation" { - println("doing a method call!") - /*return _call(vec(syntax_to_ast_helper(syntax->children[0]->children[0]->children[2], declared_template_types)) + syntax_to_ast_helper(syntax->children[0]->children[0]->children[0], declared_template_types) + get_nodes("parameter", syntax).map(fun(s: *tree): *tree {*/ - return _call(true, vec(make_ast_binding(concat(syntax->children[0]->children[0]->children[2]))) + syntax_to_ast_helper(syntax->children[0]->children[0]->children[0], declared_template_types) + get_nodes("parameter", syntax).map(fun(s: *tree): *tree { - return syntax_to_ast_helper(s->children[0], declared_template_types) - })) - } else { - println("NOT doing a method call! - is " + syntax->children[0]->data.name + " not unrad, or") - println(syntax->children[0]->children[0]->data.name + " not access_operation") - return _call(false, vec(syntax_to_ast_helper(syntax->children[0], declared_template_types)) + get_nodes("parameter", syntax).map(fun(s: *tree): *tree { - return syntax_to_ast_helper(s->children[0], declared_template_types) - })) - } - } else if (syntax->data.name == "access_operation") { - // somehow note / do the crazier scope lookup - // also handle . vs -> - return _call(true, vec(make_ast_binding(concat(syntax->children[2])), syntax_to_ast_helper(syntax->children[0], declared_template_types))) - } else if (syntax->data.name == "boolean_expression" || - syntax->data.name == "and_boolean_expression" || - syntax->data.name == "bitwise_or" || - syntax->data.name == "bitwise_xor" || - syntax->data.name == "bitwise_and" || - syntax->data.name == "bool_exp" || - syntax->data.name == "expression" || - syntax->data.name == "shiftand" || - syntax->data.name == "term" || - syntax->data.name == "factor" || - syntax->data.name == "unarad") { - if (syntax->children.size == 1) { - return syntax_to_ast_helper(syntax->children[0], declared_template_types) - } else if (syntax->children.size == 2) { - var template_inst = get_node("template_inst", syntax) - if (template_inst != null>()) { - if (syntax->children[0]->data.name != "scoped_identifier") - error(syntax, "Unexpected template instantiation (not on an identifier)") - return make_ast_binding(concat(syntax->children[0]), get_nodes("type", template_inst).map(fun(s: *tree): *binding { - return parse_type(s, declared_template_types); - })) - } else if (syntax->children[0]->data.terminal) { - return _call(true, vec(make_ast_binding("op" + concat(syntax->children[0])), - syntax_to_ast_helper(syntax->children[1], declared_template_types))) - } else { - return _call(true, vec(make_ast_binding("op" + concat(syntax->children[1])), - syntax_to_ast_helper(syntax->children[0], declared_template_types))) - } - } else { - return _call(true, vec(make_ast_binding("op" + concat(syntax->children[1])), - syntax_to_ast_helper(syntax->children[0], declared_template_types), - syntax_to_ast_helper(syntax->children[2], declared_template_types))) - } - } else if (syntax->data.name == "cast_expression") { - return _cast(parse_type(get_node("type", syntax), declared_template_types), vec(syntax_to_ast_helper(syntax->children[0], declared_template_types))) - } else if (syntax->data.name == "compiler_intrinsic") { - var name = concat(get_node("identifier", syntax)) - if name != "sizeof" { - error("unknown compiler intrinsic " + name) - } - return _compiler_intrinsic(name, binding_p(type::_ulong(), binding_epoch::pre_ref()), vec(parse_type(get_node("type", syntax), declared_template_types))) - } else if (syntax->data.name == "number") { - var number_string = concat(syntax) - if (number_string.contains('.')) - return _value(number_string, binding_p(type::_double(), binding_epoch::pre_ref())) - else - return _value(number_string, binding_p(type::_int(), binding_epoch::pre_ref())) - } else if (syntax->data.name == "string") { - var value_str = concat(syntax) - var start = 1 - var end = value_str.length() -1 - if (value_str.length() > 3 && value_str[1] == '"' && value_str[2] == '"') { - value_str = value_str.slice(3,-4) - } else { - var new_str.construct(end-start): str - var escaped = false - for (var i = 1; i < value_str.length()-1; i++;) { - if (escaped) { - escaped = false - if (value_str[i] == 'n') - new_str += '\n' - else if (value_str[i] == 't') - new_str += '\t' - else - new_str += value_str[i] - } else if (value_str[i] == '\\') { - escaped = true - } else { - new_str += value_str[i] - } - } - value_str = new_str - } - return _value(value_str, binding_p(type::_ptr(binding_p(type::_char(), binding_epoch::pre_ref())), binding_epoch::pre_ref())) - } else if (syntax->data.name == "bool") - return _value(concat(syntax), binding_p(type::_bool(), binding_epoch::pre_ref())) - else if (syntax->data.name == "scoped_identifier" || syntax->data.name == "identifier") - return make_ast_binding(concat(syntax)) - else { - error(syntax, "Cannot transform") - } - } - var declared_template_types = map>() - var result = _translation_unit(file_name, syntax->children.map(fun(x: *tree): *tree return syntax_to_ast_helper(x, declared_template_types);)) - return result -} -fun print_tree(t: *tree, level: int) { - printlnerr("\t" * level + to_string(t->data)) - for (var i = 0; i < t->children.size; i++;) - if (t->children[i]) - print_tree(t->children[i], level+1) - else - printlnerr("\t" * (level + 1) + "null!") -} -fun get_node(lookup: *char, parent: *tree): *tree { - return get_node(str(lookup), parent) -} -fun get_node(lookup: str, parent: *tree): *tree { - var results = get_nodes(lookup, parent) - if (results.size > 1) - error(parent, "get node too many results!") - if (results.size) - return results[0] - return null>() -} -fun get_nodes(lookup: *char, parent: *tree): vec<*tree> { - return get_nodes(str(lookup), parent) -} -fun get_nodes(lookup: str, parent: *tree): vec<*tree> { - return parent->children.filter(fun(node: *tree):bool return node->data.name == lookup;) -} -fun concat(node: *tree): str { - var str.construct(): str - if (node->data.data != "no_value") - str += node->data.data - node->children.for_each(fun(child: *tree) str += concat(child);) - return str -} -fun get_first_terminal(source: *tree): *tree { - if (!source) - return null>() - if (source->data.terminal) - return source - if (source->children.size == 0) - return null>() - return get_first_terminal(source->children.first()) -} -fun error(source: *tree, message: *char) error(source, str(message)); -fun error(source: *tree, message: str) { - var first = get_first_terminal(source) - if (first) - error("***error |" + concat(source) + "| *** " + first->data.source + ": " + first->data.position + " " + message) - error(message) -} -fun trim(parse_tree: *tree) { - remove_node(symbol("$NULL$", false), parse_tree) - remove_node(symbol("WS", false), parse_tree) - // the terminals have " around them, which we have to escape - remove_node(symbol("\"\\(\"", true), parse_tree) - remove_node(symbol("\"\\)\"", true), parse_tree) - remove_node(symbol("\"template\"", true), parse_tree) - remove_node(symbol("\"return\"", true), parse_tree) - remove_node(symbol("\"defer\"", true), parse_tree) - remove_node(symbol("\";\"", true), parse_tree) - remove_node(symbol("line_end", false), parse_tree) - remove_node(symbol("\"{\"", true), parse_tree) - remove_node(symbol("\"}\"", true), parse_tree) - remove_node(symbol("\"(\"", true), parse_tree) - remove_node(symbol("\")\"", true), parse_tree) - remove_node(symbol("\"if\"", true), parse_tree) - remove_node(symbol("\"else\"", true), parse_tree) - remove_node(symbol("\"while\"", true), parse_tree) - remove_node(symbol("\"for\"", true), parse_tree) - remove_node(symbol("\"__if_comp__\"", true), parse_tree) - remove_node(symbol("\"comp_simple_passthrough\"", true), parse_tree) - /*remove_node(symbol("obj_nonterm", false), parse_tree)*/ - remove_node(symbol("adt_nonterm", false), parse_tree) - - collapse_node(symbol("case_statement_list", false), parse_tree) - collapse_node(symbol("opt_param_assign_list", false), parse_tree) - collapse_node(symbol("param_assign_list", false), parse_tree) - collapse_node(symbol("opt_typed_parameter_list", false), parse_tree) - collapse_node(symbol("opt_parameter_list", false), parse_tree) - collapse_node(symbol("intrinsic_parameter_list", false), parse_tree) - collapse_node(symbol("identifier_list", false), parse_tree) - collapse_node(symbol("adt_option_list", false), parse_tree) - collapse_node(symbol("statement_list", false), parse_tree) - collapse_node(symbol("parameter_list", false), parse_tree) - collapse_node(symbol("typed_parameter_list", false), parse_tree) - collapse_node(symbol("unorderd_list_part", false), parse_tree) - collapse_node(symbol("if_comp_pred", false), parse_tree) - collapse_node(symbol("declaration_block", false), parse_tree) - collapse_node(symbol("type_list", false), parse_tree) - collapse_node(symbol("opt_type_list", false), parse_tree) - collapse_node(symbol("template_param_list", false), parse_tree) - collapse_node(symbol("trait_list", false), parse_tree) - collapse_node(symbol("dec_type", false), parse_tree) -} -fun remove_node(remove: symbol, parse_tree: *tree) { - var to_process = stack<*tree>() - to_process.push(parse_tree) - while(!to_process.empty()) { - var node = to_process.pop() - for (var i = 0; i < node->children.size; i++;) { - if (!node->children[i] || node->children[i]->data.equal_wo_data(remove)) { - node->children.remove(i) - i--; - } else { - to_process.push(node->children[i]) - } - } - } -} -fun collapse_node(remove: symbol, parse_tree: *tree) { - var to_process = stack<*tree>() - to_process.push(parse_tree) - while(!to_process.empty()) { - var node = to_process.pop() - for (var i = 0; i < node->children.size; i++;) { - if (node->children[i]->data.equal_wo_data(remove)) { - var add_children = node->children[i]->children; - // stick child's children between the current children divided - // on i, without including i - node->children = node->children.slice(0,i) + - add_children + node->children.slice(i+1,-1) - i--; - } else { - to_process.push(node->children[i]) - } - } - } -} diff --git a/k_prime.krak b/k_prime.krak deleted file mode 100644 index 4be3b25..0000000 --- a/k_prime.krak +++ /dev/null @@ -1,1544 +0,0 @@ -import mem:* -import io:* -import str:* -import vec:* -import vec_literals:* -import util:* -import map:* -import rc:* - -import fungll:* - -adt KPValue_int { - True, // 101 1 0 - False, // 100 1 0 - Env: *KPEnv, // 011 1 0 - Combiner: KPCombiner, // 010 1 0 - BuiltinCombiner: KPBuiltinCombiner, // ''' ' ' - String: str, // 001 1 0 - Symbol: str, // 000 1 0 - Int: int, // 0 0 - - Array: rc>, //<10sizebits> 1 - // same encoding, but encodes 0-length null ptr - Nil // 00000000000 1 -} -obj KPEnv (Object) { - var data: map - var outer: *KPEnv - fun construct(): *KPEnv { - return construct(null()) - } - fun construct(outer: *KPEnv): *KPEnv { - data.construct() - this->outer = outer - return this - } - fun copy_construct(old: *KPEnv): void { - data.copy_construct(&old->data) - outer = old->outer - } - fun destruct(): void { - data.destruct() - outer = null() - } - fun operator=(other:ref KPEnv):void { - destruct() - copy_construct(&other) - } - fun operator<(other: ref KPEnv):bool { - if data.keys < other.data.keys || data.values < other.data.values { - return true; - } - if (outer != null()) && ((other.outer == null()) || (*outer < *other.outer)) { - return true; - } - return false; - } - fun set(key: str, val: KPValue) { - data.set(key, val) - } - fun remove(key: str) { - data.remove(key) - } - fun find(key: str): *KPEnv { - if (data.contains_key(key)) { - return this - } else if (outer != null()) { - return outer->find(key) - } else { - return null() - } - } - fun get(key: *char): KPResult { - return get(str(key)) - } - fun get(key: ref str): KPResult { - var env = find(key) - if (env != null()) { - return KPResult::Ok(env->data.get(key)) - } else { - println(key + " wasn't found in:") - println(to_string()) - return KPResult::Err(kpString(str("'") + key + "' not found")) - } - } - fun to_string(): str { - var to_ret = str() - to_string(str("\t"), to_ret) - return to_ret - } - fun to_string(tabs: ref str, s: ref str) { - for (var i = 0; i < data.keys.size; i++;) { - s += tabs + data.keys[i] + ": " + pr_str(data.values[i], true) + "\n" - /*s += tabs + data.keys[i] + "\n"*/ - } - if outer != null() { - outer->to_string(tabs + "\t", s) - } - } -} -obj KPBuiltinCombiner (Object) { - var name: str - var wrap_level: int - var tco_eval: bool - var fp: fun(vec, *KPEnv): pair<*KPEnv, KPResult> - fun construct(name: ref str, wrap_level: int, tco_eval: bool, fp: fun(vec, *KPEnv): pair<*KPEnv, KPResult>): *KPBuiltinCombiner { - this->name.copy_construct(&name) - this->wrap_level = wrap_level - this->tco_eval = tco_eval - this->fp = fp - return this - } - fun copy_construct(old: *KPBuiltinCombiner): void { - this->fp = old->fp - this->wrap_level = old->wrap_level - this->tco_eval = old->tco_eval - this->name.copy_construct(&old->name) - } - fun destruct(): void { - this->name.destruct() - } - fun operator=(other:ref KPBuiltinCombiner):void { - destruct() - copy_construct(&other) - } - fun operator==(other: ref KPBuiltinCombiner):bool { - return name == other.name - } - fun operator<(other: ref KPBuiltinCombiner):bool { - return name < other.name - } - fun call(params: vec, dynamic_env: KPValue): pair<*KPEnv, KPResult> { - if !dynamic_env.is_env() { - return make_pair(null(), KPResult::Err(kpString(pr_str(dynamic_env, true) + " is not an env"))) - } - for (var l = 0; l < wrap_level; l++;) { - for (var i = 0; i < params.size; i++;) { - var intermediate = EVAL(dynamic_env.get_env(), params[i]); - if is_err(intermediate) { - return make_pair(null(), intermediate); - } - params[i] = get_value(intermediate); - } - } - return fp(params, dynamic_env.get_env()) - } -} -fun make_builtin_combiner(name: str, wrap_level: int, tco_eval: bool, f: fun(vec, *KPEnv): pair<*KPEnv,KPResult>): KPValue { - var to_ret.construct(name, wrap_level, tco_eval, f): KPBuiltinCombiner - return nmMV(KPValue_int::BuiltinCombiner(to_ret)) -} -obj KPCombiner (Object) { - var env: *KPEnv - var dynamic_env_name: str - var uses_dynamic_env: bool - var wrap_level: int - var parameters: vec - var is_variadic: bool - var body: *KPValue - fun construct(env: *KPEnv, dynamic_env_name: str, uses_dynamic_env: bool, parameters: vec, is_variadic: bool, body: KPValue): *KPCombiner { - this->env = env - this->dynamic_env_name.copy_construct(&dynamic_env_name) - this->uses_dynamic_env = uses_dynamic_env - this->wrap_level = 0 - this->parameters.copy_construct(¶meters) - this->is_variadic = is_variadic - this->body = new() - this->body->copy_construct(&body) - return this - } - fun copy_construct(old: *KPCombiner): void { - this->env = old->env - this->dynamic_env_name.copy_construct(&old->dynamic_env_name) - this->uses_dynamic_env = old->uses_dynamic_env - this->wrap_level = old->wrap_level - this->parameters.copy_construct(&old->parameters) - this->is_variadic = old->is_variadic - this->body = new() - this->body->copy_construct(old->body) - } - fun destruct(): void { - this->env = null() - dynamic_env_name.destruct() - parameters.destruct() - delete(body) - body = null() - } - fun operator=(other:ref KPCombiner):void { - destruct() - copy_construct(&other) - } - fun operator==(other: ref KPCombiner):bool { - // not sure about env - return env == other.env && dynamic_env_name == other.dynamic_env_name && uses_dynamic_env == other.uses_dynamic_env && wrap_level == other.wrap_level && parameters == other.parameters && is_variadic == other.is_variadic && body->equals(*other.body) - } - fun operator<(other: ref KPCombiner):bool { - // not sure about env - return *env < *other.env || dynamic_env_name < other.dynamic_env_name || uses_dynamic_env < other.uses_dynamic_env || wrap_level < other.wrap_level || parameters < other.parameters || is_variadic < other.is_variadic || body->lt(*other.body) - } - // no call b/c need to do in EVAL for TCO - fun prep_call(params: ref vec, dynamic_env: KPValue): pair<*KPEnv, KPResult> { - for (var l = 0; l < wrap_level; l++;) { - if !dynamic_env.is_env() { - return make_pair(null(), KPResult::Err(kpString(str("called combiner with wrap_level") + wrap_level + "with bad dynamic_env " + pr_str(dynamic_env, true)))); - } - for (var i = 0; i < params.size; i++;) { - var intermediate = EVAL(dynamic_env.get_env(), params[i]); - if is_err(intermediate) { - return make_pair(null(), intermediate); - } - params[i] = get_value(intermediate); - } - } - // tco - if (!is_variadic && parameters.size != params.size) || (is_variadic && parameters.size > params.size + 1) { - return make_pair(null(), KPResult::Err(kpString(str("combiner called with the wrong number of parameters: ") + params.size + " but expecting " + parameters.size + ": [ " + str(",").join(parameters) + "], was: " + pr_str(kpArray(params), true) + ", function body is " + pr_str(*body, true)))) - } - var new_env = new()->construct(env) - for (var i = 0; i < parameters.size; i++;) { - if is_variadic && i == parameters.size - 1 { - new_env->set(parameters[i], kpArray(params.slice(i, -1))) - } else { - new_env->set(parameters[i], params[i]) - } - } - if uses_dynamic_env { - new_env->set(dynamic_env_name, dynamic_env) - } - /*println("Calling with\n" + new_env->to_string())*/ - return make_pair(new_env, KPResult::Ok(*body)) - } -} - -obj KPValue (Object) { - var internal: KPValue_int - var meta: *KPValue - - fun construct(): *KPValue { - internal.copy_construct(&KPValue_int::Nil()); - meta = null() - } - fun construct(i: ref KPValue_int, m: *KPValue): *KPValue { - internal.copy_construct(&i); - meta = m - } - fun copy_construct(other: *KPValue): void { - internal.copy_construct(&other->internal); - /*meta = other->meta*/ - if other->meta != null() { - meta = new() - meta->copy_construct(other->meta) - } else { - meta = null() - } - } - fun operator=(other: ref KPValue): void { - destruct() - copy_construct(&other) - } - fun destruct(): void { - if meta != null() - delete(meta) - internal.destruct() - } - fun equals(other: ref KPValue): bool { - match (internal) { - KPValue_int::Array(d) { match (other.internal) { - KPValue_int::Array(db) { - if d.get().size != db.get().size { - return false - } - for (var i = 0; i < d.get().size; i++;) { - if !d.get()[i].equals(db.get()[i]) { - return false - } - } - return true - } - } } - KPValue_int::String(d) { match (other.internal) { KPValue_int::String(db) { return d == db; } } } - KPValue_int::Int(d) { match (other.internal) { KPValue_int::Int(db) { return d == db; } } } - KPValue_int::Symbol(d) { match (other.internal) { KPValue_int::Symbol(db) { return d == db; } } } - KPValue_int::Combiner(d){ match (other.internal) { KPValue_int::Combiner(db) { return d == db; } } } - KPValue_int::BuiltinCombiner(d) { match (other.internal) { KPValue_int::BuiltinCombiner(db) { return d == db; } } } - KPValue_int::Env(e) { match (other.internal) { KPValue_int::Env(eb) { return e == eb; } } } - KPValue_int::True() { match (other.internal) { KPValue_int::True() { return true; } } } - KPValue_int::False() { match (other.internal) { KPValue_int::False() { return true; } } } - KPValue_int::Nil() { match (other.internal) { KPValue_int::Nil() { return true; } } } - } - return false - } - fun variant(): int { - match (internal) { - KPValue_int::Array(d) { return 0; } - KPValue_int::String(d) { return 1; } - KPValue_int::Int(d) { return 2; } - KPValue_int::Symbol(d) { return 3; } - KPValue_int::Combiner(d) { return 4; } - KPValue_int::BuiltinCombiner(d) { return 5; } - KPValue_int::Env(e) { return 6; } - KPValue_int::True() { return 7; } - KPValue_int::False() { return 8; } - KPValue_int::Nil() { return 9; } - } - } - fun operator<(other: ref KPValue):bool { - return this->lt(other) - } - fun lt(other: ref KPValue): bool { - var our_variant = variant() - var their_variant = other.variant() - if our_variant < their_variant { - return true; - } else if our_variant > their_variant { - return false; - } - match (internal) { - KPValue_int::Array(d) { match (other.internal) { KPValue_int::Array(db) { return d.get() < db.get(); } } } - KPValue_int::String(d) { match (other.internal) { KPValue_int::String(db) { return d < db; } } } - KPValue_int::Int(d) { match (other.internal) { KPValue_int::Int(db) { return d < db; } } } - KPValue_int::Symbol(d) { match (other.internal) { KPValue_int::Symbol(db) { return d < db; } } } - KPValue_int::Combiner(d){ match (other.internal) { KPValue_int::Combiner(db) { return d < db; } } } - KPValue_int::BuiltinCombiner(d) { match (other.internal) { KPValue_int::BuiltinCombiner(db) { return d < db; } } } - KPValue_int::Env(e) { match (other.internal) { KPValue_int::Env(eb) { return e < eb; } } } - KPValue_int::True() { match (other.internal) { KPValue_int::True() { return false; } } } - KPValue_int::False() { match (other.internal) { KPValue_int::False() { return false; } } } - KPValue_int::Nil() { match (other.internal) { KPValue_int::Nil() { return false; } } } - } - return false - } - fun deep_clone(): KPValue { - match (internal) { - KPValue_int::Array(v) { - return kpArray(v.get()) - } - KPValue_int::Env(e) { - var newenv = new() - newenv->copy_construct(e) - return kpEnv(e) - } - } - return *this - } - fun is_combiner(): bool { - match (internal) { - KPValue_int::Combiner(f) { - return true - } - KPValue_int::BuiltinCombiner(f) { - return true - } - } - return false - } - fun is_env(): bool { - match (internal) { - KPValue_int::Env(e) { - return true - } - } - return false - } - fun get_env(): *KPEnv { - match (internal) { - KPValue_int::Env(e) { - return e - } - } - error("Tried to get env on not an env" + pr_str(*this, true)) - } - fun is_array(): bool { - match (internal) { - KPValue_int::Array(v) { - return true - } - } - return false - } - fun get_array_rc(): rc> { - match (internal) { - KPValue_int::Array(v) { - return v - } - } - error("Tried to get vec on not a vec" + pr_str(*this, true)) - } - fun is_symbol(): bool { - match (internal) { - KPValue_int::Symbol(s) { - return true - } - } - return false - } - fun is_symbol(text: *char): bool { - match (internal) { - KPValue_int::Symbol(s) { - return s == text - } - } - return false - } - fun get_symbol_text(): str { - match (internal) { - KPValue_int::Symbol(s) { - return s - } - } - error("get_symbol_text on not symbol") - } - fun is_string(): bool { - match (internal) { - KPValue_int::String(s) { - return true - } - } - return false - } - fun get_string(): str { - match (internal) { - KPValue_int::String(s) { - return s - } - } - error("get_string on not a string") - } - fun is_int(): bool { - match (internal) { - KPValue_int::Int(i) { - return true - } - } - return false - } - fun get_int(): int { - match (internal) { - KPValue_int::Int(i) { - return i - } - } - error("get_int on not an int") - } - fun is_nil(): bool { - match (internal) { - KPValue_int::Nil() { - return true - } - } - return false - } - fun is_bool(): bool { - match (internal) { - KPValue_int::True() { - return true - } - KPValue_int::False() { - return true - } - } - return false - } - fun is_truthy(): bool { - match (internal) { - KPValue_int::False() { - return false - } - KPValue_int::Nil() { - return false - } - } - return true - } - fun is_pair(): bool { - return is_array() && get_array_rc().get().size > 0 - } -} - - -fun nmMV(i: ref KPValue_int): KPValue { - var to_ret.construct(i, null()): KPValue - return to_ret -} -fun kpTrue(): KPValue { - return nmMV(KPValue_int::True()) -} -fun kpFalse(): KPValue { - return nmMV(KPValue_int::False()) -} -fun kpBool(b: bool): KPValue { - if b { - return nmMV(KPValue_int::True()) - } else { - return nmMV(KPValue_int::False()) - } -} -fun kpString(s: ref str): KPValue { - return nmMV(KPValue_int::String(s)) -} -fun kpSymbol(s: *char): KPValue { - return kpSymbol(str(s)) -} -fun kpSymbol(s: ref str): KPValue { - return nmMV(KPValue_int::Symbol(s)) -} -fun kpInt(i: int): KPValue { - return nmMV(KPValue_int::Int(i)) -} -fun kpArray(v: ref vec): KPValue { - var rcd.construct(v): rc> - return nmMV(KPValue_int::Array(rcd)) -} -fun kpNil(): KPValue { - return nmMV(KPValue_int::Nil()) -} -fun kpEnv(e: *KPEnv): KPValue { - return nmMV(KPValue_int::Env(e)) -} - -fun read_str(grammar: ref Grammer, s: str): pair { - var BSR = fungll(grammar, grammar.start_symbol, s) - var longest = -1 - for (var i = 0; i < BSR.data.size; i++;) { - if BSR.data[i].nonterminal == grammar.start_symbol && BSR.data[i].left == 0 && BSR.data[i].idx_into_rule == grammar.nonterminals[(-1*BSR.data[i].nonterminal)-1][BSR.data[i].rule_idx].size && BSR.data[i].right > longest { - longest = BSR.data[i].right - } - } - if longest >= 0 { - println("trying to parse: " + s) - println(str("length of BSR is: ") + BSR.size()) - for (var i = 0; i < BSR.data.size; i++;) { - println(str() + i + ": " + grammar.to_string(BSR.data[i])) - } - return make_pair(longest, grammar.eval_BSR(s.slice(0, longest), BSR)) - } else { - println("trying to parse: " + s) - println(str("length of BSR is: ") + BSR.size()) - for (var i = 0; i < BSR.data.size; i++;) { - println(str() + i + ": " + grammar.to_string(BSR.data[i])) - } - println("Parse failed") - return make_pair(-1, KPResult::Err(kpString(str("failed to parse")))) - } -} - -adt KPResult { - Ok: KPValue, - Err: KPValue -} -fun is_err(r: KPResult): bool { - match (r) { - KPResult::Err(e) { - return true - } - } - return false -} -fun get_err(r: KPResult): KPValue { - match (r) { - KPResult::Err(e) { - return e - } - } - error("get-err-not-error") -} -fun get_value(r: KPResult): KPValue { - match (r) { - KPResult::Ok(v) { - return v - } - } - error("get-value-is-error") -} -fun pr_str(v: KPValue, print_readably: bool): str { - match (v.internal) { - KPValue_int::Array(l) { - var to_ret = str("( ") - for (var i = 0; i < l.get().size; i++;) { - if (i != 0) { - to_ret += " " - } - to_ret += pr_str(l.get()[i], print_readably) - } - return to_ret + " )" - } - KPValue_int::Int(i) { - return to_string(i) - } - KPValue_int::String(s) { - if print_readably { - var to_ret = str("\"") //" - for (var i = 0; i < s.length(); i++;) { - if s[i] == '\n' { - to_ret += '\\' - to_ret += 'n' - } else if s[i] == '\\' || s[i] == '"' { - to_ret += '\\' - to_ret += s[i] - } else { - to_ret += s[i] - } - } - return to_ret + "\"" //" - } else { - return s - } - } - KPValue_int::Symbol(s) { - if print_readably { - return "'" + s - } else { - return s - } - } - KPValue_int::BuiltinCombiner(f) { - return "builtin_combiner_" + f.name + "(wrap_level: " + f.wrap_level + ")" - } - KPValue_int::Combiner(f) { - return str("combiner(wrap_level: ") + f.wrap_level + ")" - } - KPValue_int::Env(e) { - return str("environment") - } - KPValue_int::True() { - return str("true") - } - KPValue_int::False() { - return str("false") - } - KPValue_int::Nil() { - return str("nil") - } - } - error("can't print") -} - -fun READ(grammar: ref Grammer, s: str): KPResult { - var to_ret = read_str(grammar, s) - if to_ret.first != s.length() { - if is_err(to_ret.second) { - return to_ret.second - } else { - println("parsed to var: " + pr_str(get_value(to_ret.second), true)) - } - error("parsed some, but not all, remaining: " + s.slice(to_ret.first, -1)) - } - return to_ret.second -} - -fun EVAL(env: *KPEnv, ast: KPValue): KPResult { - // for tco - while (true) { - match (ast.internal) { - KPValue_int::Array(l) { - if (l.get().size == 0) { - return KPResult::Err(kpString(str("Eval a zero length array"))) - } else { - var combiner = EVAL(env, l.get()[0]) - if is_err(combiner) { - return combiner - } - /*println("About to call combiner evaled from " + pr_str(l.get()[0], true))*/ - match (get_value(combiner).internal) { - KPValue_int::BuiltinCombiner(f) { - var call_pair = f.call(l.get().slice(1,-1), kpEnv(env)); - if is_err(call_pair.second) || !f.tco_eval { - return call_pair.second - } - // tco_eval is true, so do tco - env = call_pair.first - ast = get_value(call_pair.second) - continue - } - KPValue_int::Combiner(f) { - var call_pair = f.prep_call(l.get().slice(1, -1), kpEnv(env)) - if is_err(call_pair.second) { - return call_pair.second - } - env = call_pair.first - ast = get_value(call_pair.second) - continue - } - } - return KPResult::Err(kpString(str("trying to call not a combiner: ") + pr_str(l.get()[0], true))) - } - } - KPValue_int::Symbol(s) { - return env->get(s) - } - } - // everything else is self-evaluating - return KPResult::Ok(ast) - } -} - -fun function_call(f: KPValue, params: ref vec, env: KPValue): KPResult { - return EVAL(env.get_env(), kpArray(vec(f) + params)) -} - -fun rep(grammar: ref Grammer, env: *KPEnv, a: str): str { - var read = READ(grammar, a) - if is_err(read) { - return pr_str(get_err(read), true) - } else { - var evaled = EVAL(env, get_value(read)) - if is_err(evaled) { - return str("Exception: ") + pr_str(get_err(evaled), true) - } else { - return pr_str(get_value(evaled), true) - } - } -} - -fun str_wrapper(params: ref vec, dynamic_env: *KPEnv, sep: *char, print_readably: bool): KPResult { - var to_ret = str() - for (var i = 0; i < params.size; i++;) { - to_ret += pr_str(params[i], print_readably) - if i != params.size-1 { - to_ret += sep - } - } - return KPResult::Ok(kpString(to_ret)) -} -fun unwrap(f: KPValue): KPResult { - match (f.internal) { - KPValue_int::Combiner(c) { - if c.wrap_level <= 0 { - return KPResult::Err(kpString(str("unwrap called with combiner at wrap_level <= 0"))) - } - var to_ret = c; - to_ret.wrap_level-- - return KPResult::Ok(nmMV(KPValue_int::Combiner(to_ret))) - } - KPValue_int::BuiltinCombiner(c) { - if c.wrap_level <= 0 { - return KPResult::Err(kpString(str("unwrap called with combiner at wrap_level <= 0"))) - } - var to_ret = c; - to_ret.wrap_level-- - return KPResult::Ok(nmMV(KPValue_int::BuiltinCombiner(to_ret))) - } - } - return KPResult::Err(kpString(str("unwrap called with not combiner ") + pr_str(f, true))) -} - -var tmp_idx: int = 0 -fun new_tmp(): str { - tmp_idx += 1 - return str("x") + tmp_idx -} -fun main(argc: int, argv: **char): int { - - var grammar.construct(): Grammer - - var ret_nil_term: fun(ref KPValue, ref str, int, int): KPResult = fun(_: ref KPValue, input: ref str, l: int, r: int): KPResult { return KPResult::Ok(kpNil()); } - var ret_nil_sym: fun(ref KPValue, ref vec): KPResult = fun(_: ref KPValue, x: ref vec): KPResult { return KPResult::Ok(kpNil()); } - var ret_0_sym: fun(ref KPValue, ref vec): KPResult = fun(_: ref KPValue, x: ref vec): KPResult { return x[0]; } - var ret_1_sym: fun(ref KPValue, ref vec): KPResult = fun(_: ref KPValue, x: ref vec): KPResult { return x[1]; } - - var WS = grammar.add_new_nonterminal("WS", vec(grammar.add_terminal("( | | -|(;[ -~]* -))+", kpNil(), ret_nil_term)), kpNil(), ret_nil_sym) - var optional_WS = grammar.add_new_nonterminal("optional_WS", vec(), kpNil(), ret_nil_sym) - grammar.add_to_nonterminal(optional_WS, vec(WS), kpNil(), ret_nil_sym) - - var atom = grammar.add_new_nonterminal("atom", vec(grammar.add_terminal("-?[0-9]+", kpNil(), fun(_: ref KPValue, input: ref str, l: int, r: int): KPResult { return KPResult::Ok(kpInt(string_to_num(input.slice(l,r)))); })), kpNil(), ret_0_sym) - grammar.add_to_nonterminal(atom, vec(grammar.add_terminal("\"([#-[]| |[]-~]|(\\\\\\\\)|(\\\\n)|(\\\\t)|(\\*)|(\\\\0)| -|[ -!]|(\\\\\"))*\"", kpNil(), fun(_: ref KPValue, input: ref str, l: int, r: int): KPResult { //" - var to_ret = str() - for (var i = l+1; i < r-1; i++;) { - if input[i] == '\\' { - if input[i+1] == 'n' { - to_ret += '\n' - } else if input[i+1] == 't' { - to_ret += '\t' - } else if input[i+1] == '0' { - to_ret += '\0' - } else if input[i+1] == '\\' || input[i+1] == '"' { - to_ret += input[i+1] - } else { - return KPResult::Err(kpString(str("bad string escape: ") + input[i+1])) - } - // skip - i++ - } else { - to_ret += input[i] - } - } - return KPResult::Ok(kpString(to_ret)); - })), kpNil(), ret_0_sym) - grammar.add_to_nonterminal(atom, vec(grammar.add_terminal("-|(([a-z]|[A-Z]|_|\\*|/|\\?|\\+|!|=|&|\\||<|>|%)([a-z]|[A-Z]|_|[0-9]|\\*|\\?|\\+|-|!|=|&|\\||<|>|%|\\.)*)", kpNil(), fun(_: ref KPValue, input: ref str, l: int, r: int): KPResult { - var s = input.slice(l,r) - if s == "true" { - return KPResult::Ok(kpTrue()); - } else if s == "false" { - return KPResult::Ok(kpFalse()); - } else if s == "nil" { - return KPResult::Ok(kpNil()); - } else { - return KPResult::Ok(kpSymbol(input.slice(l,r))); - } - })), kpNil(), ret_0_sym) - - var form = grammar.add_new_nonterminal("form", vec(atom), kpNil(), ret_0_sym) - var space_forms = grammar.add_new_nonterminal("space_forms", vec(), kpNil(), fun(_: ref KPValue, x: ref vec): KPResult { - return KPResult::Ok(kpArray(vec())) - }) - grammar.add_to_nonterminal(space_forms, vec(form), kpNil(), fun(_: ref KPValue, x: ref vec): KPResult { - if is_err(x[0]) { - return x[0] - } - return KPResult::Ok(kpArray(vec(get_value(x[0])))) - }) - grammar.add_to_nonterminal(space_forms, vec(form, WS, space_forms), kpNil(), fun(_: ref KPValue, x: ref vec): KPResult { - if is_err(x[0]) { - return x[0] - } - if is_err(x[2]) { - return x[2] - } - return KPResult::Ok(kpArray(vec(get_value(x[0])) + get_value(x[2]).get_array_rc().get())) - }) - - var call_form = grammar.add_new_nonterminal("call_form", vec(grammar.add_terminal("\\(", kpNil(), ret_nil_term), - optional_WS, - grammar.add_terminal("\\)", kpNil(), ret_nil_term)), kpNil(), fun(_: ref KPValue, x: ref vec): KPResult { return KPResult::Ok(kpArray(vec())); }) - grammar.add_to_nonterminal(call_form, vec(grammar.add_terminal("\\(", kpNil(), ret_nil_term), - optional_WS, - space_forms, - optional_WS, - grammar.add_terminal("\\)", kpNil(), ret_nil_term)), kpNil(), fun(_: ref KPValue, x: ref vec): KPResult { return x[2]; }) - - grammar.add_to_nonterminal(form, vec(call_form), kpNil(), fun(_: ref KPValue, x: ref vec): KPResult { - return x[0]; - }) - var start_symbol = grammar.add_new_nonterminal("start_symbol", vec(optional_WS, form, optional_WS), kpNil(), ret_1_sym) - grammar.set_start_symbol(start_symbol) - //grammar.set_start_symbol(form) - - - var env = new()->construct() - - env->set(str("vau"), make_builtin_combiner(str("vau"), 0, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { - var param_symbols = vec() - if params.size != 2 && params.size != 3 { - return make_pair(null(), KPResult::Err(kpString(str("bad number of params to vau: ") + params.size))) - } - var uses_dynamic_env = params.size == 3 - var offset = 0 - var dynamic_env_name = str() - if uses_dynamic_env { - if !params[0].is_symbol() { - return make_pair(null(), KPResult::Err(kpString(str("first param to vau is not symbol ") + pr_str(params[0], true)))) - } - dynamic_env_name = params[0].get_symbol_text() - offset = 1 - } - var is_variadic = false - var parameters = vec() - if !params[offset+0].is_array() { - return make_pair(null(), KPResult::Err(kpString(str("second param to vau is not array")))) - } - var parameter_objects = params[offset+0].get_array_rc() - for (var i = 0; i < parameter_objects.get().size; i++;) { - if !parameter_objects.get()[i].is_symbol() { - return make_pair(null(), KPResult::Err(kpString(str("second param to vau has a not symbol member: ") + pr_str(parameter_objects.get()[i], true)))) - } - var parameter = parameter_objects.get()[i].get_symbol_text() - if parameter == "&" { - is_variadic = true - } else { - parameters.add(parameter) - } - } - var to_ret.construct(dynamic_env, dynamic_env_name, uses_dynamic_env, parameters, is_variadic, params[offset+1]) : KPCombiner - return make_pair(null(), KPResult::Ok(nmMV(KPValue_int::Combiner(to_ret)))) - })); - // Uses TCO - env->set(str("eval"), make_builtin_combiner(str("eval"), 1, true, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { - if params.size == 1 { - return make_pair(dynamic_env, KPResult::Ok(params[0])) - } else if params.size == 2 { - if !params[1].is_env() { - return make_pair(null(), KPResult::Err(kpString(str("second param to eval is not an environment") + pr_str(params[1], true)))) - } - return make_pair(params[1].get_env(), KPResult::Ok(params[0])) - } - return make_pair(null(), KPResult::Err(kpString(str("wrong number of params to eval")))) - })); - - // cond uses TCO - env->set(str("cond"), make_builtin_combiner(str("cond"), 0, true, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { - if (params.size % 2) != 0 { - return make_pair(null(), KPResult::Err(kpString(str("Need even number of params to cond, have: ") + params.size + " last is " + pr_str(params[params.size-1], true)))) - } - for (var i = 0; i < params.size; i+=2;) { - var ip = EVAL(dynamic_env, params[i]) - if is_err(ip) { - return make_pair(null(), ip) - } - if get_value(ip).is_truthy() { - // will be evaluated above because tco is true - return make_pair(dynamic_env, KPResult::Ok(params[i+1])) - } - } - var it = str() - for (var i = 0; i < params.size; i+=1;) { - it += pr_str(params[i], true) + " " - } - return make_pair(null(), KPResult::Err(kpString(str("None of cond branches were true: ") + it))) - })); - - env->set(str("symbol?"), make_builtin_combiner(str("symbol?"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { - if params.size != 1 { - return make_pair(null(), KPResult::Err(kpString(str("Need 1 param to symbol?")))) - } - return make_pair(null(), KPResult::Ok(kpBool(params[0].is_symbol()))) - })); - - env->set(str("int?"), make_builtin_combiner(str("int?"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { - if params.size != 1 { - return make_pair(null(), KPResult::Err(kpString(str("Need 1 param to int?")))) - } - return make_pair(null(), KPResult::Ok(kpBool(params[0].is_int()))) - })); - - env->set(str("string?"), make_builtin_combiner(str("string?"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { - if params.size != 1 { - return make_pair(null(), KPResult::Err(kpString(str("Need 1 param to string?")))) - } - return make_pair(null(), KPResult::Ok(kpBool(params[0].is_string()))) - })); - - env->set(str("combiner?"), make_builtin_combiner(str("combiner?"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { - if params.size != 1 { - return make_pair(null(), KPResult::Err(kpString(str("Need 1 param to combiner?")))) - } - return make_pair(null(), KPResult::Ok(kpBool(params[0].is_combiner()))) - })); - - env->set(str("env?"), make_builtin_combiner(str("env?"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { - if params.size != 1 { - return make_pair(null(), KPResult::Err(kpString(str("Need 1 param to env?")))) - } - return make_pair(null(), KPResult::Ok(kpBool(params[0].is_env()))) - })); - - env->set(str("nil?"), make_builtin_combiner(str("nil?"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { - if params.size != 1 { - return make_pair(null(), KPResult::Err(kpString(str("Need 1 param to nil?")))) - } - return make_pair(null(), KPResult::Ok(kpBool(params[0].is_nil()))) - })); - - env->set(str("bool?"), make_builtin_combiner(str("bool?"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { - if params.size != 1 { - return make_pair(null(), KPResult::Err(kpString(str("Need 1 param to bool?")))) - } - return make_pair(null(), KPResult::Ok(kpBool(params[0].is_bool()))) - })); - - env->set(str("array?"), make_builtin_combiner(str("array?"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { - if params.size != 1 { - return make_pair(null(), KPResult::Err(kpString(str("Need 1 param to array?")))) - } - return make_pair(null(), KPResult::Ok(kpBool(params[0].is_array()))) - })); - - env->set(str("str-to-symbol"), make_builtin_combiner(str("str-to-symbol"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { - if params.size != 1 { - return make_pair(null(), KPResult::Err(kpString(str("Need 1 param to str-to-symbol")))) - } - if !params[0].is_string() { - return make_pair(null(), KPResult::Err(kpString(str("Called str-to-symbol with not a symbol")))) - } - return make_pair(null(), KPResult::Ok(kpSymbol(params[0].get_string()))) - })); - - env->set(str("get-text"), make_builtin_combiner(str("get-text"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { - if params.size != 1 { - return make_pair(null(), KPResult::Err(kpString(str("Need 1 param to get-text")))) - } - if !params[0].is_symbol() { - return make_pair(null(), KPResult::Err(kpString(str("Called get-text with not a symbol")))) - } - return make_pair(null(), KPResult::Ok(kpString(params[0].get_symbol_text()))) - })); - - env->set(str("array"), make_builtin_combiner(str("array"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { - return make_pair(null(), KPResult::Ok(kpArray(params))) - })); - env->set(str("len"), make_builtin_combiner(str("len"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { - if params.size != 1 { - return make_pair(null(), KPResult::Err(kpString(str("Need 1 param to len")))) - } - if !params[0].is_array() && !params[0].is_string() { - return make_pair(null(), KPResult::Err(kpString(str("Called len with not an array/string ") + pr_str(params[0], true) + "\nenv was\n" + dynamic_env->to_string()))) - } - if params[0].is_array() { - return make_pair(null(), KPResult::Ok(kpInt(params[0].get_array_rc().get().size))) - } else { - return make_pair(null(), KPResult::Ok(kpInt(params[0].get_string().length()))) - } - })); - env->set(str("idx"), make_builtin_combiner(str("idx"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { - if params.size != 2 { - return make_pair(null(), KPResult::Err(kpString(str("Need 2 params to idx")))) - } - if !params[0].is_array() && !params[0].is_string() { return make_pair(null(), KPResult::Err(kpString(str("Param 1 to idx is not string or array") + pr_str(params[0], true) + " " + "\nenv was\n" + dynamic_env->to_string()))); } - if !params[1].is_int() { return make_pair(null(), KPResult::Err(kpString(str("Param 2 to idx is not int ") + pr_str(params[1], true)))); } - - var index = params[1].get_int() - var size = 0 - if params[0].is_array() { - size = params[0].get_array_rc().get().size - } else { - size = params[0].get_string().length() - } - if index < 0 { - index += size - } - - if index < 0 || index >= size { - return make_pair(null(), KPResult::Err(kpString(str("idx out of bounds, tried to get index ") + index + " in " + pr_str(params[0], true)))) - } - - if params[0].is_array() { - return make_pair(null(), KPResult::Ok(params[0].get_array_rc().get()[index])) - } else { - return make_pair(null(), KPResult::Ok(kpInt((params[0].get_string()[index]) cast int))) - } - })); - env->set(str("slice"), make_builtin_combiner(str("slice"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { - if params.size != 3 { - return make_pair(null(), KPResult::Err(kpString(str("Need 3 params to slice")))) - } - if !params[0].is_array() && !params[0].is_string() { return make_pair(null(), KPResult::Err(kpString(str("first param to slice is not string or array")))); } - if !params[1].is_int() { return make_pair(null(), KPResult::Err(kpString(str("second param to slice is not int")))); } - var start = params[1].get_int(); - if !params[2].is_int() { return make_pair(null(), KPResult::Err(kpString(str("third param to slice is not int ") + pr_str(params[2], true)))); } - var end = params[2].get_int(); - - if params[0].is_array() { - return make_pair(null(), KPResult::Ok(kpArray(params[0].get_array_rc().get().slice(start, end)))) - } else { - return make_pair(null(), KPResult::Ok(kpString(params[0].get_string().slice(start, end)))) - } - })); - env->set(str("concat"), make_builtin_combiner(str("concat"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { - var to_ret = vec() - for (var i = 0; i < params.size; i++;) { - if !params[i].is_array() { return make_pair(null(), KPResult::Err(kpString(str("param to concat is not an array")))); } - to_ret += params[i].get_array_rc().get() - } - return make_pair(null(), KPResult::Ok(kpArray(to_ret))); - })); - - env->set(str("+"), make_builtin_combiner(str("+"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { - var to_ret = 0 - for (var i = 0; i < params.size; i++;) { - match (params[i].internal) { - KPValue_int::Int(v) { - to_ret += v - continue - } - } - return make_pair(null(), KPResult::Err(kpString(str("called + with not an int: ") + pr_str(params[i], false)))) - } - return make_pair(null(), KPResult::Ok(kpInt(to_ret))) - })); - env->set(str("-"), make_builtin_combiner(str("-"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { - var to_ret = 0 - for (var i = 0; i < params.size; i++;) { - match (params[i].internal) { - KPValue_int::Int(v) { - if i == 0 && params.size > 1 { - to_ret += v - } else { - to_ret -= v - } - continue - } - } - return make_pair(null(), KPResult::Err(kpString(str("called - with not an int: ") + pr_str(params[i], false)))) - } - return make_pair(null(), KPResult::Ok(kpInt(to_ret))) - })); - env->set(str("*"), make_builtin_combiner(str("*"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { - var to_ret = 1 - for (var i = 0; i < params.size; i++;) { - match (params[i].internal) { - KPValue_int::Int(v) { - to_ret *= v - continue - } - } - return make_pair(null(), KPResult::Err(kpString(str("called * with not an int: ") + pr_str(params[i], false)))) - } - return make_pair(null(), KPResult::Ok(kpInt(to_ret))) - })); - env->set(str("/"), make_builtin_combiner(str("/"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { - var to_ret = 1 - for (var i = 0; i < params.size; i++;) { - match (params[i].internal) { - KPValue_int::Int(v) { - if i == 0 { - to_ret *= v - } else { - to_ret /= v - } - continue - } - } - return make_pair(null(), KPResult::Err(kpString(str("called / with not an int: ") + pr_str(params[i], false)))) - } - return make_pair(null(), KPResult::Ok(kpInt(to_ret))) - })); - env->set(str("%"), make_builtin_combiner(str("%"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { - var to_ret = 1 - for (var i = 0; i < params.size; i++;) { - match (params[i].internal) { - KPValue_int::Int(v) { - if i == 0 { - to_ret *= v - } else { - to_ret = to_ret % v - } - continue - } - } - return make_pair(null(), KPResult::Err(kpString(str("called % with not an int: ") + pr_str(params[i], false)))) - } - return make_pair(null(), KPResult::Ok(kpInt(to_ret))) - })); - - env->set(str("&"), make_builtin_combiner(str("&"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { - if params.size != 2 { - return make_pair(null(), KPResult::Err(kpString(str("Need 2 params to &")))) - } - if !params[0].is_int() { return make_pair(null(), KPResult::Err(kpString(str("called & with first not an int")))); } - if !params[1].is_int() { return make_pair(null(), KPResult::Err(kpString(str("called & with second not an int")))); } - return make_pair(null(), KPResult::Ok(kpInt(params[0].get_int() & params[1].get_int()))) - })); - env->set(str("|"), make_builtin_combiner(str("|"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { - if params.size != 2 { - return make_pair(null(), KPResult::Err(kpString(str("Need 2 params to |")))) - } - if !params[0].is_int() { return make_pair(null(), KPResult::Err(kpString(str("called | with first not an int")))); } - if !params[1].is_int() { return make_pair(null(), KPResult::Err(kpString(str("called | with second not an int")))); } - return make_pair(null(), KPResult::Ok(kpInt(params[0].get_int() | params[1].get_int()))) - })); - env->set(str("<<"), make_builtin_combiner(str("<<"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { - if params.size != 2 { - return make_pair(null(), KPResult::Err(kpString(str("Need 2 params to <<")))) - } - if !params[0].is_int() { return make_pair(null(), KPResult::Err(kpString(str("called << with first not an int")))); } - if !params[1].is_int() { return make_pair(null(), KPResult::Err(kpString(str("called << with second not an int")))); } - return make_pair(null(), KPResult::Ok(kpInt(params[0].get_int() << params[1].get_int()))) - })); - env->set(str(">>"), make_builtin_combiner(str(">>"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { - if params.size != 2 { - return make_pair(null(), KPResult::Err(kpString(str("Need 2 params to >>")))) - } - if !params[0].is_int() { return make_pair(null(), KPResult::Err(kpString(str("called >> with first not an int")))); } - if !params[1].is_int() { return make_pair(null(), KPResult::Err(kpString(str("called >> with second not an int")))); } - return make_pair(null(), KPResult::Ok(kpInt(params[0].get_int() >> params[1].get_int()))) - })); - - env->set(str("="), make_builtin_combiner(str("="), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { - if params.size <= 1 { - return make_pair(null(), KPResult::Err(kpString(str("Need 2 or more params to =")))) - } - for (var i = 0; i < params.size - 1; i++;) { - if !(params[i].equals(params[i+1])) { - return make_pair(null(), KPResult::Ok(kpBool(false))) - } - } - return make_pair(null(), KPResult::Ok(kpBool(true))) - })); - env->set(str("!="), make_builtin_combiner(str("!="), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { - if params.size <= 1 { - return make_pair(null(), KPResult::Err(kpString(str("Need 2 or more params to !=")))) - } - for (var i = 0; i < params.size - 1; i++;) { - if (params[i].equals(params[i+1])) { - return make_pair(null(), KPResult::Ok(kpBool(false))) - } - } - return make_pair(null(), KPResult::Ok(kpBool(true))) - })); - env->set(str("<"), make_builtin_combiner(str("<"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { - if params.size <= 1 { - return make_pair(null(), KPResult::Err(kpString(str("Need 2 or more params to <")))) - } - for (var i = 0; i < params.size - 1; i++;) { - if !(params[i].lt(params[i+1])) { - return make_pair(null(), KPResult::Ok(kpBool(false))) - } - } - return make_pair(null(), KPResult::Ok(kpBool(true))) - })); - env->set(str("<="), make_builtin_combiner(str("<="), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { - if params.size <= 1 { - return make_pair(null(), KPResult::Err(kpString(str("Need 2 or more params to <=")))) - } - for (var i = 0; i < params.size - 1; i++;) { - if !(params[i].lt(params[i+1])) && !(params[i].equals(params[i+1])) { - return make_pair(null(), KPResult::Ok(kpBool(false))) - } - } - return make_pair(null(), KPResult::Ok(kpBool(true))) - })); - env->set(str(">"), make_builtin_combiner(str(">"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { - if params.size <= 1 { - return make_pair(null(), KPResult::Err(kpString(str("Need 2 or more params to >")))) - } - for (var i = 0; i < params.size - 1; i++;) { - if params[i].lt(params[i+1]) || params[i].equals(params[i+1]) { - return make_pair(null(), KPResult::Ok(kpBool(false))) - } - } - return make_pair(null(), KPResult::Ok(kpBool(true))) - })); - env->set(str(">="), make_builtin_combiner(str(">="), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { - if params.size <= 1 { - return make_pair(null(), KPResult::Err(kpString(str("Need 2 or more params to >=")))) - } - for (var i = 0; i < params.size - 1; i++;) { - if params[i].lt(params[i+1]) { - return make_pair(null(), KPResult::Ok(kpBool(false))) - } - } - return make_pair(null(), KPResult::Ok(kpBool(true))) - })); - - env->set(str("and"), make_builtin_combiner(str("and"), 0, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { - for (var i = 0; i < params.size; i++;) { - var ip = EVAL(dynamic_env, params[i]) - if is_err(ip) { return make_pair(null(), ip); } - var ipv = get_value(ip) - if !ipv.is_truthy() || i == params.size - 1 { - return make_pair(null(), ip) - } - } - return make_pair(null(), KPResult::Ok(kpFalse())) - })); - env->set(str("or"), make_builtin_combiner(str("or"), 0, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { - for (var i = 0; i < params.size; i++;) { - var ip = EVAL(dynamic_env, params[i]) - if is_err(ip) { return make_pair(null(), ip); } - var ipv = get_value(ip) - if ipv.is_truthy() || i == params.size - 1 { - return make_pair(null(), ip) - } - } - return make_pair(null(), KPResult::Ok(kpFalse())) - })); - - env->set(str("pr-str"), make_builtin_combiner(str("pr-str"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { - return make_pair(null(), str_wrapper(params, dynamic_env, " ", true)) - })); - env->set(str("str"), make_builtin_combiner(str("str"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { - return make_pair(null(), str_wrapper(params, dynamic_env, "", false)) - })); - env->set(str("prn"), make_builtin_combiner(str("prn"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { - var to_print = str_wrapper(params, dynamic_env, " ", true) - if is_err(to_print) { return make_pair(null(), to_print); } - println(get_value(to_print).get_string()) - return make_pair(null(), KPResult::Ok(kpNil())) - })); - env->set(str("println"), make_builtin_combiner(str("println"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { - var to_print = str_wrapper(params, dynamic_env, " ", false) - if is_err(to_print) { return make_pair(null(), to_print); } - println(get_value(to_print).get_string()) - return make_pair(null(), KPResult::Ok(kpNil())) - })); - - env->set(str("meta"), make_builtin_combiner(str("meta"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { - if params.size != 1 { - return make_pair(null(), KPResult::Err(kpString(str("meta called with not one argument")))) - } else { - if params[0].meta != null() { - return make_pair(null(), KPResult::Ok(*params[0].meta)) - } else { - return make_pair(null(), KPResult::Ok(kpNil())) - } - } - })); - env->set(str("with-meta"), make_builtin_combiner(str("with-meta"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { - if params.size != 2 { - return make_pair(null(), KPResult::Err(kpString(str("with-meta called with not two arguments")))) - } else { - var new_meta = new() - new_meta->copy_construct(¶ms[1]) - var new_value = params[0].deep_clone(); - new_value.meta = new_meta - return make_pair(null(), KPResult::Ok(new_value)) - } - })); - - env->set(str("wrap"), make_builtin_combiner(str("wrap"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { - if params.size != 1 { - return make_pair(null(), KPResult::Err(kpString(str("wrap called with not one argument")))) - } - match (params[0].internal) { - KPValue_int::Combiner(c) { - var to_ret = c; - to_ret.wrap_level++ - return make_pair(null(), KPResult::Ok(nmMV(KPValue_int::Combiner(to_ret)))) - } - KPValue_int::BuiltinCombiner(c) { - var to_ret = c; - to_ret.wrap_level++ - return make_pair(null(), KPResult::Ok(nmMV(KPValue_int::BuiltinCombiner(to_ret)))) - } - } - return make_pair(null(), KPResult::Err(kpString(str("wrap called with not combiner ") + pr_str(params[0], true)))) - })); - env->set(str("unwrap"), make_builtin_combiner(str("unwrap"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { - if params.size != 1 { - return make_pair(null(), KPResult::Err(kpString(str("unwrap called with not one argument")))) - } - return make_pair(null(), unwrap(params[0])) - })); - - env->set(str("error"), make_builtin_combiner(str("error"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { - if params.size != 1 { - return make_pair(null(), KPResult::Err(kpString(str("error called with not one argument")))) - } - return make_pair(null(), KPResult::Err(params[0])) - })); - - env->set(str("recover"), make_builtin_combiner(str("recover"), 0, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { - if params.size != 3 { - return make_pair(null(), KPResult::Err(kpString(str("recover called with not three arguments")))) - } - var data = EVAL(dynamic_env, params[0]) - if is_err(data) { - if !params[1].is_symbol() { - return make_pair(null(), KPResult::Err(kpString(str("recover called with not symbol as middle")))) - } - var new_env = new()->construct(dynamic_env) - new_env->set(params[1].get_symbol_text(), get_err(data)) - return make_pair(null(), EVAL(new_env, params[2])) - } - return make_pair(null(), data) - })); - - var add_grammer_rule_helper: fun(ref Grammer, str, vec, KPValue, fun(ref KPValue, ref vec): KPResult): KPResult = fun(grammar: ref Grammer, nonterminal_str: str, rule: vec, data: KPValue, f: fun(ref KPValue, ref vec): KPResult): KPResult { - var int_rule = vec() - for (var i = 0; i < rule.size; i++;) { - if rule[i].is_int() { - int_rule.add(rule[i].get_int()) - } else if rule[i].is_symbol() { - var sub_nonterminal_idx = grammar.nonterminal_names.find(rule[i].get_symbol_text()) - if sub_nonterminal_idx == -1 { - return KPResult::Err(kpString(str("Couldn't find nonterminal: ") + rule[i].get_symbol_text())) - } - var sub_nonterminal = -1*(sub_nonterminal_idx+1) - int_rule.add(sub_nonterminal) - } else if rule[i].is_string() { - int_rule.add(grammar.add_terminal(rule[i].get_string(), kpNil(), fun(f: ref KPValue, input: ref str, l: int, r: int): KPResult { - return KPResult::Ok(kpString(input.slice(l,r))) - })) - } else if rule[i].is_array() { - // A sequence! - var sub_rule_names = nonterminal_str + "_seq_" + new_tmp() - var inner_rule = add_grammer_rule_helper(grammar, sub_rule_names, rule[i].get_array_rc().get(), kpNil(), fun(_: ref KPValue, seq: ref vec): KPResult { - var to_ret = vec() - for (var i = 0; i < seq.size; i++;) { - if is_err(seq[i]) { - return seq[i] - } - to_ret.add(get_value(seq[i])) - } - return KPResult::Ok(kpArray(to_ret)) - }) - if is_err(inner_rule) { - return inner_rule - } - int_rule.add(get_value(inner_rule).get_int()) - } else { - match (rule[i].internal) { - KPValue_int::BuiltinCombiner(f) { - if f.name == "+" || f.name == "*" { - if int_rule.size == 0 { - return KPResult::Err(kpString(str("add_grammar_rule has + or * in first position, with nothing to repeat"))) - } - var current = int_rule.last() - var sub_rule_names = nonterminal_str + "_" + new_tmp() - var new = grammar.add_to_or_create_nonterminal(sub_rule_names + "_one_or_more", vec(current), kpNil(), fun(f: ref KPValue, x: ref vec): KPResult { - if is_err(x[0]) { return x[0]; } - return KPResult::Ok(kpArray(vec(get_value(x[0])))) - }) - grammar.add_to_nonterminal(new, vec(current, new), kpNil(), fun(f: ref KPValue, x: ref vec): KPResult { - if is_err(x[0]) { return x[0]; } - if is_err(x[1]) { return x[1]; } - return KPResult::Ok(kpArray(vec(get_value(x[0])) + get_value(x[1]).get_array_rc().get())) - }) - if f.name == "*" { - new = grammar.add_to_or_create_nonterminal(sub_rule_names + "_zero_or_more", vec(new), kpNil(), fun(f: ref KPValue, x: ref vec): KPResult { - if is_err(x[0]) { return x[0]; } - return KPResult::Ok(get_value(x[0])) - }) - grammar.add_to_nonterminal(new, vec(), kpNil(), fun(f: ref KPValue, x: ref vec): KPResult { - return KPResult::Ok(kpArray(vec())) - }) - } - int_rule.last() = new - continue - } - } - } - return KPResult::Err(kpString(str("add_grammar_rule called with not symbol, int, or string in rule"))) - } - } - return KPResult::Ok(kpInt(grammar.add_to_or_create_nonterminal(nonterminal_str, int_rule, data, f))) - } - - env->set(str("read-string"), make_builtin_combiner(str("read-string"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { - if params.size != 1 && params.size != 3 { - return make_pair(null(), KPResult::Err(kpString(str("read-string with not a single string, or string, grammer array, and start_symbol")))) - } else { - if !params[0].is_string() { - return make_pair(null(), KPResult::Err(kpString(str("read-string with not a single string")))) - } - if params.size == 1 { - return make_pair(null(), READ(grammar, params[0].get_string())) - } else { - if !params[1].is_array() { - return make_pair(null(), KPResult::Err(kpString(str("read-string with second param not an array")))) - } - var grammar.construct(): Grammer - - var gram_arr = params[1].get_array_rc().get() - for (var i = 0; i < gram_arr.size; i++;) { - if !gram_arr[i].is_array() { - return make_pair(null(), KPResult::Err(kpString(str("read-string with second param not containing a sub array at index: ") + i))) - } - var inner_arr = gram_arr[i].get_array_rc().get() - if !inner_arr[0].is_symbol() { - return make_pair(null(), KPResult::Err(kpString(str("read-string with second param not containing a sub array : ") + i + " index 0 not symbol"))) - } - var nonterminal_str = inner_arr[0].get_symbol_text() - if !inner_arr[1].is_array() { - return make_pair(null(), KPResult::Err(kpString(str("read-string with second param not containing a sub array : ") + i + " index 1 not array"))) - } - var rule = inner_arr[1].get_array_rc().get() - var result = add_grammer_rule_helper(grammar, nonterminal_str, rule, inner_arr[2], fun(f: ref KPValue, x: ref vec): KPResult { - var params = vec() - for (var j = 0; j < x.size; j++;) { - if is_err(x[j]) { - return x[j] - } - params.add(get_value(x[j])) - } - var unwrapped_f = unwrap(f) - if is_err(unwrapped_f) { - return unwrapped_f - } - return function_call(get_value(unwrapped_f), params, kpEnv(null())) - }) - if is_err(result) { - return make_pair(null(), result) - } - } - - if !params[2].is_symbol() { - return make_pair(null(), KPResult::Err(kpString(str("read-string with third param not a symbol")))) - } - var start_symbol_idx = grammar.nonterminal_names.find(params[2].get_symbol_text()) - if start_symbol_idx == -1 { - return make_pair(null(), KPResult::Err(kpString(str("Couldn't find nonterminal to make start symbol: ") + params[2].get_symbol_text()))) - } - grammar.set_start_symbol((-1*start_symbol_idx)-1) - println("Doing actual reading with new grammer of " + params[0].get_string()) - println("With grammer:\n" + grammar.to_string()) - return make_pair(null(), READ(grammar, params[0].get_string())) - } - } - })); - env->set(str("slurp"), make_builtin_combiner(str("slurp"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { - if params.size != 1 { - return make_pair(null(), KPResult::Err(kpString(str("slurp with not a single string")))) - } else { - if !params[0].is_string() { - return make_pair(null(), KPResult::Err(kpString(str("slurp with not a single string")))) - } - if !file_exists(params[0].get_string()) { - return make_pair(null(), KPResult::Err(kpString(str("slurp with bad path ") + params[0].get_string()))) - } - return make_pair(null(), KPResult::Ok(kpString(read_file(params[0].get_string())))) - } - })); - env->set(str("get_line"), make_builtin_combiner(str("get_line"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { - if params.size != 1 { - return make_pair(null(), KPResult::Err(kpString(str("get_line with not a single string")))) - } else { - if !params[0].is_string() { - return make_pair(null(), KPResult::Err(kpString(str("get_line with not a single string")))) - } - return make_pair(null(), KPResult::Ok(kpString(get_line(params[0].get_string(), 1024)))) - } - })); - env->set(str("write_file"), make_builtin_combiner(str("write_file"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { - if params.size != 2 { - return make_pair(null(), KPResult::Err(kpString(str("write_file with not a two params")))) - } else { - if !params[0].is_string() { - return make_pair(null(), KPResult::Err(kpString(str("write_file with first param not a (path) string")))) - } - if params[1].is_string() { - write_file(params[0].get_string(), params[1].get_string()) - } else if params[1].is_array() { - var arc = params[1].get_array_rc() - var size = arc.get().size - var out_vec = vec() - for (var i = 0; i < size; i++;) { - if !arc.get()[i].is_int() { - return make_pair(null(), KPResult::Err(kpString(str("write_file with vec member ") + i + "(" + pr_str(arc.get()[i], true) + ") isn't int"))) - } - var int_out = arc.get()[i].get_int() - if int_out < 0 || int_out > 255 { - return make_pair(null(), KPResult::Err(kpString(str("write_file with vec member ") + i + "(" + int_out + ") is out of 0-255 byte range " + int_out))) - } - out_vec.add((int_out) cast char) - } - write_file_binary(params[0].get_string(), out_vec) - } else { - return make_pair(null(), KPResult::Err(kpString(str("write_file with second param not a string or array")))) - } - return make_pair(null(), KPResult::Ok(kpNil())) - } - })); - env->set(str("empty_env"), kpEnv(new()->construct())) - - // Launch into new kraken for interface and self-hosting features - var params = vec() - for (var i = 0; i < argc; i++;) { - params.add(kpString(str(argv[i]))) - } - env->set(str("*ARGV*"), kpArray(params)) - println(rep(grammar, env, str("(eval (read-string (slurp \"./prelude.kp\")))"))) - return 0 -} diff --git a/kraken.krak b/kraken.krak deleted file mode 100644 index 7c8c14d..0000000 --- a/kraken.krak +++ /dev/null @@ -1,220 +0,0 @@ -import io:* -import grammer:* -import lexer:* -import parser:* -import str:* -import util:* -import symbol:* -import tree:* -import serialize:* -import interpreter:* -import bytecode_generator:* -import os:* -import ast_transformation:* -import importer:* -import adt_lower:* -import obj_lower:* -import defer_lower:* -import function_value_lower:* -import ref_lower:* -import ctce_lower:* -import address_of_ensure_variable_lower:* -import c_line_control:* -import node_counter:* -import c_generator:* -import vec:* -import set:* - -fun main(argc: int, argv: **char):int { - var curr_time = get_time() - // delay construction until we either load it or copy construct it - var gram: grammer - var base_dir = str("/").join(str(argv[0]).split('/').slice(0,-2)) - var file_name = base_dir + "/krakenGrammer.kgm" - var compiled_name = file_name + str(".comp_new") - var compiled_version = 1 - var file_contents = read_file(file_name) - var loaded_and_valid = false - var doing_repl = false - - if (argc <= 1) { - println("No input file!\n Call with one argument (the input file), or two arguments (input file and output name)\n Falling into REPL...") - compiled_name += ".expr" - file_contents = str("RealGoal = boolean_expression ;\n") + file_contents - doing_repl = true - } else if (str(argv[1]) == "-v" || str(argv[1]) == "--version") { - /*var version_c_string = #ctce(fun(): *char {*/ - /*var version_string = str("Self-hosted Kraken compiler \"Kalypso\" - revision ") + from_system_command(str("git rev-list HEAD | wc -l"), 100) +*/ - /*", commit: " + from_system_command(str("git rev-parse HEAD"), 100) +*/ - /*", compile date: " + from_system_command(str("date"), 100) */ - /*return version_string.toCharArray()*/ - /*}())*/ - /*println(version_c_string)*/ - exit(0) - } - var input_file_offset = 1 - var interpret_instead = false - var opt_str = str("-O2") - var line_ctrl = false - var compile_c = true - var positional_args = vec() - var flags = set() - for (var i = 1; i < argc; i++;) { - var arg_str = str(argv[i]) - if (arg_str == "-i") { - interpret_instead = true - } else if (arg_str.length() > 2 && arg_str.slice(0,2) == "-O") { - opt_str = arg_str - } else if (arg_str == "-g") { - line_ctrl = true - } else if (arg_str == "--no-c-compile") { - compile_c = false - } else if (arg_str.length() > 2 && arg_str.first() == '-') { - flags.add(arg_str.slice(1,-1)) - } else { - positional_args.add(arg_str) - } - } - /*positional_args.for_each(fun(i:str) println("positional_arg: " + i);)*/ - flags.for_each(fun(i:str) println("flag: " + i);) - - if (file_exists(compiled_name)) { - var pos = 0 - var binary = read_file_binary(compiled_name) - var saved_version = 0 - unpack(saved_version, pos) = unserialize(binary, pos) - if (saved_version == compiled_version) { - var cached_contents = str() - unpack(cached_contents, pos) = unserialize(binary, pos) - if (cached_contents == file_contents) { - loaded_and_valid = true - pos = gram.unserialize(binary, pos) - } else println("contents different") - } else println("version number different") - } else { - println("cached file does not exist") - } - if (!loaded_and_valid) { - println("Not loaded_and_valid, re-generating and writing out") - // since we now don't construct before hand - gram.copy_construct(&load_grammer(file_contents)) - println("grammer loaded, calculate_first_set") - gram.calculate_first_set() - println("grammer loaded, calculate_state_automaton") - gram.calculate_state_automaton() - println("calculated, writing out") - write_file_binary(compiled_name, serialize(compiled_version) + serialize(file_contents) + serialize(gram)) - println("done writing") - curr_time = split(curr_time, "Grammer regen") - } - - var lex = lexer(gram.terminals) - var parse1.construct(&gram, &lex): parser - /*var parse2.construct(&gram): parser*/ - /*var parse3.construct(&gram): parser*/ - /*var parse4.construct(&gram): parser*/ - /*var parse5.construct(&gram): parser*/ - /*var parse6.construct(&gram): parser*/ - /*var parse7.construct(&gram): parser*/ - /*var parse8.construct(&gram): parser*/ - var ast_pass.construct(): ast_transformation - var parsers = vec(parse1) - /*var parsers = vec(parse1,parse2,parse3,parse4)*/ - /*var parsers = vec(parse1,parse2,parse3,parse4,parse5,parse6)*/ - /*var parsers = vec(parse1,parse2,parse3,parse4,parse5,parse6,parse7,parse8)*/ - - // This is our REPL loop - var scope = _translation_unit(str("stdin")) - if (doing_repl) { - /*var globals = setup_globals(importer.name_ast_map)*/ - while (doing_repl) { - var line = get_line(str("> "), 100) - if (line == "end") - return 0 - var parse = parse1.parse_input(line, str("stdin")) - trim(parse) - var ast_expression = ast_pass.transform_expression(parse, scope, map()) - print_value(evaluate_constant_expression(ast_expression)) - /*print_value(evaluate_with_globals(ast_expression, &globals))*/ - } - } - - var kraken_file_name = positional_args[0] - var executable_name = str(".").join(kraken_file_name.split('.').slice(0,-2)) - if (positional_args.size > 1) - executable_name = positional_args[1] - curr_time = split(curr_time, "Finish setup") - var name_ast_map = import(kraken_file_name, parsers, ast_pass, vec(str(), base_dir + "/stdlib/")) - curr_time = split(curr_time, "Import") - // Passes - /*printlnerr("Counting Nodes")*/ - /*node_counter(&name_ast_map, &ast_pass.ast_to_syntax)*/ - /*printlnerr("Lowering ADTs")*/ - adt_lower(&name_ast_map, &ast_pass.ast_to_syntax) - curr_time = split(curr_time, "Lowering ADTs") - /*printlnerr("Counting Nodes")*/ - /*node_counter(&name_ast_map, &ast_pass.ast_to_syntax)*/ - /*printlnerr("Lowering Objects")*/ - obj_lower(&name_ast_map, &ast_pass.ast_to_syntax) - curr_time = split(curr_time, "Lowering Objects") - /*printlnerr("Counting Nodes")*/ - /*node_counter(&name_ast_map, &ast_pass.ast_to_syntax)*/ - /*printlnerr("Lowering Defer")*/ - defer_lower(&name_ast_map, &ast_pass.ast_to_syntax) - curr_time = split(curr_time, "Lowering Defer") - /*printlnerr("Counting Nodes")*/ - /*node_counter(&name_ast_map, &ast_pass.ast_to_syntax)*/ - // Should come after lowering of ADTs and before lowering of Refs - /*printlnerr("Lowering Function Values (Lambdas, etc)")*/ - function_value_lower(&name_ast_map, &ast_pass.ast_to_syntax) - curr_time = split(curr_time, "Lowering Function Values (Lambdas, etc)") - /*printlnerr("Counting Nodes")*/ - /*node_counter(&name_ast_map, &ast_pass.ast_to_syntax)*/ - /*printlnerr("Lowering Ref")*/ - ref_lower(&name_ast_map, &ast_pass.ast_to_syntax) - curr_time = split(curr_time, "Lowering Ref") - /*printlnerr("Counting Nodes")*/ - /*node_counter(&name_ast_map, &ast_pass.ast_to_syntax)*/ - // Lowers #ctce and the current #ctce_pass - /*printlnerr("Lowering CTCE")*/ - ctce_lower(&name_ast_map, &ast_pass.ast_to_syntax) - curr_time = split(curr_time, "Lowering CTCE") - /*printlnerr("Counting Nodes")*/ - /*node_counter(&name_ast_map, &ast_pass.ast_to_syntax)*/ - // Makes sure that & always takes reference to a variable - /*printlnerr("Lowering & to always have variable")*/ - address_of_ensure_variable_lower(&name_ast_map, &ast_pass.ast_to_syntax) - curr_time = split(curr_time, "Lowering & to always have variable") - if (interpret_instead) { - /*printlnerr("Interpreting!")*/ - /*call_main(name_ast_map)*/ - printlnerr("Generating bytecode!") - var generator.construct(): bytecode_generator - /*var bytecode = generator.generate_bytecode(name_ast_map)*/ - generator.generate_bytecode(name_ast_map) - /*printlnerr(bytecode_to_string(bytecode))*/ - printlnerr("return code is ") - printlnerr(to_string(generator.evaluate())) - } else { - if (line_ctrl) { - printlnerr("running C-specific passes") - printlnerr("running #line") - c_line_control(&name_ast_map, &ast_pass.ast_to_syntax) - } - /*printlnerr("Generating C")*/ - var c_generator.construct(): c_generator - var c_output_pair = c_generator.generate_c(name_ast_map, ast_pass.ast_to_syntax) - var kraken_c_output_name = kraken_file_name + ".c" - write_file(kraken_c_output_name, c_output_pair.first) - curr_time = split(curr_time, "Generating C") - if (compile_c) { - var compile_string = "cc -g " + opt_str + " -Wno-int-to-pointer-cast -Wno-pointer-to-int-cast -Wno-incompatible-pointer-types -std=c99 " + c_output_pair.second + " " + kraken_c_output_name + " -o " + executable_name - printlnerr(compile_string) - system(compile_string) - curr_time = split(curr_time, "Compiling C") - } - } - - return 0 -} - diff --git a/krakenGrammer.kgm b/krakenGrammer.kgm deleted file mode 100644 index 4dcdbb6..0000000 --- a/krakenGrammer.kgm +++ /dev/null @@ -1,158 +0,0 @@ -Goal = translation_unit ; -cast_expression = "\(" WS boolean_expression WS "\)" WS "cast" WS type ; -translation_unit = WS unorderd_list_part WS ; -unorderd_list_part = import WS unorderd_list_part | function WS unorderd_list_part | type_def line_end WS unorderd_list_part | adt_def line_end WS unorderd_list_part | if_comp WS unorderd_list_part | simple_passthrough WS unorderd_list_part | declaration_statement line_end WS unorderd_list_part | compiler_intrinsic line_end WS unorderd_list_part | import | function | type_def line_end | adt_def line_end | if_comp | simple_passthrough | declaration_statement line_end | compiler_intrinsic line_end ; - -type = "ref" WS pre_reffed | pre_reffed ; -pre_reffed = "\*" WS pre_reffed | "void" | "bool" | "char" | "uchar" | "short" | "ushort" | "int" | "uint" | "long" | "ulong" | "float" | "double" | scoped_identifier | scoped_identifier WS template_inst | function_type ; -function_type = "fun" WS "\(" WS opt_type_list WS "\)" WS ":" WS type | "run" WS "\(" WS opt_type_list WS "\)" WS ":" WS type ; -dec_type = ":" WS type ; - -opt_type_list = type_list | ; -template_inst = "<" WS type_list WS ">" ; -type_list = type_list WS "," WS type | type ; - -template_dec = "<" WS template_param_list WS ">" ; -template_param_list = template_param_list WS "," WS template_param | template_param ; -template_param = identifier WS traits | identifier ; - -import = "import" WS identifier line_end | "import" WS identifier WS ":" WS "\*" line_end | "import" WS identifier WS ":" WS identifier_list line_end ; -identifier_list = identifier | identifier WS "," WS identifier_list ; - -# all for optional semicolons -line_break = " -+" ; -# why use line_white here but not below? who knows. It's wayy faster this way. Or maybe when I changed it there was a typing mistake. Noone knows. -line_white = "( | )+" ; -actual_white = line_white | line_break | line_break actual_white | line_white actual_white ; -# Why is WS comment necessary? The null case SHOULD handle it, I think. I'm just a tad worred...... -WS = actual_white | WS comment WS | WS comment | ; -# cpp_comment lets us do stuff like ending a statement with a cpp comment - c comments already work as they don't eat the return - -maybe_line_white = "( | )+" | c_comment | maybe_line_white c_comment | maybe_line_white "( | )+" | ; -line_end = maybe_line_white ";" | maybe_line_white line_break | maybe_line_white cpp_comment ; -#line_end = maybe_line_white ";" | maybe_line_white line_break | maybe_line_white cpp_comment | WS c_comment line_end ; - -# line_end = "( | )+" ";" | "( | )+" line_break | "( | )+" cpp_comment | ";" | line_break | cpp_comment ; -# line_end = WS ";" | WS line_break | WS cpp_comment ; -# line_end = "( | )+" ending | ending ; -# ending = ";" | line_break | cpp_comment ; - -if_comp = "__if_comp__" WS identifier WS statement ; -#if_comp = "__if_comp__" WS identifier WS if_comp_pred ; -#if_comp_pred = code_block | simple_passthrough ; - -simple_passthrough = "simple_passthrough" WS passthrough_params WS triple_quoted_string ; -passthrough_params = "\(" WS in_passthrough_params WS ":" WS out_passthrough_params WS ":" WS opt_string WS "\)" | ; -in_passthrough_params = opt_param_assign_list ; -out_passthrough_params = opt_param_assign_list ; -opt_param_assign_list = param_assign_list | ; -param_assign_list = param_assign WS "," WS param_assign_list | param_assign ; -param_assign = identifier WS "=" WS identifier | identifier ; -opt_string = string | ; - -triple_quoted_string = "\"\"\"((\"\"(`|[0-9]|-|=| |[a-z]|\[|]|\\|;|'| -|,|.|/|~|!|@|#|$|%|^|&|\*|\(|\)|_|\+|[A-Z]|{|}|\||:|<|>|\?| )+)|(\"(`|[0-9]|-|=| |[a-z]|\[|]|\\|'| -|,|.|/|~|!|@|#|$|%|^|&|\*|\(|\)|_|\+|[A-Z]|{|}|\||:|<|>|\?| )+))*(`|[0-9]|-|=| |[a-z]|\[|]|\\|;|'| -|,|.|/|~|!|@|#|$|%|^|&|\*|\(|\)|_|\+|[A-Z]|{|}|\||:|<|>|\?| )*(((`|[0-9]|-|=| |[a-z]|\[|]|\\|;|'| -|,|.|/|~|!|@|#|$|%|^|&|\*|\(|\)|_|\+|[A-Z]|{|}|\||:|<|>|\?| )+\")|((`|[0-9]|-|=| |[a-z]|\[|]|\\|;|'| -|,|.|/|~|!|@|#|$|%|^|&|\*|\(|\)|_|\+|[A-Z]|{|}|\||:|<|>|\?| )+\"\")|((`|[0-9]|-|=| |[a-z]|\[|]|\\|;|'| -|,|.|/|~|!|@|#|$|%|^|&|\*|\(|\)|_|\+|[A-Z]|{|}|\||:|<|>|\?| )+))*\"\"\"" ; - -#identifier = alpha_alphanumeric ; -identifier = augmented_alpha_alphanumeric ; -scope_op = ":" ":" ; -scoped_identifier = scoped_identifier WS scope_op WS identifier | identifier ; - -#Note that to prevent confilct with nested templates (T>) right_shift is a nonterminal contructed as follows -right_shift = ">" ">" ; -overloadable_operator = "\+" | "-" | "\*" | "/" | "%" | "^" | "&" | "\|" | "~" | "!" | "," | "=" | "\+\+" | "--" | "<<" | "<" | ">" | "<=" | ">=" | right_shift | "==" | "!=" | "&&" | "\|\|" | "\+=" | "-=" | "/=" | "%=" | "^=" | "&=" | "\|=" | "\*=" | "<<=" | ">>=" | "->" | "\(" "\)" | "\[]" | "\[]=" ; -func_identifier = identifier | identifier overloadable_operator ; -# allow omitting of return type (automatic void) - -# HACKY - typed_return has it's own internal whitespace as to not make WS typed_return-reduces to null WS ambigious -typed_return = WS dec_type | ; -function = "ext" WS "fun" WS func_identifier WS "\(" WS opt_typed_parameter_list WS "\)" typed_return | "fun" WS func_identifier WS template_dec WS "\(" WS opt_typed_parameter_list WS "\)" typed_return WS statement | "fun" WS func_identifier WS "\(" WS opt_typed_parameter_list WS "\)" typed_return WS statement ; -lambda = "fun" WS "\(" WS opt_typed_parameter_list WS "\)" typed_return WS statement ; - -opt_typed_parameter_list = typed_parameter_list | typed_parameter_list WS "," WS "..." | ; -typed_parameter_list = typed_parameter_list WS "," WS typed_parameter | typed_parameter ; -typed_parameter = identifier WS dec_type ; - -opt_parameter_list = parameter_list | ; -parameter_list = parameter_list WS "," WS parameter | parameter ; -parameter = boolean_expression ; - -obj_nonterm = "obj" | "uni" ; -type_def = obj_nonterm WS identifier WS template_dec WS "{" WS declaration_block WS "}" | obj_nonterm WS identifier WS "{" WS declaration_block WS "}" | obj_nonterm WS identifier WS template_dec WS traits WS "{" WS declaration_block WS "}" | obj_nonterm WS identifier WS traits WS "{" WS declaration_block WS "}" ; - -declaration_block = declaration_statement line_end WS declaration_block | function WS declaration_block | declaration_statement line_end | function | ; -traits = "\(" WS trait_list WS "\)" ; -trait_list = trait_list WS "," WS scoped_identifier | scoped_identifier ; - -adt_nonterm = "adt" ; -adt_def = adt_nonterm WS identifier WS "{" WS adt_option_list WS "}" | adt_nonterm WS identifier WS template_dec WS "{" WS adt_option_list WS "}" ; -adt_option_list = adt_option | adt_option WS "," WS adt_option_list ; -adt_option = identifier | identifier WS dec_type ; - -if_statement = "if" WS boolean_expression WS statement | "if" WS boolean_expression WS statement WS "else" WS statement ; - -match_statement = "match" WS "\(" WS boolean_expression WS "\)" WS "{" WS case_statement_list WS "}" ; -case_statement_list = case_statement WS case_statement_list | case_statement ; -case_statement = scoped_identifier WS "\(" WS identifier WS "\)" WS statement | scoped_identifier WS "\(" WS "\)" WS statement ; - -while_loop = "while" WS boolean_expression WS statement ; - -for_loop = "for" WS "\(" WS statement WS boolean_expression line_end WS statement WS "\)" WS statement ; - -return_statement = "return" | "return" WS boolean_expression ; - -code_block = "{" WS statement_list WS "}" | "{" WS "}" ; - -statement_list = statement_list WS statement | statement ; -statement = if_statement | match_statement | while_loop | for_loop | return_statement line_end | boolean_expression line_end | assignment_statement line_end | declaration_statement line_end | code_block | if_comp | simple_passthrough | break_statement | continue_statement | defer_statement ; -break_statement = "break" ; -continue_statement = "continue" ; -defer_statement = "defer" WS statement ; -function_call = unarad "\(" WS opt_parameter_list WS "\)" ; - -compiler_intrinsic = "#" identifier WS "\(" WS opt_parameter_list WS "\)" | "#" identifier WS "<" WS type_list WS ">" ; - -boolean_expression = boolean_expression WS "\|\|" WS and_boolean_expression | and_boolean_expression ; -and_boolean_expression = and_boolean_expression WS "&&" WS bitwise_or | bitwise_or ; -bitwise_or = bitwise_or WS "\|" WS bitwise_xor | bitwise_xor ; -bitwise_xor = bitwise_xor WS "^" WS bitwise_and | bitwise_and ; -bitwise_and = bitwise_and WS "&" WS bool_exp | bool_exp ; -bool_exp = expression WS comparator WS expression | expression ; -comparator = "==" | "<=" | ">=" | "!=" | "<" | ">" ; - -expression = expression WS "<<" WS term | expression WS right_shift WS shiftand | shiftand ; -shiftand = shiftand WS "-" WS term | shiftand WS "\+" WS term | term ; -term = term WS "/" WS factor | term WS "\*" WS factor | term WS "%" WS factor | factor ; -factor = "\+\+" WS unarad | unarad WS "\+\+" | "--" WS unarad | unarad WS "--" | "\+" WS unarad | "-" WS unarad | "!" WS unarad | "~" WS unarad | "\*" WS unarad | "&" WS unarad | unarad ; -unarad = number | scoped_identifier | scoped_identifier WS template_inst | access_operation | function_call | compiler_intrinsic | bool | string | character | "\(" WS boolean_expression WS "\)" | unarad WS "\[" WS expression WS "]" | lambda | cast_expression ; -cast_expression = "\(" WS boolean_expression WS "\)" WS "cast" WS type ; -number = integer | floating_literal ; -access_operation = unarad WS "." WS identifier | unarad WS "->" WS identifier | unarad WS "." WS identifier WS template_inst | unarad WS "->" WS identifier WS template_inst ; - -assignment_statement = factor WS "=" WS boolean_expression | factor WS "\+=" WS boolean_expression | factor WS "-=" WS boolean_expression | factor WS "\*=" WS boolean_expression | factor WS "/=" WS boolean_expression | factor WS "^=" WS boolean_expression ; -# if it's being assigned to, we allow type inferencing -declaration_statement = "var" WS identifier WS "=" WS boolean_expression | "var" WS identifier WS dec_type WS "=" WS boolean_expression | "var" WS identifier WS dec_type | "ext" WS "var" WS identifier WS dec_type | "var" WS identifier WS "." WS identifier WS "\(" WS opt_parameter_list WS "\)" WS dec_type ; -hexadecimal = "0x([0-9]|[a-f])+" ; -integer = "[0-9]+u?(c|s|l)?" | hexadecimal ; -floating_literal = "[0-9]+.[0-9]+(f|d)?" ; -bool = "true" | "false" ; -character = "'(`|[0-9]|-|=|(\\t)|[a-z]|\[|]|(\\\\)|;|(\\')|(\\n)|,|.|/|~|!|@|#|$|%|^|&|\*|\(|\)|_|\+|[A-Z]|{|}|\||:|\"|<|>|\?| |(\\0))'" ; - -keywords_also_identifiers = "obj" | "def" | "fun" | "run" | "var" | "ref" | "adt" | "cast" | "import" | "simple_passthrough" ; -alpha_alphanumeric = "([a-z]|[A-Z]|_)([a-z]|[A-Z]|_|[0-9])*" ; -augmented_alpha_alphanumeric = alpha_alphanumeric augmented_alpha_alphanumeric | keywords_also_identifiers augmented_alpha_alphanumeric | alpha_alphanumeric | keywords_also_identifiers ; - -# note the hacks around \things. Hmm, I feel like it actually shouldn't be like this. Added \\\* because I want to come back later -string = triple_quoted_string | "\"([#-[]| |[]-~]|(\\\\)|(\\n)|(\\t)|(\\\*)|(\\0)| -|[ -!]|(\\\"))*\"" ; -comment = cpp_comment | c_comment ; -cpp_comment = "//[ -~]* -" ; -c_comment = "(/\*/*\**(([ -)]|[0-~]|[+-.]| | -)/*\**)+\*/)|(/\*\*/)" ; diff --git a/kraken_cloc_definition.txt b/kraken_cloc_definition.txt deleted file mode 100644 index fc1a2e9..0000000 --- a/kraken_cloc_definition.txt +++ /dev/null @@ -1,6 +0,0 @@ -Kraken - filter remove_matches ^\s*// - filter remove_inline //.*$ - filter call_regexp_common C - extension krak - 3rd_gen_scale 1.0 diff --git a/llvm.krak b/llvm.krak deleted file mode 100644 index 09890f4..0000000 --- a/llvm.krak +++ /dev/null @@ -1,78 +0,0 @@ -import vector_literals: * -import string:* -import io:* -import mem: * -import util: * -import os: * - -obj LLVMModule {} -obj LLVMType {} -obj LLVMValue {} -obj LLVMGenericValue {} -obj LLVMBasicBlock {} -obj LLVMBuilder {} -obj LLVMExecutionEngine {} - -ext fun LLVMModuleCreateWithName(ModuleID: *char): *LLVMModule -ext fun LLVMInt32Type(): *LLVMType -ext fun LLVMFunctionType(ret_type: *LLVMType, param_types: **LLVMType, ParamCount: uint, isVarArg: int): *LLVMType -ext fun LLVMAddFunction(mod: *LLVMModule, name: *char, rettype: *LLVMType): *LLVMValue -ext fun LLVMAppendBasicBlock(func: *LLVMValue, name: *char): *LLVMBasicBlock -ext fun LLVMCreateBuilder(): *LLVMBuilder -ext fun LLVMPositionBuilderAtEnd(builder: *LLVMBuilder, block: *LLVMBasicBlock) -ext fun LLVMGetParam(func: *LLVMValue, num: int): *LLVMValue -ext fun LLVMBuildAdd(builder: *LLVMBuilder, first: *LLVMValue, second: *LLVMValue, name: *char): *LLVMValue -ext fun LLVMBuildRet(builder: *LLVMBuilder, value: *LLVMValue): *LLVMValue -ext fun LLVMVerifyModule(M: *LLVMModule, Action: int, error: **char): int -var LLVMAbortProcessAction = 1 -ext fun LLVMDisposeMessage(error: *char) -ext fun LLVMLinkInMCJIT() -/*ext fun LLVMInitializeNativeTarget(): bool*/ -ext fun LLVMInitializeX86Target(): bool -ext fun LLVMCreateExecutionEngineForModule(engine: **LLVMExecutionEngine, M: *LLVMModule, error: **char): int -ext fun LLVMCreateGenericValueOfInt(Ty: *LLVMType, N: ulong, IsSigned: int): *LLVMGenericValue -ext fun LLVMRunFunction(EE: *LLVMExecutionEngine, F: *LLVMValue, NumArgs: uint, Args: **LLVMGenericValue): *LLVMGenericValue -ext fun LLVMGenericValueToInt(GenVal: *LLVMGenericValue, IsSigned: int): ulong - -#link("LLVM-3.8") - -fun main(argc: int, argv: **char): int { - var mod = LLVMModuleCreateWithName("my_module") - var param_types = vector(LLVMInt32Type(), LLVMInt32Type()) - var ret_type = LLVMFunctionType(LLVMInt32Type(), param_types.getBackingMemory(), (2) cast uint, 0) - var sum = LLVMAddFunction(mod, "sum", ret_type) - var entry = LLVMAppendBasicBlock(sum, "entry") - var builder = LLVMCreateBuilder() - LLVMPositionBuilderAtEnd(builder, entry) - var tmp = LLVMBuildAdd(builder, LLVMGetParam(sum,0), LLVMGetParam(sum,1), "tmp") - LLVMBuildRet(builder, tmp) - - var error = null() - LLVMVerifyModule(mod, LLVMAbortProcessAction, &error) - LLVMDisposeMessage(error) - - var engine: *LLVMExecutionEngine - error = null() - LLVMLinkInMCJIT() - /*LLVMInitializeNativeTarget()*/ - // LLVMInitializeNativeTarget is static/inline :/ - LLVMInitializeX86Target() - - if (LLVMCreateExecutionEngineForModule(&engine, mod, &error)) { - error("Failed to create execution engine") - } - if (error) { - println(string("error: ") + error) - LLVMDisposeMessage(error) - exit(1) - } - if (argc < 3) error(string("usage: ") + argv[0] + " x y") - var x = string_to_num(string(argv[1])) - var y = string_to_num(string(argv[2])) - var args = vector(LLVMCreateGenericValueOfInt(LLVMInt32Type(), x, 0), - LLVMCreateGenericValueOfInt(LLVMInt32Type(), y, 0)) - var res = LLVMRunFunction(engine, sum, 2u, args.getBackingMemory()) - println(string("result: ") + (LLVMGenericValueToInt(res, 0)) cast int) - return 0 -} - diff --git a/mal.krak b/mal.krak deleted file mode 100644 index 8c4c70e..0000000 --- a/mal.krak +++ /dev/null @@ -1,1578 +0,0 @@ -import io:* -import str:* -import vec:* -import vec_literals:* -import util:* -import map:* - -fun tokenize(s: str): vec { - var to_ret = vec() - for (var i = 0; i < s.length(); i++;) { - if (s[i] == ' ' || s[i] == '\t' || s[i] == ',' || s[i] == '\n') { - i++ - while (i < s.length() && (s[i] == ' ' || s[i] == '\t' || s[i] == ',' || s[i] == '\n')) { - i++; - } - i-- - } else if (i+1 < s.length() && s[i] == '~' && s[i+1] == '@') { - to_ret.add(str("~@")) - i++ - } else if ( s[i] == '[' || s[i] == ']' || s[i] == '{' || s[i] == '}' || s[i] == '(' || s[i] == ')' || s[i] == '\'' || s[i] == '`' || s[i] == '~' || s[i] == '^' || s[i] == '@') { // ' - to_ret.add(str(s[i])) - } else if (s[i] == ';') { - var next_tok = str(s[i]) - i++ - while (i < s.length() && (s[i] != '\n')) { - next_tok += s[i] - i++ - } - i-- - } else if (s[i] == '"') { - var str_start = i - var next_tok = str(s[i]) - i++ - while (i < s.length()) { - next_tok += s[i] - if s[i] == '"' { - var backslash_count = 0 - while ((i-backslash_count)-1 > str_start && s[(i-backslash_count)-1] == '\\') { - backslash_count++ - } - // even number of backslashes - if (backslash_count & 1) == 0 { - break - } - } - i++ - } - to_ret.add(next_tok) - } else { - var next_tok = str(s[i]) - i++ - while (i < s.length() && !( s[i] == ' ' || s[i] == '\t' || s[i] == ',' || s[i] == '\n' || s[i] == '[' || s[i] == ']' || s[i] == '{' || s[i] == '}' || s[i] == '(' || s[i] == ')' || s[i] == '\'' || s[i] == '`' || s[i] == '~' || s[i] == '^' || s[i] == '@' || s[i] == ';')) { // ' - next_tok += s[i] - i++ - } - to_ret.add(next_tok) - i-- - } - } - return to_ret -} - - -fun read_form(tokens: *vec, i: *int): MalResult { - if ((*tokens)[*i] == "(" || (*tokens)[*i] == "[") { - return read_list(tokens, i, (*tokens)[*i] == "[") - } else if ((*tokens)[*i] == "{") { - return read_dict(tokens, i) - } else if ((*tokens)[*i] == "@") { - (*i)++; - var inner = read_form(tokens, i) - if (is_err(inner)) { - return inner - } - return MalResult::Ok(MalValue::List(vec(MalValue::Symbol(str("deref")), get_value(inner)))) - } else if ((*tokens)[*i] == "'") { - (*i)++; - var inner = read_form(tokens, i) - if (is_err(inner)) { - return inner - } - return MalResult::Ok(MalValue::List(vec(MalValue::Symbol(str("quote")), get_value(inner)))) - } else if ((*tokens)[*i] == "`") { - (*i)++; - var inner = read_form(tokens, i) - if (is_err(inner)) { - return inner - } - return MalResult::Ok(MalValue::List(vec(MalValue::Symbol(str("quasiquote")), get_value(inner)))) - } else if ((*tokens)[*i] == "~") { - (*i)++; - var inner = read_form(tokens, i) - if (is_err(inner)) { - return inner - } - return MalResult::Ok(MalValue::List(vec(MalValue::Symbol(str("unquote")), get_value(inner)))) - } else if ((*tokens)[*i] == "~@") { - (*i)++; - var inner = read_form(tokens, i) - if (is_err(inner)) { - return inner - } - return MalResult::Ok(MalValue::List(vec(MalValue::Symbol(str("splice-unquote")), get_value(inner)))) - } else { - return read_atom(tokens, i) - } -} -fun read_dict(tokens: *vec, i: *int): MalResult { - (*i)++; - var values = vec() - while (*i < tokens->size && (*tokens)[*i] != "}") { - var result = read_form(tokens, i) - if (is_err(result)) { - return result - } - values.add(get_value(result)) - } - if (*i == tokens->size) { - return MalResult::Err(MalValue::String(str("unbalanced {"))) - } - (*i)++; - return create_map(values) -} -fun create_map(values: vec): MalResult { - var to_ret = map() - if values.size & 1 == 1 { - return MalResult::Err(MalValue::String(str("odd number of keys/values"))) - } - for (var i = 0; i < values.size; i+=2;) { - to_ret.set(values[i], values[i+1]) - } - return MalResult::Ok(MalValue::Map(to_ret)) -} -fun is_map(m: MalValue): bool { - match (m) { - MalValue::Map(m) { - return true - } - MalValue::Nil() { - return true - } - } - return false -} -fun get_map(m: MalValue): map { - match (m) { - MalValue::Map(m) { - return m - } - MalValue::Nil() { - return map() - } - } - error("can't get_map not a map") -} -fun read_list(tokens: *vec, i: *int, is_vec: bool): MalResult { - var to_ret = vec() - (*i)++; - while (*i < tokens->size && ((!is_vec &&(*tokens)[*i] != ")") || (is_vec &&(*tokens)[*i] != "]"))) { - var result = read_form(tokens, i) - if (is_err(result)) { - return result - } - to_ret.add(get_value(result)) - } - if (*i == tokens->size) { - if is_vec { - return MalResult::Err(MalValue::String(str("unbalanced ["))) - } else { - return MalResult::Err(MalValue::String(str("unbalanced ("))) - } - } - (*i)++; - if is_vec { - return MalResult::Ok(MalValue::Vector(to_ret)) - } else { - return MalResult::Ok(MalValue::List(to_ret)) - } -} -fun read_atom(tokens: *vec, i: *int): MalResult { - var all_num = true - var token = (*tokens)[*i] - (*i)++ - for (var j = 0; j < token.length(); j++;) { - all_num = all_num && ((j == 0 && token[j] == '-' && token.length() > 1) || token[j] >= '0' && token[j] <= '9') - } - if (all_num) { - return MalResult::Ok(MalValue::Int(string_to_num(token))) - } else if (token == "true") { - return MalResult::Ok(MalValue::True()) - } else if (token == "false") { - return MalResult::Ok(MalValue::False()) - } else if (token == "nil") { - return MalResult::Ok(MalValue::Nil()) - } else if (token[0] == '"') { - var to_ret = str() - if token.length() == 1 || token[token.length()-1] != '"' { - return MalResult::Err(MalValue::String(str("unbalanced \""))) //" - } - for (var i = 1; i < token.length()-1; i++;) { - if token[i] == '\\' { - if i == token.length()-2 { - return MalResult::Err(MalValue::String(str("unbalanced \""))) //" - } - if token[i+1] == 'n' { - to_ret += '\n' - } else if token[i+1] == '\\' || token[i+1] == '"' { - to_ret += token[i+1] - } else { - return MalResult::Err(MalValue::String(str("bad string escape"))) - } - // skip - i++ - } else { - to_ret += token[i] - } - } - return MalResult::Ok(MalValue::String(to_ret)) - } else if (token[0] == ':') { - return MalResult::Ok(MalValue::Keyword(token.slice(1,-1))) - } else { - return MalResult::Ok(MalValue::Symbol(token)) - } -} -fun read_str(s: str): MalResult { - var tokens = tokenize(s) - // comment, print nothing - if tokens.size == 0 { - return MalResult::Err(MalValue::String(str(""))) - } - var i = 0 - return read_form(&tokens, &i) -} -adt MalValue { - Nil, - True, - False, - Int: int, - String: str, - Symbol: str, - Keyword: str, - List: vec, - Vector: vec, - Map: map, - Function: MalFunction, - BuiltinFunction: MalBuiltinFunction, - Atom: *MalValue -} -fun equals_MalValue(a: MalValue, b: MalValue): bool { - match (a) { - MalValue::List(d) { match (b) { - MalValue::List(db) { - if d.size != db.size { - return false - } - for (var i = 0; i < d.size; i++;) { - if !equals_MalValue(d[i], db[i]) { - return false - } - } - return true - } - MalValue::Vector(db) { - if d.size != db.size { - return false - } - for (var i = 0; i < d.size; i++;) { - if !equals_MalValue(d[i], db[i]) { - return false - } - } - return true - } - } } - MalValue::Vector(d) { match (b) { - MalValue::List(db) { - if d.size != db.size { - return false - } - for (var i = 0; i < d.size; i++;) { - if !equals_MalValue(d[i], db[i]) { - return false - } - } - return true - } - MalValue::Vector(db) { - if d.size != db.size { - return false - } - for (var i = 0; i < d.size; i++;) { - if !equals_MalValue(d[i], db[i]) { - return false - } - } - return true - } - } } - MalValue::Map(d) { match (b) { MalValue::Map(db) { - if d.size() != db.size() { - return false - } - for (var i = 0; i < d.keys.size; i++;) { - if !db.contains_key(d.keys[i]) || !equals_MalValue(d.values[i], db[d.keys[i]]) { - return false - } - } - return true - } } } - MalValue::String(d) { match (b) { MalValue::String(db) { return d == db; } } } - MalValue::Int(d) { match (b) { MalValue::Int(db) { return d == db; } } } - MalValue::Symbol(d) { match (b) { MalValue::Symbol(db) { return d == db; } } } - MalValue::Keyword(d) { match (b) { MalValue::Keyword(db) { return d == db; } } } - MalValue::Function(d) { match (b) { MalValue::Function(db) { return d == db; } } } - MalValue::BuiltinFunction(d) { match (b) { MalValue::BuiltinFunction(db) { return d == db; } } } - MalValue::Atom(d) { match (b) { MalValue::Atom(db) { return d == db; } } } - MalValue::True() { match (b) { MalValue::True() { return true; } } } - MalValue::False() { match (b) { MalValue::False() { return true; } } } - MalValue::Nil() { match (b) { MalValue::Nil() { return true; } } } - } - return false -} -fun is_keyword(v: MalValue): bool { - match (v) { - MalValue::Keyword(k) { - return true - } - } - return false -} -fun is_keyword_or_string(v: MalValue): bool { - match (v) { - MalValue::Keyword(k) { - return true - } - MalValue::String(s) { - return true - } - } - return false -} -fun get_keyword_or_string_text(v: MalValue): str { - match (v) { - MalValue::Keyword(k) { - return k - } - MalValue::String(s) { - return s - } - } - error("Tried to get_keyword_or_string_text on not a keyword or string!") -} -fun is_list(v: MalValue): bool { - match (v) { - MalValue::List(l) { - return true - } - } - return false -} -fun get_list(v: MalValue): vec { - match (v) { - MalValue::List(l) { - return l - } - } - error("Tried to get list on not a list") -} -fun is_vector(v: MalValue): bool { - match (v) { - MalValue::Vector(v) { - return true - } - } - return false -} -fun is_list_or_vec(v: MalValue): bool { - match (v) { - MalValue::List(l) { - return true - } - MalValue::Vector(v) { - return true - } - MalValue::Nil() { - return true - } - } - return false -} -fun get_list_or_vec(v: MalValue): vec { - match (v) { - MalValue::List(l) { - return l - } - MalValue::Vector(v) { - return v - } - MalValue::Nil() { - return vec() - } - } - error("Tried to get list or vec on not a list or vec") -} -fun is_symbol(v: MalValue): bool { - match (v) { - MalValue::Symbol(s) { - return true - } - } - return false -} -fun is_symbol(v: MalValue, text: *char): bool { - match (v) { - MalValue::Symbol(s) { - return s == text - } - } - return false -} -fun get_symbol_text(v: MalValue): str { - match (v) { - MalValue::Symbol(s) { - return s - } - } - error("get_symbol_text on not symbol") -} -fun is_string(v: MalValue): bool { - match (v) { - MalValue::String(s) { - return true - } - } - return false -} -fun get_string(v: MalValue): str { - match (v) { - MalValue::String(s) { - return s - } - } - error("get_string on not a string") -} -fun is_int(v: MalValue): bool { - match (v) { - MalValue::Int(i) { - return true - } - } - return false -} -fun get_int(v: MalValue): int { - match (v) { - MalValue::Int(i) { - return i - } - } - error("get_int on not an int") -} -fun is_nil(v: MalValue): bool { - match (v) { - MalValue::Nil() { - return true - } - } - return false -} -fun is_atom(v: MalValue): bool { - match (v) { - MalValue::Atom(a) { - return true - } - } - return false -} -fun get_atom(v: MalValue): *MalValue { - match (v) { - MalValue::Atom(a) { - return a - } - } - error("Called get_atom on not an atom") -} -fun is_truthy(v: MalValue): bool { - match (v) { - MalValue::False() { - return false - } - MalValue::Nil() { - return false - } - } - return true -} -fun bool_to_MalValue(b: bool): MalValue { - if b { - return MalValue::True() - } else { - return MalValue::False() - } -} - -fun is_pair(v: MalValue): bool { - return is_list_or_vec(v) && get_list_or_vec(v).size > 0 -} - -fun is_macro_call(ast: MalValue, env: *Env): bool { - if !is_list(ast) { - return false - } - var l = get_list(ast) - if l.size == 0 || !is_symbol(l[0]) { - return false - } - var res = env->get(get_symbol_text(l[0])) - if is_err(res) { - return false - } - var v = get_value(res) - match (v) { - MalValue::Function(f) { - return f.is_macro - } - } - return false -} - -fun macroexpand(ast: MalValue, env: *Env): MalResult { - while is_macro_call(ast, env) { - var l = get_list(ast) - var v = get_value(env->get(get_symbol_text(l[0]))) - match (v) { - MalValue::Function(f) { - var params = l.slice(1,-1) - if (!f.is_variadic && f.parameters.size != params.size) || (f.is_variadic && f.parameters.size > params.size + 1) { - return MalResult::Err(MalValue::String(str("called with the wrong number of parameters"))) - } - env = new()->construct(f.env) - for (var i = 0; i < f.parameters.size; i++;) { - if f.is_variadic && i == f.parameters.size - 1 { - env->set(f.parameters[i], MalValue::List(params.slice(i, -1))) - } else { - env->set(f.parameters[i], params[i]) - } - } - var tmp = *f.body - var tmp2 = EVAL(env, tmp) - if is_err(tmp2) { - return tmp2 - } - ast = get_value(tmp2) - } - } - } - return MalResult::Ok(ast) -} - -fun quasiquote(ast: MalValue): MalValue { - if !is_pair(ast) { - return MalValue::List(vec(MalValue::Symbol(str("quote")), ast)) - } else { - var ast_list = get_list_or_vec(ast) - if is_symbol(ast_list[0], "unquote") { - return ast_list[1] - } else { - if is_pair(ast_list[0]) && is_symbol(get_list_or_vec(ast_list[0])[0], "splice-unquote") { - return MalValue::List(vec(MalValue::Symbol(str("concat")), get_list_or_vec(ast_list[0])[1], quasiquote(MalValue::List(ast_list.slice(1,-1))))) - } else { - return MalValue::List(vec(MalValue::Symbol(str("cons")), quasiquote(ast_list[0]), quasiquote(MalValue::List(ast_list.slice(1,-1))))) - } - } - } -} - -obj Env (Object) { - var data: map - var outer: *Env - fun construct(): *Env { - return construct(null()) - } - fun construct(outer: *Env): *Env { - data.construct() - this->outer = outer - return this - } - fun copy_construct(old: *Env): void { - data.copy_construct(&old->data) - outer = old->outer - } - fun destruct(): void { - data.destruct() - outer = null() - } - fun operator=(other:ref Env):void { - destruct() - copy_construct(&other) - } - fun set(key: str, val: MalValue) { - data.set(key, val) - } - fun find(key: str): *Env { - if (data.contains_key(key)) { - return this - } else if (outer != null()) { - return outer->find(key) - } else { - return null() - } - } - fun get(key: str): MalResult { - var env = find(key) - if (env != null()) { - return MalResult::Ok(env->data.get(key)) - } else { - return MalResult::Err(MalValue::String(str("'") + key + "' not found")) - } - } -} -obj MalBuiltinFunction (Object) { - var fp: fun(vec): MalResult - fun construct(fp: fun(vec): MalResult): *MalBuiltinFunction { - this->fp = fp - return this - } - fun copy_construct(old: *MalBuiltinFunction): void { - this->fp = old->fp - } - fun destruct(): void { - } - fun operator=(other:ref MalBuiltinFunction):void { - destruct() - copy_construct(&other) - } - fun operator==(other: ref MalBuiltinFunction):bool { - return false - } - fun call(params: vec): MalResult { - return fp(params) - } -} -fun make_builtin_function(f: fun(vec): MalResult): MalValue { - var to_ret.construct(f): MalBuiltinFunction - return MalValue::BuiltinFunction(to_ret) -} -obj MalFunction (Object) { - var env: *Env - var parameters: vec - var is_variadic: bool - var is_macro: bool - var body: *MalValue - fun construct(env: *Env, parameters: vec, is_variadic: bool, is_macro: bool, body: MalValue): *MalFunction { - this->env = env - this->parameters.copy_construct(¶meters) - this->is_variadic = is_variadic - this->is_macro = is_macro - this->body = new() - this->body->copy_construct(&body) - return this - } - fun copy_construct(old: *MalFunction): void { - this->env = old->env - this->parameters.copy_construct(&old->parameters) - this->is_variadic = old->is_variadic - this->is_macro = old->is_macro - this->body = new() - this->body->copy_construct(old->body) - } - fun destruct(): void { - this->env = null() - parameters.destruct() - delete(body) - body = null() - } - fun operator=(other:ref MalFunction):void { - destruct() - copy_construct(&other) - } - fun operator==(other: ref MalFunction):bool { - // not sure about env - return env == other.env && parameters == other.parameters && is_variadic == other.is_variadic && is_macro == other.is_macro && equals_MalValue(*body, *other.body) - } - // no call b/c need to do in EVAL for TCO - fun prep_call(params: vec): pair<*Env, MalResult> { - // tco - if (!is_variadic && parameters.size != params.size) || (is_variadic && parameters.size > params.size + 1) { - return make_pair(null(), MalResult::Err(MalValue::String(str("called with the wrong number of parameters")))) - } - var new_env = new()->construct(env) - for (var i = 0; i < parameters.size; i++;) { - if is_variadic && i == parameters.size - 1 { - new_env->set(parameters[i], MalValue::List(params.slice(i, -1))) - } else { - new_env->set(parameters[i], params[i]) - } - } - return make_pair(new_env, MalResult::Ok(*body)) - } -} - -fun function_call(f: MalValue, params: vec): MalResult { - match (f) { - MalValue::BuiltinFunction(f) { - return f.call(params) - } - MalValue::Function(f) { - var call_pair = f.prep_call(params) - if is_err(call_pair.second) { - return call_pair.second - } - return EVAL(call_pair.first, get_value(call_pair.second)) - } - } - return MalResult::Err(MalValue::String(str("trying to apply not a function"))) -} - -adt MalResult { - Ok: MalValue, - Err: MalValue -} -fun is_err(r: MalResult): bool { - match (r) { - MalResult::Err(e) { - return true - } - } - return false -} -fun get_err(r: MalResult): MalValue { - match (r) { - MalResult::Err(e) { - return e - } - } - return MalValue::String(str("not error")) -} -fun get_value(r: MalResult): MalValue { - match (r) { - MalResult::Ok(v) { - return v - } - } - return MalValue::Symbol(str("error")) -} -fun pr_str(v: MalValue, print_readably: bool): str { - match (v) { - MalValue::List(l) { - var to_ret = str("(") - for (var i = 0; i < l.size; i++;) { - if (i != 0) { - to_ret += " " - } - to_ret += pr_str(l[i], print_readably) - } - return to_ret + ")" - } - MalValue::Vector(l) { - var to_ret = str("[") - for (var i = 0; i < l.size; i++;) { - if (i != 0) { - to_ret += " " - } - to_ret += pr_str(l[i], print_readably) - } - return to_ret + "]" - } - MalValue::Map(m) { - var to_ret = str("{") - for (var i = 0; i < m.keys.size; i++;) { - if (i != 0) { - to_ret += " " - } - to_ret += pr_str(m.keys[i], print_readably) - to_ret += str(" ") - to_ret += pr_str(m.values[i], print_readably) - } - return to_ret + "}" - } - MalValue::Int(i) { - return to_string(i) - } - MalValue::String(s) { - if print_readably { - var to_ret = str("\"") //" - for (var i = 0; i < s.length(); i++;) { - if s[i] == '\n' { - to_ret += '\\' - to_ret += 'n' - } else if s[i] == '\\' || s[i] == '"' { - to_ret += '\\' - to_ret += s[i] - } else { - to_ret += s[i] - } - } - return to_ret + "\"" //" - } else { - return s - } - } - MalValue::Symbol(s) { - return s - } - MalValue::Keyword(k) { - return str(":") + k - } - MalValue::BuiltinFunction(f) { - return str("builtin function") - } - MalValue::Function(f) { - return str("function") - } - MalValue::Atom(a) { - return str("(atom ") + pr_str(*a, print_readably) + ")" - } - MalValue::True() { - return str("true") - } - MalValue::False() { - return str("false") - } - MalValue::Nil() { - return str("nil") - } - } - error("can't print") -} - -fun READ(s: str): MalResult { - return read_str(s) -} - -fun eval_ast(env: *Env, ast: MalValue): MalResult { - match (ast) { - MalValue::List(l) { - var to_ret = vec() - for (var i = 0; i < l.size; i++;) { - var mid = EVAL(env, l[i]) - if is_err(mid) { - return mid - } - to_ret.add(get_value(mid)) - } - return MalResult::Ok(MalValue::List(to_ret)) - } - MalValue::Vector(l) { - var to_ret = vec() - for (var i = 0; i < l.size; i++;) { - var mid = EVAL(env, l[i]) - if is_err(mid) { - return mid - } - to_ret.add(get_value(mid)) - } - return MalResult::Ok(MalValue::Vector(to_ret)) - } - MalValue::Map(l) { - var to_ret = map() - for (var i = 0; i < l.keys.size; i++;) { - var mid = EVAL(env, l.values[i]) - if is_err(mid) { - return mid - } - to_ret.set(l.keys[i], get_value(mid)) - } - return MalResult::Ok(MalValue::Map(to_ret)) - } - MalValue::Symbol(s) { - return env->get(s) - } - } - return MalResult::Ok(ast) -} - -fun EVAL(env: *Env, ast: MalValue): MalResult { - // for tco - while (true) { - var expanded = macroexpand(ast, env) - if (is_err(expanded)) { - return expanded - } - ast = get_value(expanded) - if !is_list(ast) { - return eval_ast(env, ast) - } - match (ast) { - MalValue::List(l) { - if (l.size == 0) { - return MalResult::Ok(ast) - } else if (is_symbol(l[0], "def!")) { - if (l.size != 3) { - return MalResult::Err(MalValue::String(str("def! without exaclty key and value"))) - } - if (!is_symbol(l[1])) { - return MalResult::Err(MalValue::String(str("def! not on symbol"))) - } - var value = EVAL(env, l[2]) - if (is_err(value)) { - return value - } - env->set(get_symbol_text(l[1]), get_value(value)) - return value - } else if (is_symbol(l[0], "defmacro!")) { - if (l.size != 3) { - return MalResult::Err(MalValue::String(str("defmacro! without exaclty key and value"))) - } - if (!is_symbol(l[1])) { - return MalResult::Err(MalValue::String(str("defmacro! not on symbol"))) - } - var value = EVAL(env, l[2]) - if (is_err(value)) { - return value - } - var v = get_value(value) - match (v) { - MalValue::Function(f) { - f.is_macro = true - env->set(get_symbol_text(l[1]), MalValue::Function(f)) - return value - } - } - return MalResult::Err(MalValue::String(str("defmacro! on not a function"))) - } else if (is_symbol(l[0], "let*")) { - if (l.size != 3) { - return MalResult::Err(MalValue::String(str("let* without list of bindings & end value"))) - } - if (!is_list_or_vec(l[1])) { - return MalResult::Err(MalValue::String(str("let* without list of bindings"))) - } - var bindings = get_list_or_vec(l[1]) - if (bindings.size & 1 != 0) { - return MalResult::Err(MalValue::String(str("let* list of bindings has odd number of entries"))) - } - var new_env = new()->construct(env) - for (var i = 0; i < bindings.size; i+=2;) { - if (!is_symbol(bindings[i])) { - return MalResult::Err(MalValue::String(str("let* var name not symbol"))) - } - var to_set_value = EVAL(new_env, bindings[i+1]) - if (is_err(to_set_value)) { - return to_set_value - } - new_env->set(get_symbol_text(bindings[i]), get_value(to_set_value)) - } - // tco - env = new_env - var tmp = l[2] - ast = tmp - continue - } else if (is_symbol(l[0], "do")) { - for (var i = 1; i < l.size-1; i++;) { - var mid = EVAL(env, l[i]) - if is_err(mid) { - return mid - } - } - // tco - var tmp = l[l.size-1] - ast = tmp - continue - } else if (is_symbol(l[0], "if")) { - if l.size != 3 && l.size != 4 { - return MalResult::Err(MalValue::String(str("if needs 2 or 3 children"))) - } - var cond = EVAL(env, l[1]) - if is_err(cond) { - return cond - } - // tco - if is_truthy(get_value(cond)) { - var tmp = l[2] - ast = tmp - } else if l.size == 4 { - var tmp = l[3] - ast = tmp - } else { - return MalResult::Ok(MalValue::Nil()) - } - continue - } else if (is_symbol(l[0], "fn*")) { - if l.size != 3 { - return MalResult::Err(MalValue::String(str("fn* needs 2 children"))) - } - if (!is_list_or_vec(l[1])) { - return MalResult::Err(MalValue::String(str("fn* without list of parameters"))) - } - var parameters = get_list_or_vec(l[1]) - var parameters_str = vec() - var is_variadic = false - for (var i = 0; i < parameters.size; i++;) { - if (!is_symbol(parameters[i])) { - return MalResult::Err(MalValue::String(str("fn* parameter name not symbol"))) - } - var symbol_text = get_symbol_text(parameters[i]) - if symbol_text == "&" { - if i != parameters.size - 2 { - return MalResult::Err(MalValue::String(str("fn* has wrong number of arguments after &"))) - } - if (!is_symbol(parameters[i+1])) { - return MalResult::Err(MalValue::String(str("fn* parameter name not symbol"))) - } - is_variadic = true - i++ - symbol_text = get_symbol_text(parameters[i]) - } - parameters_str.add(symbol_text) - } - var to_ret.construct(env, parameters_str, is_variadic, false, l[2]): MalFunction - return MalResult::Ok(MalValue::Function(to_ret)) - } else if (is_symbol(l[0], "quote")) { - if l.size == 1 { - return MalResult::Err(MalValue::String(str("quote with no arguments"))) - } - return MalResult::Ok(l[1]) - } else if (is_symbol(l[0], "quasiquote")) { - if l.size == 1 { - return MalResult::Err(MalValue::String(str("quasiquote with no arguments"))) - } - var tmp = quasiquote(l[1]) - ast = tmp - continue - } else if (is_symbol(l[0], "macroexpand")) { - if l.size == 1 { - return MalResult::Err(MalValue::String(str("macroexpand with no arguments"))) - } - return macroexpand(l[1], env) - } else if (is_symbol(l[0], "try*")) { - if l.size != 2 && (l.size != 3 || !is_list(l[2])) { - return MalResult::Err(MalValue::String(str("try* wrong arguments"))) - } - var A = EVAL(env, l[1]) - if l.size == 3 && is_err(A) { - var catch = get_list(l[2]) - if catch.size != 3 || !is_symbol(catch[0], "catch*") || !is_symbol(catch[1]) { - return MalResult::Err(MalValue::String(str("catch* block malformed"))) - } - var new_env = new()->construct(env) - env->set(get_symbol_text(catch[1]), get_err(A)) - return EVAL(new_env, catch[2]) - } else { - return A - } - } else { - var mid = eval_ast(env, ast) - if is_err(mid) { - return mid - } - var to_call = get_list(get_value(mid)) - match (to_call[0]) { - MalValue::BuiltinFunction(f) { - return f.call(to_call.slice(1,-1)) - } - MalValue::Function(f) { - var params = to_call.slice(1,-1) - var call_pair = f.prep_call(to_call.slice(1, -1)) - if is_err(call_pair.second) { - return call_pair.second - } - env = call_pair.first - ast = get_value(call_pair.second) - continue - } - } - return MalResult::Err(MalValue::String(str("trying to call not a function"))) - } - } - } - return eval_ast(env, ast) - } -} - -fun PRINT(v: MalValue): str { - return pr_str(v, true) -} - -fun rep(env: *Env, a: str): str { - var read = READ(a) - if is_err(read) { - return PRINT(get_err(read)) - } else { - var evaled = EVAL(env, get_value(read)) - if is_err(evaled) { - return str("Exception: ") + PRINT(get_err(evaled)) - } else { - return PRINT(get_value(evaled)) - } - } -} -fun print_wrapper(params: vec, sep: *char, print_readably: bool): str { - var to_ret = str() - for (var i = 0; i < params.size; i++;) { - to_ret += pr_str(params[i], print_readably) - if i != params.size-1 { - to_ret += sep - } - } - return to_ret -} - -fun main(argc: int, argv: **char): int { - var env = new()->construct() - env->set(str("+"), make_builtin_function(fun(params: vec): MalResult { - var to_ret = 0 - for (var i = 0; i < params.size; i++;) { - match (params[i]) { - MalValue::Int(v) { - to_ret += v - continue - } - } - return MalResult::Err(MalValue::String(str("called + with not an int: ") + pr_str(params[i], false))) - } - return MalResult::Ok(MalValue::Int(to_ret)) - })); - env->set(str("-"), make_builtin_function(fun(params: vec): MalResult { - var to_ret = 0 - for (var i = 0; i < params.size; i++;) { - match (params[i]) { - MalValue::Int(v) { - if (i == 0) { - to_ret += v - } else { - to_ret -= v - } - continue - } - } - return MalResult::Err(MalValue::String(str("called - with not an int: ") + pr_str(params[i], false))) - } - return MalResult::Ok(MalValue::Int(to_ret)) - })); - env->set(str("*"), make_builtin_function(fun(params: vec): MalResult { - var to_ret = 1 - for (var i = 0; i < params.size; i++;) { - match (params[i]) { - MalValue::Int(v) { - to_ret *= v - continue - } - } - return MalResult::Err(MalValue::String(str("called * with not an int: ") + pr_str(params[i], false))) - } - return MalResult::Ok(MalValue::Int(to_ret)) - })); - env->set(str("/"), make_builtin_function(fun(params: vec): MalResult { - var to_ret = 1 - for (var i = 0; i < params.size; i++;) { - match (params[i]) { - MalValue::Int(v) { - if (i == 0) { - to_ret *= v - } else { - to_ret /= v - } - continue - } - } - return MalResult::Err(MalValue::String(str("called / with not an int: ") + pr_str(params[i], false))) - } - return MalResult::Ok(MalValue::Int(to_ret)) - })); - env->set(str("prn"), make_builtin_function(fun(params: vec): MalResult { - if params.size == 0 { - return MalResult::Err(MalValue::String(str("Called prn with 0 parameters"))) - } - println(pr_str(params[0], true)) - return MalResult::Ok(MalValue::Nil()) - })); - env->set(str("list"), make_builtin_function(fun(params: vec): MalResult { - return MalResult::Ok(MalValue::List(params)) - })); - env->set(str("list?"), make_builtin_function(fun(params: vec): MalResult { - if params.size > 0 && (is_list(params[0]) || is_nil(params[0])) { - return MalResult::Ok(MalValue::True()) - } else { - return MalResult::Ok(MalValue::False()) - } - })); - env->set(str("empty?"), make_builtin_function(fun(params: vec): MalResult { - if params.size == 0 || !is_list_or_vec(params[0]) { - return MalResult::Err(MalValue::String(str("first parameter of empty? is not a list"))) - } else { - return MalResult::Ok(bool_to_MalValue(get_list_or_vec(params[0]).size == 0)) - } - })); - env->set(str("count"), make_builtin_function(fun(params: vec): MalResult { - if params.size == 0 || !is_list_or_vec(params[0]) { - return MalResult::Err(MalValue::String(str("first parameter of count is not a list"))) - } else { - return MalResult::Ok(MalValue::Int(get_list_or_vec(params[0]).size)) - } - })); - env->set(str("="), make_builtin_function(fun(params: vec): MalResult { - if params.size != 2 { - return MalResult::Err(MalValue::String(str("= with not two parameters"))) - } else { - return MalResult::Ok(bool_to_MalValue(equals_MalValue(params[0], params[1]))) - } - })); - env->set(str("<"), make_builtin_function(fun(params: vec): MalResult { - if params.size != 2 || !is_int(params[0]) || !is_int(params[1]) { - return MalResult::Err(MalValue::String(str("< with not two numbers"))) - } else { - return MalResult::Ok(bool_to_MalValue(get_int(params[0]) < get_int(params[1]))) - } - })); - env->set(str("<="), make_builtin_function(fun(params: vec): MalResult { - if params.size != 2 || !is_int(params[0]) || !is_int(params[1]) { - return MalResult::Err(MalValue::String(str("<= with not two numbers"))) - } else { - return MalResult::Ok(bool_to_MalValue(get_int(params[0]) <= get_int(params[1]))) - } - })); - env->set(str(">"), make_builtin_function(fun(params: vec): MalResult { - if params.size != 2 || !is_int(params[0]) || !is_int(params[1]) { - return MalResult::Err(MalValue::String(str("> with not two numbers"))) - } else { - return MalResult::Ok(bool_to_MalValue(get_int(params[0]) > get_int(params[1]))) - } - })); - env->set(str(">="), make_builtin_function(fun(params: vec): MalResult { - if params.size != 2 || !is_int(params[0]) || !is_int(params[1]) { - return MalResult::Err(MalValue::String(str(">= with not two numbers"))) - } else { - return MalResult::Ok(bool_to_MalValue(get_int(params[0]) >= get_int(params[1]))) - } - })); - env->set(str("pr-str"), make_builtin_function(fun(params: vec): MalResult { - return MalResult::Ok(MalValue::String(print_wrapper(params, " ", true))) - })); - env->set(str("str"), make_builtin_function(fun(params: vec): MalResult { - return MalResult::Ok(MalValue::String(print_wrapper(params, "", false))) - })); - env->set(str("prn"), make_builtin_function(fun(params: vec): MalResult { - println(print_wrapper(params, " ", true)) - return MalResult::Ok(MalValue::Nil()) - })); - env->set(str("println"), make_builtin_function(fun(params: vec): MalResult { - println(print_wrapper(params, " ", false)) - return MalResult::Ok(MalValue::Nil()) - })); - env->set(str("read-string"), make_builtin_function(fun(params: vec): MalResult { - if params.size != 1 || !is_string(params[0]) { - return MalResult::Err(MalValue::String(str("read-string with not a single string"))) - } else { - return read_str(get_string(params[0])) - } - })); - env->set(str("slurp"), make_builtin_function(fun(params: vec): MalResult { - if params.size != 1 || !is_string(params[0]) { - return MalResult::Err(MalValue::String(str("slurp with not a single string"))) - } else { - return MalResult::Ok(MalValue::String(read_file(get_string(params[0])))) - } - })); - env->set(str("eval"), make_builtin_function(fun(params: vec): MalResult { - if params.size != 1 { - return MalResult::Err(MalValue::String(str("eval with wrong number of params"))) - } else { - return EVAL(env, params[0]) - } - })); - env->set(str("atom"), make_builtin_function(fun(params: vec): MalResult { - if params.size != 1 { - return MalResult::Err(MalValue::String(str("atom with wrong number of params"))) - } else { - var atom = new() - atom->copy_construct(¶ms[0]) - return MalResult::Ok(MalValue::Atom(atom)) - } - })); - env->set(str("atom?"), make_builtin_function(fun(params: vec): MalResult { - if params.size != 1 { - return MalResult::Err(MalValue::String(str("atom? with wrong number of params"))) - } else { - return MalResult::Ok(bool_to_MalValue(is_atom(params[0]))) - } - })); - env->set(str("deref"), make_builtin_function(fun(params: vec): MalResult { - if params.size != 1 || !is_atom(params[0]) { - return MalResult::Err(MalValue::String(str("deref called with wrong number of params or not an atom"))) - } else { - return MalResult::Ok(*get_atom(params[0])) - } - })); - env->set(str("reset!"), make_builtin_function(fun(params: vec): MalResult { - if params.size != 2 || !is_atom(params[0]) { - return MalResult::Err(MalValue::String(str("reset! called with wrong number of params or first not an atom"))) - } else { - var tmp = params[1] - *get_atom(params[0]) = tmp - return MalResult::Ok(params[1]) - } - })); - env->set(str("swap!"), make_builtin_function(fun(params: vec): MalResult { - if params.size < 2 || !is_atom(params[0]) { - return MalResult::Err(MalValue::String(str("swap! called with wrong number of params or first not an atom"))) - } else { - var call = vec(params[1], *get_atom(params[0])) + params.slice(2,-1) - var res = function_call(params[1], vec(*get_atom(params[0])) + params.slice(2, -1)) - if !is_err(res) { - *get_atom(params[0]) = get_value(res) - } - return res - } - })); - env->set(str("cons"), make_builtin_function(fun(params: vec): MalResult { - if params.size != 2 || !is_list_or_vec(params[1]) { - return MalResult::Err(MalValue::String(str("cons called with wrong number of params or second not an list/vec"))) - } else { - return MalResult::Ok(MalValue::List(vec(params[0]) + get_list_or_vec(params[1]))) - } - })); - env->set(str("concat"), make_builtin_function(fun(params: vec): MalResult { - var to_ret = vec() - for (var i = 0; i < params.size; i++;) { - if !is_list_or_vec(params[i]) { - return MalResult::Err(MalValue::String(str("concat called with not an list"))) - } - to_ret += get_list_or_vec(params[i]) - } - return MalResult::Ok(MalValue::List(to_ret)) - })); - env->set(str("nth"), make_builtin_function(fun(params: vec): MalResult { - if params.size != 2 || !is_list_or_vec(params[0]) || !is_int(params[1]) { - return MalResult::Err(MalValue::String(str("nth called with wrong number or type of params"))) - } else { - var list = get_list_or_vec(params[0]) - var idx = get_int(params[1]) - if idx >= list.size { - return MalResult::Err(MalValue::String(str("nth idx out of range"))) - } - return MalResult::Ok(list[idx]) - } - })); - env->set(str("first"), make_builtin_function(fun(params: vec): MalResult { - if params.size != 1 || !is_list_or_vec(params[0]) { - return MalResult::Err(MalValue::String(str("first called with wrong number or type of params"))) - } else { - var list = get_list_or_vec(params[0]) - if list.size == 0 { - return MalResult::Ok(MalValue::Nil()) - } - return MalResult::Ok(list[0]) - } - })); - env->set(str("rest"), make_builtin_function(fun(params: vec): MalResult { - if params.size != 1 || !is_list_or_vec(params[0]) { - return MalResult::Err(MalValue::String(str("rest called with wrong number or type of params"))) - } else { - var list = get_list_or_vec(params[0]) - if list.size == 0 { - return MalResult::Ok(MalValue::List(vec())) - } - return MalResult::Ok(MalValue::List(list.slice(1,-1))) - } - })); - env->set(str("throw"), make_builtin_function(fun(params: vec): MalResult { - if params.size != 1 { - return MalResult::Err(MalValue::String(str("throw called with wrong number or type of params"))) - } else { - return MalResult::Err(params[0]) - } - })); - env->set(str("apply"), make_builtin_function(fun(params: vec): MalResult { - if params.size < 2 || !is_list_or_vec(params[params.size-1]) { - return MalResult::Err(MalValue::String(str("apply called with wrong number or type of params"))) - } else { - var inner_params = params.slice(1,-2) + get_list_or_vec(params[params.size-1]) - return function_call(params[0], inner_params) - } - })); - env->set(str("map"), make_builtin_function(fun(params: vec): MalResult { - if params.size != 2 || !is_list_or_vec(params[1]) { - return MalResult::Err(MalValue::String(str("map called with wrong number or type of params"))) - } else { - var l = get_list_or_vec(params[1]) - var to_ret = vec() - for (var i = 0; i < l.size; i++;) { - var mid = function_call(params[0], vec(l[i])) - if is_err(mid) { - return mid - } - to_ret.add(get_value(mid)) - } - return MalResult::Ok(MalValue::List(to_ret)) - } - })); - env->set(str("symbol?"), make_builtin_function(fun(params: vec): MalResult { - if params.size != 1 { - return MalResult::Err(MalValue::String(str("symbol? called with wrong number of params"))) - } else { - return MalResult::Ok(bool_to_MalValue(is_symbol(params[0]))) - } - })); - env->set(str("symbol"), make_builtin_function(fun(params: vec): MalResult { - if params.size != 1 || !is_string(params[0]) { - return MalResult::Err(MalValue::String(str("symbol called with wrong number or type of params"))) - } else { - return MalResult::Ok(MalValue::Symbol(get_string(params[0]))) - } - })); - env->set(str("keyword?"), make_builtin_function(fun(params: vec): MalResult { - if params.size != 1 { - return MalResult::Err(MalValue::String(str("keyword? called with wrong number of params"))) - } else { - return MalResult::Ok(bool_to_MalValue(is_keyword(params[0]))) - } - })); - env->set(str("keyword"), make_builtin_function(fun(params: vec): MalResult { - if params.size != 1 || !is_keyword_or_string(params[0]) { - return MalResult::Err(MalValue::String(str("keyword called with wrong number or type of params"))) - } else { - return MalResult::Ok(MalValue::Keyword(get_keyword_or_string_text(params[0]))) - } - })); - env->set(str("vector"), make_builtin_function(fun(params: vec): MalResult { - return MalResult::Ok(MalValue::Vector(params)) - })); - env->set(str("vector?"), make_builtin_function(fun(params: vec): MalResult { - if params.size != 1 { - return MalResult::Err(MalValue::String(str("vector? called with wrong number of params"))) - } else { - return MalResult::Ok(bool_to_MalValue(is_vector(params[0]))) - } - })); - env->set(str("sequential?"), make_builtin_function(fun(params: vec): MalResult { - if params.size != 1 { - return MalResult::Err(MalValue::String(str("sequential? called with wrong number of params"))) - } else if is_nil(params[0]) { - return MalResult::Ok(MalValue::False()) - } else { - return MalResult::Ok(bool_to_MalValue(is_list_or_vec(params[0]))) - } - })); - env->set(str("hash-map"), make_builtin_function(fun(params: vec): MalResult { - return create_map(params) - })); - env->set(str("map?"), make_builtin_function(fun(params: vec): MalResult { - if params.size != 1 { - return MalResult::Err(MalValue::String(str("map? called with wrong number of params"))) - } else { - return MalResult::Ok(bool_to_MalValue(is_map(params[0]))) - } - })); - env->set(str("assoc"), make_builtin_function(fun(params: vec): MalResult { - if params.size & 1 != 1 || !is_map(params[0]) { - return MalResult::Err(MalValue::String(str("assoc? called with wrong number or type of params"))) - } else { - var base = get_map(params[0]) - var new = create_map(params.slice(1,-1)) - if is_err(new) { - return new - } - var new_map = get_map(get_value(new)) - for (var i = 0; i < new_map.keys.size; i++;) { - base.set(new_map.keys[i], new_map.values[i]) - } - return MalResult::Ok(MalValue::Map(base)) - } - })); - env->set(str("dissoc"), make_builtin_function(fun(params: vec): MalResult { - if params.size < 2 || !is_map(params[0]) { - return MalResult::Err(MalValue::String(str("dissoc? called with wrong number or type of params"))) - } else { - var base = get_map(params[0]) - var remove = vec() - if params.size != 2 || !is_list(params[1]) { - remove = params.slice(1,-1) - } else { - remove = get_list(params[1]) - } - for (var i = 0; i < remove.size; i++;) { - if base.contains_key(remove[i]) { - base.remove(remove[i]) - } - } - return MalResult::Ok(MalValue::Map(base)) - } - })); - env->set(str("get"), make_builtin_function(fun(params: vec): MalResult { - if params.size != 2 || !is_map(params[0]) || !is_keyword_or_string(params[1]) { - return MalResult::Err(MalValue::String(str("get called with wrong number or type of params"))) - } else { - var base = get_map(params[0]) - if base.contains_key(params[1]) { - return MalResult::Ok(base.get(params[1])) - } else { - return MalResult::Ok(MalValue::Nil()) - } - } - })); - env->set(str("contains?"), make_builtin_function(fun(params: vec): MalResult { - if params.size != 2 || !is_map(params[0]) || !is_keyword_or_string(params[1]) { - return MalResult::Err(MalValue::String(str("contains? called with wrong number or type of params"))) - } else { - var base = get_map(params[0]) - if base.contains_key(params[1]) { - return MalResult::Ok(MalValue::True()) - } else { - return MalResult::Ok(MalValue::False()) - } - } - })); - env->set(str("keys"), make_builtin_function(fun(params: vec): MalResult { - if params.size != 1 || !is_map(params[0]) { - return MalResult::Err(MalValue::String(str("keys called with wrong number or type of params"))) - } else { - return MalResult::Ok(MalValue::List(get_map(params[0]).keys)) - } - })); - env->set(str("vals"), make_builtin_function(fun(params: vec): MalResult { - if params.size != 1 || !is_map(params[0]) { - return MalResult::Err(MalValue::String(str("vals called with wrong number or type of params"))) - } else { - return MalResult::Ok(MalValue::List(get_map(params[0]).values)) - } - })); - env->set(str("readline"), make_builtin_function(fun(params: vec): MalResult { - if params.size != 1 || !is_string(params[0]) { - return MalResult::Err(MalValue::String(str("readline called with wrong number or type of params"))) - } else { - var entered = get_line(get_string(params[0]), 1024) - if entered == "***EOF***" { - return MalResult::Ok(MalValue::Nil()) - } - return MalResult::Ok(MalValue::String(entered)) - } - })); - env->set(str("time-ms"), make_builtin_function(fun(params: vec): MalResult { - return MalResult::Err(MalValue::String(str("not implemented"))) - })); - env->set(str("meta"), make_builtin_function(fun(params: vec): MalResult { - return MalResult::Err(MalValue::String(str("not implemented"))) - })); - env->set(str("with-meta"), make_builtin_function(fun(params: vec): MalResult { - return MalResult::Err(MalValue::String(str("not implemented"))) - })); - env->set(str("fn?"), make_builtin_function(fun(params: vec): MalResult { - return MalResult::Err(MalValue::String(str("not implemented"))) - })); - env->set(str("string?"), make_builtin_function(fun(params: vec): MalResult { - return MalResult::Err(MalValue::String(str("not implemented"))) - })); - env->set(str("number?"), make_builtin_function(fun(params: vec): MalResult { - return MalResult::Err(MalValue::String(str("not implemented"))) - })); - env->set(str("seq"), make_builtin_function(fun(params: vec): MalResult { - return MalResult::Err(MalValue::String(str("not implemented"))) - })); - env->set(str("conj"), make_builtin_function(fun(params: vec): MalResult { - return MalResult::Err(MalValue::String(str("not implemented"))) - })); - rep(env, str("(def! not (fn* (a) (if a false true)))")) - rep(env, str("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \" \\nnil)\")))))")) - rep(env, str("(defmacro! cond (fn* (& xs) (if (> (count xs) 0) (list 'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw \"odd number of forms to cond\")) (cons 'cond (rest (rest xs)))))))")) - rep(env, str("(def! nil? (fn* (a) (= nil a)))")) - rep(env, str("(def! true? (fn* (a) (= true a)))")) - rep(env, str("(def! false? (fn* (a) (= false a)))")) - rep(env, str("(def! *host-language* \"kraken\")")) - var params = vec() - if argc > 1 { - for (var i = 2; i < argc; i++;) { - params.add(MalValue::String(str(argv[i]))) - } - env->set(str("*ARGV*"), MalValue::List(params)) - rep(env, str("(load-file \"") + argv[1] + "\")") - } else { - env->set(str("*ARGV*"), MalValue::List(params)) - rep(env, str("(println (str \"Mal [\" *host-language* \"]\"))")) - while (true) { - var line = get_line(str("user> "), 1024) - if (line == "***EOF***") - break - println(rep(env, line)) - } - } -} diff --git a/shell.nix b/shell.nix index 5679056..5c6ae1f 100644 --- a/shell.nix +++ b/shell.nix @@ -4,13 +4,7 @@ with import { }; mkShell { LANG="en_US.UTF-8"; nativeBuildInputs = [ - emscripten - nodejs - valgrind - kcachegrind chicken - chez - racket wabt wasmtime wasm3 diff --git a/stdlib/.math.krak.un~ b/stdlib/.math.krak.un~ deleted file mode 100644 index 07455494389c2b04df3a76ffbebf771e75bcb7f8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27548 zcmWH`%$*;a=aT=Ff$4!snMX_SffY$_^$uF_=wEoh)pyx#H9y%PKc?GF`=^I8FfimY zFfa%yC@5#rmSpH<*fB6LFflMNa4|42FfuSOfcOkh8pH-+hER^ff-E3e zR)+WsAX%s;C=;v^WC)o5|NsC0U=c8Hl%ReHgmNS=2S*13!&eDtys*aQ3etN3ynq_I2dS1gmNUWLXI|&RV)k)4BXIY zV}M2zC|W?`AbAi5MHxs8#AXvzW9@>Ny#rw%1Ol?fv^aJIS~|@pa=w|fYAtq zg$m8+P>z%wd=V%Qk3e6?5RZ6V*$@(oCT8x51ftEOwBPAbSEXu)S zF*w8pXC#6m3|wwPoeGLjP&NeBougS18Yr}*LOD{FAx9z)l2xE6V625UEkW@D>gmDc zL2)Js9Ic&Tp+Yk{lq1y)Ii7?W7#KitBo2)yHU%(%MiwY?_>kNJ zia3yJu+V6x0tW*PiBOJI59G)KuvC1YuB|f(!x;n~Y{UP>9eJhjOHPBF7^rnm|zmiYibvF)Jv*8ik;k0aaTt z_kdyzq!grVG^SvoLNhv)BNb&J1QbIs%Ro^8Z@h!z1=JLQNrK`Gu6VR$gar$&=unQ- zO5_{`D$Jx97#QGL1zPZdq6O3pfw=<|WuRyR#pP&rf`tmr=unQ-YV>FVMG+{fKvBS? zpa6|1P{e@RA~2_bB25y;8O=|ykf0SE%8}ZH9#Np+2Vqc4gGoUFWHq>v0m?rhaZn_J zr8Km=2FqcfXaUuMFsFc`4Aevc^GBlz91JuhLOD{;BS#Y`hkyz_S+r;ZMGL6- zggFHiW%4l2Xf(k>f>v}WN9sf5Xp%#+2viWlauX<8kPAsrl#NCcQee@R8Oo8yh8|6z z=7%0yZURLMs2Krs4JgV+qX`xol+vKG3sn1q%mI~UAR2_rpba>NP>wW9^k~v%U|@hp z6S%bqiV#@j!SWXNGwX%gsqkXMHa{knA<=R2}%QC{%A8291P?WppYe${U#zu9!P^0QshAf zLqHJ%Dic9b3aj`~B8q{50i;utfq?@1}VsIV47?eRYQ%Vx^jIg#^K+&a$px9{sg9ZxO6fu#vA7A8&qc=H?P}-cJ*aF2j%z>bo1T|ei z>$yf_4;Cuq(!|8xb>!FsHC;e$PFU8%*K`3z6)2;@90!U?g4Vt znL)b>u&9G|4nWZY>I1^u0gAHGXo7_Xr8F_o^a?$iKpg{kG=WFNKoJ7!(Sbx^5eJGW zH6-_eA`zqxEHs+Gz`;O1K}^J7z0&_Fh_!7(`Ixy6BZm4(!|8zSL7J9W?*2jWnf@{ z#UTEU0VuLSO-Yz5K@sT)-HSikw1kBUxim46_YXPp92giFoRA_9U(*s4RiI`l%yFP- z1eL#_-8iFB2MZN)X(FO7of$dmOc)p#K$RRU-{FfoP*i~iKVgmoMI)%a1LlvmTEM|T zK0!>>86!s>D93@?C9tT2Od^0H1k}_7iNczjpor2zav3NRLF&LlqY(!V2J#7FBF+Rk z;y^VODEK2Wnwy{~1w|f62D!NjiZERy7lI-aWWs2ni4-VgGl_{nE93}-MNPa@2ux zO%zhTgS1&d5dvz-fFcyuW&uT%A(GQTkqA;VI>Le!C}cB3Q^#t8QfOG;kRHqE&o`ST@ zq{O_$leNNfRyb25Lk2 y&RbBFAv+NiouD(YMyKwPLxpDSP>#a_;3#B;L?Nii1T}?VIS,*ast_node>>, ast_to_syntax: *map<*ast_node, *tree>) { - var visited = hash_set<*ast_node>() - name_ast_map->for_each(fun(name: str, syntax_ast_pair: pair<*tree,*ast_node>) { - var helper_before = fun(node: *ast_node, parent_chain: *stack<*ast_node>) { - match(*node) { - ast_node::function_call(backing) { - if (is_function(backing.func) && backing.func->function.name == "&") { - var addresse = backing.parameters[0] - // Identifier is always fine. The other options are - // function call, value, or cast. The only fine one here - // is a function call of * - if ( (is_function_call(addresse) && - !(is_function(addresse->function_call.func) && - (addresse->function_call.func->function.name == "*" || - addresse->function_call.func->function.name == "." || - addresse->function_call.func->function.name == "->" || - addresse->function_call.func->function.name == "[]"))) || - is_value(addresse) || is_cast(addresse) ) { - // so we're a function call that's not * or a cast or value - // so make a temp variable for us - // Note that we don't have to worry about destruction because - // all object stuff has already ran, so this isn't an object - - var enclosing_block_idx = parent_chain->index_from_top_satisfying(is_code_block) - var enclosing_block = parent_chain->from_top(enclosing_block_idx) - var before_block_parent = parent_chain->from_top(enclosing_block_idx-1) - var ident = _ident("for_address_of_temp", - backing.func->function.type->parameter_types[0], - enclosing_block) - var decl = _declaration(ident, addresse) - add_before_in(decl, before_block_parent, enclosing_block) - replace_with_in(addresse, ident, node) - } - } - } - } - } - run_on_tree(helper_before, empty_pass_second_half(), syntax_ast_pair.second, &visited) - }) -} - diff --git a/stdlib/adt_lower.krak b/stdlib/adt_lower.krak deleted file mode 100644 index 6a17b67..0000000 --- a/stdlib/adt_lower.krak +++ /dev/null @@ -1,200 +0,0 @@ -import symbol:* -import tree:* -import vec:* -import map:* -import util:* -import str:* -import mem:* -import io:* -import ast_nodes:* -import ast_transformation:* -import hash_set:* - -import pass_common:* - - -fun adt_lower(name_ast_map: *map,*ast_node>>, ast_to_syntax: *map<*ast_node, *tree>) { - var type_def_option_map = map<*ast_node, vec<*ast_node>>() - var visited1 = hash_set<*ast_node>() - var visited2 = hash_set<*ast_node>() - name_ast_map->for_each(fun(name: str, syntax_ast_pair: pair<*tree,*ast_node>) { - var helper_before = fun(node: *ast_node, parent_chain: *stack<*ast_node>) { - match(*node) { - ast_node::adt_def(backing) { - /*println(backing.name + ": transforming!")*/ - type_def_option_map[node] = vec<*ast_node>() - var replacement = _type_def(backing.name, false); - // we're going to be replacing adt_def in the same ptr, so this works - replacement->type_def.self_type = node->adt_def.self_type - - var option_union = _type_def(backing.name + "_union", true); - node->adt_def.options.for_each(fun(opt: *ast_node) { - if (!opt->identifier.type->is_empty_adt_option()) - option_union->type_def.variables.add(_declaration(opt, null())) - type_def_option_map[node].add(opt) - }) - var option_union_type = type_ptr(option_union) - option_union->type_def.self_type = option_union_type - var option_union_ident = _ident(str("data"), option_union_type, replacement) - replacement->type_def.variables.add(_declaration(option_union_ident, null())) - add_to_scope("data", option_union_ident, replacement) - var flag = _ident(str("flag"), type_ptr(base_type::integer()), replacement) - replacement->type_def.variables.add(_declaration(flag, null())) - add_to_scope("flag", flag, replacement) - add_before_in(option_union, node, parent_chain) - var enclosing_scope = node->adt_def.scope[str("~enclosing_scope")][0] - var idx = 0 - node->adt_def.option_funcs.for_each(fun(func: *ast_node) { - var adt_type = replacement->type_def.self_type - var block = _code_block() - add_to_scope("~enclosing_scope", func, block) - func->function.body_statement = block - var to_ret = _ident(str("to_ret"), adt_type, block) - block->code_block.children.add(_declaration(to_ret, null())) - - var value = _value(to_string(idx), type_ptr(base_type::integer())) - block->code_block.children.add(_assign(make_operator_call(".", vec(to_ret, flag)), value)) - var opt = type_def_option_map[node][idx] - var lvalue = make_operator_call(".", vec(make_operator_call(".", vec(to_ret, option_union_ident)), opt)) - if (func->function.parameters.size) { - // do copy_construct if it should - block->code_block.children.add(assign_or_copy_construct_statement(lvalue, func->function.parameters[0])) - } - block->code_block.children.add(_return(to_ret)) - add_before_in(func, node, parent_chain) - add_to_scope(func->function.name, func, enclosing_scope) - add_to_scope("~enclosing_scope", enclosing_scope, func) - idx++ - }) - node->adt_def.regular_funcs.for_each(fun(func: *ast_node) { - var block = _code_block() - add_to_scope("~enclosing_scope", func, block) - func->function.body_statement = block - var func_this = func->function.this_param - if (func->function.name == "operator==") { - var other = func->function.parameters[0] - var if_stmt = _if(make_operator_call("!=", vec(make_operator_call("->", vec(func_this, flag)), make_operator_call(".", vec(other, flag))))) - if_stmt->if_statement.then_part = _return(_value(str("false"), type_ptr(base_type::boolean()))) - block->code_block.children.add(if_stmt) - - for (var i = 0; i < type_def_option_map[node].size; i++;) { - if (get_ast_type(type_def_option_map[node][i])->is_empty_adt_option()) - continue - var if_stmt_inner = _if(make_operator_call("==", vec(make_operator_call("->", vec(func_this, flag)), _value(to_string(i), type_ptr(base_type::integer()))))) - var option = type_def_option_map[node][i] - var our_option = make_operator_call(".", vec(make_operator_call("->", vec(func_this, option_union_ident)), option)) - var their_option = make_operator_call(".", vec(make_operator_call(".", vec(other, option_union_ident)), option)) - if_stmt_inner->if_statement.then_part = _return(possible_object_equality(our_option, their_option)) - block->code_block.children.add(if_stmt_inner) - } - block->code_block.children.add(_return(_value(str("true"), type_ptr(base_type::boolean())))) - } else if (func->function.name == "operator!=") { - var other = func->function.parameters[0] - block->code_block.children.add(_return(make_operator_call("!", vec(make_method_call(func_this, "operator==", vec(other)))))) - } else if (func->function.name == "construct") { - var value = _value(str("-1"), type_ptr(base_type::integer())) - block->code_block.children.add(_assign(make_operator_call("->", vec(func_this, flag)), value)) - block->code_block.children.add(_return(func_this)) - } else if (func->function.name == "copy_construct") { - var other = func->function.parameters[0] - block->code_block.children.add(_assign(make_operator_call("->", vec(func_this, flag)), make_operator_call("->", vec(other, flag)))) - for (var i = 0; i < type_def_option_map[node].size; i++;) { - if (get_ast_type(type_def_option_map[node][i])->is_empty_adt_option()) - continue - var if_stmt_inner = _if(make_operator_call("==", vec(make_operator_call("->", vec(func_this, flag)), _value(to_string(i), type_ptr(base_type::integer()))))) - var option = type_def_option_map[node][i] - var our_option = make_operator_call(".", vec(make_operator_call("->", vec(func_this, option_union_ident)), option)) - var their_option = make_operator_call(".", vec(make_operator_call("->", vec(other, option_union_ident)), option)) - if_stmt_inner->if_statement.then_part = assign_or_copy_construct_statement(our_option, their_option) - block->code_block.children.add(if_stmt_inner) - } - block->code_block.children.add(_return(func_this)) - } else if (func->function.name == "operator=") { - var other = func->function.parameters[0] - block->code_block.children.add(make_method_call(func_this, "destruct", vec<*ast_node>())) - block->code_block.children.add(make_method_call(func_this, "copy_construct", vec(make_operator_call("&", vec(other))))) - } else if (func->function.name == "destruct") { - for (var i = 0; i < type_def_option_map[node].size; i++;) { - var option = type_def_option_map[node][i] - var option_type = get_ast_type(option) - if (option_type->is_empty_adt_option()) - continue - if (option_type->indirection == 0 && option_type->is_object() && has_method(option_type->type_def, "destruct", vec<*type>())) { - var if_stmt_inner = _if(make_operator_call("==", vec(make_operator_call("->", vec(func_this, flag)), _value(to_string(i), type_ptr(base_type::integer()))))) - var our_option = make_operator_call(".", vec(make_operator_call("->", vec(func_this, option_union_ident)), option)) - if_stmt_inner->if_statement.then_part = make_method_call(our_option, "destruct", vec<*ast_node>()) - block->code_block.children.add(if_stmt_inner) - } - } - } else error("impossible adt method") - replacement->type_def.methods.add(func) - add_to_scope(func->function.name, func, replacement) - add_to_scope("~enclosing_scope", replacement, func) - }) - add_to_scope("~enclosing_scope", enclosing_scope, option_union) - add_to_scope("~enclosing_scope", enclosing_scope, replacement) - *node = *replacement - } - } - } - run_on_tree(helper_before, empty_pass_second_half(), syntax_ast_pair.second, &visited1) - }) - name_ast_map->for_each(fun(name: str, syntax_ast_pair: pair<*tree,*ast_node>) { - var second_helper = fun(node: *ast_node, parent_chain: *stack<*ast_node>) { - match(*node) { - ast_node::match_statement(backing) { - var block = _code_block() - add_to_scope("~enclosing_scope", parent_chain->item_from_top_satisfying(fun(i: *ast_node): bool return is_code_block(i) || is_function(i);), block) - var value = backing.value - var holder = _ident(str("holder"), get_ast_type(value)->clone_with_increased_indirection(), block) - block->code_block.children.add(_declaration(holder, null())) - block->code_block.children.add(_assign(holder, make_operator_call("&", vec(value)))) - backing.cases.for_each(fun(case_stmt: *ast_node) { - var option = case_stmt->case_statement.option - if (!get_ast_scope(get_ast_type(value)->type_def)->contains_key(str("flag"))) - error("trying to get flag from struct without it - are you matching on not an adt? - " + get_ast_type(value)->to_string()) - var flag = get_from_scope(get_ast_type(value)->type_def, "flag") - var data = get_from_scope(get_ast_type(value)->type_def, "data") - var option_num = -7 - if (!type_def_option_map.contains_key(get_ast_type(value)->type_def)) - error("trying to match on non-adt") - for (var i = 0; i < type_def_option_map[get_ast_type(value)->type_def].size; i++;) - if (type_def_option_map[get_ast_type(value)->type_def][i] == option) - option_num = i; - var condition = make_operator_call("==", vec(make_operator_call("->", vec(holder, flag)), _value(to_string(option_num), type_ptr(base_type::integer())))) - var if_stmt = _if(condition) - var inner_block = _code_block() - add_to_scope("~enclosing_scope", block, inner_block) - var unpack_ident = case_stmt->case_statement.unpack_ident - if (unpack_ident) { - var get_option = make_operator_call(".", vec(make_operator_call("->", vec(holder, data)), option)) - get_option = make_operator_call("&", vec(get_option)) - unpack_ident->identifier.type = unpack_ident->identifier.type->clone_with_ref() - inner_block->code_block.children.add(_declaration(unpack_ident, get_option)) - } - inner_block->code_block.children.add(case_stmt->case_statement.statement) - if_stmt->if_statement.then_part = inner_block - block->code_block.children.add(if_stmt) - }) - *node = *block - } - ast_node::function_call(backing) { - if (is_function(backing.func) && (backing.func->function.name == "." || backing.func->function.name == "->")) { - var left_type = get_ast_type(backing.parameters[0]) - if (left_type->is_object() && is_identifier(backing.parameters[1])) { - for (var i = 0; i < left_type->type_def->type_def.variables.size; i++;) - if (left_type->type_def->type_def.variables[i]->declaration_statement.identifier == backing.parameters[1]) - return; - /*println(backing.parameters[1]->identifier.name + " getting, adt . or -> call!")*/ - var object = node->function_call.parameters[0] - node->function_call.parameters[0] = make_operator_call(backing.func->function.name, vec(object, get_from_scope(left_type->type_def, "data"))) - node->function_call.func = get_builtin_function(".", vec(get_ast_type(get_from_scope(left_type->type_def, "data")), get_ast_type(backing.parameters[1]))) - } - } - } - } - } - run_on_tree(second_helper, empty_pass_second_half(), syntax_ast_pair.second, &visited2) - }) -} - diff --git a/stdlib/ast.krak b/stdlib/ast.krak deleted file mode 100644 index 5845f76..0000000 --- a/stdlib/ast.krak +++ /dev/null @@ -1,324 +0,0 @@ -import tree:* -import type2:* -import vec:* -import set:* -import util:* -import str:* -import mem:* -import binding:* - -adt ast { - _translation_unit: str, - _import: pair<*tree, set>, - _identifier: pair>, - _binding: triple>, *binding>>, - _type_def: str, - _adt_def: str, - _function: triple, bool>, - // needs to be a map that retains order - _template: pair>>, - _declaration, - _block, - _if, - _match, - _case, - _while, - _for, - _return, - _break, - _continue, - _defer, - _call: bool, - _compiler_intrinsic: triple, vec<*binding>>, - _cast: *binding, - _value: pair> -} -fun deref_to_string(in: *T): str - if (in == mem::null()) - return str("null") - else - return to_string(in) -fun deref_to_string(in: *T, ts: fun(*T): str): str - if (in == mem::null()) - return str("null") - else - return ts(in) -fun binding_deref_to_string(b: *binding): str { - var pre = b->get_bound_to(binding_epoch::pre_ref()) - var post = b->get_bound_to(binding_epoch::post_ref()) - if pre == post { - return deref_to_string(pre) - } else { - return "pre_ref:" + deref_to_string(pre) + "/post_ref:" + deref_to_string(post) - } -} -fun binding_deref_to_string(b: *binding, ts: fun(*T): str): str { - var pre = b->get_bound_to(binding_epoch::pre_ref()) - var post = b->get_bound_to(binding_epoch::post_ref()) - if pre == post { - return deref_to_string(pre, ts) - } else { - return "pre_ref:" + deref_to_string(pre, ts) + "/post_ref:" + deref_to_string(post, ts) - } -} -fun to_string(a: ref ast): str { - match(a) { - ast::_translation_unit(b) return str("_translation_unit(") + b + ")" - ast::_import(b) return str("_import(") + to_string(b.first->data) + ")[" + str(",").join(b.second.data) + "]" - ast::_identifier(b) return str("_identifier(") + b.first + ": " + binding_deref_to_string(b.second) + ")" - ast::_binding(b) return str("_binding(") + b.first + "[" + str(",").join(b.second.map(fun(x:*binding): str { return binding_deref_to_string(x); })) + "]" + "-> " + binding_deref_to_string(b.third, fun(t: *tree): str return to_string(t->data);) + ")" - ast::_type_def(b) return str("_type_def(") + b + ")" - ast::_adt_def(b) return str("_adt_def(") + b + ")" - ast::_function(b) return str("_function(") + b.first + ": " + binding_deref_to_string(b.second) + ", ext?:" + to_string(b.third) + ")" - ast::_template(b) return str("_template(") + b.first + "[" + str(",").join(b.second.keys) + "])" - ast::_declaration() return str("_declaration") - ast::_block() return str("_block") - ast::_if() return str("_if") - ast::_match() return str("_match") - ast::_case() return str("_case") - ast::_while() return str("_while") - ast::_for() return str("_for") - ast::_return() return str("_return") - ast::_break() return str("_break") - ast::_continue() return str("_continue") - ast::_defer() return str("_defer") - ast::_call(b) return "_call(add_scope: " + to_string(b) + ")" - ast::_compiler_intrinsic(b) return str("_compiler_intrinsic(") + b.first + ": " + binding_deref_to_string(b.second) + ")" - ast::_cast(b) return str("_cast") - ast::_value(b) return str("_value(") + b.first + ": " + binding_deref_to_string(b.second) + ")" - } -} -fun _translation_unit(p: str): *tree { - return new>()->construct(ast::_translation_unit(p)) -} -fun _import(p1: *tree, p2: set): *tree { - return new>()->construct(ast::_import(make_pair(p1,p2))) -} -fun _type_def(p: str): *tree { - return new>()->construct(ast::_type_def(p)) -} -fun _adt_def(p: str): *tree { - return new>()->construct(ast::_adt_def(p)) -} -fun _cast(p: *binding): *tree { - return new>()->construct(ast::_cast(p)) -} -fun _identifier(p1: str, p2: *binding): *tree { - return new>()->construct(ast::_identifier(make_pair(p1, p2))) -} -fun _binding(p1: str, p2: vec<*binding>, p3: *binding>): *tree { - return new>()->construct(ast::_binding(make_triple(p1, p2, p3))) -} -fun _function(p1: str, p2: *binding, p3: bool): *tree { - return new>()->construct(ast::_function(make_triple(p1, p2, p3))) -} -fun _template(p1: str, p2: map>): *tree { - return new>()->construct(ast::_template(make_pair(p1, p2))) -} -fun _compiler_intrinsic(p1: str, p2: *binding, p3: vec<*binding>): *tree { - return new>()->construct(ast::_compiler_intrinsic(make_triple(p1, p2, p3))) -} -fun _value(p1: str, p2: *binding): *tree { - return new>()->construct(ast::_value(make_pair(p1, p2))) -} -fun _declaration(): *tree { - return new>()->construct(ast::_declaration()) -} -fun _block(): *tree { - return new>()->construct(ast::_block()) -} -fun _if(): *tree { - return new>()->construct(ast::_if()) -} -fun _match(): *tree { - return new>()->construct(ast::_match()) -} -fun _case(): *tree { - return new>()->construct(ast::_case()) -} -fun _while(): *tree { - return new>()->construct(ast::_while()) -} -fun _for(): *tree { - return new>()->construct(ast::_for()) -} -fun _return(): *tree { - return new>()->construct(ast::_return()) -} -fun _break(): *tree { - return new>()->construct(ast::_break()) -} -fun _continue(): *tree { - return new>()->construct(ast::_continue()) -} -fun _defer(): *tree { - return new>()->construct(ast::_defer()) -} -fun _call(add_scope: bool): *tree { - return new>()->construct(ast::_call(add_scope)) -} - - - -fun _translation_unit(p: str, c: ref vec<*tree>): *tree { - return new>()->construct(ast::_translation_unit(p), c) -} -fun _import(p1: *tree, p2: set, c: ref vec<*tree>): *tree { - return new>()->construct(ast::_import(make_pair(p1,p2)), c) -} -fun _type_def(p: str, c: ref vec<*tree>): *tree { - return new>()->construct(ast::_type_def(p), c) -} -fun _adt_def(p: str, c: ref vec<*tree>): *tree { - return new>()->construct(ast::_adt_def(p), c) -} -fun _cast(p: *binding, c: ref vec<*tree>): *tree { - return new>()->construct(ast::_cast(p), c) -} -fun _identifier(p1: str, p2: *binding, c: ref vec<*tree>): *tree { - return new>()->construct(ast::_identifier(make_pair(p1, p2)), c) -} -fun _binding(p1: str, p2: vec<*binding>, p3: *binding>, c: ref vec<*tree>): *tree { - return new>()->construct(ast::_binding(make_triple(p1, p2, p3)), c) -} -fun _function(p1: str, p2: *binding, p3: bool, c: ref vec<*tree>): *tree { - return new>()->construct(ast::_function(make_triple(p1, p2, p3)), c) -} -fun _template(p1: str, p2: map>, c: ref vec<*tree>): *tree { - return new>()->construct(ast::_template(make_pair(p1, p2)), c) -} -fun _compiler_intrinsic(p1: str, p2: *binding, p3: vec<*binding>, c: ref vec<*tree>): *tree { - return new>()->construct(ast::_compiler_intrinsic(make_triple(p1, p2, p3)), c) -} -fun _value(p1: str, p2: *binding, c: ref vec<*tree>): *tree { - return new>()->construct(ast::_value(make_pair(p1, p2)), c) -} -fun _declaration(c: ref vec<*tree>): *tree { - return new>()->construct(ast::_declaration(), c) -} -fun _block(c: ref vec<*tree>): *tree { - return new>()->construct(ast::_block(), c) -} -fun _if(c: ref vec<*tree>): *tree { - return new>()->construct(ast::_if(), c) -} -fun _match(c: ref vec<*tree>): *tree { - return new>()->construct(ast::_match(), c) -} -fun _case(c: ref vec<*tree>): *tree { - return new>()->construct(ast::_case(), c) -} -fun _while(c: ref vec<*tree>): *tree { - return new>()->construct(ast::_while(), c) -} -fun _for(c: ref vec<*tree>): *tree { - return new>()->construct(ast::_for(), c) -} -fun _return(c: ref vec<*tree>): *tree { - return new>()->construct(ast::_return(), c) -} -fun _defer(c: ref vec<*tree>): *tree { - return new>()->construct(ast::_defer(), c) -} -fun _call(add_scope: bool, c: ref vec<*tree>): *tree { - return new>()->construct(ast::_call(add_scope), c) -} - - - -fun is_translation_unit(i: *tree): bool { match(i->data) { ast::_translation_unit(b) return true; } return false; } -fun is_import(i: *tree): bool { match(i->data) { ast::_import(b) return true; } return false; } -fun is_identifier(i: *tree): bool { match(i->data) { ast::_identifier(b) return true; } return false; } -fun is_binding(i: *tree): bool { match(i->data) { ast::_binding(b) return true; } return false; } -fun is_type_def(i: *tree): bool { match(i->data) { ast::_type_def(b) return true; } return false; } -fun is_adt_def(i: *tree): bool { match(i->data) { ast::_adt_def(b) return true; } return false; } -fun is_function(i: *tree): bool { match(i->data) { ast::_function(b) return true; } return false; } -fun is_template(i: *tree): bool { match(i->data) { ast::_template(b) return true; } return false; } -fun is_declaration(i: *tree): bool { match(i->data) { ast::_declaration() return true; } return false; } -fun is_block(i: *tree): bool { match(i->data) { ast::_block() return true; } return false; } -fun is_if(i: *tree): bool { match(i->data) { ast::_if() return true; } return false; } -fun is_match(i: *tree): bool { match(i->data) { ast::_match() return true; } return false; } -fun is_case(i: *tree): bool { match(i->data) { ast::_case() return true; } return false; } -fun is_while(i: *tree): bool { match(i->data) { ast::_while() return true; } return false; } -fun is_for(i: *tree): bool { match(i->data) { ast::_for() return true; } return false; } -fun is_return(i: *tree): bool { match(i->data) { ast::_return() return true; } return false; } -fun is_break(i: *tree): bool { match(i->data) { ast::_break() return true; } return false; } -fun is_continue(i: *tree): bool { match(i->data) { ast::_continue() return true; } return false; } -fun is_defer(i: *tree): bool { match(i->data) { ast::_defer() return true; } return false; } -fun is_call(i: *tree): bool { match(i->data) { ast::_call(b) return true; } return false; } -fun is_compiler_intrinsic(i: *tree): bool { match(i->data) { ast::_compiler_intrinsic(b) return true; } return false; } -fun is_cast(i: *tree): bool { match(i->data) { ast::_cast(b) return true; } return false; } -fun is_value(i: *tree): bool { match(i->data) { ast::_value(b) return true; } return false; } - -fun is_top_level_item(i: *tree): bool { return i->parent == null>() || is_translation_unit(i->parent); } - -fun get_ancestor_satisfying(t: *tree, p: fun(*tree): bool): *tree { - t = t->parent - while (t != null>() && !p(t)) - t = t->parent - return t -} - -fun make_ast_binding(s: *char): *tree { - return make_ast_binding(str(s)) -} -fun make_ast_binding(s: str): *tree { - return make_ast_binding(s, vec<*binding>()) -} -fun make_ast_binding(s: str, v: vec<*binding>): *tree { - return _binding(s, v, binding>()) -} -fun clone_ast_binding(binding: *tree): *tree { - match(binding->data) { - ast::_binding(b) { - return _binding(b.first, b.second, b.third) - } - } - error("trying to get binding on not a binding") -} -fun get_ast_binding_inst_types(binding: *tree): ref vec<*binding> { - match(binding->data) { - ast::_binding(b) { - return b.second - } - } - error("trying to get binding on not a binding") -} -fun get_ast_binding(binding: *tree, epoch: binding_epoch): *tree { - match(binding->data) { - ast::_binding(b) { - return b.third->get_bound_to(epoch) - } - } - error("trying to get binding on not a binding") -} -fun set_ast_binding(binding: *tree, to: *tree, epoch: binding_epoch) { - match(binding->data) { - ast::_binding(b) { - b.third->set(to, epoch) - return - } - } - error("trying to set binding on not a binding") -} -fun set_single_ast_binding(binding: *tree, to: *tree, epoch: binding_epoch) { - match(binding->data) { - ast::_binding(b) { - b.third->set_single(to, epoch) - return - } - } - error("trying to set binding on not a binding") -} -fun ast_bound(binding: *tree): bool { - match(binding->data) { - ast::_binding(b) return b.third->bound() - } - error("Trying to check bound for not a binding") -} -fun ast_binding_str(binding: *tree): str { - match(binding->data) { - ast::_binding(b) return b.first - } - error("Trying to get name for not a binding") -} diff --git a/stdlib/ast_nodes.krak b/stdlib/ast_nodes.krak deleted file mode 100644 index af40333..0000000 --- a/stdlib/ast_nodes.krak +++ /dev/null @@ -1,1207 +0,0 @@ -import tree:* -import symbol:* -import vec:* -import vec_literals:* -import set:* -import stack:* -import map:* -import util:* -import str:* -import mem:* -import io:* -import type:* - -adt ast_node { - translation_unit: translation_unit, - import: import, - identifier: identifier, - type_def: type_def, - adt_def: adt_def, - function: function, - template: template, - code_block: code_block, - if_statement: if_statement, - match_statement: match_statement, - case_statement: case_statement, - while_loop: while_loop, - for_loop: for_loop, - return_statement: return_statement, - branching_statement: branching_statement, - defer_statement: defer_statement, - assignment_statement: assignment_statement, - declaration_statement: declaration_statement, - if_comp: if_comp, - simple_passthrough: simple_passthrough, - function_call: function_call, - compiler_intrinsic: compiler_intrinsic, - cast: cast, - value: value -} -fun ast_node_ptr(node: ast_node): *ast_node { - var to_ret = new() - to_ret->copy_construct(&node) - return to_ret -} -fun _translation_unit(name: str): *ast_node { - var obj_var.construct(name): translation_unit - var ptr = new() - ptr->copy_construct(&ast_node::translation_unit(obj_var)) - return ptr -} -fun is_translation_unit(node: *ast_node): bool { - match(*node) { - ast_node::translation_unit(backing) return true - } - return false -} -obj translation_unit (Object) { - var scope: map> - var children: vec<*ast_node> - var lambdas: vec<*ast_node> - var name: str - fun construct(nameIn: str): *translation_unit { - scope.construct() - children.construct() - lambdas.construct() - name.copy_construct(&nameIn) - return this - } - fun copy_construct(old: *translation_unit) { - scope.copy_construct(&old->scope) - children.copy_construct(&old->children) - lambdas.copy_construct(&old->lambdas) - name.copy_construct(&old->name) - } - fun destruct() { - scope.destruct() - children.destruct() - lambdas.destruct() - name.destruct() - } - fun operator=(other: ref translation_unit) { - destruct() - copy_construct(&other) - } - fun operator==(other: ref translation_unit): bool { - return children == other.children && name == other.name && lambdas == other.lambdas - } -} -fun _import(name: str, containing_tu: *ast_node): *ast_node { - var to_ret.construct(name, containing_tu): import - var ptr = new() - ptr->copy_construct(&ast_node::import(to_ret)) - return ptr -} -fun is_import(node: *ast_node): bool { - match(*node) { - ast_node::import(backing) return true - } - return false -} -obj import (Object) { - var scope: map> - var imported: set - var containing_translation_unit: *ast_node - var translation_unit: *ast_node - var name: str - var starred: bool - fun construct(nameIn: str, containing_tu: *ast_node): *import { - scope.construct() - imported.construct() - name.copy_construct(&nameIn) - containing_translation_unit = containing_tu - translation_unit = null() - starred = false - return this - } - fun copy_construct(old: *import) { - scope.copy_construct(&old->scope) - imported.copy_construct(&old->imported) - name.copy_construct(&old->name) - containing_translation_unit = old->containing_translation_unit - translation_unit = old->translation_unit - starred = old->starred - } - fun destruct() { - scope.destruct() - imported.destruct() - name.destruct() - } - fun operator=(other: ref import) { - destruct() - copy_construct(&other) - } - fun operator==(other: ref import): bool { - return imported == other.imported && name == other.name && containing_translation_unit == other.containing_translation_unit && translation_unit == other.translation_unit && starred == other.starred - } -} -fun _ident(name: *char, type: *type, enclosing_scope: *ast_node): *ast_node { - return _ident(str(name), type, enclosing_scope) -} -fun _ident(name: str, type: *type, enclosing_scope: *ast_node): *ast_node { - return _ident(name, type, enclosing_scope, false) -} -fun _ident(name: str, type: *type, enclosing_scope: *ast_node, is_extern: bool): *ast_node { - var to_ret.construct(name, type, enclosing_scope, is_extern): identifier - var ptr = new() - ptr->copy_construct(&ast_node::identifier(to_ret)) - return ptr -} -fun is_identifier(node: *ast_node): bool { - match(*node) { - ast_node::identifier(backing) return true - } - return false -} -obj identifier (Object) { - var name: str - var scope: map> - var type: *type - var enclosing_scope: *ast_node - var is_extern: bool - fun construct(name_in: str, type_in: *type, enclosing_scope: *ast_node, is_extern_in: bool): *identifier { - name.copy_construct(&name_in) - scope.construct() - type = type_in - identifier::enclosing_scope = enclosing_scope - is_extern = is_extern_in - return this - } - fun copy_construct(old: *identifier) { - name.copy_construct(&old->name) - scope.copy_construct(&old->scope) - type = old->type - enclosing_scope = old->enclosing_scope - is_extern = old->is_extern - } - fun destruct() { - name.destruct() - scope.destruct() - } - fun operator=(other: ref identifier) { - destruct() - copy_construct(&other) - } - fun operator==(other: ref identifier): bool { - return name == other.name && type == other.type && enclosing_scope == other.enclosing_scope && is_extern == other.is_extern - } -} -/*fun _type_def(name: str): *ast_node {*/ -fun _type_def(name: ref str): *ast_node { - return _type_def(name, false) -} -fun _type_def(name: ref str, is_union: bool): *ast_node { - var to_ret.construct(name, is_union): type_def - /*var to_ret.construct(name): type_def*/ - var ptr = new() - ptr->copy_construct(&ast_node::type_def(to_ret)) - return ptr -} -fun is_type_def(node: *ast_node): bool { - match(*node) { - ast_node::type_def(backing) return true - } - return false -} -obj type_def (Object) { - var scope: map> - var name: str - var self_type: *type - var variables: vec<*ast_node> - var methods: vec<*ast_node> - var is_union: bool - fun construct(nameIn: ref str, is_unionIn: bool): *type_def { - /*fun construct(nameIn: ref str): *type_def {*/ - /*fun construct(nameIn: str): *type_def {*/ - scope.construct() - name.copy_construct(&nameIn) - is_union = is_unionIn - self_type = null() - variables.construct() - methods.construct() - return this - } - fun copy_construct(old: *type_def) { - self_type = old->self_type - scope.copy_construct(&old->scope) - name.copy_construct(&old->name) - is_union = old->is_union - variables.copy_construct(&old->variables) - methods.copy_construct(&old->methods) - } - fun destruct() { - scope.destruct() - name.destruct() - variables.destruct() - methods.destruct() - } - fun operator=(other: ref type_def) { - destruct() - copy_construct(&other) - } - fun operator==(other: ref type_def): bool { - return name == other.name && is_union == other.is_union && self_type == other.self_type && variables == other.variables && methods == other.methods - /*return name == other.name && self_type == other.self_type && variables == other.variables && methods == other.methods*/ - } -} -fun _adt_def(name: str): *ast_node { - var to_ret.construct(name): adt_def - var ptr = new() - ptr->copy_construct(&ast_node::adt_def(to_ret)) - return ptr -} -fun is_adt_def(node: *ast_node): bool { - match(*node) { - ast_node::adt_def(backing) return true - } - return false -} -obj adt_def (Object) { - var scope: map> - var name: str - var self_type: *type - var options: vec<*ast_node> - var option_funcs: vec<*ast_node> - var regular_funcs: vec<*ast_node> - fun construct(nameIn: str): *adt_def { - scope.construct() - name.copy_construct(&nameIn) - self_type = null() - options.construct() - option_funcs.construct() - regular_funcs.construct() - return this - } - fun copy_construct(old: *adt_def) { - scope.copy_construct(&old->scope) - name.copy_construct(&old->name) - self_type = old->self_type - options.copy_construct(&old->options) - option_funcs.copy_construct(&old->option_funcs) - regular_funcs.copy_construct(&old->regular_funcs) - } - fun destruct() { - scope.destruct() - name.destruct() - options.destruct() - option_funcs.destruct() - regular_funcs.destruct() - } - fun operator=(other: ref adt_def) { - destruct() - copy_construct(&other) - } - fun operator==(other: ref adt_def): bool { - return name == other.name && self_type == other.self_type && options == other.options && option_funcs == other.option_funcs && regular_funcs == other.regular_funcs - } -} -fun _function(name: str, type: *type, parameters: vec<*ast_node>, is_extern: bool): *ast_node - return _function(name, type, parameters, null(), is_extern, false) -fun _function(name: str, type: *type, parameters: vec<*ast_node>, this_param: *ast_node, is_extern: bool, is_variadic: bool): *ast_node { - var to_ret.construct(name, type, parameters, this_param, is_extern, is_variadic): function - var ptr = new() - ptr->copy_construct(&ast_node::function(to_ret)) - return ptr -} -fun is_function(node: *ast_node): bool { - match(*node) { - ast_node::function(backing) return true - } - return false -} -obj function (Object) { - var name: str - var type: *type - var parameters: vec<*ast_node> - var this_param: *ast_node - var closed_variables: set<*ast_node> - var body_statement: *ast_node - var scope: map> - var is_extern: bool - var is_variadic: bool - fun construct(name_in: str, type_in: *type, parameters_in: vec<*ast_node>, this_param_in: *ast_node, is_extern_in: bool, is_variadic_in: bool): *function { - name.copy_construct(&name_in) - parameters.copy_construct(¶meters_in) - this_param = this_param_in - closed_variables.construct() - scope.construct() - type = type_in - body_statement = null() - is_extern = is_extern_in - is_variadic = is_variadic_in - return this - } - fun copy_construct(old: *function) { - name.copy_construct(&old->name) - type = old->type - body_statement = old->body_statement - parameters.copy_construct(&old->parameters) - this_param = old->this_param - closed_variables.copy_construct(&old->closed_variables) - scope.copy_construct(&old->scope) - is_extern = old->is_extern - is_variadic = old->is_variadic - } - fun destruct() { - name.destruct() - parameters.destruct() - closed_variables.destruct() - scope.destruct() - } - fun operator=(other: ref function) { - destruct() - copy_construct(&other) - } - fun operator==(other: ref function): bool { - return name == name && type == other.type && parameters == other.parameters && this_param == other.this_param && body_statement == other.body_statement && closed_variables == other.closed_variables && is_extern == other.is_extern && is_variadic == other.is_variadic - } -} -fun _template(name: str, syntax_node: *tree, template_types: vec, template_type_replacements: map, is_function: bool): *ast_node { - var to_ret.construct(name, syntax_node, template_types, template_type_replacements, is_function): template - var ptr = new() - ptr->copy_construct(&ast_node::template(to_ret)) - return ptr -} -fun is_template(node: *ast_node): bool { - match(*node) { - ast_node::template(backing) return true - } - return false -} -obj template (Object) { - var name: str - var syntax_node: *tree - var instantiated: vec<*ast_node> - var template_types: vec - var template_type_replacements: map - var instantiated_map: map, *ast_node> - var scope: map> - var is_function: bool - fun construct(name_in: str, syntax_node_in: *tree, template_types_in: vec, template_type_replacements_in: map, is_function: bool): *template { - name.copy_construct(&name_in) - syntax_node = syntax_node_in - instantiated.construct() - template_types.copy_construct(&template_types_in) - template_type_replacements.copy_construct(&template_type_replacements_in) - instantiated_map.construct() - scope.construct() - template::is_function = is_function - return this - } - fun copy_construct(old: *template) { - name.copy_construct(&old->name) - syntax_node = old->syntax_node - instantiated.copy_construct(&old->instantiated) - template_types.copy_construct(&old->template_types) - template_type_replacements.copy_construct(&old->template_type_replacements) - instantiated_map.copy_construct(&old->instantiated_map) - scope.copy_construct(&old->scope) - is_function = old->is_function - } - fun destruct() { - name.destruct() - instantiated.destruct() - template_types.destruct() - template_type_replacements.destruct() - instantiated_map.destruct() - scope.destruct() - } - fun operator=(other: ref template) { - destruct() - copy_construct(&other) - } - fun operator==(other: ref template): bool { - return name == name && syntax_node == other.syntax_node && instantiated == other.instantiated && - scope == other.scope && template_types == other.template_types && template_type_replacements == other.template_type_replacements && - instantiated_map == other.instantiated_map && is_function == other.is_function - } -} -fun _code_block(stmt: *ast_node): *ast_node { - var to_ret = _code_block() - to_ret->code_block.children.add(stmt) - return to_ret -} -fun _code_block(): *ast_node { - var to_ret.construct(): code_block - var ptr = new() - ptr->copy_construct(&ast_node::code_block(to_ret)) - return ptr -} -fun is_code_block(node: *ast_node): bool { - match(*node) { - ast_node::code_block(backing) return true - } - return false -} -obj code_block (Object) { - var scope: map> - var children: vec<*ast_node> - fun construct(): *code_block { - scope.construct() - children.construct() - return this - } - fun copy_construct(old: *code_block) { - scope.copy_construct(&old->scope) - children.copy_construct(&old->children) - } - fun destruct() { - scope.destruct() - children.destruct() - } - fun operator=(other: ref code_block) { - destruct() - copy_construct(&other) - } - fun operator==(other: ref code_block): bool { - return children == other.children && scope == other.scope - } -} -fun _if(condition: *ast_node): *ast_node { - var to_ret.construct(condition): if_statement - var ptr = new() - ptr->copy_construct(&ast_node::if_statement(to_ret)) - return ptr -} -fun is_if_statement(node: *ast_node): bool { - match(*node) { - ast_node::if_statement(backing) return true - } - return false -} -obj if_statement (Object) { - var condition: *ast_node - // these are not a part of the constructor because they have to be trnasformed with this as its scope - var then_part: *ast_node - var else_part: *ast_node - var scope: map> - fun construct(condition_in: *ast_node): *if_statement { - condition = condition_in - then_part = null() - else_part = null() - scope.construct() - return this - } - fun copy_construct(old: *if_statement) { - condition = old->condition - then_part = old->then_part - else_part = old->else_part - scope.copy_construct(&old->scope) - } - fun destruct() { - scope.destruct() - } - fun operator=(other: ref if_statement) { - destruct() - copy_construct(&other) - } - fun operator==(other: ref if_statement): bool { - return condition == other.condition && then_part == other.then_part && else_part == other.else_part - } -} -fun _match(value: *ast_node): *ast_node { - var to_ret.construct(value): match_statement - var ptr = new() - ptr->copy_construct(&ast_node::match_statement(to_ret)) - return ptr -} -fun is_match_statement(node: *ast_node): bool { - match(*node) { - ast_node::match_statement(backing) return true - } - return false -} -obj match_statement (Object) { - var scope: map> - var value: *ast_node - var cases: vec<*ast_node> - fun construct(value_in: *ast_node): *match_statement { - scope.construct() - value = value_in - cases.construct() - return this - } - fun copy_construct(old: *match_statement) { - scope.copy_construct(&old->scope) - value = old->value - cases.copy_construct(&old->cases) - } - fun destruct() { - scope.destruct() - cases.destruct() - } - fun operator=(other: ref match_statement) { - destruct() - copy_construct(&other) - } - fun operator==(other: ref match_statement): bool { - return value == other.value && cases == other.cases && scope == other.scope - } -} -fun _case(): *ast_node { - var to_ret.construct(): case_statement - var ptr = new() - ptr->copy_construct(&ast_node::case_statement(to_ret)) - return ptr -} -fun is_case_statement(node: *ast_node): bool { - match(*node) { - ast_node::case_statement(backing) return true - } - return false -} -obj case_statement (Object) { - var scope: map> - var option: *ast_node - var unpack_ident: *ast_node - var statement: *ast_node - fun construct(): *case_statement { - scope.construct() - option = null() - unpack_ident = null() - statement = null() - return this - } - fun copy_construct(old: *case_statement) { - scope.copy_construct(&old->scope) - option = old->option - unpack_ident = old->unpack_ident - statement = old->statement - } - fun destruct() { - scope.destruct() - } - fun operator=(other: ref case_statement) { - destruct() - copy_construct(&other) - } - fun operator==(other: ref case_statement): bool { - return option == other.option && unpack_ident == other.unpack_ident && statement == other.statement - } -} -fun _while(condition: *ast_node): *ast_node { - var to_ret.construct(condition): while_loop - var ptr = new() - ptr->copy_construct(&ast_node::while_loop(to_ret)) - return ptr -} -fun is_while_loop(node: *ast_node): bool { - match(*node) { - ast_node::while_loop(backing) return true - } - return false -} -obj while_loop (Object) { - var condition: *ast_node - var statement: *ast_node - var scope: map> - fun construct(condition_in: *ast_node): *while_loop { - condition = condition_in - statement = null() - scope.construct() - return this - } - fun copy_construct(old: *while_loop) { - condition = old->condition - statement = old->statement - scope.copy_construct(&old->scope) - } - fun destruct() { - scope.destruct() - } - fun operator=(other: ref while_loop) { - destruct() - copy_construct(&other) - } - fun operator==(other: ref while_loop): bool { - return condition == other.condition && statement == other.statement - } -} -fun _for(): *ast_node { - var to_ret.construct(): for_loop - var ptr = new() - ptr->copy_construct(&ast_node::for_loop(to_ret)) - return ptr -} -fun is_for_loop(node: *ast_node): bool { - match(*node) { - ast_node::for_loop(backing) return true - } - return false -} -obj for_loop (Object) { - var init: *ast_node - var condition: *ast_node - var update: *ast_node - var body: *ast_node - var scope: map> - fun construct(): *for_loop { - scope.construct() - init = null() - condition = null() - update = null() - body = null() - return this - } - fun copy_construct(old: *for_loop) { - init = old->init - condition = old->condition - update = old->update - body = old->body - scope.copy_construct(&old->scope) - } - fun destruct() { - scope.destruct() - } - fun operator=(other: ref for_loop) { - destruct() - copy_construct(&other) - } - fun operator==(other: ref for_loop): bool { - return init == other.init && condition == other.condition && update == other.update && body == other.body - } -} -fun _return(return_value: *ast_node): *ast_node { - var to_ret.construct(return_value): return_statement - var ptr = new() - ptr->copy_construct(&ast_node::return_statement(to_ret)) - return ptr -} -fun is_return_statement(node: *ast_node): bool { - match(*node) { - ast_node::return_statement(backing) return true - } - return false -} -obj return_statement (Object) { - var return_value: *ast_node - var scope: map> - fun construct(return_value_in: *ast_node): *return_statement { - return_value = return_value_in - scope.construct() - return this - } - fun copy_construct(old: *return_statement) { - return_value = old->return_value - scope.copy_construct(&old->scope) - } - fun destruct() { - scope.destruct() - } - fun operator=(other: ref return_statement) { - destruct() - copy_construct(&other) - } - fun operator==(other: ref return_statement): bool { - return return_value == other.return_value - } -} -adt branching_type { - break_stmt, - continue_stmt -} -fun _branch(b_type: branching_type): *ast_node { - var to_ret.construct(b_type): branching_statement - var ptr = new() - ptr->copy_construct(&ast_node::branching_statement(to_ret)) - return ptr -} -fun is_branching_statement(node: *ast_node): bool { - match(*node) { - ast_node::branching_statement(backing) return true - } - return false -} -obj branching_statement (Object) { - var b_type: branching_type - fun construct(b_type_in: branching_type): *branching_statement { - b_type.copy_construct(&b_type_in) - return this - } - fun copy_construct(old: *branching_statement) { - b_type.copy_construct(&old->b_type) - } - fun destruct() { - b_type.destruct() - } - fun operator=(other: ref branching_statement) { - destruct() - copy_construct(&other) - } - fun operator==(other: ref branching_statement): bool { - return true - } -} -fun _defer(statement_in: *ast_node): *ast_node { - var to_ret.construct(statement_in): defer_statement - var ptr = new() - ptr->copy_construct(&ast_node::defer_statement(to_ret)) - return ptr -} -fun is_defer_statement(node: *ast_node): bool { - match(*node) { - ast_node::defer_statement(backing) return true - } - return false -} -obj defer_statement (Object) { - var statement: *ast_node - fun construct(statement_in: *ast_node): *defer_statement { - statement = statement_in - return this - } - fun copy_construct(old: *defer_statement) { - statement = old->statement - } - fun destruct() { - } - fun operator=(other: ref defer_statement) { - destruct() - copy_construct(&other) - } - fun operator==(other: ref defer_statement): bool { - return true - } -} -fun _assign(to: *ast_node, from: *ast_node): *ast_node { - var to_ret.construct(to, from): assignment_statement - var ptr = new() - ptr->copy_construct(&ast_node::assignment_statement(to_ret)) - return ptr -} -fun is_assignment_statement(node: *ast_node): bool { - match(*node) { - ast_node::assignment_statement(backing) return true - } - return false -} -obj assignment_statement (Object) { - var to: *ast_node - var from: *ast_node - fun construct(to_in: *ast_node, from_in: *ast_node): *assignment_statement { - to = to_in - from = from_in - return this - } - fun copy_construct(old: *assignment_statement) { - to = old->to - from = old->from - } - fun destruct() { - } - fun operator=(other: ref assignment_statement) { - destruct() - copy_construct(&other) - } - fun operator==(other: ref assignment_statement): bool { - return to == other.to && from == other.from - } -} -fun _declaration(ident: *ast_node, expression: *ast_node): *ast_node { - var to_ret.construct(ident, expression): declaration_statement - var ptr = new() - ptr->copy_construct(&ast_node::declaration_statement(to_ret)) - return ptr -} -fun is_declaration_statement(node: *ast_node): bool { - match(*node) { - ast_node::declaration_statement(backing) return true - } - return false -} -obj declaration_statement (Object) { - var identifier: *ast_node - var expression: *ast_node - var init_method_call: *ast_node - fun construct(identifier_in: *ast_node, expression_in: *ast_node): *declaration_statement { - identifier = identifier_in - expression = expression_in - init_method_call = null() - return this - } - fun copy_construct(old: *declaration_statement) { - identifier = old->identifier - expression = old->expression - init_method_call = old->init_method_call - } - fun destruct() { - } - fun operator=(other: ref declaration_statement) { - destruct() - copy_construct(&other) - } - fun operator==(other: ref declaration_statement): bool { - return identifier == other.identifier && expression == other.expression && init_method_call == other.init_method_call - } -} -fun _if_comp(): *ast_node { - var to_ret.construct(): if_comp - var ptr = new() - ptr->copy_construct(&ast_node::if_comp(to_ret)) - return ptr -} -fun is_if_comp(node: *ast_node): bool { - match(*node) { - ast_node::if_comp(backing) return true - } - return false -} -obj if_comp (Object) { - var wanted_generator: str - var statement: *ast_node - fun construct(): *if_comp { - wanted_generator.construct() - return this - } - fun copy_construct(old: *if_comp) { - wanted_generator.copy_construct(&old->wanted_generator) - statement = old->statement - } - fun destruct() { - wanted_generator.destruct() - } - fun operator=(other: if_comp) { - destruct() - copy_construct(&other) - } - fun operator==(other: if_comp): bool { - return wanted_generator == other.wanted_generator && statement == other.statement - } -} -fun _passthrough(): *ast_node { - var to_ret.construct(): simple_passthrough - var ptr = new() - ptr->copy_construct(&ast_node::simple_passthrough(to_ret)) - return ptr -} -fun is_simple_passthrough(node: *ast_node): bool { - match(*node) { - ast_node::simple_passthrough(backing) return true - } - return false -} -obj simple_passthrough (Object) { - var scope: map> - var passthrough_str: str - var in_params: vec> - var out_params: vec> - var linker_str: str - fun construct(): *simple_passthrough { - scope.construct() - passthrough_str.construct() - in_params.construct() - out_params.construct() - linker_str.construct() - return this - } - fun copy_construct(old: *simple_passthrough) { - scope.copy_construct(&old->scope) - passthrough_str.copy_construct(&old->passthrough_str) - in_params.copy_construct(&old->in_params) - out_params.copy_construct(&old->out_params) - linker_str.copy_construct(&old->linker_str) - } - fun destruct() { - scope.destruct() - passthrough_str.destruct() - in_params.destruct() - out_params.destruct() - linker_str.destruct() - } - fun operator=(other: ref simple_passthrough) { - destruct() - copy_construct(&other) - } - fun operator==(other: ref simple_passthrough): bool { - return scope == other.scope && passthrough_str == other.passthrough_str && in_params == other.in_params && - out_params == other.out_params && linker_str == other.linker_str - } -} -fun _func_call(func: *ast_node, parameters: vec<*ast_node>): *ast_node { - var to_ret.construct(func, parameters): function_call - var ptr = new() - ptr->copy_construct(&ast_node::function_call(to_ret)) - return ptr -} -fun is_function_call(node: *ast_node): bool { - match(*node) { - ast_node::function_call(backing) return true - } - return false -} -obj function_call (Object) { - var func: *ast_node - var parameters: vec<*ast_node> - fun construct(func_in: *ast_node, parameters_in: vec<*ast_node>): *function_call { - func = func_in - parameters.copy_construct(¶meters_in) - return this - } - fun copy_construct(old: *function_call) { - func = old->func - parameters.copy_construct(&old->parameters) - } - fun destruct() { - parameters.destruct() - } - fun operator=(other: ref function_call) { - destruct() - copy_construct(&other) - } - fun operator==(other: ref function_call): bool { - return func == func && parameters == other.parameters - } -} -fun _compiler_intrinsic(intrinsic: str, parameters: vec<*ast_node>, type_parameters: vec<*type>, return_type: *type): *ast_node { - var to_ret.construct(intrinsic, parameters, type_parameters, return_type): compiler_intrinsic - var ptr = new() - ptr->copy_construct(&ast_node::compiler_intrinsic(to_ret)) - return ptr -} -fun is_compiler_intrinsic(node: *ast_node): bool { - match(*node) { - ast_node::compiler_intrinsic(backing) return true - } - return false -} -obj compiler_intrinsic (Object) { - var intrinsic: str - var parameters: vec<*ast_node> - var type_parameters: vec<*type> - var return_type: *type - fun construct(intrinsic_in: str, parameters_in: vec<*ast_node>, type_parameters_in: vec<*type>, return_type_in: *type): *compiler_intrinsic { - intrinsic.copy_construct(&intrinsic_in) - parameters.copy_construct(¶meters_in) - type_parameters.copy_construct(&type_parameters_in) - return_type = return_type_in - return this - } - /*fun copy_construct(old: *function_call) {*/ - fun copy_construct(old: *compiler_intrinsic) { - intrinsic.copy_construct(&old->intrinsic) - parameters.copy_construct(&old->parameters) - type_parameters.copy_construct(&old->type_parameters) - return_type = old->return_type - } - fun destruct() { - intrinsic.destruct() - parameters.destruct() - type_parameters.destruct() - } - fun operator=(other: ref compiler_intrinsic) { - destruct() - copy_construct(&other) - } - fun operator==(other: ref compiler_intrinsic): bool { - return intrinsic == intrinsic && parameters == other.parameters && type_parameters == other.type_parameters && return_type == other.return_type - } -} -fun _cast(value: *ast_node, to_type: *type): *ast_node { - var to_ret.construct(value, to_type): cast - var ptr = new() - ptr->copy_construct(&ast_node::cast(to_ret)) - return ptr -} -fun is_cast(node: *ast_node): bool { - match(*node) { - ast_node::cast(backing) return true - } - return false -} -obj cast (Object) { - var value: *ast_node - var to_type: *type - fun construct(value_in: *ast_node, to_type_in: *type): *cast { - value = value_in - to_type = to_type_in - return this - } - fun copy_construct(old: *cast) { - value = old->value - to_type = old->to_type - } - fun destruct() { - } - fun operator=(other: cast) { - destruct() - copy_construct(&other) - } - fun operator==(other: cast): bool { - return value == other.value && to_type == other.to_type - } -} -fun _value(string_value: str, value_type: *type): *ast_node { - var to_ret.construct(string_value, value_type): value - var ptr = new() - ptr->copy_construct(&ast_node::value(to_ret)) - return ptr -} -fun is_value(node: *ast_node): bool { - match(*node) { - ast_node::value(backing) return true - } - return false -} -obj value (Object) { - var string_value: str - var value_type: *type - var scope: map> - fun construct(string_value_in: str, value_type_in: *type): *value { - scope.construct() - string_value.copy_construct(&string_value_in) - value_type = value_type_in - return this - } - fun copy_construct(old: *value) { - scope.copy_construct(&old->scope) - string_value.copy_construct(&old->string_value) - value_type = old->value_type - } - fun destruct() { - scope.destruct() - string_value.destruct() - } - fun operator=(other: ref value) { - destruct() - copy_construct(&other) - } - fun operator==(other: ref value): bool { - return string_value == other.string_value && value_type == other.value_type - } -} - -fun get_ast_children(node: *ast_node): vec<*ast_node> { - match (*node) { - // Don't get lambdas, let them come up naturally in passes (so can get enclosing function and stuff) - /*ast_node::translation_unit(backing) return backing.children + backing.lambdas*/ - ast_node::translation_unit(backing) return backing.children - ast_node::import(backing) return vec<*ast_node>() - ast_node::identifier(backing) return vec<*ast_node>() - ast_node::type_def(backing) return backing.variables + backing.methods - ast_node::adt_def(backing) return backing.options + backing.option_funcs - ast_node::function(backing) return backing.parameters + backing.body_statement - ast_node::template(backing) return backing.instantiated - ast_node::code_block(backing) return backing.children - ast_node::if_statement(backing) return vec(backing.condition, backing.then_part, backing.else_part) - ast_node::match_statement(backing) return vec(backing.value) + backing.cases - ast_node::case_statement(backing) return vec(backing.option, backing.unpack_ident, backing.statement) - ast_node::while_loop(backing) return vec(backing.condition, backing.statement) - ast_node::for_loop(backing) return vec(backing.init, backing.condition, backing.update, backing.body) - ast_node::return_statement(backing) return vec(backing.return_value) - ast_node::branching_statement(backing) return vec<*ast_node>() - ast_node::defer_statement(backing) return vec(backing.statement) - ast_node::assignment_statement(backing) return vec(backing.to, backing.from) - ast_node::declaration_statement(backing) return vec(backing.identifier, backing.expression, backing.init_method_call) - ast_node::if_comp(backing) return vec<*ast_node>(backing.statement) - ast_node::simple_passthrough(backing) return vec<*ast_node>() - ast_node::function_call(backing) return vec(backing.func) + backing.parameters - ast_node::compiler_intrinsic(backing) return backing.parameters - ast_node::cast(backing) return vec<*ast_node>(backing.value) - ast_node::value(backing) return vec<*ast_node>() - } -} -fun get_ast_name(node: *ast_node): str { - match (*node) { - ast_node::translation_unit(backing) return str("translation_unit: ") + backing.name - ast_node::import(backing) return str("import: ") + backing.name + "; [" + backing.imported.reduce(fun(name: str, acc: str): str return acc + " " + name;, str()) + " ]" - ast_node::identifier(backing) return str("identifier: ") + backing.name + ": " + backing.type->to_string() - ast_node::type_def(backing) { - /*if (backing.is_union)*/ - /*return str("type_def union: ") + backing.name*/ - /*else*/ - return str("type_def: ") + backing.name - } - ast_node::adt_def(backing) return str("adt_def: ") + backing.name - ast_node::function(backing) { - if (backing.is_extern) - return str("extern function: ") + backing.name + ": " + backing.type->to_string() - else - return str("function: ") + backing.name + ": " + backing.type->to_string() - } - ast_node::template(backing) return str("template: ") + backing.name - ast_node::code_block(backing) return str("code_block") - ast_node::if_statement(backing) return str("if_statement") - ast_node::match_statement(backing) return str("match_statement") - ast_node::case_statement(backing) return str("case_statement") - ast_node::while_loop(backing) return str("while_loop") - ast_node::for_loop(backing) return str("for_loop") - ast_node::return_statement(backing) return str("return_statement") - ast_node::branching_statement(backing) return str("branching_statement") - ast_node::defer_statement(backing) return str("defer_statement") - ast_node::assignment_statement(backing) return str("assignment_statement") - ast_node::declaration_statement(backing) return str("declaration_statement") - ast_node::if_comp(backing) return str("if_comp: ") + backing.wanted_generator - ast_node::simple_passthrough(backing) return str("simple_passthrough: , str:") + backing.passthrough_str - ast_node::function_call(backing) return str("function_call:") + get_ast_name(backing.func) + "(" + backing.parameters.size + ")" - ast_node::compiler_intrinsic(backing) return str("compiler_intrinsic:") + backing.intrinsic + "(" + backing.parameters.size + "," + backing.type_parameters.size + "):" + backing.return_type->to_string() - ast_node::cast(backing) return str("cast: ") + get_ast_name(backing.value) + ": " + backing.to_type->to_string() - ast_node::value(backing) return str("value: ") + backing.string_value + ": " + backing.value_type->to_string() - } - return str("impossible adt type") -} -fun get_ast_scope(node: *ast_node): *map> { - match (*node) { - ast_node::translation_unit() return &node->translation_unit.scope - ast_node::import() return &node->import.scope - ast_node::identifier() return &node->identifier.scope - ast_node::type_def() return &node->type_def.scope - ast_node::adt_def() return &node->adt_def.scope - ast_node::function() return &node->function.scope - ast_node::template() return &node->template.scope - ast_node::code_block() return &node->code_block.scope - ast_node::if_statement() return &node->if_statement.scope - ast_node::match_statement() return &node->match_statement.scope - ast_node::case_statement() return &node->case_statement.scope - ast_node::while_loop() return &node->while_loop.scope - ast_node::for_loop() return &node->for_loop.scope - ast_node::return_statement() return &node->return_statement.scope - ast_node::simple_passthrough() return &node->simple_passthrough.scope - ast_node::value() return &node->value.scope - } - return null>>() -} -fun get_ast_type(node: *ast_node): *type { - match (*node) { - ast_node::identifier(backing) return backing.type - ast_node::function(backing) return backing.type - ast_node::function_call(backing) return get_ast_type(backing.func)->return_type - ast_node::compiler_intrinsic(backing) return backing.return_type - ast_node::cast(backing) return backing.to_type - ast_node::value(backing) return backing.value_type - } - return null() -} - -fun ast_to_dot(root: *ast_node): str { - var ret = str("digraph Kaken {\n") - var counter = 0 - var node_name_map = map<*ast_node, str>() - var get_name = fun(node: *ast_node): str { - if (node_name_map.contains_key(node)) - return node_name_map[node] - var escaped = str("") - get_ast_name(node).data.for_each(fun(c: char) { - if (c != '"') - escaped += c - else - escaped += "\\\"" - }) - escaped += to_string(counter++) - node_name_map.set(node, escaped) - return escaped - } - var done_set = set<*ast_node>() - var helper: fun(*ast_node):void = fun(node: *ast_node) { - done_set.add(node) - get_ast_children(node).for_each(fun(child: *ast_node) { - if (!child || done_set.contains(child)) - return; // where on earth does the null come from - ret += str("\"") + get_name(node) + "\" -> \"" + get_name(child) + "\"\n"; - helper(child) - }) - } - if (root) - helper(root) - return ret + "}" -} - diff --git a/stdlib/ast_transformation.krak b/stdlib/ast_transformation.krak deleted file mode 100644 index 01ff8cc..0000000 --- a/stdlib/ast_transformation.krak +++ /dev/null @@ -1,1077 +0,0 @@ -import symbol:* -import tree:* -import vec:* -import queue:* -import stack:* -import map:* -import util:* -import str:* -import mem:* -import io:* -import os:* -import importer:* -import ast_nodes:* -import type:* -import pass_common:* - -adt search_type { - none, - function: vec<*type> -} - -obj ast_transformation (Object) { - var ast_to_syntax: map<*ast_node, *tree> - var type_def_to_this: map<*ast_node, *ast_node> - var fourth_pass_worklist: queue<*ast_node> - fun construct(): *ast_transformation { - ast_to_syntax.construct() - type_def_to_this.construct() - fourth_pass_worklist.construct() - return this - } - fun copy_construct(old: *ast_transformation) { - ast_to_syntax.copy_construct(&old->ast_to_syntax) - type_def_to_this.copy_construct(&old->type_def_to_this) - fourth_pass_worklist.copy_construct(&old->fourth_pass_worklist) - } - fun operator=(old: ref ast_transformation) { - destruct() - copy_construct(&old) - } - fun destruct() { - ast_to_syntax.destruct() - type_def_to_this.destruct() - fourth_pass_worklist.destruct() - } - // first pass defines all type_defs (objects and aliases), ADTs, and top-level if-comps/passthroughs - fun first_pass(file_name: str, parse_tree: *tree): pair<*ast_node, vec<*ast_node>> { - var translation_unit = _translation_unit(file_name) - parse_tree->children.for_each(fun(child: *tree) { - if (child->data.name == "type_def") { - translation_unit->translation_unit.children.add(first_pass_type_def(child, translation_unit, false)) - } else if (child->data.name == "adt_def") { - var name = concat_symbol_tree(get_node("identifier", child)) - var adt_def_node = _adt_def(name) - adt_def_node->adt_def.self_type = type_ptr(adt_def_node, set(str("Object"))) - translation_unit->translation_unit.children.add(adt_def_node) - ast_to_syntax.set(adt_def_node, child) - add_to_scope("~enclosing_scope", translation_unit, adt_def_node) - add_to_scope(name, adt_def_node, translation_unit) - } else if (child->data.name == "if_comp") { - var if_comp_node = transform_if_comp(child, translation_unit) - translation_unit->translation_unit.children.add(if_comp_node) - ast_to_syntax.set(if_comp_node, child) - } - }) - - // now do all imports - // re return a vec of them so importer can fix them (and our translation unit scope) - // up with actual pointers to the other ASTs - var imports = vec<*ast_node>() - parse_tree->children.for_each(fun(child: *tree) { - if (child->data.name == "import") { - var import_identifier_children = get_nodes("identifier", child) - var name = concat_symbol_tree(import_identifier_children[0]) - var import_node = _import(name, translation_unit) - imports.add(import_node) - translation_unit->translation_unit.children.add(import_node) - ast_to_syntax.set(import_node, child) - add_to_scope("~enclosing_scope", translation_unit, import_node) - import_node->import.imported = from_vector(import_identifier_children.slice(1,-1).map(fun(ident: *tree):str return concat_symbol_tree(ident);)) - if (get_node("\"\\*\"", child)) - import_node->import.starred = true - } - }) - return make_pair(translation_unit, imports) - } - fun transform_traits(traits_node: *tree): set { - if (!traits_node) - return set() - return from_vector(get_nodes("scoped_identifier", traits_node).map(fun(s: *tree): str return concat_symbol_tree(s);)) - } - fun first_pass_type_def(child: *tree, scope: *ast_node, instantiate_template: bool): *ast_node { - var name = concat_symbol_tree(get_node("identifier", child)) - var template_dec = get_node("template_dec", child) - if (template_dec && !instantiate_template) { - var template_types = vec() - var template_type_replacements = map() - // XXX add traits - get_nodes("template_param", template_dec).for_each(fun(template_param: *tree) { - template_types.add(concat_symbol_tree(get_node("identifier", template_param))) - template_type_replacements.set(template_types.last(), type_ptr(transform_traits(get_node("traits", template_param)))) - }) - var template = _template(name, child, template_types, template_type_replacements, false) - add_to_scope("~enclosing_scope", scope, template) - add_to_scope(name, template, scope) - return template - } else { - // pass in whether or not this is a union - var type_def_node = _type_def(name, concat_symbol_tree(get_node("obj_nonterm", child)) == "uni") - /*var type_def_node = _type_def(name, false)*/ - /*var type_def_node = _type_def(name)*/ - type_def_node->type_def.self_type = type_ptr(type_def_node, transform_traits(get_node("traits", child))) - ast_to_syntax.set(type_def_node, child) - add_to_scope("~enclosing_scope", scope, type_def_node) - add_to_scope(name, type_def_node, scope) - return type_def_node - } - } - // defines inside of objects + ADTs, outside declaration statements, and function prototypes - fun second_pass(parse_tree: *tree, translation_unit: *ast_node) { - // we go through the parse tree for getting functions, but we're going through the ast for the things we've already set up and using the ast_to_syntax map - parse_tree->children.for_each(fun(child: *tree) { - if (child->data.name == "function") { - // also handles templated function - var function_node = second_pass_function(child, translation_unit, map(), true) - translation_unit->translation_unit.children.add(function_node) - ast_to_syntax.set(function_node, child) - } else if (child->data.name == "declaration_statement") { - // second pass declaration can actually just call a normal transform (but maybe should be it's own method to do so because typedef has to do it too?)... - translation_unit->translation_unit.children.add(transform_declaration_statement(child, translation_unit, map())) - } - }) - // work on the ones already started - translation_unit->translation_unit.children.for_each(fun(node: *ast_node) { - match(*node) { - ast_node::type_def(backing) second_pass_type_def(ast_to_syntax[node], node, translation_unit, map()) - ast_node::adt_def(backing) second_pass_adt_def(ast_to_syntax[node], node, translation_unit, map()) - } - }) - } - fun second_pass_type_def(type_def_syntax: *tree, node: *ast_node, scope: *ast_node, template_replacements: map) { - type_def_syntax->children.for_each(fun(child: *tree) { - if (child->data.name == "declaration_statement") { - var declaration_node = transform_declaration_statement(child, node, template_replacements) - node->type_def.variables.add(declaration_node) - ast_to_syntax.set(declaration_node, child) - } else if (child->data.name == "function") { - // again, also handles templates - var function_node = second_pass_function(child, node, template_replacements, true) - node->type_def.methods.add(function_node) - ast_to_syntax.set(function_node, child) - } - }) - } - fun second_pass_adt_def(adt_def_syntax: *tree, node: *ast_node, scope: *ast_node, template_replacements: map) { - get_nodes("adt_option", adt_def_syntax).for_each(fun(adt_option: *tree) { - var ident_type: *type - var type_syntax = get_node("type", adt_option) - if (type_syntax) - ident_type = transform_type(type_syntax, scope, template_replacements) - else - ident_type = type_ptr(base_type::no_type_adt_option()) - var option_name = concat_symbol_tree(get_node("identifier", adt_option)) - var identifier = _ident(option_name, ident_type, node) - node->adt_def.options.add(identifier) - // we add the identifier first so that it's found before the function when doing option.thingy - add_to_scope(option_name, identifier, node) - add_to_scope("~enclosing_scope", node, identifier) - ast_to_syntax.set(identifier, adt_option) - - var function_node = null() - if (type_syntax) { - var identifier_param = _ident(option_name, ident_type, node) - function_node = _function(option_name, type_ptr(vec(get_ast_type(identifier_param)), node->adt_def.self_type, 0, false, false, true), vec(identifier_param), false) - } else { - function_node = _function(option_name, type_ptr(vec<*type>(), node->adt_def.self_type, 0, false, false, true), vec<*ast_node>(), false) - } - add_to_scope(option_name, function_node, node) - add_to_scope("~enclosing_scope", node, function_node) - node->adt_def.option_funcs.add(function_node) - }) - // we fake operator==, operator!=, copy_construct, operator=, and destruct like so - // note they don't even have real parameters (but the type has them correctly) or bodies - - // I'm not sure this is the correct enclosing scope, but I'm not sure how to do it with the function either - var equals_param = _ident(str("in"), node->adt_def.self_type->clone_with_indirection(0,true), node) - var nequals_param = _ident(str("in"), node->adt_def.self_type->clone_with_indirection(0,true), node) - var copy_construct_param = _ident(str("in"), node->adt_def.self_type->clone_with_indirection(1,false), node) - var assign_param = _ident(str("in"), node->adt_def.self_type->clone_with_indirection(0,true), node) - vec( - make_pair("operator==", _function(str("operator=="), - type_ptr(vec(equals_param->identifier.type), type_ptr(base_type::boolean()), 0, false, false, true), - vec(equals_param), _ident("this", node->adt_def.self_type->clone_with_indirection(1), node), false, false)), - make_pair("operator!=", _function(str("operator!="), - type_ptr(vec(nequals_param->identifier.type), type_ptr(base_type::boolean()), 0, false, false, true), - vec(nequals_param), _ident("this", node->adt_def.self_type->clone_with_indirection(1), node), false, false)), - make_pair("construct", _function(str("construct"), - type_ptr(vec<*type>(), node->adt_def.self_type->clone_with_increased_indirection(), 0, false, false, true), - vec<*ast_node>(), _ident("this", node->adt_def.self_type->clone_with_indirection(1), node), false, false)), - make_pair("copy_construct", _function(str("copy_construct"), - type_ptr(vec(copy_construct_param->identifier.type), node->adt_def.self_type->clone_with_increased_indirection(), 0, false, false, true), - vec(copy_construct_param), _ident("this", node->adt_def.self_type->clone_with_indirection(1), node), false, false)), - make_pair("operator=", _function(str("operator="), - type_ptr(vec(assign_param->identifier.type), type_ptr(base_type::void_return()), 0, false, false, true), - vec(assign_param), _ident("this", node->adt_def.self_type->clone_with_indirection(1), node), false, false)), - make_pair("destruct", _function(str("destruct"), - type_ptr(vec<*type>(), type_ptr(base_type::void_return()), 0, false, false, true), - vec<*ast_node>(), _ident("this", node->adt_def.self_type->clone_with_indirection(1), node), false, false)) - ).for_each(fun(func_pair: pair<*char, *ast_node>) { - node->adt_def.regular_funcs.add(func_pair.second) - add_to_scope(str(func_pair.first), func_pair.second, node) - add_to_scope("~enclosing_scope", node, func_pair.second) - }) - } - fun second_pass_function(node: *tree, scope: *ast_node, template_replacements: map, do_raw_template: bool): *ast_node { - var func_identifier_node = get_node("func_identifier", node) - var function_name = str("__compiler_lambda__") - if (func_identifier_node) - function_name = concat_symbol_tree(func_identifier_node) - var template_dec = get_node("template_dec", node) - if (do_raw_template && template_dec) { - var template_types = vec() - var template_type_replacements = map() - get_nodes("template_param", template_dec).for_each(fun(template_param: *tree) { - template_types.add(concat_symbol_tree(get_node("identifier", template_param))) - template_type_replacements.set(template_types.last(), type_ptr(transform_traits(get_node("traits", template_param)))) - }) - var template = _template(function_name, node, template_types, template_type_replacements, true) - add_to_scope(function_name, template, scope) - add_to_scope("~enclosing_scope", scope, template) - return template - } - // check to see if it is a template - // figure out return type - var typed_return_node = get_node("typed_return", node) - // darn no ternary yet - var return_type = null() - if (typed_return_node) return_type = transform_type(get_node("type", typed_return_node), scope, template_replacements) - else return_type = type_ptr(base_type::void_return()) - if (return_type->is_none()) - error(node, "return type none") - // transform parameters - var parameters = vec<*ast_node>() - get_nodes("typed_parameter", node).for_each(fun(child: *tree) { - // note the temporary null() which gets replaced below, as the dependency is circular - var param_type = transform_type(get_node("type", child), scope, template_replacements) - if (param_type->is_none()) - error(child, "parameter type none") - parameters.add(_ident(concat_symbol_tree(get_node("identifier", child)), param_type, null())) - }) - var is_variadic = get_node("\"...\"", node) != null>() - var is_raw = function_name != "__compiler_lambda__" - var this_param = null() - if (is_type_def(scope)) { - this_param = _ident("this", scope->type_def.self_type->clone_with_indirection(1), scope) - } else if (is_template(scope)) { - var parent_scope = get_ast_scope(scope)->get(str("~enclosing_scope"))[0] - if (is_type_def(parent_scope)) { - this_param = _ident("this", parent_scope->type_def.self_type->clone_with_indirection(1), parent_scope) - } - } - // figure out function type and make function_node - var function_node = _function(function_name, - type_ptr(parameters.map(fun(parameter: *ast_node): *type return parameter->identifier.type;), - return_type, 0, false, is_variadic, is_raw), parameters, this_param, get_node("\"ext\"", node) != null>(), is_variadic) - // fix up the enclosing_scope's - parameters.for_each(fun(n: *ast_node) n->identifier.enclosing_scope = function_node;) - // add to scope - add_to_scope(function_name, function_node, scope) - add_to_scope("~enclosing_scope", scope, function_node) - // add parameters to scope of function - parameters.for_each(fun(parameter: *ast_node) add_to_scope(parameter->identifier.name, parameter, function_node);) - return function_node - } - // The third pass finishes up by doing all function bodies (top level and methods in objects), and top level compiler intrinsics - fun third_pass(parse_tree: *tree, translation_unit: *ast_node) { - translation_unit->translation_unit.children.for_each(fun(node: *ast_node) { - match(*node) { - ast_node::type_def(backing) { - // also same body problem as below - backing.methods.for_each(fun(method: *ast_node) { - if (!is_template(method)) - method->function.body_statement = transform_statement(get_node("statement", ast_to_syntax[method]), method, map()) - }) - } - ast_node::function(backing) { - // make sure not a template - if (!backing.is_extern) - backing.body_statement = transform_statement(get_node("statement", ast_to_syntax[node]), node, map()) - } - } - }) - parse_tree->children.for_each(fun(child: *tree) { - if (child->data.name == "compiler_intrinsic") { - translation_unit->translation_unit.children.add(transform_compiler_intrinsic(child, translation_unit, map())) - } - }) - } - // The fourth pass generates the class templates that have not yet been generated in a worklist loop - fun fourth_pass(parse_tree: *tree, translation_unit: *ast_node) { - while (!fourth_pass_worklist.empty()) { - var partially_inst_type_def = fourth_pass_worklist.pop() - partially_inst_type_def->type_def.methods.for_each(fun(method: *ast_node) { - // if this is a templated method, we've either instantiatedit if we need it or not if we didn't, so we don't do anything with it here - if (is_template(method)) - return - var template = partially_inst_type_def->type_def.scope[str("~enclosing_scope")][0] - var template_types = template->template.template_types - var real_types = template->template.instantiated_map.reverse_get(partially_inst_type_def) - var replacements = map() - for (var i = 0; i < template_types.size; i++;) - replacements.set(template_types[i], real_types[i].clone()) - method->function.body_statement = transform_statement(get_node("statement", ast_to_syntax[method]), method, replacements) - }) - } - } - fun transform_type(node: *tree, scope: *ast_node, template_replacements: map): *type { - // check for references and step down - // always get to pre-reffed level - var is_ref = get_node("\"ref\"", node) != null>() - var real_node = get_node("pre_reffed", node) - // check for indirection and step down - var indirection = 0 - while (get_node("pre_reffed", real_node)) { - real_node = get_node("pre_reffed", real_node) - indirection++ - } - var template_inst = get_node("template_inst", real_node) - if (template_inst) { - var name = concat_symbol_tree(get_node("scoped_identifier", real_node)) - var real_types = get_nodes("type", template_inst).map(fun(t: *tree): *type return transform_type(t, scope, template_replacements);) - var real_types_deref = real_types.map(fun(t:*type):type return *t;) - var results = scope_lookup(name, scope) - - var fitting_types = vec>() - for (var i = 0; i < results.size; i++;) { - if (!is_template(results[i]) || results[i]->template.is_function) - continue - var template_types = results[i]->template.template_types - var template_type_replacements = results[i]->template.template_type_replacements - if (template_types.size != real_types.size) - continue - - var num_satisfied_traits = 0 - var satisfied_traits = true - template_type_replacements.for_each(fun(key: str, value: *type) num_satisfied_traits += value->traits.size();) - for (var j = 0; j < template_types.size; j++;) { - satisfied_traits = satisfied_traits && real_types[j]->traits.contains(template_type_replacements[template_types[j]]->traits) && - (real_types[j]->indirection == 0 || template_type_replacements[template_types[j]]->traits.size() == 0) - template_type_replacements[template_types[j]] = real_types[j] - } - if (!satisfied_traits) - continue - - var inst_type = null() - // check if already instantiated - if (results[i]->template.instantiated_map.contains_key(real_types_deref)) { - inst_type = results[i]->template.instantiated_map[real_types_deref] - } else { - var typeStr = str() - real_types_deref.for_each(fun(t: type) typeStr += t.to_string(false) + " ";) - results[i]->template.instantiated_map.for_each(fun(key: vec, value: *ast_node) { - var hasTypStr = str() - key.for_each(fun(t: type) hasTypStr += t.to_string(false) + " ";) - if (typeStr == hasTypStr) - error(node, "they're equal but really shouldnt be") - }) - if (real_types.any_true(fun(t: *type): bool return t->is_none() || t ->is_template_type();)) { - error(node, "Instantiating types for templated object are not all real types!") - } - inst_type = first_pass_type_def(results[i]->template.syntax_node, results[i], true) - // no change up it's name so we can see that it's instantiated when printed out and keep track of it - inst_type->type_def.name += "<" + typeStr + ">" - // add to instantiated_map so we only instantiate with a paticular set of types once - // put in map first for recursive purposes - results[i]->template.instantiated_map.set(real_types_deref, inst_type) - results[i]->template.instantiated.add(inst_type) - second_pass_type_def(results[i]->template.syntax_node, inst_type, results[i], template_type_replacements) - fourth_pass_worklist.push(inst_type) - } - fitting_types.add(make_pair(inst_type, num_satisfied_traits)) - } - if (fitting_types.size == 0) { - println("no working templated object found") - error(node, "FREAK OUT AUTOMATON") - return null() - } - return fitting_types.max(fun(a: pair<*ast_node, int>, b: pair<*ast_node, int>): bool return a.second < b.second;).first->type_def.self_type->clone_with_indirection(indirection, is_ref) - } - var type_syntax_str = concat_symbol_tree(real_node) - if (template_replacements.contains_key(type_syntax_str)) { - var to_ret = template_replacements[type_syntax_str]->clone_with_increased_indirection(indirection, is_ref) - return to_ret - } - // should take into account references... - if (type_syntax_str == "void") - return type_ptr(base_type::void_return(), indirection, is_ref) - else if (type_syntax_str == "bool") - return type_ptr(base_type::boolean(), indirection, is_ref) - else if (type_syntax_str == "char") - return type_ptr(base_type::character(), indirection, is_ref) - else if (type_syntax_str == "uchar") - return type_ptr(base_type::ucharacter(), indirection, is_ref) - else if (type_syntax_str == "short") - return type_ptr(base_type::short_int(), indirection, is_ref) - else if (type_syntax_str == "ushort") - return type_ptr(base_type::ushort_int(), indirection, is_ref) - else if (type_syntax_str == "int") - return type_ptr(base_type::integer(), indirection, is_ref) - else if (type_syntax_str == "uint") - return type_ptr(base_type::uinteger(), indirection, is_ref) - else if (type_syntax_str == "long") - return type_ptr(base_type::long_int(), indirection, is_ref) - else if (type_syntax_str == "ulong") - return type_ptr(base_type::ulong_int(), indirection, is_ref) - else if (type_syntax_str == "float") - return type_ptr(base_type::floating(), indirection, is_ref) - else if (type_syntax_str == "double") - return type_ptr(base_type::double_precision(), indirection, is_ref) - else if (get_node("function_type", real_node)) { - var function_type = get_node("function_type", real_node) - var types = get_nodes("type", function_type).map(fun(node: *tree): *type transform_type(node, scope, template_replacements);) - return type_ptr(types.slice(0,-2), types.last(), indirection, is_ref, false, get_node("\"run\"", function_type) != null>()) // check for raw function pointer - } else { - // do lookup for objects, ADTs, templates, etc - var possibilities = scope_lookup(type_syntax_str, scope) - for (var i = 0; i < possibilities.size; i++;) { - match(*possibilities[i]) { - ast_node::type_def(backing) return backing.self_type->clone_with_indirection(indirection, is_ref) - ast_node::adt_def(backing) return backing.self_type->clone_with_indirection(indirection, is_ref) - } - } - // error("no types found for " + type_syntax_str) - return type_ptr(base_type::none(), indirection, is_ref) - } - } - fun transform(node: *tree, scope: *ast_node, template_replacements: map): *ast_node return transform(node, scope, search_type::none(), template_replacements) - fun transform(node: *tree, scope: *ast_node, searching_for: search_type, template_replacements: map): *ast_node { - var name = node->data.name - if (name == "identifier" || name == "scoped_identifier") { - return transform_identifier(node, scope, searching_for) - } else if (name == "code_block") { - return transform_code_block(node, scope, template_replacements) - } else if (name == "if_comp") { - return transform_if_comp(node, scope) - } else if (name == "simple_passthrough") { - return transform_simple_passthrough(node, scope) - } else if (name == "statement") { - return transform_statement(node, scope, template_replacements) - } else if (name == "declaration_statement") { - return transform_declaration_statement(node, scope, template_replacements) - } else if (name == "assignment_statement") { - return transform_assignment_statement(node, scope, template_replacements) - } else if (name == "if_statement") { - return transform_if_statement(node, scope, template_replacements) - } else if (name == "while_loop") { - return transform_while_loop(node, scope, template_replacements) - } else if (name == "for_loop") { - return transform_for_loop(node, scope, template_replacements) - } else if (name == "return_statement") { - return transform_return_statement(node, scope, template_replacements) - } else if (name == "continue_statement" || name == "break_statement") { - return transform_branching_statement(node, scope) - } else if (name == "defer_statement") { - return transform_defer_statement(node, scope, template_replacements) - } else if (name == "match_statement") { - return transform_match_statement(node, scope, template_replacements) - } else if (name == "function_call") { - return transform_function_call(node, scope, template_replacements) - } else if (name == "compiler_intrinsic") { - return transform_compiler_intrinsic(node, scope, template_replacements) - } else if (name == "lambda") { - return transform_lambda(node, scope, template_replacements) - } else if (name == "boolean_expression" || name == "and_boolean_expression" - || name == "bitwise_or" || name == "bitwise_xor" || name == "bitwise_and" - || name == "bool_exp" || name == "expression" - || name == "shiftand" || name == "term" - || name == "factor" || name == "unarad" - || name == "access_operation" || name == "cast_expression" - ) { - return transform_expression(node, scope, searching_for, template_replacements) - } else if (name == "bool" || name == "string" - || name == "character" || name == "number" - ) { - return transform_value(node, scope) - } - print("FAILED TO TRANSFORM: "); print(name + ": "); println(concat_symbol_tree(node)) - error(node, "FAILED TO TRANSFORM") - return null() - } - fun transform_all(nodes: vec<*tree>, scope: *ast_node, template_replacements: map): vec<*ast_node> { - return nodes.map(fun(node: *tree): *ast_node return transform(node, scope, template_replacements);) - } - fun transform_identifier(node: *tree, scope: *ast_node, searching_for: search_type): *ast_node { - // first, we check for and generate this - var name = concat_symbol_tree(node) - if (name == "this") { - while (!is_function(scope) || scope->function.this_param == null()) - scope = get_ast_scope(scope)->get(str("~enclosing_scope"))[0] - if (!is_function(scope)) - error(node, "Couldn't find this") - return scope->function.this_param - } - match (searching_for) { - search_type::none() return identifier_lookup(name, scope) - search_type::function(type_vec) { - var possible_func = function_lookup(name, scope, type_vec) - if (possible_func) - return possible_func - var possible_obj = identifier_lookup(name, scope) - // sometimes identifier lookup doesn't return identfiers, i.e. function values, etc - if (possible_obj && is_identifier(possible_obj)) { - var possible_obj_type = get_ast_type(possible_obj) - // note operator() has had it's () stripped out... - if (possible_obj_type->is_object() && has_method(possible_obj_type->type_def, "operator", type_vec)) { - return possible_obj - } - } - } - } - return null() - } - fun transform_value(node: *tree, scope: *ast_node): *ast_node { - var value_str = concat_symbol_tree(node) - var value_type = null() - if (value_str[0] == '"') { // " // Comment hack for emacs now - value_type = type_ptr(base_type::character(), 1) - var start = 1 - var end = value_str.length() -1 - if (value_str.length() > 3 && value_str[1] == '"' && value_str[2] == '"') { - value_str = value_str.slice(3,-4) - } else { - var new_str.construct(end-start): str - var escaped = false - for (var i = 1; i < value_str.length()-1; i++;) { - if (escaped) { - escaped = false - if (value_str[i] == 'n') - new_str += '\n' - else if (value_str[i] == 't') - new_str += '\t' - else - new_str += value_str[i] - } else if (value_str[i] == '\\') { - escaped = true - } else { - new_str += value_str[i] - } - } - value_str = new_str - } - } else if (value_str[0] == '\'') { //'// lol, comment hack for vim syntax highlighting (my fault, of course) - value_type = type_ptr(base_type::character()) - value_str = value_str.slice(1,-2) - } else if (value_str == "true" || value_str == "false") - value_type = type_ptr(base_type::boolean()) - else { - // should differentiate between float and double... - var contains_dot = false - for (var i = 0; i < value_str.length(); i++;) { - if (value_str[i] == '.') { - contains_dot = true - break - } - } - if (contains_dot) { - if (value_str.last() == 'f') - value_type = type_ptr(base_type::floating()) - else - value_type = type_ptr(base_type::double_precision()) - } else { - var chop = 0 - if (value_str.length() > 2) { - var s = value_str.slice(-3,-1) - if (s == "uc") { chop = 2; value_type = type_ptr(base_type::ucharacter()); } - else if (s == "us") { chop = 2; value_type = type_ptr(base_type::ushort_int()); } - else if (s == "ul") { chop = 2; value_type = type_ptr(base_type::ulong_int()); } - } - if (chop == 0) { - if (value_str.last() == 'c') { chop = 1; value_type = type_ptr(base_type::character()); } - else if (value_str.last() == 's') { chop = 1; value_type = type_ptr(base_type::short_int()); } - else if (value_str.last() == 'u') { chop = 1; value_type = type_ptr(base_type::uinteger()); } - else if (value_str.last() == 'l') { chop = 1; value_type = type_ptr(base_type::long_int()); } - } - if (chop == 0) value_type = type_ptr(base_type::integer()) - value_str = value_str.slice(0, -1-chop) - } - } - return _value(value_str, value_type) - } - fun transform_code_block(node: *tree, scope: *ast_node, template_replacements: map): *ast_node { - var new_block = _code_block() - add_to_scope("~enclosing_scope", scope, new_block) - new_block->code_block.children = transform_all(node->children, new_block, template_replacements) - return new_block - } - fun transform_if_comp(node: *tree, scope: *ast_node): *ast_node { - var new_if_comp = _if_comp() - new_if_comp->if_comp.wanted_generator = concat_symbol_tree(get_node("identifier", node)) - new_if_comp->if_comp.statement = transform_statement(get_node("statement", node), scope, map()) - return new_if_comp - } - fun transform_simple_passthrough(node: *tree, scope: *ast_node): *ast_node { - var new_passthrough = _passthrough() - new_passthrough->simple_passthrough.passthrough_str = concat_symbol_tree(get_node("triple_quoted_string", node)).slice(3,-4) - // setup passthrough params and str - var passthrough_params = get_node("passthrough_params", node) - if (!passthrough_params) - return new_passthrough - var in_passthrough_params = get_node("in_passthrough_params", passthrough_params) - var out_passthrough_params = get_node("out_passthrough_params", passthrough_params) - var linker_str = get_node("opt_string", passthrough_params) - if (in_passthrough_params) - get_nodes("param_assign", in_passthrough_params).for_each(fun(p: *tree) { - var idents = get_nodes("identifier", p) - if (idents.size == 2) - new_passthrough->simple_passthrough.in_params.add(make_pair(transform_identifier(idents[0], scope, search_type::none()), concat_symbol_tree(idents[1]))) - else - new_passthrough->simple_passthrough.in_params.add(make_pair(transform_identifier(idents[0], scope, search_type::none()), concat_symbol_tree(idents[0]))) - }) - if (out_passthrough_params) - get_nodes("param_assign", out_passthrough_params).for_each(fun(p: *tree) { - var idents = get_nodes("identifier", p) - if (idents.size == 2) - new_passthrough->simple_passthrough.out_params.add(make_pair(transform_identifier(idents[0], scope, search_type::none()), concat_symbol_tree(idents[1]))) - else - new_passthrough->simple_passthrough.out_params.add(make_pair(transform_identifier(idents[0], scope, search_type::none()), concat_symbol_tree(idents[0]))) - }) - if (linker_str) - new_passthrough->simple_passthrough.linker_str = concat_symbol_tree(linker_str).slice(1,-2) - return new_passthrough - } - fun transform_statement(node: *tree, scope: *ast_node, template_replacements: map): *ast_node { - return transform(node->children[0], scope, template_replacements); - } - fun transform_declaration_statement(node: *tree, scope: *ast_node, template_replacements: map): *ast_node { - // this might have an init position method call - var identifiers = get_nodes("identifier", node) - var name = concat_symbol_tree(identifiers[0]) - // may have type, or an expression, or both - var type_syntax_node = get_node("type", node) - var expression_syntax_node = get_node("boolean_expression", node) - var expression = null() - // we do it early so that if there is a type_syntax_node we can add to scope so that the expression can find this for things like rec closures - var identifier = _ident(name, null(), scope, get_node("\"ext\"", node) != null>()) - add_to_scope(name, identifier, scope) - if (type_syntax_node) identifier->identifier.type = transform_type(type_syntax_node, scope, template_replacements) - if (expression_syntax_node) { - expression = transform(expression_syntax_node, scope, template_replacements) - if (!type_syntax_node) - identifier->identifier.type = get_ast_type(expression)->clone_without_ref() - } - if (!identifier->identifier.type) error(node, "declaration statement with no type or expression from which to inference type") - if (identifier->identifier.type->is_none() || (identifier->identifier.type->indirection == 0 && identifier->identifier.type->is_void())) error(node, "declaration statement with bad type") - var declaration = _declaration(identifier, expression) - // ok, deal with the possible init position method call - if (identifiers.size == 2) { - var parameters = get_nodes("parameter", node).map(fun(child: *tree): *ast_node return transform(get_node("boolean_expression", child), scope, template_replacements);) - var method = transform(identifiers[1], identifier->identifier.type->type_def, search_type::function(parameters.map(fun(i:*ast_node):*type return get_ast_type(i);)), template_replacements) - if (!method) - error(identifiers[1], "Cannot find method for declaration site method call") - declaration->declaration_statement.init_method_call = make_method_call(identifier, method, parameters) - } - return declaration - } - fun transform_assignment_statement(node: *tree, scope: *ast_node, template_replacements: map): *ast_node { - var to_assign = transform(get_node("boolean_expression", node), scope, template_replacements) - // for []= overloading - if (get_node("\"=\"", node)) { - var factor_part = get_node("factor", node) - if (factor_part->children.size == 1) { - var inner_unarad = get_node("unarad", factor_part) - if (get_node("\"]\"", inner_unarad)) { - var assign_to = transform(get_node("unarad", inner_unarad), scope, template_replacements) - var assign_idx = transform(get_node("expression", inner_unarad), scope, template_replacements) - var possible_bracket_assign = find_and_make_any_operator_overload_call(str("[]="), vec(assign_to, assign_idx, to_assign), scope, template_replacements) - if (possible_bracket_assign) { - return possible_bracket_assign - } - } - } - } - var assign_to = transform(get_node("factor", node), scope, template_replacements) - if (get_node("\"=\"", node)) { - var possible_assign = find_and_make_any_operator_overload_call(str("="), vec(assign_to, to_assign), scope, template_replacements) - if (possible_assign) { - return possible_assign - } - } else if (get_node("\"\\+=\"", node)) { - var possible_assign = find_and_make_any_operator_overload_call(str("+="), vec(assign_to, to_assign), scope, template_replacements) - if (possible_assign) { - return possible_assign - } - to_assign = make_operator_call("+", vec(assign_to, to_assign)) - } else if (get_node("\"-=\"", node)) { - var possible_assign = find_and_make_any_operator_overload_call(str("-="), vec(assign_to, to_assign), scope, template_replacements) - if (possible_assign) { - return possible_assign - } - to_assign = make_operator_call("-", vec(assign_to, to_assign)) - } else if (get_node("\"\\*=\"", node)) { - var possible_assign = find_and_make_any_operator_overload_call(str("*="), vec(assign_to, to_assign), scope, template_replacements) - if (possible_assign) { - return possible_assign - } - to_assign = make_operator_call("*", vec(assign_to, to_assign)) - } else if (get_node("\"/=\"", node)){ - var possible_assign = find_and_make_any_operator_overload_call(str("/="), vec(assign_to, to_assign), scope, template_replacements) - if (possible_assign) { - return possible_assign - } - to_assign = make_operator_call("/", vec(assign_to, to_assign)) - } else if (get_node("\"^=\"", node)){ - var possible_assign = find_and_make_any_operator_overload_call(str("^="), vec(assign_to, to_assign), scope, template_replacements) - if (possible_assign) { - return possible_assign - } - to_assign = make_operator_call("^", vec(assign_to, to_assign)) - } - var assignment = _assign(assign_to, to_assign) - return assignment - } - fun transform_if_statement(node: *tree, scope: *ast_node, template_replacements: map): *ast_node { - if (get_node("AmbiguityInner", node)) - error(node, "Ambigious two ifs with one else!") - var if_statement = _if(transform_expression(get_node("boolean_expression", node), scope, template_replacements)) - // one variable declarations might be in a code_block-less if statement - add_to_scope("~enclosing_scope", scope, if_statement) - var statements = transform_all(get_nodes("statement", node), if_statement, template_replacements) - if_statement->if_statement.then_part = statements[0] - // we have an else - if (statements.size == 2) - if_statement->if_statement.else_part = statements[1] - return if_statement - } - fun transform_while_loop(node: *tree, scope: *ast_node, template_replacements: map): *ast_node { - var while_loop = _while(transform_expression(get_node("boolean_expression", node), scope, template_replacements)) - add_to_scope("~enclosing_scope", scope, while_loop) - while_loop->while_loop.statement = transform(get_node("statement", node), while_loop, template_replacements) - return while_loop - } - fun transform_for_loop(node: *tree, scope: *ast_node, template_replacements: map): *ast_node { - var for_loop = _for() - add_to_scope("~enclosing_scope", scope, for_loop) - var statements = get_nodes("statement", node) - for_loop->for_loop.init = transform(statements[0], for_loop, template_replacements) - for_loop->for_loop.condition = transform(get_node("boolean_expression", node), for_loop, template_replacements) - for_loop->for_loop.update = transform(statements[1], for_loop, template_replacements) - for_loop->for_loop.body = transform(statements[2], for_loop, template_replacements) - return for_loop - } - fun transform_return_statement(node: *tree, scope: *ast_node, template_replacements: map): *ast_node { - var return_value = get_node("boolean_expression", node) - var to_ret: *ast_node - if (return_value) - to_ret = _return(transform(return_value, scope, template_replacements)) - else - to_ret = _return(null()) - ast_to_syntax.set(to_ret, node) - return to_ret - } - fun transform_branching_statement(node: *tree, scope: *ast_node): *ast_node { - if (node->data.name == "break_statement") - return _branch(branching_type::break_stmt()) - return _branch(branching_type::continue_stmt()) - } - fun transform_defer_statement(node: *tree, scope: *ast_node, template_replacements: map): *ast_node { - return _defer(transform(node->children[0], scope, template_replacements)) - } - fun transform_match_statement(node: *tree, scope: *ast_node, template_replacements: map): *ast_node { - var to_ret = _match(transform(get_node("boolean_expression", node), scope, template_replacements)) - get_nodes("case_statement", node).for_each(fun(syntax: *tree) to_ret->match_statement.cases.add(transform_case_statement(syntax, scope, template_replacements));) - return to_ret - } - fun transform_case_statement(node: *tree, scope: *ast_node, template_replacements: map): *ast_node { - var to_ret = _case() - var the_adts = scope_lookup(concat_symbol_tree(get_node("scoped_identifier", get_node("scoped_identifier", node))), scope).filter(fun(i: *ast_node): bool return is_adt_def(i);) - if (the_adts.size != 1) - error(node, str("the number of adts found was not 1, it was ") + the_adts.size + " for " + concat_symbol_tree(get_node("scoped_identifier", node))) - var the_adt = the_adts[0] - var the_option_name = concat_symbol_tree(get_node("identifier", get_node("scoped_identifier", node))) - // ADD IN ERROR CHECKING HERE - var the_option = the_adt->adt_def.options.find_first_satisfying(fun(option: *ast_node): bool return option->identifier.name == the_option_name;) - to_ret->case_statement.option = the_option - var possible_ident = get_node("identifier", node) - if (possible_ident) { - var ident = _ident(concat_symbol_tree(possible_ident), the_option->identifier.type, scope) - to_ret->case_statement.unpack_ident = ident - add_to_scope(ident->identifier.name, ident, to_ret) - } - //add to scope - add_to_scope("~enclosing_scope", scope, to_ret) - to_ret->case_statement.statement = transform(get_node("statement", node), to_ret, template_replacements) - return to_ret - } - fun transform_function_call(node: *tree, scope: *ast_node, template_replacements: map): *ast_node { - // don't bother with a full transform for parameters with their own function, just get the boolean expression and transform it - var parameters = get_nodes("parameter", node).map(fun(child: *tree): *ast_node return transform(get_node("boolean_expression", child), scope, template_replacements);) - var parameter_types = parameters.map(fun(param: *ast_node): *type return get_ast_type(param);) - if (parameter_types.any_true(fun(ptype: *type): bool return !ptype;)) - error(node, "One of the parameter types is null!") - var func = transform(get_node("unarad", node), scope, search_type::function(parameter_types), template_replacements) - // may return an identifier of type object if doing operator() - but the () have been stripped out by importer - var func_type = get_ast_type(func) - if (func_type->is_object() && func_type->indirection == 0) { - return make_method_call(func, "operator", parameters) - } - if (!(func_type->is_function() && func_type->indirection == 0)) - error(node, "trying to call not a function") - var f = _func_call(func, parameters) - return f - } - fun transform_compiler_intrinsic(node: *tree, scope: *ast_node, template_replacements: map): *ast_node { - var parameters = get_nodes("parameter", node).map(fun(child: *tree): *ast_node return transform(get_node("boolean_expression", child), scope, template_replacements);) - var type_parameters = get_nodes("type", node).map(fun(child: *tree): *type return transform_type(child, scope, template_replacements);) - var intrinsic_name = concat_symbol_tree(get_node("identifier", node)) - var intrinsic_return_type: *type - if (intrinsic_name == "ctce") - intrinsic_return_type = get_ast_type(parameters[0]) - else - intrinsic_return_type = type_ptr(base_type::ulong_int()) - return _compiler_intrinsic(intrinsic_name, parameters, type_parameters, intrinsic_return_type) - } - fun transform_lambda(node: *tree, scope: *ast_node, template_replacements: map): *ast_node { - var function_node = second_pass_function(node, scope, template_replacements, false) - function_node->function.body_statement = transform_statement(get_node("statement", node), function_node, template_replacements) - while (!is_translation_unit(scope)) scope = get_ast_scope(scope)->get(str("~enclosing_scope"))[0] - scope->translation_unit.lambdas.add(function_node) - return function_node - } - fun transform_expression(node: *tree, scope: *ast_node, template_replacements: map): *ast_node - return transform_expression(node, scope, search_type::none(), template_replacements) - fun transform_expression(node: *tree, scope: *ast_node, searching_for: search_type, template_replacements: map): *ast_node { - var func_name = str() - var parameters = vec<*ast_node>() - if (node->children.size == 1) { - var possible_value = transform(node->children[0], scope, searching_for, template_replacements) - if (!possible_value) match (searching_for) { - search_type::function(type_vec) possible_value = find_or_instantiate_template_function(concat_symbol_tree(node->children[0]), null>(), scope, type_vec, template_replacements, map()); - } - if (!possible_value) { - var function_error_str = str() - match (searching_for) { - search_type::function() { - function_error_str = "(" + searching_for.function.reduce(fun(n:*type, s:str):str { - if (n) - return s+","+n->to_string() - else - return s+",null" - }, str()) + ")" - } - } - error(node, concat_symbol_tree(node) + ": HAS NO POSSIBLE FUNCTION OR FUNCTION TEMPLATE SOLUTIONS\nlooking for: " + - concat_symbol_tree(node->children[0]) + function_error_str) - } - return possible_value - } else if (node->children.size == 2) { - var template_inst = get_node("template_inst", node) - if (template_inst) { - var identifier = get_node("scoped_identifier", node) - var result = null() - match (searching_for) { - // I guess this should never happen? - search_type::none() error(template_inst, "TEMPLATE LOOKUP WITHOUT PERENS ()") - search_type::function(type_vec) result = find_or_instantiate_template_function(concat_symbol_tree(identifier), template_inst, scope, type_vec, template_replacements, map()) - } - if (!result) - error(node, "Could not find templated function " + concat_symbol_tree(identifier) + " even though had a template_inst") - return result - } - var check_if_post = concat_symbol_tree(node->children[1]) - if (check_if_post == "--" || check_if_post == "++") { - // give the post-operators a special suffix so the c_generator knows to emit them post - func_name = concat_symbol_tree(node->children[1]) + "p" - parameters = vec(transform(node->children[0], scope, template_replacements)) - } else { - func_name = concat_symbol_tree(node->children[0]) - parameters = vec(transform(node->children[1], scope, template_replacements)) - } - } else { - func_name = concat_symbol_tree(node->children[1]) - if (func_name == "[") - func_name += "]" - if (func_name == "cast") - return _cast(transform(get_node("boolean_expression", node), scope, template_replacements), transform_type(get_node("type", node), scope, template_replacements)) - var first_param = transform(node->children[0], scope, template_replacements) - var second_param = null() - if (func_name == "." || func_name == "->") { - var first_param_type = get_ast_type(first_param) - if (!first_param_type) - error(node, "Cannot get type from left side of access operation") - if (!first_param_type->is_object()) - error(node, "Type from left side of access operation (" + func_name + ") isn't object, is: " + first_param_type->to_string()) - second_param = transform(node->children[2], first_param_type->type_def, searching_for, template_replacements) - // template member functions - // XXX add in template inst if it exists - if (!second_param) match (searching_for) { - search_type::function(type_vec) { - var template_inst = get_node("template_inst", node) - var inherited_replacements = map() - var parent = get_ast_scope(get_ast_type(first_param)->type_def)->get(str("~enclosing_scope"))[0] - if (is_template(parent)) - for (var i = 0; i < parent->template.template_types.size; i++;) - inherited_replacements[parent->template.template_types[i]] = parent->template.instantiated_map.reverse_get(get_ast_type(first_param)->type_def)[i].clone() - - var method_name = concat_symbol_tree(node->children[2]) - second_param = find_or_instantiate_template_function(method_name, template_inst, get_ast_type(first_param)->type_def, type_vec, template_replacements, inherited_replacements); - if (!second_param) { - error(node, "Could not find method " + method_name + " on the right side of (. or ->) " + concat_symbol_tree(node->children[0]) + - ", whole str: " + concat_symbol_tree(node) + ", left type: " + get_ast_type(first_param)->to_string()) - } - } - } - // this is the case where it's null but not a method call. Should add default to case above and move there - if (!second_param) { - error(node, "Could not find member " + concat_symbol_tree(node->children[2]) + " on the right side of (. or ->) " + concat_symbol_tree(node->children[0]) + - ", whole str: " + concat_symbol_tree(node) + ", left type: " + get_ast_type(first_param)->to_string()) - } - } else { - second_param = transform(node->children[2], scope, template_replacements) - } - parameters = vec(first_param, second_param) - } - parameters.for_each(fun(param: *ast_node) if (!is_legal_parameter_node_type(param)) error(node, "illegal node type used as parameter (perhaps name resolves to type or translation unit?)");) - var parameter_types = parameters.map(fun(param: *ast_node): *type return get_ast_type(param);) - // check for operator overloading - var possible_overload_call = find_and_make_any_operator_overload_call(func_name, parameters, scope, template_replacements) - if (possible_overload_call) - return possible_overload_call - return _func_call(get_builtin_function(func_name, parameter_types, node), parameters) - } - fun find_and_make_any_operator_overload_call(func_name: str, parameters: vec<*ast_node>, scope: *ast_node, template_replacements: map): *ast_node { - var parameter_types = parameters.map(fun(param: *ast_node): *type return get_ast_type(param);) - var possible_overload = null() - if (parameter_types[0]->is_object() && parameter_types[0]->indirection == 0) { - possible_overload = function_lookup(str("operator")+func_name, parameter_types.first()->type_def, parameter_types.slice(1,-1)) - if (!possible_overload) { - var inherited_replacements = map() - var parent = get_ast_scope(parameter_types.first()->type_def)->get(str("~enclosing_scope"))[0] - if (is_template(parent)) { - for (var i = 0; i < parent->template.template_types.size; i++;) - inherited_replacements[parent->template.template_types[i]] = parent->template.instantiated_map.reverse_get(parameter_types.first()->type_def)[i].clone() - } - possible_overload = find_or_instantiate_template_function(str("operator")+func_name, null>(), parameter_types.first()->type_def, parameter_types.slice(1,-1), template_replacements, inherited_replacements) - } - if (possible_overload) - return make_method_call(parameters.first(), possible_overload, parameters.slice(1,-1)) - } - possible_overload = function_lookup(str("operator")+func_name, scope, parameter_types) - if (!possible_overload) - possible_overload = find_or_instantiate_template_function(str("operator")+func_name, null>(), scope, parameter_types, template_replacements, map()) - if (possible_overload) - return _func_call(possible_overload, parameters) - return null() - } - fun find_or_instantiate_template_function(name: str, template_inst: *tree, scope: *ast_node, param_types: vec<*type>, template_replacements: map, replacements_base: map): *ast_node { - // replacments base is for templated methods starting off with the replacements of their parent (possibly templated) object - var results = scope_lookup(name, scope) - var real_types = vec<*type>() - var real_types_deref = vec() - var had_real_types = false - if (template_inst) { - real_types = get_nodes("type", template_inst).map(fun(t: *tree): *type return transform_type(t, scope, template_replacements);) - real_types_deref = real_types.map(fun(t:*type):type return *t;) - had_real_types = true - } - var fitting_functions = vec>() - for (var i = 0; i < results.size; i++;) { - if (is_template(results[i]) && results[i]->template.is_function) { - var template_types = results[i]->template.template_types - var template_type_replacements = results[i]->template.template_type_replacements - if (!had_real_types) { - var unify_template_type_replacements = template_type_replacements - // reset the vars, cuz we might be iterating through multiple of them - real_types = vec<*type>() - real_types_deref = vec() - // Template Function Instance Inference time - var typed_params = get_nodes("typed_parameter", results[i]->template.syntax_node).map(fun(t: *tree): *tree return get_node("type",t);) - if (param_types.size != typed_params.size) - continue - for (var j = 0; j < typed_params.size; j++;) - unify_type(typed_params[j], param_types[j], &unify_template_type_replacements, template_replacements) - for (var j = 0; j < template_types.size; j++;) { - var t = unify_template_type_replacements[template_types[j]]; - real_types.add(t) - real_types_deref.add(*t) - } - } else if (template_types.size != real_types.size) - continue - var num_satisfied_traits = 0 - var satisfied_traits = true - template_type_replacements.for_each(fun(key: str, value: *type) num_satisfied_traits += value->traits.size();) - // check if already instantiated - var inst_func = null() - for (var j = 0; j < template_types.size; j++;) { - satisfied_traits = satisfied_traits && real_types[j]->traits.contains(template_type_replacements[template_types[j]]->traits) && - (real_types[j]->indirection == 0 || template_type_replacements[template_types[j]]->traits.size() == 0) - template_type_replacements[template_types[j]] = real_types[j] - } - replacements_base.for_each(fun(key: str, value: *type) { - template_type_replacements[key] = value - }) - - if (!satisfied_traits) { - continue - } - if (real_types.any_true(fun(t: *type): bool return t->is_none() || t ->is_template_type();)) - continue - - if (results[i]->template.instantiated_map.contains_key(real_types_deref)) { - inst_func = results[i]->template.instantiated_map[real_types_deref] - } else { - inst_func = second_pass_function(results[i]->template.syntax_node, results[i], template_type_replacements, false) - // add to instantiated_map so we only instantiate with a paticular set of types once - // put in map first for recursive purposes - results[i]->template.instantiated_map.set(real_types_deref, inst_func) - results[i]->template.instantiated.add(inst_func) - // and fully instantiate it - inst_func->function.body_statement = transform_statement(get_node("statement", results[i]->template.syntax_node), inst_func, template_type_replacements) - } - if (function_satisfies_params(inst_func, param_types)) - fitting_functions.add(make_pair(inst_func, num_satisfied_traits)) - } - } - if (fitting_functions.size == 0) { - return null() - } - return fitting_functions.max(fun(a: pair<*ast_node, int>, b: pair<*ast_node, int>): bool return a.second < b.second;).first - } -} -fun unify_type(template_type: *tree, param_type: *type, new_map: *map, template_replacements: map) { - // first get rid of the reference if we have it - we don't care for unification - if (get_node("pre_reffed", template_type)) - template_type = get_node("pre_reffed", template_type) - // There are a couple options for the template parameter type here - // 1) template type - perfect, stick it in the map, that's what we're here for - // 2) basic type - stick it in the map, it won't get copied out so no worries - // 3) pointer type, go down a level - // 4) function type - fine, unify on all parameters and return types - // 5) instantiated template - fun stuff, have to figure out what it was origionally - // instantiated with, but we don't have to worry about it yet as I haven't gotten - // to object templates at all ;) - if (template_type->children.size == 1) { - if (get_node("function_type", template_type)) { - var template_function_types = get_nodes("type", get_node("function_type", template_type)) - if (!param_type->is_function() || template_function_types.size -1 != param_type->parameter_types.size) { - return; - } - for (var i = 0; i < template_function_types.size-1; i++;) - unify_type(template_function_types[i], param_type->parameter_types[i], new_map, template_replacements) - unify_type(template_function_types.last(), param_type->return_type, new_map, template_replacements) - } else { - new_map->set(concat_symbol_tree(template_type), param_type) - } - } else if (get_node("\"\\*\"", template_type)) { - // only unify on decreased indirection if we're not already at 0 - if (param_type->indirection) - unify_type(template_type->children[1], param_type->clone_with_decreased_indirection(), new_map, template_replacements) - else return; - } else if (get_node("template_inst", template_type)) { - if (param_type->is_object()) { - var enclosing_template = param_type->type_def->type_def.scope[str("~enclosing_scope")][0] - if (is_template(enclosing_template)) { - var inst_params = enclosing_template->template.instantiated_map.reverse_get(param_type->type_def) - var template_params = get_nodes("type", get_node("template_inst", template_type)) - if (inst_params.size == template_params.size) { - for (var i = 0; i < inst_params.size; i++;) - unify_type(template_params[i], inst_params[i].clone(), new_map, template_replacements) - } - } - } - } else { - println(template_type->children[0]->data.name) - println(template_type->children[0]->data.data) - error(template_type, "TYPE INFERENCE NOT GOOD ENOUGH") - } -} diff --git a/stdlib/binding.krak b/stdlib/binding.krak deleted file mode 100644 index c141c72..0000000 --- a/stdlib/binding.krak +++ /dev/null @@ -1,111 +0,0 @@ -import vec:* -import str:* -// for decent to string -// should be fixed by UFCS or decent scoping on template types -import ast:* -import type2:* - -adt binding_epoch { - pre_ref, - post_ref, - all -} - -var bindings: *vec<*void> - -fun binding(): *binding { - return binding(null(), binding_epoch::all()) -} -fun binding_p(it: T, epoch: binding_epoch): *binding { - var p = new() - p->copy_construct(&it) - return binding(p, epoch) -} -fun binding(it: *T, epoch: binding_epoch): *binding { - var to_ret = new>()->construct(it, epoch) - if (bindings == null>()) - bindings = new>()->construct() - bindings->add( (to_ret) cast *void ) - return to_ret -} - -obj binding (Object) { - var bound_to_pre_ref: *T - var bound_to_post_ref: *T - fun construct(): *binding { - bound_to_pre_ref = null() - bound_to_post_ref = null() - return this - } - fun construct(it: *T, epoch: binding_epoch): *binding { - bound_to_pre_ref = null() - bound_to_post_ref = null() - set_single(it, epoch) - return this - } - fun copy_construct(old: *binding): void { - bound_to_pre_ref = old->bound_to_pre_ref - bound_to_post_ref = old->bound_to_post_ref - } - fun destruct() { - bound_to_pre_ref = null() - bound_to_post_ref = null() - } - fun bound(epoch: binding_epoch): bool { - return bound_to_pre_ref != null() || bound_to_post_ref != null() - } - fun set(to: T, epoch: binding_epoch) { - var p = new() - p->copy_construct(&to) - set(p, epoch) - } - fun set(to: *T, epoch: binding_epoch) { - var pre_ref_from = bound_to_pre_ref - var post_ref_from = bound_to_post_ref - if epoch == binding_epoch::pre_ref() || epoch == binding_epoch::all() { - bound_to_pre_ref = to - // don't set null, that will set all unbound ones - if pre_ref_from != null() { - for (var i = 0; i < bindings->size; i++;) - if ( ((bindings->get(i)) cast *binding)->bound_to_pre_ref == pre_ref_from) - ((bindings->get(i)) cast *binding)->bound_to_pre_ref = to - } - } - if epoch == binding_epoch::post_ref() || epoch == binding_epoch::all() { - bound_to_post_ref = to - // don't set null, that will set all unbound ones - if post_ref_from != null() { - for (var i = 0; i < bindings->size; i++;) - if ( ((bindings->get(i)) cast *binding)->bound_to_post_ref == post_ref_from) - ((bindings->get(i)) cast *binding)->bound_to_post_ref = to - } - } - } - fun set_single(to: T, epoch: binding_epoch) { - var p = new() - p->copy_construct(&to) - set_single(p, epoch) - } - fun set_single(to: *T, epoch: binding_epoch) { - match (epoch) { - binding_epoch::pre_ref() { bound_to_pre_ref = to; } - binding_epoch::post_ref() { bound_to_post_ref = to; } - binding_epoch::all() { bound_to_pre_ref = to; bound_to_post_ref = to; } - } - } - fun bound(): bool { - return bound_to_pre_ref != null() || bound_to_post_ref != null() - } - fun get_bound_to(epoch: binding_epoch): *T { - match (epoch) { - binding_epoch::pre_ref() { return bound_to_pre_ref; } - binding_epoch::post_ref() if bound_to_post_ref != null() { return bound_to_post_ref; } else { return bound_to_pre_ref; } - binding_epoch::all() { error("trying to get_bound_to for all, which doesn't make any sense"); } - } - } - fun to_string(): str { - /*return "binding(" + to_string(bound_to) + ")"*/ - return "binding(pre_ref:" + deref_to_string(bound_to_pre_ref) + "/post_ref:" + deref_to_string(bound_to_post_ref) + ")" - } -} - diff --git a/stdlib/bytecode_generator.krak b/stdlib/bytecode_generator.krak deleted file mode 100644 index cbd82a3..0000000 --- a/stdlib/bytecode_generator.krak +++ /dev/null @@ -1,1261 +0,0 @@ -import io:* -import os:* -import mem:* -import map:* -import hash_map:* -import stack:* -import str:* -import util:* -import tree:* -import symbol:* -import ast_nodes:* -// for error with syntax tree -import pass_common:* - -fun type_size(t: *type): ulong - return type_size_and_alignment(t).first -fun type_size_and_alignment(t: *type): pair { - if (t->indirection) - return make_pair(#sizeof<*void>, #sizeof<*void>) - match (t->base) { - base_type::object() { - var total_size: ulong = 0 - var max_size: ulong = 0 - var max_align: ulong = 0 - t->type_def->type_def.variables.for_each(fun(i: *ast_node) { - var individual = type_size_and_alignment(i->declaration_statement.identifier->identifier.type) - max_size = max(max_size, individual.first) - max_align = max(max_align, individual.second) - // increase total size by the individual size + padding to get alignment - var padding = 0 - if (individual.second != 0) - padding = (individual.second - (total_size % individual.second)) % individual.second - total_size += individual.first + padding - }) - if (t->type_def->type_def.is_union) - total_size = max_size - // pad the end so that consecutive objects in memory are aligned - if (max_align != 0) - total_size += (max_align - (total_size % max_align)) % max_align - return make_pair(total_size, max_align) - } - base_type::function() return make_pair(#sizeof<*void>, #sizeof<*void>) - base_type::boolean() return make_pair(#sizeof, #sizeof) - base_type::character() return make_pair(#sizeof, #sizeof) - base_type::ucharacter() return make_pair(#sizeof, #sizeof) - base_type::short_int() return make_pair(#sizeof, #sizeof) - base_type::ushort_int() return make_pair(#sizeof, #sizeof) - base_type::integer() return make_pair(#sizeof, #sizeof) - base_type::uinteger() return make_pair(#sizeof, #sizeof) - base_type::long_int() return make_pair(#sizeof, #sizeof) - base_type::ulong_int() return make_pair(#sizeof, #sizeof) - base_type::floating() return make_pair(#sizeof, #sizeof) - base_type::double_precision() return make_pair(#sizeof, #sizeof) - } - error(str("Invalid type for type_size: ") + t->to_string()) -} - -fun offset_into_struct(struct_type: *type, ident: *ast_node): ulong { - var offset: ulong = 0 - if (struct_type->type_def->type_def.is_union) - return offset - for (var i = 0; i < struct_type->type_def->type_def.variables.size; i++;) { - var size_and_align = type_size_and_alignment(struct_type->type_def->type_def.variables[i]->declaration_statement.identifier->identifier.type) - var align = size_and_align.second - if (align != 0) - offset += (align - (offset % align)) % align - if (struct_type->type_def->type_def.variables[i]->declaration_statement.identifier == ident) - break - else - offset += size_and_align.first - } - return offset -} - - -var register_size = #sizeof<*void> -var malloc_addr = -1 -var free_addr = -2 -var memmove_addr = -3 -var printf_addr = -4 -var fprintf_addr = -5 -var fflush_addr = -6 -var fgets_addr = -7 -var fopen_addr = -8 -var fclose_addr = -9 -var ftell_addr = -10 -var fseek_addr = -11 -var fread_addr = -12 -var fwrite_addr = -13 -var system_addr = -14 -var exit_addr = -15 -var popen_addr = -16 -var pclose_addr = -17 -var snprintf_addr = -18 - -adt operand_size { - b8, - b16, - b32, - b64 -} -fun size_to_operand_size(size: ulong): operand_size { - if (size == 1) return operand_size::b8() - if (size == 2) return operand_size::b16() - if (size == 4) return operand_size::b32() - if (size == 8) return operand_size::b64() - error(str("invalid operand size ") + size) -} -adt byte_inst { - nop, - imm: imm, - add: reg2, - addi: reg1i, - smul: reg2, - umul: reg2, - sdiv: reg2, - udiv: reg2, - mod: reg2, - shl: reg2, - shr: reg2, - sar: reg2, - and: reg2, - or: reg2, - xor: reg2, - not: reg1, - gz: reg1, - lz: reg1, - ez: reg1, // also logical not - ldr: reg1is, - str: reg1is, - jmp: long, - jz: test, - call: int, - ret -} -obj imm { - var to_reg: int - var val: long -} -obj reg1 { - var to_reg: int - var a: int -} -obj reg1i { - var to_reg: int - var a: int - var bi:long -} -obj reg1is { - var reg: int - var base_reg: int - var offset: long - var size: operand_size -} -obj reg2 { - var to_reg: int - var a: int - var b: int -} -obj test { - var reg: int - var offset: long -} - -fun to_string(s: operand_size): str { - match (s) { - operand_size::b8() return str("8") - operand_size::b16() return str("16") - operand_size::b32() return str("32") - operand_size::b64() return str("64") - } - return str("missed operand size") -} - -fun to_string(b: byte_inst): str { - match (b) { - byte_inst::nop() return str("nop") - byte_inst::imm(i) return str("r") + i.to_reg + " = imm " + i.val - byte_inst::add(a) return str("r") + a.to_reg + " = r" + a.a + " + r" + a.b - byte_inst::addi(a) return str("r") + a.to_reg + " = r" + a.a + " + " + a.bi - byte_inst::smul(a) return str("r") + a.to_reg + " = r" + a.a + " * r" + a.b - byte_inst::umul(a) return str("r") + a.to_reg + " = r" + a.a + " u* r"+ a.b - byte_inst::sdiv(a) return str("r") + a.to_reg + " = r" + a.a + " / r" + a.b - byte_inst::udiv(a) return str("r") + a.to_reg + " = r" + a.a + " u/ r"+ a.b - byte_inst::mod(a) return str("r") + a.to_reg + " = r" + a.a + " % r" + a.b - byte_inst::and(a) return str("r") + a.to_reg + " = r" + a.a + " & r" + a.b - byte_inst::shl(a) return str("r") + a.to_reg + " = r" + a.a + " u<< r" + a.b - byte_inst::shr(a) return str("r") + a.to_reg + " = r" + a.a + " u>> r" + a.b - byte_inst::sar(a) return str("r") + a.to_reg + " = r" + a.a + " s>> r" + a.b - byte_inst::or(a) return str("r") + a.to_reg + " = r" + a.a + " | r" + a.b - byte_inst::xor(a) return str("r") + a.to_reg + " = r" + a.a + " ^ r" + a.b - byte_inst::not(a) return str("r") + a.to_reg + " = ~r" + a.a - byte_inst::gz(a) return str("r") + a.to_reg + " = r" + a.a + " > 0" - byte_inst::lz(a) return str("r") + a.to_reg + " = r" + a.a + " < 0" - byte_inst::ez(a) return str("r") + a.to_reg + " = r" + a.a + " == 0" - byte_inst::ldr(l) return str("r") + l.reg + " = ldr" + to_string(l.size) + " r" + l.base_reg + " (" + l.offset + ")" - byte_inst::str(s) return "str" + to_string(s.size) + " (r" + s.base_reg + "(" + s.offset + ") <= r" + s.reg + ")" - byte_inst::jmp(j) return str("jmp(pc += ") + j + ")" - byte_inst::jz(j) return str("jmp(r") + j.reg + " == 0, pc += " + j.offset + ")" - byte_inst::call(c) return str("call pc = r") + c - byte_inst::ret() return str("ret") - } - return str("Missed byte_inst case in to_string") -} - -fun bytecode_to_string(functions: ref vec, instructions: ref vec): str { - return str("\n").join(functions.map(fun(bb: ref bytecode_function): str return bb.to_string(instructions);)) -} - -fun bytecode_function(name: ref str, start: int): bytecode_function { - var to_ret.construct(name, start): bytecode_function - return to_ret -} -obj bytecode_function (Object) { - var name: str - var instruction_start: int - var instruction_end: int - var var_to_frame_offset: map<*ast_node, int> - var frame_size: int - - fun construct(): *bytecode_function { - instruction_start = 0 - instruction_end = 0 - name.construct() - var_to_frame_offset.construct() - frame_size = 0 - return this - } - fun construct(name_in: ref str, instruction_start_in: int): *bytecode_function { - instruction_start = instruction_start_in - instruction_end = 0 - name.copy_construct(&name_in) - var_to_frame_offset.construct() - frame_size = 0 - return this - } - fun copy_construct(old: *bytecode_function) { - instruction_start = old->instruction_start - instruction_end = old->instruction_end - name.copy_construct(&old->name) - var_to_frame_offset.copy_construct(&old->var_to_frame_offset) - frame_size = old->frame_size - } - fun operator=(other: ref bytecode_function) { - destruct() - copy_construct(&other) - } - fun destruct() { - name.destruct() - var_to_frame_offset.destruct() - } - fun to_string(instructions: ref vec): str { - var res = name + "(frame size " + frame_size + "):\n" - res += "\t frame layout\n" - res += "\t\tsaved RBP : RPB = 0\n" - var_to_frame_offset.for_each(fun(n: *ast_node, o: int) { - res += "\t\t" + n->identifier.name + ": RBP + " + o + "\n" - }) - res += "\n\t bytecode\n" - for (var i = instruction_start; i < instruction_end; i++;) - res += str("\t\t") + i + str(": ") + to_string(instructions[i]) + "\n" - return res - } -} - -obj bytecode_generator (Object) { - var reg_counter: int - var reg_max: int - var id_counter: int - var ast_name_map: hash_map<*ast_node, str> - var functions: vec - var node_function_idx: map<*ast_node, int> - var instructions: vec - var fixup_function_addresses: vec> - var fixup_break_addresses: stack> - var fixup_continue_addresses: stack> - fun construct(): *bytecode_generator { - id_counter = 0 - ast_name_map.construct() - functions.construct() - node_function_idx.construct() - instructions.construct() - fixup_function_addresses.construct() - fixup_break_addresses.construct() - fixup_continue_addresses.construct() - reg_counter = 3 - reg_max = 3 - - return this - } - fun copy_construct(old: *bytecode_generator) { - reg_counter = old->reg_counter - reg_max = old->reg_max - id_counter = old->id_counter - ast_name_map.copy_construct(&old->ast_name_map) - functions.copy_construct(&old->functions) - node_function_idx.copy_construct(&old->node_function_idx) - instructions.copy_construct(&old->instructions) - fixup_function_addresses.copy_construct(&old->fixup_function_addresses) - fixup_break_addresses.copy_construct(&old->fixup_break_addresses) - fixup_continue_addresses.copy_construct(&old->fixup_continue_addresses) - } - fun operator=(other: ref bytecode_generator) { - destruct() - copy_construct(&other) - } - fun destruct() { - ast_name_map.destruct() - functions.destruct() - node_function_idx.destruct() - instructions.destruct() - fixup_function_addresses.destruct() - fixup_break_addresses.destruct() - fixup_continue_addresses.destruct() - } - fun get_id(): str return to_string(id_counter++); - fun get_reg(): int return reg_counter++; - fun peek_reg(): int return reg_counter; - fun reset_reg() reset_reg(3); - fun reset_reg(to: int) { - if (reg_counter > reg_max) { - reg_max = reg_counter - } - reg_counter = to - } - /*fun generate_bytecode(name_ast_map: map,*ast_node>>): pair, vec> {*/ - fun generate_bytecode(name_ast_map: map,*ast_node>>) { - - // iterate through asts - name_ast_map.for_each(fun(name: str, tree_pair: pair<*tree,*ast_node>) { - // iterate through children for each ast - tree_pair.second->translation_unit.lambdas.for_each(fun(child: *ast_node) { - generate_function_definition(child) - }) - tree_pair.second->translation_unit.children.for_each(fun(child: *ast_node) { - match (*child) { - ast_node::declaration_statement(backing) generate_declaration_statement(child) - ast_node::compiler_intrinsic(backing) generate_compiler_intrinsic(child) - ast_node::function(backing) generate_function_definition(child) - ast_node::template(backing) { - backing.instantiated.for_each(fun(node: *ast_node) { - match (*node) { - ast_node::function(backing) generate_function_definition(node) - ast_node::type_def(backing) { - backing.methods.for_each(fun(method: *ast_node) { - if (is_template(method)) - method->template.instantiated.for_each(fun(m: *ast_node) generate_function_definition(m);) - else - generate_function_definition(method) - }) - } - } - }) - } - ast_node::type_def(backing) { - backing.methods.for_each(fun(method: *ast_node) { - if (is_template(method)) - method->template.instantiated.for_each(fun(m: *ast_node) generate_function_definition(m);) - else - generate_function_definition(method) - }) - } - } - }) - }) - fixup_function_addresses.for_each(fun(p: pair) { - if (p.second->function.is_extern) { - if (p.second->function.name == "malloc") - instructions[p.first].imm.val = malloc_addr - else if (p.second->function.name == "free") - instructions[p.first].imm.val = free_addr - else if (p.second->function.name == "memmove") - instructions[p.first].imm.val = memmove_addr - else if (p.second->function.name == "printf") - instructions[p.first].imm.val = printf_addr - else if (p.second->function.name == "fprintf") - instructions[p.first].imm.val = fprintf_addr - else if (p.second->function.name == "fflush") - instructions[p.first].imm.val = fflush_addr - else if (p.second->function.name == "fgets") - instructions[p.first].imm.val = fgets_addr - else if (p.second->function.name == "fopen") - instructions[p.first].imm.val = fopen_addr - else if (p.second->function.name == "fclose") - instructions[p.first].imm.val = fclose_addr - else if (p.second->function.name == "ftell") - instructions[p.first].imm.val = ftell_addr - else if (p.second->function.name == "fseek") - instructions[p.first].imm.val = fseek_addr - else if (p.second->function.name == "fread") - instructions[p.first].imm.val = fread_addr - else if (p.second->function.name == "fwrite") - instructions[p.first].imm.val = fwrite_addr - else if (p.second->function.name == "system") - instructions[p.first].imm.val = system_addr - else if (p.second->function.name == "exit") - instructions[p.first].imm.val = exit_addr - else if (p.second->function.name == "popen") - instructions[p.first].imm.val = popen_addr - else if (p.second->function.name == "pclose") - instructions[p.first].imm.val = pclose_addr - else if (p.second->function.name == "snprintf") - instructions[p.first].imm.val = snprintf_addr - else - error("bad extern function used: " + p.second->function.name) - } else { - instructions[p.first].imm.val = functions[node_function_idx[p.second]].instruction_start - } - }) - for (var i = 0; i < functions.size - 1; i++;) - functions[i].instruction_end = functions[i+1].instruction_start - functions.last().instruction_end = instructions.size - /*return make_pair(functions, instructions)*/ - } - fun generate_function_definition(node: *ast_node) { - if (node->function.is_extern) { - println("Skipping extern function " + node->function.name) - return - } - reset_reg() - node_function_idx[node] = functions.size - functions.add(bytecode_function(get_name(node), instructions.size)) - var parameter_offset = (register_size*2) cast int // have to pass saved RBP and return address - - var return_type = get_ast_type(node)->return_type - // if we're returning an object, our caller passes the address - // we should save our return value as as the first parameter - if (return_type->is_object() && return_type->indirection == 0) { - var ptr_type = return_type->clone_with_increased_indirection() - functions.last().var_to_frame_offset[_ident("bytecode_struct_return_temp_address", ptr_type, null())] = parameter_offset - parameter_offset += type_size(ptr_type) - } - node->function.parameters.for_each(fun(p: *ast_node) { - functions.last().var_to_frame_offset[p] = parameter_offset - parameter_offset += type_size(p->identifier.type) - }) - emit_addi(0, 0, -register_size) // these two lines push rbp onto the stack, which grows towards negative - emit_str(0, 0, 1, operand_size::b64()) // rsp[0] <= rbp - emit_addi(1, 0, 0) // note that we start the frame size at register_size for this reason - - var push_frame_idx = instructions.size - emit_addi(0, 0, 0) // this has to be fixed afterwards to be the -frame_size - - generate(node->function.body_statement) - - // generate a return just in case the function itself doesn't have one - generate_return_statement(_return(null())) - - instructions[push_frame_idx].addi.bi = -functions.last().frame_size - - } - fun generate_declaration_statement(node: *ast_node): int { - var identifier = node->declaration_statement.identifier - var ident_type = identifier->identifier.type - functions.last().frame_size += type_size(ident_type) - functions.last().var_to_frame_offset[identifier] = -functions.last().frame_size - if (node->declaration_statement.expression) { - // STRUCT HERE - if (ident_type->is_object() && ident_type->indirection == 0) - emit_struct_copy(1, functions.last().var_to_frame_offset[identifier], generate(node->declaration_statement.expression), 0, get_ast_type(identifier)) - else - emit_str(1, functions.last().var_to_frame_offset[identifier], generate(node->declaration_statement.expression), size_to_operand_size(type_size(get_ast_type(identifier)))) - reset_reg() - } - return -1 - } - fun generate_assignment_statement(node: *ast_node): int { - var from = generate(node->assignment_statement.from) - var to = generate(node->assignment_statement.to, true) - var var_type = get_ast_type(node->assignment_statement.to) - // STRUCT HERE - if (var_type->is_object() && var_type->indirection == 0) - emit_struct_copy(to, 0, from, 0, var_type) - else - emit_str(to, 0, from, size_to_operand_size(type_size(var_type))) - reset_reg() - return -1 - } - fun generate_if_statement(node: *ast_node): int { - var cond_reg = generate(node->if_statement.condition) - var jz_index = instructions.size - emit_jz(cond_reg,0) - reset_reg() - generate(node->if_statement.then_part) - reset_reg() - if (node->if_statement.else_part) { - var jmp_index = instructions.size - emit_jmp(0) - instructions[jz_index].jz.offset = instructions.size - jz_index - generate(node->if_statement.else_part) - instructions[jmp_index].jmp = instructions.size - jmp_index - reset_reg() - } else { - instructions[jz_index].jz.offset = instructions.size - jz_index - } - return -1 - } - fun generate_while_loop(node: *ast_node): int { - var top_index = instructions.size - var cond_reg = generate(node->while_loop.condition) - var jz_index = instructions.size - emit_jz(cond_reg,0) - reset_reg() - fixup_break_addresses.push(vec()) - fixup_continue_addresses.push(vec()) - generate(node->while_loop.statement) - reset_reg() - emit_jmp(top_index - instructions.size) - instructions[jz_index].jz.offset = instructions.size - jz_index - fixup_continue_addresses.pop().for_each(fun(i: int) { - instructions[i].jmp = instructions.size - i - }) - fixup_break_addresses.pop().for_each(fun(i: int) { - instructions[i].jmp = instructions.size - i - }) - return -1 - } - fun generate_for_loop(node: *ast_node): int { - if (node->for_loop.init) - generate(node->for_loop.init) - reset_reg() - var top_index = instructions.size - var cond_reg = 0 - if (node->for_loop.condition) - cond_reg = generate(node->for_loop.condition) - else - cond_reg = emit_imm(1) - var jz_index = instructions.size - emit_jz(cond_reg,0) - reset_reg() - fixup_break_addresses.push(vec()) - fixup_continue_addresses.push(vec()) - - generate(node->for_loop.body) - reset_reg() - - fixup_continue_addresses.pop().for_each(fun(i: int) { - instructions[i].jmp = instructions.size - i - }) - - if (node->for_loop.update) { - generate(node->for_loop.update) - reset_reg() - } - - emit_jmp(top_index - instructions.size) - - instructions[jz_index].jz.offset = instructions.size - jz_index - fixup_break_addresses.pop().for_each(fun(i: int) { - instructions[i].jmp = instructions.size - i - }) - - return -1 - } - fun generate_branching_statement(node: *ast_node): int { - match(node->branching_statement.b_type) { - branching_type::break_stmt() { - fixup_break_addresses.top().add(instructions.size) - emit_jmp(0) - } - branching_type::continue_stmt() { - fixup_continue_addresses.top().add(instructions.size) - emit_jmp(0) - } - } - return -1 - } - fun generate_identifier(node: *ast_node, lvalue: bool): int { - // STRUCT HERE - var ident_type = get_ast_type(node) - if (node->identifier.is_extern) { - var addr_reg = -1 - - if (node->identifier.name == "stderr") addr_reg = emit_imm( (&stderr) cast long) - else if (node->identifier.name == "stdin") addr_reg = emit_imm( (&stdin) cast long) - else error("does not support external identifier " + node->identifier.name + " in bytecode") - - if (lvalue || (ident_type->is_object() && ident_type->indirection == 0)) - return addr_reg - else - return emit_ldr(addr_reg, 0, size_to_operand_size(type_size(ident_type))) - } else { - if (lvalue || (ident_type->is_object() && ident_type->indirection == 0)) - return emit_addi(1, functions.last().var_to_frame_offset[node]) - else - return emit_ldr(1, functions.last().var_to_frame_offset[node], size_to_operand_size(type_size(ident_type))) - } - } - fun generate_return_statement(node: *ast_node): int { - // STRUCT HERE - if (node->return_statement.return_value) { - var return_value_reg = generate(node->return_statement.return_value) - var return_type = get_ast_type(node->return_statement.return_value) - if (return_type->is_object() && return_type->indirection == 0) { - // fix this up to be nicer - // this is the hardcoded offset of the "first parameter" which - // is the address into which we should save our resulting struct - emit_struct_copy(emit_ldr(1, (register_size*2) cast int, size_to_operand_size(register_size)), 0, return_value_reg, 0, return_type) - } else { - emit_addi(2, return_value_reg, 0) - } - } - - emit_addi(0, 1, register_size) - emit_ldr(1, 1, 0, operand_size::b64()) - reset_reg() - emit_ret() - - return -1 - } - fun generate_cast(node: *ast_node): int { - return generate(node->cast.value) - } - fun generate_value(node: *ast_node): int { - if (node->value.value_type->is_bool()) - return emit_imm((node->value.string_value == "true") cast long) - else if (node->value.value_type->base == base_type::character() && node->value.value_type->indirection == 1) - return emit_imm((node->value.string_value.toCharArray()) cast long) - else if (node->value.value_type->base == base_type::character() && node->value.value_type->indirection == 0) - return emit_imm((node->value.string_value[0]) cast long) - else if (node->value.value_type->base == base_type::floating() && node->value.value_type->indirection == 0) { - var double_temp: double = ((string_to_double(node->value.string_value)) cast float) - return emit_imm(*(&double_temp) cast *long) - } else if (node->value.value_type->base == base_type::double_precision() && node->value.value_type->indirection == 0) { - var double_temp: double = string_to_double(node->value.string_value) - return emit_imm(*(&double_temp) cast *long) - } else - return emit_imm(string_to_num(node->value.string_value)) - } - fun generate_code_block(node: *ast_node): int { - node->code_block.children.for_each(fun(child: *ast_node) { - // registers aren't used between statements (only stack reg) - reset_reg() - generate(child) - }) - return -1 - } - // this generates the function as a value, not the actual function - fun generate_function(node: *ast_node): int { - if (!is_function(node)) - error("trying to generate a function but isn't a function") - fixup_function_addresses.add(make_pair(instructions.size,node)) - return emit_imm(-2) - } - fun generate_function_call(node: *ast_node, lvalue: bool): int { - var func = node->function_call.func - if (is_function(func) && !func->function.is_extern && func->function.body_statement == null()) { - var name = func->function.name - var parameter_nodes = node->function_call.parameters - // generate with lvalue=true to make return a pointer - if (name == "&" && parameter_nodes.size == 1) - return generate(parameter_nodes[0], true) - if (name == "++" || name == "++p" || name == "--" || name == "--p") { - var op_size = size_to_operand_size(type_size(get_ast_type(parameter_nodes[0]))) - var addr_reg = generate(parameter_nodes[0], true) - var value_reg = emit_ldr(addr_reg, 0, op_size) - var mod_reg = -1 - if (name[0] == '+') - mod_reg = emit_addi(value_reg, 1) - else - mod_reg = emit_addi(value_reg, -1) - emit_str(addr_reg, 0, mod_reg, op_size) - // if preincrement, return modified value, else unmodified - if (name.length() == 2) - return mod_reg - else - return value_reg - } - - // STRUCT HERE - if (name == "." || name == "->") { - var base = generate(parameter_nodes[0]) - if (!is_identifier(parameter_nodes[1])) - error("trying to access not an identifier") - var val_type = get_ast_type(parameter_nodes[1]) - var offset = offset_into_struct(get_ast_type(parameter_nodes[0]), parameter_nodes[1]) - var member_ptr = emit_addi(base, offset) - if (lvalue || (val_type->is_object() && val_type->indirection == 0)) - return member_ptr - return emit_ldr(member_ptr, 0, size_to_operand_size(type_size(get_ast_type(parameter_nodes[1])))) - } - - var params = parameter_nodes.map(fun(n: *ast_node): int return generate(n);) - var lhs_type = get_ast_type(parameter_nodes[0]) - if (name == "+") { - if (params.size == 1) { - return emit_smul(params[0], emit_or(emit_gz(params[0]), emit_smul(emit_lz(params[0]), emit_imm(-1)))) - } else { - if (lhs_type->indirection == 0) { - return emit_add(params[0], params[1]) - } else { - return emit_add(params[0], emit_smul(params[1], emit_imm(type_size(lhs_type->clone_with_decreased_indirection())))) - } - } - } else if (name == "-") { - if (params.size == 1) { - return emit_addi(emit_not(params[0]), 1) - } else { - if (lhs_type->indirection == 0) { - return emit_add(params[0], emit_addi(emit_not(params[1]), 1)) - } else { - return emit_add(params[0], emit_addi(emit_not(emit_smul(params[1], emit_imm(type_size(lhs_type->clone_with_decreased_indirection())))), 1)) - } - } - } else if (name == "!") { - return emit_ez(params[0]) - } else if (name == "[]" || (name == "*" && params.size == 1)) { - var derefed_type = lhs_type->clone_with_decreased_indirection() - var derefed_size = type_size(derefed_type) - if (name == "[]") { - var offset_reg = params[1] - if (derefed_size != 1) - offset_reg = emit_smul(offset_reg, emit_imm(derefed_size)) - var addr_reg = emit_add(params[0], offset_reg) - if (lvalue || (derefed_type->is_object() && derefed_type->indirection == 0)) - return addr_reg - else - return emit_ldr(addr_reg, 0, size_to_operand_size(derefed_size)) - } - if (name == "*") { - if (lvalue || (derefed_type->is_object() && derefed_type->indirection == 0)) - return params[0] - else - return emit_ldr(params[0], 0, size_to_operand_size(derefed_size)) - } - } else if (name == "==" || name == "<=" || name == ">=" || name == "!=" || name == "<" || name == ">") { - var diff = emit_add(params[0], emit_addi(emit_not(params[1]), 1)) - if (name == "==") return emit_ez(diff) - if (name == "<=") return emit_or(emit_ez(diff), emit_lz(diff)) - if (name == ">=") return emit_or(emit_ez(diff), emit_gz(diff)) - if (name == "!=") return emit_ez(emit_ez(diff)) - if (name == "<") return emit_lz(diff) - if (name == ">") return emit_gz(diff) - } else if (name == "|" || (name == "&" && params.size == 2) || name == "^" || name == "~") { - if (name == "|") return emit_or(params[0], params[1]) - if (name == "&") return emit_and(params[0], params[1]) - if (name == "^") return emit_xor(params[0], params[1]) - if (name == "~") return emit_not(params[0]) - } else if (name == ">>" || name == "<<") { - if (name == "<<") - return emit_shl(params[0], params[1]) - if (get_ast_type(parameter_nodes[0])->is_signed_type()) - return emit_sar(params[0], params[1]) - else - return emit_shr(params[0], params[1]) - } else if (name == "/" || name == "%" || (name == "*" && params.size == 2)) { - if (get_ast_type(parameter_nodes[0])->is_signed_type()) { - if (name == "/") return emit_sdiv(params[0], params[1]) - if (name == "*") return emit_smul(params[0], params[1]) - } else { - if (name == "/") return emit_udiv(params[0], params[1]) - if (name == "*") return emit_umul(params[0], params[1]) - } - if (name == "%") return emit_mod(params[0], params[1]) - } - error("unknown operator " + name) - } else { - // if this function returns a struct, we have to allocate space for it on the top of the stack - // before we save registers, as it has to persist beyond the call (for whatever happens to it next) - // We stick it in the function as if this is the declaration of a temporary variable, basically - - var return_type = get_ast_type(func)->return_type - var struct_return_temp_ident = null() - if (return_type->is_object() && return_type->indirection == 0) { - struct_return_temp_ident = _ident("bytecode_struct_return_temp", return_type, null()) - functions.last().frame_size += type_size(return_type) - functions.last().var_to_frame_offset[struct_return_temp_ident] = -functions.last().frame_size - } - - // save regs - var save_til = peek_reg() - var save_size = (save_til - 3) * register_size - if (save_size != 0) { - emit_addi(0, 0, -save_size) - for (var i = 3; i < save_til; i++;) { - emit_str(0, ((i-3)*register_size) cast int, i, operand_size::b64()) - } - } - // STRUCT HERE - // reverse order - var total_param_size = 0 - node->function_call.parameters.reverse().for_each(fun(child: *ast_node) { - // push param onto stack - var param_type = get_ast_type(child) - var param_size = type_size(param_type) - var param_reg = generate(child) - emit_addi(0, 0, -param_size) - total_param_size += param_size - if (param_type->is_object() && param_type->indirection == 0) - emit_struct_copy(0, 0, param_reg, 0, param_type) - else - emit_str(0, 0, param_reg, size_to_operand_size(param_size)) - reset_reg(save_til) - }) - // pass the address to save the struct into as a parameter - if (return_type->is_object() && return_type->indirection == 0) { - emit_addi(0, 0, -(register_size) cast int) - total_param_size += (register_size) cast int - emit_str(0, 0, emit_addi(1, functions.last().var_to_frame_offset[struct_return_temp_ident]), size_to_operand_size(register_size)) - reset_reg(save_til) - } - var return_reg = emit_call(generate(node->function_call.func)) - - if (return_type->is_object() && return_type->indirection == 0) { - // if returned struct, then the struct was saved where we asked for it to be - // return pointer with that address - return_reg = emit_addi(1, functions.last().var_to_frame_offset[struct_return_temp_ident]) - } else { - // returning through r2 every time doesn't give unique regs for functions used together in an expression - // so get a new one for this time - return_reg = emit_addi(return_reg, 0) - } - emit_addi(0, 0, total_param_size) - - // restore regs - for (var i = 3; i < save_til; i++;) { - emit_ldr(i, 0, ((i-3)*register_size) cast int, operand_size::b64()) - } - if (save_size != 0) - emit_addi(0, 0, save_size) - - return return_reg - } - } - - fun generate_compiler_intrinsic(node: *ast_node): int { - if (node->compiler_intrinsic.intrinsic == "sizeof") { - if (node->compiler_intrinsic.parameters.size || node->compiler_intrinsic.type_parameters.size != 1) - error("wrong parameters to sizeof compiler intrinsic") - return emit_imm(type_size(node->compiler_intrinsic.type_parameters[0])) - } - error("bad compiler intrinsic " + node->compiler_intrinsic.intrinsic) - } - - fun generate(node: *ast_node): int return generate(node, false) - fun generate(node: *ast_node, lvalue: bool): int { - match (*node) { - ast_node::declaration_statement(backing) return generate_declaration_statement(node) - ast_node::assignment_statement(backing) return generate_assignment_statement(node) - ast_node::if_statement(backing) return generate_if_statement(node) - ast_node::while_loop(backing) return generate_while_loop(node) - ast_node::for_loop(backing) return generate_for_loop(node) - ast_node::function(backing) return generate_function(node) - ast_node::function_call(backing) return generate_function_call(node, lvalue) - ast_node::compiler_intrinsic(backing) return generate_compiler_intrinsic(node) - ast_node::code_block(backing) return generate_code_block(node) - ast_node::return_statement(backing) return generate_return_statement(node) - ast_node::branching_statement(backing) return generate_branching_statement(node) - ast_node::cast(backing) return generate_cast(node) - ast_node::value(backing) return generate_value(node) - ast_node::identifier(backing) return generate_identifier(node, lvalue) - } - error("Bad node") - } - fun get_name(node: *ast_node): str { - var maybe_it = ast_name_map.get_ptr_or_null(node); - if (maybe_it) - return *maybe_it - var result = get_ast_name(node) + get_id() - if (is_function(node) && node->function.name == "main") - result = "main" - ast_name_map.set(node, result) - return result - } - fun emit_struct_copy(to: int, to_offset: int, from: int, from_offset: int, t: *type) { - for (var i = 0; i < t->type_def->type_def.variables.size; i++;) { - var member_var = t->type_def->type_def.variables[i]->declaration_statement.identifier - var member_type = get_ast_type(member_var) - var member_offset = offset_into_struct(t, member_var) - if (member_type->is_object() && member_type->indirection == 0) { - emit_struct_copy(to, (to_offset + member_offset) cast int, from, (from_offset + member_offset) cast int, member_type) - } else { - var member_size = size_to_operand_size(type_size(member_type)) - emit_str(to, (to_offset + member_offset) cast int, emit_ldr(from, (from_offset + member_offset) cast int, member_size), member_size) - } - } - } - fun emit_imm(value: ulong): int { return emit_imm((value) cast long); } - fun emit_imm(value: int): int { return emit_imm((value) cast long); } - fun emit_imm(value: long): int { - var i: imm - i.to_reg = get_reg() - i.val = value - instructions.add(byte_inst::imm(i)) - return i.to_reg - } - fun emit_add(a: int, b: int): int { return emit_add(get_reg(), a, b); } - fun emit_add(dest: int, a: int, b: int): int { - var i: reg2 - i.to_reg = dest - i.a = a - i.b = b - instructions.add(byte_inst::add(i)) - return i.to_reg - } - fun emit_addi(a: int, bi: long): int { return emit_addi(get_reg(), a, bi); } - fun emit_addi(a: int, bi: int): int { return emit_addi(get_reg(), a, (bi) cast long); } - fun emit_addi(dest: int, a: int, bi: int): int { return emit_addi(dest, a, (bi) cast long); } - fun emit_addi(a: int, bi: ulong): int { return emit_addi(get_reg(), a, (bi) cast long); } - fun emit_addi(dest: int, a: int, bi: ulong): int { return emit_addi(dest, a, (bi) cast long); } - fun emit_addi(dest: int, a: int, bi: long): int { - var i: reg1i - i.to_reg = dest - i.a = a - i.bi = bi - instructions.add(byte_inst::addi(i)) - return i.to_reg - } - fun emit_umul(a: int, b: int): int { - var i: reg2 - i.to_reg = get_reg() - i.a = a - i.b = b - instructions.add(byte_inst::umul(i)) - return i.to_reg - } - fun emit_smul(a: int, b: int): int { - var i: reg2 - i.to_reg = get_reg() - i.a = a - i.b = b - instructions.add(byte_inst::smul(i)) - return i.to_reg - } - fun emit_udiv(a: int, b: int): int { - var i: reg2 - i.to_reg = get_reg() - i.a = a - i.b = b - instructions.add(byte_inst::udiv(i)) - return i.to_reg - } - fun emit_sdiv(a: int, b: int): int { - var i: reg2 - i.to_reg = get_reg() - i.a = a - i.b = b - instructions.add(byte_inst::sdiv(i)) - return i.to_reg - } - fun emit_mod(a: int, b: int): int { - var i: reg2 - i.to_reg = get_reg() - i.a = a - i.b = b - instructions.add(byte_inst::mod(i)) - return i.to_reg - } - fun emit_shr(a: int, b: int): int { - var i: reg2 - i.to_reg = get_reg() - i.a = a - i.b = b - instructions.add(byte_inst::shr(i)) - return i.to_reg - } - fun emit_sar(a: int, b: int): int { - var i: reg2 - i.to_reg = get_reg() - i.a = a - i.b = b - instructions.add(byte_inst::sar(i)) - return i.to_reg - } - fun emit_shl(a: int, b: int): int { - var i: reg2 - i.to_reg = get_reg() - i.a = a - i.b = b - instructions.add(byte_inst::shl(i)) - return i.to_reg - } - fun emit_and(a: int, b: int): int { return emit_and(get_reg(), a, b); } - fun emit_and(dest: int, a: int, b: int): int { - var i: reg2 - i.to_reg = dest - i.a = a - i.b = b - instructions.add(byte_inst::and(i)) - return i.to_reg - } - fun emit_or(a: int, b: int): int { return emit_or(get_reg(), a, b); } - fun emit_or(dest: int, a: int, b: int): int { - var i: reg2 - i.to_reg = dest - i.a = a - i.b = b - instructions.add(byte_inst::or(i)) - return i.to_reg - } - fun emit_xor(a: int, b: int): int { return emit_xor(get_reg(), a, b); } - fun emit_xor(dest: int, a: int, b: int): int { - var i: reg2 - i.to_reg = dest - i.a = a - i.b = b - instructions.add(byte_inst::xor(i)) - return i.to_reg - } - fun emit_not(a: int): int { return emit_not(get_reg(), a); } - fun emit_not(dest: int, a: int): int { - var i: reg1 - i.to_reg = dest - i.a = a - instructions.add(byte_inst::not(i)) - return i.to_reg - } - fun emit_gz(a: int): int { - var i: reg1 - i.to_reg = get_reg() - i.a = a - instructions.add(byte_inst::gz(i)) - return i.to_reg - } - fun emit_lz(a: int): int { - var i: reg1 - i.to_reg = get_reg() - i.a = a - instructions.add(byte_inst::lz(i)) - return i.to_reg - } - fun emit_ez(a: int): int { - var i: reg1 - i.to_reg = get_reg() - i.a = a - instructions.add(byte_inst::ez(i)) - return i.to_reg - } - fun emit_ldr(reg: int, offset: int, size: operand_size): int { return emit_ldr(get_reg(), reg, offset, size); } - fun emit_ldr(dest: int, reg: int, offset: int, size: operand_size): int { - var l: reg1is - l.reg = dest - l.base_reg = reg - l.offset = offset - l.size = size - instructions.add(byte_inst::ldr(l)) - return l.reg - } - fun emit_str(to_reg: int, offset: int, from_reg: int, size: operand_size): int { - var s: reg1is - s.reg = from_reg - s.offset = offset - s.base_reg = to_reg - s.size = size - instructions.add(byte_inst::str(s)) - return -1 - } - fun emit_jmp(offset: int): int { return emit_jmp((offset) cast long); } - fun emit_jmp(offset: long): int { - instructions.add(byte_inst::jmp(offset)) - return -1 - } - fun emit_jz(reg: int, offset: int): int { - var j: test - j.reg = reg - j.offset = offset - instructions.add(byte_inst::jz(j)) - return -1 - } - fun emit_ret(): int { - instructions.add(byte_inst::ret()) - return -1 - } - fun emit_call(reg: int): int { - instructions.add(byte_inst::call(reg)) - return 2 - } - - // Stack ABI - // it's system v x64ish, but all params passed on stack - fun evaluate(): int { - println("evaling main") - println(bytecode_to_string(functions, instructions)) - var main_entry = functions.find_first_satisfying(fun(block: bytecode_function): bool return block.name == "main";) - var registers.construct(reg_max): vec - registers.size = reg_max - registers[1] = 0xdeadbeefcafebabe - var stack_size = 8 * 1024 * 1024 - var got_malloc = null() - var stack = new(stack_size) + stack_size - for (var i = 0; i < stack_size; i++;) - stack[-i + -1] = 0 - registers[0] = (stack-register_size) cast long // with the stack being zeroed out, this makes it a return address of 0 - for (var i = main_entry.instruction_start; i < instructions.size; i++;) { - /*println(str("evaling: ") + i + ": " + to_string(instructions[i]))*/ - match(instructions[i]) { - byte_inst::nop() {} - byte_inst::imm(i) registers[i.to_reg] = i.val - byte_inst::add(a) registers[a.to_reg] = registers[a.a] + registers[a.b] - byte_inst::addi(a) registers[a.to_reg] = registers[a.a] + a.bi - byte_inst::umul(a) registers[a.to_reg] = (registers[a.a]) cast ulong * (registers[a.b]) cast ulong - byte_inst::smul(a) registers[a.to_reg] = registers[a.a] * registers[a.b] - byte_inst::udiv(a) registers[a.to_reg] = (registers[a.a]) cast ulong / (registers[a.b]) cast ulong - byte_inst::sdiv(a) registers[a.to_reg] = registers[a.a] / registers[a.b] - byte_inst::mod(a) registers[a.to_reg] = (registers[a.a]) cast ulong % (registers[a.b]) cast ulong - byte_inst::shr(a) registers[a.to_reg] = (registers[a.a]) cast ulong >>(registers[a.b]) cast ulong - byte_inst::sar(a) registers[a.to_reg] = registers[a.a] >> registers[a.b] - byte_inst::shl(a) registers[a.to_reg] = (registers[a.a]) cast ulong <<(registers[a.b]) cast ulong - byte_inst::and(a) registers[a.to_reg] = registers[a.a] & registers[a.b] - byte_inst::or(a) registers[a.to_reg] = registers[a.a] | registers[a.b] - byte_inst::xor(a) registers[a.to_reg] = registers[a.a] ^ registers[a.b] - byte_inst::not(a) registers[a.to_reg] = ~registers[a.a] - byte_inst::gz(a) registers[a.to_reg] = registers[a.a] > 0 - byte_inst::lz(a) registers[a.to_reg] = registers[a.a] < 0 - byte_inst::ez(a) registers[a.to_reg] = registers[a.a] == 0 - byte_inst::ldr(l) match (l.size) { - operand_size::b8() registers[l.reg] = *(registers[l.base_reg] + l.offset) cast *char - operand_size::b16() registers[l.reg] = *(registers[l.base_reg] + l.offset) cast *short - operand_size::b32() registers[l.reg] = *(registers[l.base_reg] + l.offset) cast *int - operand_size::b64() registers[l.reg] = *(registers[l.base_reg] + l.offset) cast *long - } - byte_inst::str(s) match (s.size) { - operand_size::b8() *(registers[s.base_reg] + s.offset) cast *uchar = registers[s.reg] - operand_size::b16() *(registers[s.base_reg] + s.offset) cast *ushort = registers[s.reg] - operand_size::b32() *(registers[s.base_reg] + s.offset) cast *uint = registers[s.reg] - operand_size::b64() *(registers[s.base_reg] + s.offset) cast *ulong = registers[s.reg] - } - byte_inst::jmp(offset) i += offset - 1 // to counteract pc inc - byte_inst::jz(j) if (registers[j.reg] == 0) - i += j.offset - 1 // to counteract pc inc - byte_inst::call(c) { - var func_start = registers[c] - // extern call - -/*ext fun malloc(size: ulong): *void*/ -/*ext fun free(size: *void)*/ -/*ext fun memmove(dest: *void, src: *void, size: ulong): *void*/ - -/*ext fun printf(fmt_str: *char, ...): int*/ -/*ext fun fprintf(file: *void, format: *char, ...): int*/ -/*ext fun fflush(file: int): int*/ -/*ext fun fgets(buff: *char, size: int, file: *void): *char*/ -/*ext var stderr: *void*/ -/*ext var stdin: *void*/ - -/*ext fun fopen(path: *char, mode: *char): *void*/ -/*ext fun fclose(file: *void): int*/ -/*ext fun ftell(file: *void): long*/ -/*ext fun fseek(file: *void, offset: long, whence: int): int*/ -/*ext fun fread(ptr: *void, size: ulong, nmemb: ulong, file: *void): ulong*/ -/*ext fun fwrite(ptr: *void, size: ulong, nmemb: ulong, file: *void): ulong*/ - -/*ext fun system(call_string: *char): int*/ -/*ext fun exit(code: int):void*/ - -/*ext fun popen(command: *char, mode: *char): *void*/ -/*ext fun pclose(file: *void): int*/ - -/*ext fun snprintf(to_str: *char, num: ulong, format: *char, ...): int*/ - if (func_start < 0) { - if (func_start == malloc_addr) - registers[2] = (malloc(*(registers[0]) cast *ulong)) cast long - else if (func_start == free_addr) - free(*(registers[0]) cast **void) - else if (func_start == memmove_addr) - registers[2] = (memmove(*(registers[0]) cast **void, - *(registers[0] + #sizeof<*void>) cast **void, - *(registers[0] + 2*#sizeof<*void>) cast *ulong)) cast long - else if (func_start == printf_addr) - registers[2] = (printf( *(registers[0]) cast **char, - *(registers[0] + #sizeof<*char>) cast **char)) cast long - else if (func_start == fprintf_addr) - registers[2] = (fprintf(*(registers[0]) cast **void, - *(registers[0] + #sizeof<*void>) cast **char, - *(registers[0] + #sizeof<*void> + #sizeof<*char>) cast **char)) cast long - else if (func_start == fflush_addr) - registers[2] = (fflush( *(registers[0]) cast *int)) cast long - else if (func_start == fgets_addr) - registers[2] = (fgets( *(registers[0]) cast **char, - *(registers[0] + #sizeof<*char>) cast *int, - *(registers[0] + #sizeof<*char> + #sizeof) cast **void)) cast long - else if (func_start == fopen_addr) - registers[2] = (fopen( *(registers[0]) cast **char, - *(registers[0] + #sizeof<*char>) cast **char)) cast long - else if (func_start == fclose_addr) - registers[2] = (fclose( *(registers[0]) cast **void)) cast long - else if (func_start == ftell_addr) - registers[2] = (ftell( *(registers[0]) cast **void)) cast long - else if (func_start == fseek_addr) - registers[2] = (fseek( *(registers[0]) cast **void, - *(registers[0] + #sizeof<*void>) cast *long, - *(registers[0] + #sizeof<*void> + #sizeof) cast *int)) cast long - else if (func_start == fread_addr) - registers[2] = (fread( *(registers[0]) cast **void, - *(registers[0] + #sizeof<*void>) cast *ulong, - *(registers[0] + #sizeof<*void> + #sizeof) cast *ulong, - *(registers[0] + #sizeof<*void>+2*#sizeof) cast **void)) cast long - else if (func_start == fwrite_addr) - registers[2] = (fwrite( *(registers[0]) cast **void, - *(registers[0] + #sizeof<*void>) cast *ulong, - *(registers[0] + #sizeof<*void> + #sizeof) cast *ulong, - *(registers[0] + #sizeof<*void>+2*#sizeof) cast **void)) cast long - else if (func_start == system_addr) - registers[2] = (system( *(registers[0]) cast **char)) cast long - else if (func_start == exit_addr) - exit(*(registers[0]) cast *int) - else if (func_start == popen_addr) - registers[2] = (popen( *(registers[0]) cast **char, - *(registers[0] + #sizeof<*char>) cast **char)) cast long - else if (func_start == pclose_addr) - registers[2] = (pclose( *(registers[0]) cast **void)) cast long - else if (func_start == snprintf_addr) - registers[2] =(snprintf(*(registers[0]) cast **char, - *(registers[0] + #sizeof<*char>) cast *ulong, - *(registers[0] + #sizeof<*char> + #sizeof) cast **char, - *(registers[0] + #sizeof<*char> + #sizeof + #sizeof<*char>) cast *double)) cast long - else - error(str("bad extern call number") + func_start) - } else { - /*registers[0] -= register_size*/ - registers[0] = registers[0] - register_size - *(registers[0]) cast *long = i + 1 - i = func_start - 1 - /*print("call!")*/ - /*println("call: " + functions.find_first_satisfying(fun(f: bytecode_function): bool return f.instruction_start == func_start;).name)*/ - /*println("first part of memory is (after push)")*/ - /*for (var i = 0; i < 8*8; i+=8;) {*/ - /*print(str("-") + i + str(": "))*/ - /*for (var j = 0; j < 8; j++;) {*/ - /*if (j == 4)*/ - /*print(" ")*/ - /*print(*(stack - (i+j)*#sizeof - 1) cast *uchar)*/ - /*print(" ")*/ - /*}*/ - /*println()*/ - /*}*/ - /*println("Done")*/ - } - } - byte_inst::ret() { - var pc = *(registers[0]) cast *long - /*registers[0] += register_size*/ - registers[0] = registers[0] + register_size - /*print("returning!")*/ - /*println("first part of memory is")*/ - /*for (var i = 0; i < 8*8; i+=8;) {*/ - /*print(str("-") + i + str(": "))*/ - /*for (var j = 0; j < 8; j++;) {*/ - /*if (j == 4)*/ - /*print(" ")*/ - /*print(*(stack - (i+j)*#sizeof - 1) cast *uchar)*/ - /*print(" ")*/ - /*}*/ - /*println()*/ - /*}*/ - /*println("Done")*/ - if (pc == 0) { - /*println(str("got malloc is ") + *(got_malloc) cast *int)*/ - var value = registers[2] - println(str("returning from main, value is ") + value) - return value - } else { - i = pc - 1 - /*println(str("returning to ") + pc)*/ - } - } - } - } - return -1 - } -} diff --git a/stdlib/c_generator.krak b/stdlib/c_generator.krak deleted file mode 100644 index 6abbf06..0000000 --- a/stdlib/c_generator.krak +++ /dev/null @@ -1,509 +0,0 @@ -import io:* -import mem:* -import map:* -import hash_map:* -import stack:* -import str:* -import util:* -import tree:* -import symbol:* -import ast_nodes:* -// for error with syntax tree -import pass_common:* -import poset:* - -obj c_generator (Object) { - var id_counter: int - var ast_name_map: hash_map<*ast_node, str> - var used_names: hash_set - var function_type_map: map - var replacement_map: map - var longest_replacement: int - var function_typedef_string: str - var linker_string: str - fun construct(): *c_generator { - id_counter = 0 - ast_name_map.construct() - used_names.construct() - // to avoid using c keywords - used_names.add(str("extern")) - used_names.add(str("register")) - function_type_map.construct() - function_typedef_string.construct() - linker_string.construct() - - replacement_map.construct() - replacement_map[str("+")] = str("plus") - replacement_map[str("-")] = str("minus") - replacement_map[str("*")] = str("star") - replacement_map[str("/")] = str("div") - replacement_map[str("%")] = str("mod") - replacement_map[str("^")] = str("carat") - replacement_map[str("&")] = str("amprsd") - replacement_map[str("|")] = str("pipe") - replacement_map[str("~")] = str("tilde") - replacement_map[str("!")] = str("exlmtnpt") - replacement_map[str(",")] = str("comma") - replacement_map[str("=")] = str("eq") - replacement_map[str("++")] = str("dbplus") - replacement_map[str("--")] = str("dbminus") - replacement_map[str("<<")] = str("dbleft") - replacement_map[str(">>")] = str("dbright") - replacement_map[str("::")] = str("scopeop") - replacement_map[str(":")] = str("colon") - replacement_map[str("==")] = str("dbq") - replacement_map[str("!=")] = str("notequals") - replacement_map[str("&&")] = str("doubleamprsnd") - replacement_map[str("||")] = str("doublepipe") - replacement_map[str("+=")] = str("plusequals") - replacement_map[str("-=")] = str("minusequals") - replacement_map[str("/=")] = str("divequals") - replacement_map[str("%=")] = str("modequals") - replacement_map[str("^=")] = str("caratequals") - replacement_map[str("&=")] = str("amprsdequals") - replacement_map[str("|=")] = str("pipeequals") - replacement_map[str("*=")] = str("starequals") - replacement_map[str("<<=")] = str("doublerightequals") - replacement_map[str("<")] = str("lt") - replacement_map[str(">")] = str("gt") - replacement_map[str(">>=")] = str("doubleleftequals") - replacement_map[str("(")] = str("openparen") - replacement_map[str(")")] = str("closeparen") - replacement_map[str("[")] = str("obk") - replacement_map[str("]")] = str("cbk") - replacement_map[str(" ")] = str("_") - replacement_map[str(".")] = str("dot") - replacement_map[str("->")] = str("arrow") - - longest_replacement = 0 - replacement_map.for_each(fun(key: str, value: str) { - if (key.length() > longest_replacement) - longest_replacement = key.length() - }) - - return this - } - fun copy_construct(old: *c_generator) { - id_counter = old->id_counter - ast_name_map.copy_construct(&old->ast_name_map) - used_names.copy_construct(&old->used_names) - function_type_map.copy_construct(&old->function_type_map) - function_typedef_string.copy_construct(&old->function_typedef_string) - replacement_map.copy_construct(&old->replacement_map) - longest_replacement = old->longest_replacement - linker_string.copy_construct(&old->linker_string) - } - fun operator=(other: ref c_generator) { - destruct() - copy_construct(&other) - } - fun destruct() { - ast_name_map.destruct() - used_names.destruct() - function_type_map.destruct() - function_typedef_string.destruct() - replacement_map.destruct() - linker_string.destruct() - } - fun get_id(): str return to_string(id_counter++); - fun generate_function_prototype_and_header(child: *ast_node):pair { - var backing = child->function - var parameter_types = str() - var parameters = str() - var decorated_name = str() - - if (backing.is_extern) - decorated_name = backing.name - else - decorated_name = generate_function(child) - - backing.parameters.for_each(fun(parameter: *ast_node) { - if (parameter_types != "") { parameter_types += ", "; parameters += ", ";} - parameter_types += type_to_c(parameter->identifier.type) - parameters += type_to_c(parameter->identifier.type) + " " + get_name(parameter) - }) - if (backing.is_variadic) { - parameter_types += ", ..." - parameters += ", ..." - } - return make_pair(type_to_c(backing.type->return_type) + " " + decorated_name + "(" + parameter_types + ");\n", - type_to_c(backing.type->return_type) + " " + decorated_name + "(" + parameters + ")") - } - fun generate_c(name_ast_map: map,*ast_node>>, ast_to_syntax_in: map<*ast_node, *tree> ): pair { - var prequal: str = "#include \n" - var plain_typedefs: str = "\n/**Plain Typedefs**/\n" - var top_level_c_passthrough: str = "" - var variable_extern_declarations: str = "" - var structs: str = "\n/**Type Structs**/\n" - function_typedef_string = "\n/**Typedefs**/\n" - var function_prototypes: str = "\n/**Function Prototypes**/\n" - var function_definitions: str = "\n/**Function Definitions**/\n" - var variable_declarations: str = "\n/**Variable Declarations**/\n" - - // moved out from below so that it can be used for methods as well as regular functions (and eventually lambdas...) - var generate_function_definition = fun(child: *ast_node) { - var backing = child->function - var prototype_and_header = generate_function_prototype_and_header(child) - function_prototypes += prototype_and_header.first - if (!backing.is_extern) - function_definitions += prototype_and_header.second - if (backing.body_statement) { - function_definitions += " {\n" + generate(backing.body_statement) - function_definitions += ";\n}\n" - } - } - - var type_poset = poset<*ast_node>() - // iterate through asts - name_ast_map.for_each(fun(name: str, tree_pair: pair<*tree,*ast_node>) { - // iterate through children for each ast - // do lambdas seperatly, so we can reconstitute the enclosing object if it has one - tree_pair.second->translation_unit.lambdas.for_each(fun(child: *ast_node) { - generate_function_definition(child) - }) - tree_pair.second->translation_unit.children.for_each(fun(child: *ast_node) { - match (*child) { - ast_node::if_comp(backing) error("if_comp not currently supported") - ast_node::simple_passthrough(backing) error("simple_passthrough removed") - ast_node::declaration_statement(backing) variable_declarations += generate_declaration_statement(child) + ";\n" // false - don't do defer - // shouldn't need to do anything with return, as the intrinsic should be something like link - ast_node::compiler_intrinsic(backing) generate_compiler_intrinsic(child) - ast_node::function(backing) { - // check for and add to parameters if a closure - generate_function_definition(child) - } - ast_node::template(backing) { - backing.instantiated.for_each(fun(node: *ast_node) { - match (*node) { - ast_node::function(backing) generate_function_definition(node) - ast_node::type_def(backing) { - type_poset.add_job(node) - backing.variables.for_each(fun(i: *ast_node) { - var var_type = get_ast_type(i->declaration_statement.identifier) - if (!var_type->indirection && var_type->type_def) - type_poset.add_open_dep(node, var_type->type_def) - }) - } - } - }) - } - ast_node::type_def(backing) { - type_poset.add_job(child) - backing.variables.for_each(fun(i: *ast_node) { - var var_type = get_ast_type(i->declaration_statement.identifier) - if (!var_type->indirection && var_type->type_def) - type_poset.add_open_dep(child, var_type->type_def) - }) - } - ast_node::adt_def(backing) error("ADT remaining!") - } - }) - }) - type_poset.get_sorted().for_each(fun(vert: *ast_node) { - var base_name = get_name(vert) - plain_typedefs += str("typedef ") - if (vert->type_def.is_union) { - plain_typedefs += "union " - structs += "union " - } else { - plain_typedefs += "struct " - structs += "struct " - } - plain_typedefs += base_name + "_dummy " + base_name + ";\n" - structs += base_name + "_dummy {\n" - vert->type_def.variables.for_each(fun(variable_declaration: *ast_node) structs += generate_declaration_statement(variable_declaration) + ";\n";) - // generate the methods (note some of these may be templates) - vert->type_def.methods.for_each(fun(method: *ast_node) { - if (is_template(method)) - method->template.instantiated.for_each(fun(m: *ast_node) generate_function_definition(m);) - else - generate_function_definition(method); - }) - structs += "};\n" - }) - - return make_pair(prequal+plain_typedefs+function_typedef_string+top_level_c_passthrough+variable_extern_declarations+structs+function_prototypes+variable_declarations+function_definitions + "\n", linker_string) - } - fun generate_declaration_statement(node: *ast_node): str { - var identifier = node->declaration_statement.identifier - var ident_type = identifier->identifier.type - var to_ret = type_to_c(identifier->identifier.type) + " " + get_name(identifier) - if (identifier->identifier.is_extern) - to_ret = "extern " + to_ret - if (node->declaration_statement.expression) { - // in case of recursive closures, make sure variable is declared before assignment - /*to_ret += ";\n"*/ - /*to_ret += get_name(identifier) + " = " + generate(node->declaration_statement.expression)*/ - to_ret += " = " + generate(node->declaration_statement.expression) - } - if (node->declaration_statement.init_method_call) { - error("init_method_call remaining") - } - return to_ret - } - fun generate_assignment_statement(node: *ast_node): str { - return generate(node->assignment_statement.to) + " = " + generate(node->assignment_statement.from) - } - fun generate_if_statement(node: *ast_node): str { - var if_str = "if (" + generate(node->if_statement.condition) + ") {\n" + generate(node->if_statement.then_part) + "}" - if (node->if_statement.else_part) - if_str += " else {\n" + generate(node->if_statement.else_part) + "}" - return if_str + "\n" - } - fun generate_while_loop(node: *ast_node): str { - return "while (" + generate(node->while_loop.condition) + ")\n" + generate(node->while_loop.statement) - } - fun generate_for_loop(node: *ast_node): str { - var init = str(";") - if (node->for_loop.init) - init = generate(node->for_loop.init) - var cond = str(";") - if (node->for_loop.condition) - cond = generate(node->for_loop.condition) - // gotta take off last semicolon - var update = str() - if (node->for_loop.update) { - update = generate(node->for_loop.update) - if (update.length() < 2) - error("update less than 2! Likely legal, but need easy compiler mod here") - update = update.slice(0,-2) - } - return "for (" + init + cond + "; " + update + ")\n" + generate(node->for_loop.body) - } - fun generate_identifier(node: *ast_node): str { - if (get_ast_type(node)->is_ref) - error("still existin ref in identifier") - return get_name(node) - } - fun generate_return_statement(node: *ast_node): str { - if (node->return_statement.return_value) - return "return " + generate(node->return_statement.return_value) - return str("return") - } - fun generate_branching_statement(node: *ast_node): str { - match(node->branching_statement.b_type) { - branching_type::break_stmt() return str("break") - branching_type::continue_stmt() return str("continue") - } - } - fun generate_cast(node: *ast_node): str { - return "((" + type_to_c(node->cast.to_type) + ")(" + generate(node->cast.value) + "))" - } - fun generate_value(node: *ast_node): str { - var value = node->value.string_value - if (node->value.value_type->base == base_type::character() && node->value.value_type->indirection == 0) - return "'" + value + "'" - if (node->value.value_type->base != base_type::character() || node->value.value_type->indirection != 1) - return value - - var to_ret = str("\"") //" - value.for_each(fun(c: char) { - if (c == '\n') - to_ret += "\\n" - else if (c == '\\') - to_ret += "\\\\" - else if (c == '"') - to_ret += "\\\"" - else - to_ret += c - }) - return to_ret + "\"" - } - fun generate_code_block(node: *ast_node): str { - var to_ret = str("{\n") - node->code_block.children.for_each(fun(child: *ast_node) to_ret += generate(child) + ";\n";) - return to_ret + "}" - } - // this generates the function as a value, not the actual function - fun generate_function(node: *ast_node): str { - return get_name(node) - } - fun generate_function_call(node: *ast_node): str { - var func_name = generate(node->function_call.func) - var call_string = str() - var func_return_type = get_ast_type(node) - - var parameters = node->function_call.parameters - if ( parameters.size == 2 && (func_name == "+" || func_name == "-" || func_name == "*" || func_name == "/" - || func_name == "<" || func_name == ">" || func_name == "<=" || func_name == ">=" - || func_name == "==" || func_name == "!=" || func_name == "%" || func_name == "^" - || func_name == "|" || func_name == "&" || func_name == ">>" || func_name == "<<" - )) - return "(" + generate(parameters[0]) + func_name + generate(parameters[1]) + ")" - if ( parameters.size == 2 && (func_name == "||" || func_name == "&&")) - error("Remaining || or &&") - // don't propegate enclosing function down right of access - // XXX what about enclosing object? should it be the thing on the left? - if (func_name == "." || func_name == "->") - return "(" + generate(parameters[0]) + func_name + generate(parameters[1]) + ")" - if (func_name == "[]") - return "(" + generate(parameters[0]) + "[" + generate(parameters[1]) + "])" - // the post ones need to be post-ed specifically, and take the p off - if (func_name == "++p" || func_name == "--p") - return "(" + generate(parameters[0]) + ")" + func_name.slice(0,-2) - - // So we don't end up copy_constructing etc, we just handle the unary operators right here - if (func_name == "*" || func_name == "&") - return "(" + func_name + generate(parameters[0]) + ")" - - var func_type = get_ast_type(node->function_call.func) - // regular parameter generation - for (var i = 0; i < parameters.size; i++;) { - var param = parameters[i] - var in_function_param_type = null() - // grab type from param itself if we're out of param types (because variadic function) - if (i < func_type->parameter_types.size) - in_function_param_type = func_type->parameter_types[i] - else - in_function_param_type = get_ast_type(param)->clone_without_ref() - if (call_string != "") - call_string += ", " - - call_string += generate(param) - } - call_string = func_name + "(" + call_string + ")" - return call_string - } - - fun generate_compiler_intrinsic(node: *ast_node): str { - if (node->compiler_intrinsic.intrinsic == "sizeof") { - if (node->compiler_intrinsic.parameters.size || node->compiler_intrinsic.type_parameters.size != 1) - error("wrong parameters to sizeof compiler intrinsic") - return "sizeof(" + type_to_c(node->compiler_intrinsic.type_parameters[0]) + ")" - } else if (node->compiler_intrinsic.intrinsic == "link") { - node->compiler_intrinsic.parameters.for_each(fun(value: *ast_node) { - linker_string += str("-l") + value->value.string_value + " " - }) - return str() - } - error(node->compiler_intrinsic.intrinsic + ": unknown intrinsic") - return str("ERROR") - } - - fun generate(node: *ast_node): str { - if (!node) return str("/*NULL*/") - match (*node) { - ast_node::declaration_statement(backing) return generate_declaration_statement(node) - ast_node::assignment_statement(backing) return generate_assignment_statement(node) - ast_node::if_statement(backing) return generate_if_statement(node) - ast_node::while_loop(backing) return generate_while_loop(node) - ast_node::for_loop(backing) return generate_for_loop(node) - ast_node::function(backing) return generate_function(node) - ast_node::function_call(backing) return generate_function_call(node) - ast_node::compiler_intrinsic(backing) return generate_compiler_intrinsic(node) - ast_node::code_block(backing) return generate_code_block(node) - ast_node::return_statement(backing) return generate_return_statement(node) - ast_node::branching_statement(backing) return generate_branching_statement(node) - ast_node::defer_statement(backing) error("unremoved defer") - ast_node::match_statement(backing) error("unremoved match") - ast_node::cast(backing) return generate_cast(node) - ast_node::value(backing) return generate_value(node) - ast_node::identifier(backing) return generate_identifier(node) - } - error(str("COULD NOT GENERATE ") + get_ast_name(node)) - return str("/* COULD NOT GENERATE */") - } - fun type_to_c(type: *type): str { - var indirection = str() - if (type->is_ref) error("still ref in type_to_c") //indirection += "/*ref*/ *" - for (var i = 0; i < type->indirection; i++;) indirection += "*" - match (type->base) { - base_type::none() return str("none") + indirection - base_type::template() return str("template") + indirection - base_type::template_type() return str("template_type") + indirection - base_type::void_return() return str("void") + indirection - base_type::boolean() return str("bool") + indirection - base_type::character() return str("char") + indirection - base_type::ucharacter() return str("unsigned char") + indirection - base_type::short_int() return str("short") + indirection - base_type::ushort_int() return str("unsigned short") + indirection - base_type::integer() return str("int") + indirection - base_type::uinteger() return str("unsigned int") + indirection - base_type::long_int() return str("long") + indirection - base_type::ulong_int() return str("unsigned long") + indirection - base_type::floating() return str("float") + indirection - base_type::double_precision() return str("double") + indirection - base_type::object() return get_name(type->type_def) + indirection - base_type::function() { - type = type->clone_with_indirection(0,false) - if (!function_type_map.contains_key(*type)) { - var temp_name = str("function") + get_id() - var temp = str() - type->parameter_types.for_each(fun(parameter_type: *type) { - temp += str(", ") + type_to_c(parameter_type) + " " - temp_name += "_" + cify_name(type_to_c(parameter_type)) - }) - if (type->is_raw) - function_typedef_string += str("typedef ") + type_to_c(type->return_type) + " (*" + temp_name + ")(" + temp.slice(1,-1) + ");\n" - else - error(type->to_string() + " is not raw!") - // again, the indirection - function_type_map[*type] = temp_name - } - return function_type_map[*type] + indirection - } - } - return str("impossible type") + indirection - } - fun type_decoration(type: *type): str { - return cify_name(type->to_string()) - } - fun get_name(node: *ast_node): str { - var maybe_it = ast_name_map.get_ptr_or_null(node); - if (maybe_it) - return *maybe_it - var result = str("impossible name") - var make_unique = true - match (*node) { - ast_node::type_def(backing) { - var upper = backing.scope[str("~enclosing_scope")][0] - result = cify_name(backing.name) - if (is_template(upper)) - upper->template.instantiated_map.reverse_get(node).for_each(fun(t: ref type) result += str("_") + type_decoration(&t);) - } - ast_node::function(backing) { - // be careful, operators like . come through this - if (backing.name == "main" || backing.is_extern || !backing.body_statement) { - result = backing.name - make_unique = false - } else { - result = "fun_" - var upper = backing.scope.get_with_default(str("~enclosing_scope"), vec(null()))[0] - if (upper && is_type_def(upper)) - result += get_name(upper) + "_" - result += cify_name(node->function.name) - node->function.parameters.for_each(fun(param: *ast_node) result += str("_") + type_decoration(param->identifier.type);) - } - } - ast_node::identifier(backing) { - if (backing.name == "this" || backing.is_extern) - make_unique = false - result = backing.name - } - } - if (result == "impossible name") - error("HUGE PROBLEMS") - if (make_unique && used_names.contains(result)) - result += get_id() - ast_name_map.set(node, result) - used_names.add(result) - return result - } - fun cify_name(name: str): str { - var to_ret = str() - for (var i = 0; i < name.length(); i++;) { - var replaced = false - for (var j = longest_replacement; j > 0; j--;) { - if (i + j <= name.length() && replacement_map.contains_key(name.slice(i,i+j))) { - to_ret += replacement_map[name.slice(i,i+j)] - replaced = true - i += j-1; - break - } - } - if (!replaced) - to_ret += name[i] - } - return to_ret - } -} diff --git a/stdlib/c_line_control.krak b/stdlib/c_line_control.krak deleted file mode 100644 index bbccdde..0000000 --- a/stdlib/c_line_control.krak +++ /dev/null @@ -1,37 +0,0 @@ -import symbol:* -import tree:* -import vec:* -import map:* -import util:* -import str:* -import mem:* -import io:* -import ast_nodes:* -import ast_transformation:* - -import pass_common:* - -fun get_line(node: *tree, name: str): *ast_node { - var to_ret = _passthrough() - to_ret->simple_passthrough.passthrough_str = str("\n#line ") + get_first_terminal(node)->data.position + " \"" + name + "\"\n" - return to_ret -} - -fun c_line_control(name_ast_map: *map,*ast_node>>, ast_to_syntax: *map<*ast_node, *tree>) { - var first = true - name_ast_map->for_each(fun(name: str, syntax_ast_pair: pair<*tree,*ast_node>) { - /*var helper = fun(node: *ast_node, parent_chain: *stack<*ast_node>) {*/ - /*match(*node) {*/ - /*if (is_code_block(parent_chain->top()) && ast_to_syntax->contains_key(node)) {*/ - /*println(str("adding ") + get_ast_name(node) + " to " + get_ast_name(parent))*/ - /*add_before_in(get_line(ast_to_syntax->get(node), name), node, parent_chain->top())*/ - /*}*/ - /*}*/ - /*}*/ - /*if (first)*/ - /*run_on_tree(helper, empty_pass_second_half(), syntax_ast_pair.second)*/ - first = false - }) -} - - diff --git a/stdlib/ctce_lower.krak b/stdlib/ctce_lower.krak deleted file mode 100644 index 2ff4986..0000000 --- a/stdlib/ctce_lower.krak +++ /dev/null @@ -1,46 +0,0 @@ -import symbol:* -import tree:* -import vec:* -import map:* -import util:* -import str:* -import mem:* -import io:* -import ast_nodes:* -import ast_transformation:* -import interpreter:* -import hash_set:* - -import pass_common:* - -fun ctce_lower(name_ast_map: *map,*ast_node>>, ast_to_syntax: *map<*ast_node, *tree>) { - var visited = hash_set<*ast_node>() - var globals = setup_globals(*name_ast_map) - var ctce_passes = vec<*ast_node>() - name_ast_map->for_each(fun(name: str, syntax_ast_pair: pair<*tree,*ast_node>) { - var helper_before = fun(node: *ast_node, parent_chain: *stack<*ast_node>) { - match(*node) { - ast_node::compiler_intrinsic(backing) { - if (backing.intrinsic == "ctce") { - var result = evaluate_with_globals(backing.parameters[0], &globals) - *node = *unwrap_value(result) - } else if (backing.intrinsic == "ctce_pass") { - ctce_passes.add(backing.parameters[0]) - remove(node, parent_chain) - } - } - } - } - run_on_tree(helper_before, empty_pass_second_half(), syntax_ast_pair.second, &visited) - }) - ctce_passes.for_each(fun(func: *ast_node) { - // don't want to pick up the ast_node::value - var params = vec() - // easier to pick up types from the function itself - if (!is_function(func)) error(str("trying to CTCE pass with non function") + get_ast_name(func)) - params.add(interpreter::value::pointer(make_pair((name_ast_map) cast *void, func->function.type->parameter_types[0]))) - params.add(interpreter::value::pointer(make_pair((ast_to_syntax) cast *void, func->function.type->parameter_types[1]))) - call_function(func, params, &globals) - }) -} - diff --git a/stdlib/defer_lower.krak b/stdlib/defer_lower.krak deleted file mode 100644 index 382772e..0000000 --- a/stdlib/defer_lower.krak +++ /dev/null @@ -1,81 +0,0 @@ -import symbol:* -import tree:* -import vec:* -import map:* -import util:* -import str:* -import mem:* -import io:* -import ast_nodes:* -import ast_transformation:* -import hash_set:* - -import pass_common:* - -fun defer_lower(name_ast_map: *map,*ast_node>>, ast_to_syntax: *map<*ast_node, *tree>) { - var visited = hash_set<*ast_node>() - name_ast_map->for_each(fun(name: str, syntax_ast_pair: pair<*tree,*ast_node>) { - var defer_triple_stack = stack>>() - var loop_stack = stack(-1) - var helper_before = fun(node: *ast_node, parent_chain: *stack<*ast_node>) { - match(*node) { - ast_node::defer_statement(backing) { - if (is_code_block(parent_chain->top())) { - remove(node, parent_chain) - defer_triple_stack.top().top().push(backing.statement) - } else { - replace_with_in(node, backing.statement, parent_chain) - } - } - ast_node::code_block(backing) { - defer_triple_stack.top().push(stack<*ast_node>()) - } - ast_node::for_loop(backing) { - loop_stack.push(defer_triple_stack.top().size()) - } - ast_node::while_loop(backing) { - loop_stack.push(defer_triple_stack.top().size()) - } - ast_node::function(backing) { - defer_triple_stack.push(stack>()) - } - } - } - var helper_after = fun(node: *ast_node, parent_chain: *stack<*ast_node>) { - match(*node) { - ast_node::branching_statement(backing) { - var block = _code_block() - add_to_scope("~enclosing_scope", parent_chain->item_from_top_satisfying(fun(i: *ast_node): bool return is_code_block(i) || is_function(i);), block) - replace_with_in(node, block, parent_chain) - for (var i = 0; i < defer_triple_stack.top().size() - loop_stack.top(); i++;) - block->code_block.children.add_all(defer_triple_stack.top().from_top(i).reverse_vector()) - block->code_block.children.add(node) - } - ast_node::return_statement(backing) { - var block = parent_chain->top() - if (!is_code_block(block)) - error("defer doesn't have block - it should from obj lower") - for (var i = 0; i < defer_triple_stack.top().size(); i++;) { - defer_triple_stack.top().from_top(i).reverse_vector().for_each(fun(c: *ast_node) { - add_before_in(c, node, block) - }) - } - } - ast_node::code_block(backing) { - node->code_block.children.add_all(defer_triple_stack.top().pop().reverse_vector()) - } - ast_node::for_loop(backing) { - loop_stack.pop() - } - ast_node::while_loop(backing) { - loop_stack.pop() - } - ast_node::function(backing) { - defer_triple_stack.pop() - } - } - } - run_on_tree(helper_before, helper_after, syntax_ast_pair.second, &visited) - }) -} - diff --git a/stdlib/function_value_lower.krak b/stdlib/function_value_lower.krak deleted file mode 100644 index 26af279..0000000 --- a/stdlib/function_value_lower.krak +++ /dev/null @@ -1,329 +0,0 @@ -import symbol:* -import tree:* -import vec:* -import map:* -import util:* -import type:* -import str:* -import mem:* -import io:* -import ast_nodes:* -import ast_transformation:* -import hash_set:* -import os:* - -import pass_common:* - -obj function_parent_block { - var function: *ast_node - var parent: *ast_node - var parent_block: *ast_node - var parent_function: *ast_node -} -fun make_function_parent_block(function: *ast_node, parent: *ast_node, parent_block: *ast_node, parent_function: *ast_node): function_parent_block { - var result: function_parent_block - result.function = function - result.parent = parent - result.parent_block = parent_block - result.parent_function = parent_function - return result -} -fun find_closed_variables(func: *ast_node, node: *ast_node): set<*ast_node> { - if (!node) return set<*ast_node>() - match (*node) { - ast_node::identifier(backing) { - if (!in_scope_chain(backing.enclosing_scope, func)) { - if (backing.name == "temporary_return_boomchaka" || - backing.name == "temp_boom_return") - error("trying to close over temp return") - else - return set(node); - } - } - ast_node::code_block(backing) { - var to_ret = set<*ast_node>() - backing.children.for_each(fun(n: *ast_node) to_ret += find_closed_variables(func, n);) - return to_ret - } - ast_node::function_call(backing) { - if (is_function(backing.func) && (backing.func->function.name == "." || backing.func->function.name == "->")) - return find_closed_variables(func, backing.parameters.first()) - var to_ret = find_closed_variables(func, backing.func) - backing.parameters.for_each(fun(n: *ast_node) to_ret += find_closed_variables(func, n);) - return to_ret - } - ast_node::function(backing) { - // if this is a lambda, we need to check all of the things it closes over - var to_ret = set<*ast_node>() - backing.closed_variables.for_each(fun(n: *ast_node) to_ret += find_closed_variables(func, n);) - return to_ret - } - ast_node::return_statement(backing) return find_closed_variables(func, backing.return_value) - ast_node::if_statement(backing) return find_closed_variables(func, backing.condition) + find_closed_variables(func, backing.then_part) + find_closed_variables(func, backing.else_part) - ast_node::match_statement(backing) { - var to_ret = set<*ast_node>() - backing.cases.for_each(fun(n: *ast_node) to_ret += find_closed_variables(func, n);) - return to_ret - } - ast_node::case_statement(backing) return find_closed_variables(func, backing.statement) - ast_node::while_loop(backing) return find_closed_variables(func, backing.condition) + find_closed_variables(func, backing.statement) - ast_node::for_loop(backing) { - return find_closed_variables(func, backing.init) + find_closed_variables(func, backing.condition) + - find_closed_variables(func, backing.update) + find_closed_variables(func, backing.body) - } - ast_node::return_statement(backing) return find_closed_variables(func, backing.return_value) - ast_node::defer_statement(backing) return find_closed_variables(func, backing.statement) - ast_node::assignment_statement(backing) return find_closed_variables(func, backing.to) + find_closed_variables(func, backing.from) - ast_node::declaration_statement(backing) return find_closed_variables(func, backing.expression) + find_closed_variables(func, backing.init_method_call) - ast_node::if_comp(backing) return find_closed_variables(func, backing.statement) - ast_node::cast(backing) return find_closed_variables(func, backing.value) - } - return set<*ast_node>() -} -fun in_scope_chain(node: *ast_node, high_scope: *ast_node): bool { - if (node == high_scope) - return true - if (get_ast_scope(node)->contains_key(str("~enclosing_scope"))) - return in_scope_chain(get_ast_scope(node)->get(str("~enclosing_scope"))[0], high_scope) - return false -} - -fun function_value_lower(name_ast_map: *map,*ast_node>>, ast_to_syntax: *map<*ast_node, *tree>) { - var curr_time = get_time() - var visited = hash_set<*ast_node>() - var lambdas = set<*ast_node>() - name_ast_map->for_each(fun(name: str, syntax_ast_pair: pair<*tree,*ast_node>) { - lambdas.add(syntax_ast_pair.second->translation_unit.lambdas) - // do in order so that inner lambdas are done before outer ones, so enclosed - // variables can propegate outwards - syntax_ast_pair.second->translation_unit.lambdas.for_each(fun(n: *ast_node) { - n->function.closed_variables = find_closed_variables(n, n->function.body_statement) - }) - }) - var all_types = hash_set<*type>() - var function_value_creation_points = vec() - var function_value_call_points = vec() - var closed_over_uses = vec>>() - name_ast_map->for_each(fun(name: str, syntax_ast_pair: pair<*tree,*ast_node>) { - var helper_before = fun(node: *ast_node, parent_chain: *stack<*ast_node>) { - var t = get_ast_type(node) - if (t) all_types.add(t) - match(*node) { - // gotta get #sizeof - ast_node::compiler_intrinsic(c) c.type_parameters.for_each( fun(item: *type) all_types.add(item); ) - ast_node::identifier(backing) { - // see if this identifier use is a closed variable in a closure - var enclosing_func = parent_chain->item_from_top_satisfying_or(fun(n: *ast_node): bool return is_function(n);, null()) - if (enclosing_func && enclosing_func->function.closed_variables.contains(node)) { - closed_over_uses.add(make_pair(node, make_pair(parent_chain->top(), enclosing_func))) - } - } - ast_node::function(backing) { - var parent = parent_chain->top() - // need to use function value if - // it isn't a regular function definition (or lambda top reference) - var need_done = !is_translation_unit(parent) && !backing.type->is_raw - if (need_done) { - function_value_creation_points.add(make_function_parent_block(node, parent_chain->top(), - parent_chain->item_from_top_satisfying(fun(i: *ast_node): bool return is_code_block(i);), - parent_chain->item_from_top_satisfying(fun(i: *ast_node): bool return is_function(i);) - )) - } - - } - ast_node::function_call(backing) { - if (!get_ast_type(backing.func)->is_raw) - function_value_call_points.add(make_function_parent_block(backing.func, node, null(), null())) - } - } - } - run_on_tree(helper_before, empty_pass_second_half(), syntax_ast_pair.second, &visited) - }) - curr_time = split(curr_time, "\tclosed_over_uses + function_value_call_points") - - var void_ptr = type_ptr(base_type::void_return(), 1) - var lambda_type_to_struct_type_and_call_func = map>(); //freaking vexing parse moved - all_types.chaotic_closure(fun(t: *type): set<*type> { - if (t->is_function()) - return from_vector(t->parameter_types + t->return_type) - return set<*type>() - }) - var all_type_values = all_types.map(fun(t: *type): type { - if (t->indirection != 0 || t->is_ref) - return *t->clone_with_indirection(0, false) - else - return *t - }) - curr_time = split(curr_time, "\tall types/all type values") - all_type_values.for_each(fun(t: type) { - if (t.is_function() && t.indirection == 0 && !t.is_ref && !t.is_raw && !lambda_type_to_struct_type_and_call_func.contains_key(t)) { - var cleaned = t.clone() - cleaned->is_raw = true - - var new_type_def_name = t.to_string() + "_function_value_struct" - var new_type_def = _type_def(new_type_def_name) - - var func_ident = _ident("func", cleaned, new_type_def) - add_to_scope("func", func_ident, new_type_def) - - var func_closure_type = cleaned->clone() - func_closure_type->parameter_types.add(0, type_ptr(base_type::void_return(), 1)) - var func_closure_ident = _ident("func_closure", func_closure_type, new_type_def) - add_to_scope("func_closure", func_closure_ident, new_type_def) - - var data_ident = _ident("data", void_ptr, new_type_def) - add_to_scope("data", data_ident, new_type_def) - - new_type_def->type_def.variables.add(_declaration(func_ident, null())) - new_type_def->type_def.variables.add(_declaration(func_closure_ident, null())) - new_type_def->type_def.variables.add(_declaration(data_ident, null())) - - add_to_scope("~enclosing_scope", name_ast_map->values.first().second, new_type_def) - add_to_scope(new_type_def_name, new_type_def, name_ast_map->values.first().second) - name_ast_map->values.first().second->translation_unit.children.add(new_type_def) - - var lambda_struct_type = type_ptr(new_type_def) - - var lambda_call_type = type_ptr(vec(lambda_struct_type) + t.parameter_types, t.return_type, 0, false, false, true) - // create parameters - var lambda_call_func_param = _ident("func_struct", lambda_struct_type, null()) - var lambda_call_parameters = vec(lambda_call_func_param) + cleaned->parameter_types.map(fun(t:*type): *ast_node { - return _ident("pass_through_param", t, null()) - }) - var lambda_call_function = _function(str("lambda_call"), lambda_call_type, lambda_call_parameters, false) - // create call body with if, etc - var if_statement = _if(access_expression(lambda_call_func_param, "data")) - lambda_call_function->function.body_statement = _code_block(if_statement) - if_statement->if_statement.then_part = _code_block(_return(_func_call(access_expression(lambda_call_func_param, "func_closure"), - vec(access_expression(lambda_call_func_param, "data")) + lambda_call_parameters.slice(1,-1)))) - if_statement->if_statement.else_part = _code_block(_return(_func_call(access_expression(lambda_call_func_param, "func"), - lambda_call_parameters.slice(1,-1)))) - - lambda_type_to_struct_type_and_call_func[t] = make_pair(lambda_struct_type, lambda_call_function) - // we have to add it for t and *cleaned since we might get either (we make the lambda's type raw later, so if used at creation point will be cleaned...) - // NOPE does this for other functions not lambdas super wrong - /*lambda_type_to_struct_type_and_call_func[*cleaned] = make_pair(lambda_struct_type, lambda_call_function)*/ - - name_ast_map->values.first().second->translation_unit.children.add(new_type_def) - name_ast_map->values.first().second->translation_unit.children.add(lambda_call_function) - } - }) - curr_time = split(curr_time, "\tall type values forEach") - - var lambda_creation_funcs = map<*ast_node, *ast_node>() - // create the closure type for each lambda - var closure_id = 0 - lambdas.for_each(fun(l: *ast_node) { - var closure_struct_type: *type - if (l->function.closed_variables.size()) { - var new_type_def_name = str("closure_struct_") + closure_id++ - var new_type_def = _type_def(new_type_def_name) - l->function.closed_variables.for_each(fun(v: *ast_node) { - // THIS MIGHT HAVE TO ACCOUNT FOR FUNC REFS - var closed_var_type = v->identifier.type - if (lambda_type_to_struct_type_and_call_func.contains_key(*closed_var_type)) - closed_var_type = lambda_type_to_struct_type_and_call_func[*closed_var_type].first - var closed_ident = _ident(v->identifier.name, closed_var_type->clone_with_increased_indirection(), new_type_def) - new_type_def->type_def.variables.add(_declaration(closed_ident, null())) - add_to_scope(v->identifier.name, closed_ident, new_type_def) - }) - add_to_scope("~enclosing_scope", name_ast_map->values.first().second, new_type_def) - add_to_scope(new_type_def_name, new_type_def, name_ast_map->values.first().second) - name_ast_map->values.first().second->translation_unit.children.add(new_type_def) - closure_struct_type = type_ptr(new_type_def)->clone_with_increased_indirection() - } - - var return_type = lambda_type_to_struct_type_and_call_func[*l->function.type].first - var creation_type = type_ptr(vec<*type>(), return_type, 0, false, false, true) - lambda_creation_funcs[l] = _function(l->function.name + "_creation", creation_type, vec<*ast_node>(), false); - var body = _code_block() - var ident = _ident("to_ret", return_type, body) - body->code_block.children.add(_declaration(ident, null())) - body->code_block.children.add(_assign(access_expression(ident, "func"), l)) - body->code_block.children.add(_assign(access_expression(ident, "func_closure"), l)) - if (l->function.closed_variables.size()) { - var closure_lambda_param = _ident("closure_data_pass", closure_struct_type, l) - l->function.parameters.add(0, closure_lambda_param) - var closure_param = _ident("closure", closure_struct_type, body) - lambda_creation_funcs[l]->function.parameters.add(closure_param) - body->code_block.children.add(_assign(access_expression(ident, "data"), closure_param)) - l->function.closed_variables.for_each(fun(v: *ast_node) { - // have to make sure to clean here as well - // THIS MIGHT HAVE TO ACCOUNT FOR FUNC REFS - var closed_param_type = v->identifier.type - if (lambda_type_to_struct_type_and_call_func.contains_key(*closed_param_type)) - closed_param_type = lambda_type_to_struct_type_and_call_func[*closed_param_type].first - var closed_param = _ident("closed_param", closed_param_type->clone_with_increased_indirection(), l) - lambda_creation_funcs[l]->function.parameters.add(closed_param) - body->code_block.children.add(_assign(access_expression(closure_param, v->identifier.name), closed_param)) - }) - } else { - body->code_block.children.add(_assign(access_expression(ident, "data"), _value(str("0"), type_ptr(base_type::void_return(), 1)))) - } - body->code_block.children.add(_return(ident)) - lambda_creation_funcs[l]->function.body_statement = body - name_ast_map->values.first().second->translation_unit.children.add(lambda_creation_funcs[l]) - }) - curr_time = split(curr_time, "\tlambdas forEach") - function_value_call_points.for_each(fun(p: function_parent_block) { - // parent is the function call - var function_struct = p.function - var func_type = get_ast_type(p.function) - if (func_type->is_ref) - func_type = func_type->clone_without_ref() - p.parent->function_call.func = lambda_type_to_struct_type_and_call_func[*func_type].second - p.parent->function_call.parameters.add(0, function_struct) - }) - curr_time = split(curr_time, "\tfunction_value_call_points.forEach") - function_value_creation_points.for_each(fun(p: function_parent_block) { - var lambda_creation_params = vec<*ast_node>() - // add the declaration of the closure struct to the enclosing code block - if (p.function->function.closed_variables.size()) { - // pull closure type off lambda creation func parameter - var closure_type = get_ast_type(lambda_creation_funcs[p.function]->function.parameters[0])->clone_with_decreased_indirection() - var closure_struct_ident = _ident("closure_struct", closure_type, p.parent_block) - p.parent_block->code_block.children.add(0,_declaration(closure_struct_ident, null())) - lambda_creation_params.add(make_operator_call("&", vec(closure_struct_ident))) - p.function->function.closed_variables.for_each(fun(v: *ast_node) { - var addr_of = make_operator_call("&", vec(v)) - if (p.parent_function->function.closed_variables.contains(v)) { - closed_over_uses.add(make_pair(v, make_pair(addr_of, p.parent_function))) - } - lambda_creation_params.add(addr_of) - }) - } - var func_call = _func_call(lambda_creation_funcs[p.function], lambda_creation_params) - replace_with_in(p.function, func_call, p.parent) - }) - curr_time = split(curr_time, "\tfunction_value_creation_points.forEach") - lambdas.for_each(fun(l: *ast_node) l->function.type = l->function.type->clone();) - all_types.for_each(fun(t: *type) { - var t_nptr = t - if (t->indirection != 0 || t->is_ref) { - t_nptr = t->clone() - t_nptr->indirection = 0 - t_nptr->is_ref = false - } - if (lambda_type_to_struct_type_and_call_func.contains_key(*t_nptr)) { - if (t_nptr != t) - *t = *lambda_type_to_struct_type_and_call_func[*t_nptr].first->clone_with_indirection(t->indirection, t->is_ref) - else - *t = *lambda_type_to_struct_type_and_call_func[*t_nptr].first - } - }) - curr_time = split(curr_time, "\tlambdas.for_each") - closed_over_uses.for_each(fun(p: pair<*ast_node, pair<*ast_node, *ast_node>>) { - var variable = p.first - var parent = p.second.first - var lambda = p.second.second - var closure_param = lambda->function.parameters[0] - replace_with_in(variable, make_operator_call("*", vec(access_expression(closure_param, variable->identifier.name))), parent) - }) - curr_time = split(curr_time, "\tclosed_over_uses") - // now we can make them raw - lambdas.for_each(fun(l: *ast_node) { - l->function.type->is_raw = true; - }) - curr_time = split(curr_time, "\tlambdas is raw") -} - diff --git a/stdlib/future.krak b/stdlib/future.krak deleted file mode 100644 index b105553..0000000 --- a/stdlib/future.krak +++ /dev/null @@ -1,86 +0,0 @@ -import mem:* - -__if_comp__ __C__ simple_passthrough(::"-pthread") -""" -#include -""" - -fun pthread_create(thrd : *ulong, strt_routine : fun(*void) : *void, input : *void) : int { - __if_comp__ __C__ { - simple_passthrough(thrd,strt_routine,input::) """ - pthread_attr_t attr; - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); - //int ret = pthread_create((pthread_t*)thrd, &attr, strt_routine.func, strt_routine.data); - int ret = pthread_create((pthread_t*)thrd, &attr, strt_routine.func, input); - pthread_attr_destroy(&attr); - return ret; - """ - } - return 0 -} - -fun pthread_join(thrd : *ulong) : int { - __if_comp__ __C__ { simple_passthrough(thrd::) """ - pthread_t thread = *((pthread_t*)thrd); - return pthread_join(thread, NULL); - """ - } - return 0 -} - -fun pthread_exit() : *void { - __if_comp__ __C__ { simple_passthrough - """ - pthread_exit(NULL); - """ - } -} - - - -fun future(in : fun() : T ) : future { - var out.construct(in) : future - return out -} - -obj func_res { var func : *void; var result : *void; } - -obj future { - var result : T - var status : int - var psy : fun() : T - var wrapper : fun(*void) : * void; - var thread : ulong - - fun construct(in : fun() : T) : *future { - status = 0 - psy = in - wrapper = fun(in : *void) : *void { - var triple = (in) cast *func_res; - var func = (triple->func) cast *fun() : T; - var res : *T = (triple->result) cast *T; - (*res) = (*func)(); - pthread_exit(); - delete(in); - return null(); - } - return this - } - - fun run() { - var in = new(); - in->result = (&result) cast *void; - in->func = (&psy) cast *void; - status = pthread_create(&thread,wrapper,(in) cast *void) - } - - fun get_status():int { - return status - } - - fun finish() : T { - pthread_join(&thread) - return result - } -} diff --git a/stdlib/grammer.krak b/stdlib/grammer.krak deleted file mode 100644 index e97bcce..0000000 --- a/stdlib/grammer.krak +++ /dev/null @@ -1,639 +0,0 @@ -import str -import vec -import set -import stack -import map -import symbol -import regex -import io -import util -import serialize - -fun split_into_words(gram_str: str::str): vec::vec { - // var out.construct(): vec::vec - var out.construct(): vec::vec - var begin = 0 - for (var i = 0; i < gram_str.length(); i++;) { - if (gram_str[i] == '#') { - while(gram_str[i] != '\n') i++ - i++ - io::print("comment: "); io::print(gram_str.slice(begin, i)) - begin = i - } - if (gram_str[i] == '"') { - i++ - while (gram_str[i] != '"') { - i++ - // if we hit a " we check to see if an odd number of backslashes preceed it - // (meaning that the " is escaped), and if so, we move on. Otherwise, we found - // the end of the quoted str - if (gram_str[i] == '"') { - var escaped = 0 - while (gram_str[i-(1+escaped)] == '\\') escaped++ - if (escaped % 2) - i++ - } - } - } - if (gram_str[i] == ' ') { - out.add(gram_str.slice(begin, i)) - // allow multiple spaces between words - while (gram_str[i] == ' ') i++ - begin = i - i-- - } - if (gram_str[i] == '\n') { - if (i != begin) - out.add(gram_str.slice(begin, i)) - begin = i + 1 - } - } - return out -} - -fun load_grammer(gram_str: str::str): grammer { - var gram.construct(): grammer - var leftSide = symbol::symbol("", false) - var doLeftSide = true - var rightSide = vec::vec() - /*split_into_words(io::read_file(path)).for_each(fun(word: str::str) {*/ - /*io::print("word: "); io::println(word);*/ - /*})*/ - /*return gram*/ - split_into_words(gram_str).for_each(fun(word: str::str) { - /*io::print("word: "); io::println(word)*/ - if (word == "=") { - // do nothing - } else if (word == "|") { - gram.rules.add(rule(leftSide, rightSide)) - rightSide = vec::vec() - } else if (word == ";") { - gram.rules.add(rule(leftSide, rightSide)) - rightSide = vec::vec() - doLeftSide = true - } else { - if (doLeftSide) { - leftSide = symbol::symbol(word, false) - gram.non_terminals.add(leftSide) - } else { - if (word[0] == '"') { - // ok, we support both plain terminals "hia*" - // and decorated terminals "hia*":hi_with_as - // so first check to find the ending " and see if it's - // the end of the str - var last_quote = word.length()-1 - while(word[last_quote] != '"') last_quote-- - if (last_quote != word.length()-1) { - rightSide.add(symbol::symbol(word.slice(last_quote+2, -1), true)) - gram.terminals.add(util::make_pair(symbol::symbol(word.slice(last_quote+2, -1), true), regex::regex(word.slice(1,last_quote)))) - } else { - rightSide.add(symbol::symbol(word, true)) - gram.terminals.add(util::make_pair(symbol::symbol(word, true), regex::regex(word.slice(1,last_quote)))) - } - } else { - var non_term = symbol::symbol(word, false) - rightSide.add(non_term) - gram.non_terminals.add(non_term) - } - } - doLeftSide = false - } - }) - return gram -} - -obj grammer (Object, Serializable) { - var rules: vec::vec - var non_terminals: set::set - var terminals: vec::vec> - var first_set_map: map::map> - var parse_table: table - - fun construct(): *grammer { - rules.construct() - non_terminals.construct() - terminals.construct() - first_set_map.construct() - parse_table.construct() - } - fun copy_construct(old: *grammer) { - rules.copy_construct(&old->rules) - non_terminals.copy_construct(&old->non_terminals) - terminals.copy_construct(&old->terminals) - first_set_map.copy_construct(&old->first_set_map) - parse_table.copy_construct(&old->parse_table) - } - fun operator=(other: grammer) { - destruct() - copy_construct(&other) - } - fun destruct() { - rules.destruct() - non_terminals.destruct() - terminals.destruct() - first_set_map.destruct() - parse_table.destruct() - } - - fun serialize(): vec::vec { - return serialize::serialize(rules) + serialize::serialize(non_terminals) + serialize::serialize(terminals) + serialize::serialize(first_set_map) + serialize::serialize(parse_table) - } - fun unserialize(it: ref vec::vec, pos: int): int { - // get everything constructed before the assignment - /*construct()*/ - /*util::unpack(rules, pos) = serialize::unserialize>(it, pos)*/ - /*util::unpack(non_terminals, pos) = serialize::unserialize>(it, pos)*/ - /*util::unpack(terminals, pos) = serialize::unserialize>>(it, pos)*/ - /*util::unpack(first_set_map, pos) = serialize::unserialize>>(it, pos)*/ - /*util::unpack(parse_table, pos) = serialize::unserialize(it, pos)*/ - - // do it in place. Actually looks nicer too - pos = rules.unserialize(it, pos) - pos = non_terminals.unserialize(it, pos) - pos = terminals.unserialize(it, pos) - pos = first_set_map.unserialize(it, pos) - pos = parse_table.unserialize(it, pos) - return pos - } - - fun calculate_first_set() { - // the first set of a terminal is itself - terminals.for_each( fun(terminal: util::pair) - first_set_map[terminal.first] = set::set(terminal.first) - ) - // start out the non-terminals as empty sets - non_terminals.for_each( fun(non_terminal: symbol::symbol) - first_set_map[non_terminal] = set::set() - ) - var changed = true - while (changed) { - changed = false - rules.for_each( fun(r: rule) { - var rule_lookahead = first_vector(r.rhs) - if (!changed) { - changed = !first_set_map[r.lhs].contains(rule_lookahead) - } - first_set_map[r.lhs].add(rule_lookahead) - }) - } - } - fun first_vector(rhs: ref vec::vec): set::set { - var toRet = set::set() - if (rhs.size) { - for (var i = 0; i < rhs.size; i++;) { - var lookahead = first_set_map[rhs[i]] - if (lookahead.contains(symbol::null_symbol())) { - // remove the null if this is not the last in the rule - if (i != rhs.size-1) - lookahead.remove(symbol::null_symbol()) - toRet.add(lookahead) - } else { - toRet.add(lookahead) - break - } - } - } else { - toRet.add(symbol::null_symbol()) - } - return toRet - } - - fun calculate_state_automaton() { - var first_state = closure(state(vec::vec(rules[0].with_lookahead(set::set(symbol::eof_symbol()))))) - var states = vec::vec(first_state) // vec instead of set because we need to iterate by index - var newItems = stack::stack(0) // 0 is the index of the first and only item in states - var count = 0 - while (newItems.size()) { - if (count%200 == 0) { - io::print("calculate_state_automaton while") - io::println(count) - } - count++ - var I = newItems.pop() - var possGoto = set::set() - states[I].items.for_each(fun(r: ref rule) { - if (!r.at_end()) - possGoto.add(r.next()) - // if r is at end or the rest reduces to null, add a reduce for each lookahead symbol - if ( r.at_end() || first_vector(r.after()).contains(symbol::null_symbol()) ) { - var rule_no = rules.find(r.plain()) - r.lookahead.for_each(fun(sym: ref symbol::symbol) { - parse_table.add_reduce(I, sym, rule_no, r.position) - }) - } - }) - possGoto.for_each(fun(X: ref symbol::symbol) { - var goneState = goto(states[I], X) - if (goneState.items.size) { - var already_state = states.find(goneState) - if (already_state == -1) { - parse_table.add_push(I, X, states.size) - newItems.push(states.size) - states.add(goneState) - } else { - parse_table.add_push(I, X, already_state) - } - } - }) - } - /*io::println("ALL STATES:\n")*/ - /*states.for_each(fun(i: ref state) {*/ - /*io::println("STATE:\n")*/ - /*i.items.for_each(fun(r: ref rule) {*/ - /*io::println(str::str("\t") + r.to_string())*/ - /*})*/ - /*})*/ - io::println(" there were : states") - io::println(states.size) - /*io::println(" there were : table")*/ - /*io::println(parse_table.to_string())*/ - /*parse_table.print_string()*/ - } - - fun closure(initial: ref state): state { - initial.items = closure(initial.items) - return initial - } - fun closure(initial: ref vec::vec): vec::vec { - var continueIt = true - //var count = 0 - while (continueIt) { - //io::print("closure while") - //io::println(count) - //count++ - continueIt = false - for (var i = 0; i < initial.size; i++;) { - if (initial[i].at_end()) { - continue - } - rules.for_each(fun(r: ref rule) { - // if i is |a::=c . Bb, a|, we're doing each B::=... in rules - if (r.lhs != initial[i].next()) - return // continue the for-each - // add r with lookahead - var newLookahead = first_vector(initial[i].after_next()) - if (newLookahead.contains(symbol::null_symbol())) { - newLookahead.remove(symbol::null_symbol()) - newLookahead.add(initial[i].lookahead) - } - var alreadyInInSomeForm = false - for (var index = 0; index < initial.size; index++;) { - if (initial[index].equals_but_lookahead(r)) { - alreadyInInSomeForm = true - if (!initial[index].lookahead.contains(newLookahead)) { - //io::println("\n\n\n") - //io::println(initial[index].to_string()) - //io::println("and") - //io::println(r.to_string()) - //io::println("with") - //var result = str::str("|lookahead {") - //newLookahead.for_each(fun(i: symbol::symbol) { - //result += i.to_string() - //}) - //io::println(result) - //io::println("are the same with different lookaheads") - initial[index].lookahead += newLookahead - //io::println("so now it's") - //io::println(initial[index].to_string()) - //io::println("contineu because equal_but_different") - continueIt = true - return // continue the rules for-each - } - } - } - if (!alreadyInInSomeForm) { - continueIt = true - //io::println("\n\n\n") - //io::println("contineu because not contains") - //io::println(newRule.to_string()) - initial.add(r.with_lookahead(newLookahead)) - } - }) - } - } - return initial - } - - fun goto(I: ref state, X: ref symbol::symbol): state { - // loop through i, find all that have thing::= something . X more, - // add thing ::= something X . more - var jPrime = vec::vec() - I.items.for_each(fun(i: ref rule) { - if (!i.at_end() && i.next() == X) - jPrime.add(i.advanced()) - }) - // return closure(that)? - return state(closure(jPrime)) - } - - fun to_string(): str::str { - var result = str::str("grammer rules:") - rules.for_each( fun(i : rule) { result += str::str("\n\t") + i.to_string(); } ) - result += "\nnon_terminals:" - non_terminals.for_each( fun(i : symbol::symbol) { result += str::str("\n\t") + i.to_string(); } ) - result += "\nterminals:" - terminals.for_each( fun(i : util::pair) { result += str::str("\n\t") + i.first.to_string() + ": " + i.second.regexString; } ) - return result - } -} - -fun rule(lhs: symbol::symbol, rhs: vec::vec): rule { - var toRet.construct(): rule - toRet.lhs = lhs - toRet.rhs = rhs - return toRet -} - -obj rule (Object, Serializable) { - var lhs: symbol::symbol - var rhs: vec::vec - var position: int - var lookahead: set::set - - fun serialize(): vec::vec { - return serialize::serialize(lhs) + serialize::serialize(rhs) + serialize::serialize(position) + serialize::serialize(lookahead) - } - fun unserialize(it: ref vec::vec, pos: int): int { - /*var tempLhs = symbol::invalid_symbol()*/ - /*var tempRhs = vec::vec()*/ - /*var tempLookahead = set::set()*/ - /*util::unpack(tempLhs, pos) = serialize::unserialize(it, pos)*/ - /*util::unpack(tempRhs, pos) = serialize::unserialize>(it, pos)*/ - /*util::unpack(position, pos) = serialize::unserialize(it, pos)*/ - /*util::unpack(tempLookahead, pos) = serialize::unserialize>(it, pos)*/ - - /*lhs.copy_construct(&tempLhs)*/ - /*rhs.copy_construct(&tempRhs)*/ - /*lookahead.copy_construct(&tempLookahead)*/ - - pos = lhs.unserialize(it, pos) - pos = rhs.unserialize(it, pos) - util::unpack(position, pos) = serialize::unserialize(it, pos) - return lookahead.unserialize(it, pos) - } - - fun construct(): *rule { - lhs.construct() - rhs.construct() - position = 0 - lookahead.construct() - } - fun copy_construct(other: *rule) { - lhs.copy_construct(&other->lhs) - rhs.copy_construct(&other->rhs) - position = other->position - lookahead.copy_construct(&other->lookahead) - } - fun operator=(other: rule) { - destruct() - copy_construct(&other) - } - fun operator==(other: ref rule):bool { - return lhs == other.lhs && rhs == other.rhs && - position == other.position && lookahead == other.lookahead - } - fun equals_but_lookahead(other: ref rule):bool { - return lhs == other.lhs && rhs == other.rhs && - position == other.position - } - fun destruct() { - lhs.destruct() - rhs.destruct() - lookahead.destruct() - } - - fun next(): ref symbol::symbol { - return rhs[position] - } - fun after(): vec::vec { - return rhs.slice(position, -1) - } - fun after_next(): vec::vec { - return rhs.slice(position + 1, -1) - } - fun at_end(): bool { - return position >= rhs.size - } - fun plain(): rule { - return rule(lhs, rhs) - } - fun with_lookahead(newLookahead: set::set): rule { - var toRet = rule(lhs, rhs) - toRet.position = position - toRet.lookahead = newLookahead - return toRet - } - fun advanced(): rule { - var toRet = rule(lhs, rhs) - toRet.position = position+1 - toRet.lookahead = lookahead - return toRet - } - - fun to_string(): str::str { - var result = lhs.name + " -> " - for (var i = 0; i < rhs.size; i++;) - if (i == position) - result += str::str(" . ") + rhs[i].to_string() + ", "; - else - result += rhs[i].to_string() + ", "; - if (position == rhs.size) - result += " . " - result += "|lookahead {" - lookahead.for_each(fun(i: symbol::symbol) { - result += i.to_string() - }) - result += "}" - return result - } -} - -fun state(itemsIn: ref vec::vec): state { - var toRet.construct(itemsIn): state - return toRet -} - -obj state (Object) { - var items: vec::vec - - fun construct(): *state { - items.construct() - } - fun construct(itemsIn: ref vec::vec): *state { - items.copy_construct(&itemsIn) - } - fun copy_construct(other: *state) { - items.copy_construct(&other->items) - } - fun operator=(other: state) { - destruct() - copy_construct(&other) - } - fun destruct() { - items.destruct() - } - fun operator==(other: ref state):bool { - return items == other.items - } - fun to_string(): str::str { - return str::str("woo a state") - } -} - -adt action_type { - push, - reduce, -// note that these two are not actually currently used -// accept is the reduce of the goal rule and reject is the -// absence of actions - accept, - reject, - invalid -} - -fun action(act: action_type, state_or_rule: int): action { - var toRet: action - toRet.act = act - toRet.state_or_rule = state_or_rule - toRet.rule_position = -1 - return toRet -} -fun action(act: action_type, state_or_rule: int, rule_position: int): action { - var toRet: action - toRet.act = act - toRet.state_or_rule = state_or_rule - toRet.rule_position = rule_position - return toRet -} -obj action { - var act: action_type - var state_or_rule: int // sigh - var rule_position: int // sigh - fun operator==(other: action): bool { - return act == other.act && state_or_rule == other.state_or_rule && rule_position == other.rule_position - } - fun print() { - match (act) { - action_type::push() - io::print("push ") - action_type::reduce() - io::print("reduce ") - action_type::accept() - io::print("accept ") - action_type::reject() - io::print("reject ") - } - /*if (act == action_type::push)*/ - /*io::print("push ")*/ - /*else if (act == action_type::reduce)*/ - /*io::print("reduce ")*/ - /*else if (act == action_type::accept)*/ - /*io::print("accept ")*/ - /*else if (act == action_type::reject)*/ - /*io::print("reject ")*/ - io::print(state_or_rule) - io::print(" ") - io::print(rule_position) - io::println() - } -} - -obj table (Object, Serializable) { - // a 2 dimensional table made of a vec and a map that maps from stateno & symbol to a vec of parse actions - var items: vec::vec>> - - fun construct(): *table { - items.construct() - } - fun copy_construct(other: *table) { - items.copy_construct(&other->items) - } - fun operator=(other: table) { - destruct() - copy_construct(&other) - } - fun destruct() { - items.destruct() - } - fun serialize(): vec::vec { - return serialize::serialize(items) - } - fun unserialize(it: ref vec::vec, pos: int): int { - /*construct()*/ - /*util::unpack(items, pos) = serialize::unserialize>>>(it, pos)*/ - pos = items.unserialize(it, pos) - return pos - } - fun expand_to(include_state: int) { - while (include_state >= items.size) - items.addEnd(map::map>()) - } - // we always "clean" the symbol before using it so that having different data doesn't - // prevent us from finding the symbol in the table - fun clean_symbol(sym: ref symbol::symbol): symbol::symbol { - return symbol::symbol(sym.name, sym.terminal) - } - fun add_push(from_state: int, on_symbol: ref symbol::symbol, to_state: int) { - expand_to(from_state) - var cleaned_symbol = clean_symbol(on_symbol) - if (items[from_state].contains_key(cleaned_symbol)) - items[from_state][cleaned_symbol].addEnd(action(action_type::push(), to_state)) - else - items[from_state].set(cleaned_symbol, vec::vec(action(action_type::push(), to_state))) - } - fun add_reduce(from_state: int, on_symbol: ref symbol::symbol, by_rule_no: int, rule_position: int) { - expand_to(from_state) - var cleaned_symbol = clean_symbol(on_symbol) - if (items[from_state].contains_key(cleaned_symbol)) - items[from_state][cleaned_symbol].addEnd(action(action_type::reduce(), by_rule_no, rule_position)) - else - items[from_state].set(cleaned_symbol, vec::vec(action(action_type::reduce(), by_rule_no, rule_position))) - } - fun add_accept(from_state: int, on_symbol: ref symbol::symbol) { - expand_to(from_state) - var cleaned_symbol = clean_symbol(on_symbol) - if (items[from_state].contains_key(cleaned_symbol)) - items[from_state][cleaned_symbol].addEnd(action(action_type::accept(), 0)) - else - items[from_state].set(cleaned_symbol, vec::vec(action(action_type::accept(), 0))) - } - fun get(state: int, on_symbol: ref symbol::symbol): vec::vec { - var cleaned_symbol = clean_symbol(on_symbol) - if (items[state].contains_key(cleaned_symbol)) - return items[state][cleaned_symbol] - return vec::vec() - } - fun get_shift(state: int, on_symbol: ref symbol::symbol): action { - var actions = get(state, on_symbol) - for (var i = 0; i < actions.size; i++;) - if (actions[i].act == action_type::push()) - return actions[i] - io::println("tried to get a shift when none existed") - io::print("for state ") - io::print(state) - io::print(" and symbol ") - io::println(on_symbol.to_string()) - return action(action_type::invalid(),-1) - } - fun get_reduces(state: int, on_symbol: ref symbol::symbol): vec::vec { - return get(state, on_symbol).filter(fun(act: action):bool { return act.act == action_type::reduce(); }) - } - fun print_string() { - /*return str::str("woo a table of size: ") + items.size*/ - io::print("woo a table of size: ") - io::println(items.size) - for (var i = 0; i < items.size; i++;) { - io::print("for state: ") - io::println(i) - items[i].for_each(fun(sym: symbol::symbol, actions: vec::vec) { - actions.for_each(fun(action: action) { - io::print("\ton symbol: ") - io::print(sym.to_string()) - io::print(" do action: ") - action.print() - }) - }) - } - } -} - diff --git a/stdlib/hash_map.krak b/stdlib/hash_map.krak deleted file mode 100644 index 41f945e..0000000 --- a/stdlib/hash_map.krak +++ /dev/null @@ -1,120 +0,0 @@ -import vec -import map -import io -import serialize -import util - -fun hash_map(): hash_map { - var toRet.construct(): hash_map - return toRet -} -fun hash_map(key: ref T, value: ref U): hash_map { - var toRet.construct(): hash_map - toRet.set(key, value) - return toRet -} - -obj hash_map (Object, Serializable) { - var data: vec::vec> - var size: int - - fun construct(): *hash_map { - data.construct() - data.add(map::map()) - size = 0 - return this - } - fun copy_construct(old: *hash_map) { - data.copy_construct(&old->data) - size = old->size - } - fun operator=(rhs: ref hash_map) { - data = rhs.data - size = rhs.size - } - fun destruct() { - data.destruct() - } - fun serialize(): vec::vec { - return serialize::serialize(data) + serialize::serialize(size) - } - fun unserialize(it: ref vec::vec, pos: int): int { - pos = data.unserialize(it, pos) - util::unpack(size, pos) = serialize::unserialize(it, pos) - return pos - } - // the old unnecessary template to prevent generation - // if not used trick (in this case, changing out U with V) - fun operator==(other: ref hash_map): bool { - return data == other.data - } - fun set(key: ref T, value: ref U) { - var key_hash = util::hash(key) - if (!data[(key_hash%data.size) cast int].contains_key(key)) { - size++ - if (size > data.size) { - var new_data.construct(size*2): vec::vec> - for (var i = 0; i < size*2; i++;) - new_data.addEnd(map::map()) - for_each(fun(key: T, value: U) { - new_data[(util::hash(key)%new_data.size) cast int].set(key, value) - }) - data.swap(new_data) - } - } - data[(key_hash%data.size) cast int].set(key, value) - } - fun get(key: ref T): ref U { - return data[(util::hash(key)%data.size) cast int].get(key) - } - fun get_ptr_or_null(key: ref T): *U { - return data[(util::hash(key)%data.size) cast int].get_ptr_or_null(key) - } - fun contains_key(key: ref T): bool { - return data[(util::hash(key)%data.size) cast int].contains_key(key) - } - fun contains_value(value: ref U): bool { - for (var i = 0; i < data.size; i++;) { - if (data[i].contains_value(value)) - return true - } - return false - } - fun reverse_get(value: ref U): ref T { - for (var i = 0; i < data.size; i++;) { - if (data[i].contains_value(value)) - return data[i].reverse_get(value) - } - io::println("trying to reverse get a value that is not in the hash_map") - } - fun remove(key: ref T) { - data[(util::hash(key)%data.size) cast int].remove(key) - } - fun for_each(func: fun(T, U):void) { - for (var i = 0; i < data.size; i++;) - data[i].for_each(func) - } - fun operator[](key: ref T): ref U { - return get(key) - } - fun operator[]=(key: ref T, value: ref U) { - set(key,value) - } - fun get_with_default(key: ref T, default_val: ref U): ref U { - if (contains_key(key)) - return get(key) - return default_val - } - fun clear() { - data.clear() - size = 0 - data.add(map::map()) - } - fun pop(): util::pair { - for (var i = 0; i < data.size; i++;) - if (data[i].size() > 0) - return data[i].pop() - io::println("trying to pop out of an empty hash_map") - } -} - diff --git a/stdlib/hash_set.krak b/stdlib/hash_set.krak deleted file mode 100644 index 586924f..0000000 --- a/stdlib/hash_set.krak +++ /dev/null @@ -1,147 +0,0 @@ -import hash_map -import vec -import io -import serialize -import set - -fun hash_set(): hash_set { - var toRet.construct() : hash_set - return toRet -} - -fun hash_set(item: T): hash_set { - var toRet.construct() : hash_set - toRet.add(item) - return toRet -} - -fun from_vector(items: vec::vec): hash_set { - var toRet.construct() : hash_set - items.for_each( fun(item: T) toRet.add(item); ) - return toRet -} - -obj hash_set (Object, Serializable) { - var data: hash_map::hash_map - fun construct(): *hash_set { - data.construct() - return this - } - /*fun construct(ammt: int): *hash_set {*/ - /*data.construct(ammt)*/ - /*return this*/ - /*}*/ - fun copy_construct(old: *hash_set) { - data.copy_construct(&old->data) - } - fun operator=(rhs: ref hash_set) { - data = rhs.data - } - fun serialize(): vec::vec { - return serialize::serialize(data) - } - fun unserialize(it: ref vec::vec, pos: int): int { - return data.unserialize(it, pos) - } - // the old unnecessary template to prevent generation - // if not used trick (in this case, changing out U with V) - fun operator==(other: ref hash_set): bool { - return data == other.data - } - fun operator!=(rhs: ref hash_set): bool { - return ! (*this == rhs) - } - fun destruct() { - data.destruct() - } - fun size():int { - return data.size - } - /*fun contains(items: ref hash_set): bool {*/ - /*return items.size() == 0 || !items.any_true( fun(item: T): bool return !contains(item); )*/ - /*}*/ - fun contains(item: ref T): bool { - return data.contains_key(item) - } - fun operator+=(item: ref T) { - add(item) - } - /*fun operator+=(items: ref hash_set) {*/ - /*add(items)*/ - /*}*/ - /*fun operator+(items: ref hash_set): hash_set {*/ - /*var to_ret.copy_construct(this): hash_set*/ - /*to_ret.add(items)*/ - /*return to_ret*/ - /*}*/ - fun add(item: ref T) { - if (!contains(item)) - data.set(item,true) - } - /*fun add_all(items: ref hash_set) {*/ - /*add(items)*/ - /*}*/ - /*fun add(items: ref hash_set) {*/ - /*items.for_each( fun(item: ref T) add(item); )*/ - /*}*/ - fun remove(item: ref T) { - data.remove(item) - } - /*fun for_each(func: fun(ref T):void) {*/ - /*data.for_each(func)*/ - /*}*/ - fun for_each(func: fun(T):void) { - data.for_each(fun(key: T, value: bool) { func(key); }) - } - fun map(func: fun(T):U): set::set { - var newSet.construct(size()): set::set - for_each(fun(i: T) { newSet.add(func(i)); }) - return newSet - } - /*fun any_true(func: fun(T):bool):bool {*/ - /*return data.any_true(func)*/ - /*}*/ - /*fun reduce(func: fun(T,U): U, initial: U): U {*/ - /*return data.reduce(func, initial)*/ - /*}*/ - /*fun flatten_map(func: fun(T):hash_set):hash_set {*/ - /*var newSet.construct(size()): hash_set*/ - /*for (var i = 0; i < size(); i++;)*/ - /*func(data[i]).for_each(fun(item: ref U) newSet.add(item);)*/ - /*return newSet*/ - /*}*/ - /*fun filter(func: fun(T):bool):hash_set {*/ - /*var newSet.construct(): hash_set*/ - /*newSet.data = data.filter(func)*/ - /*return newSet*/ - /*}*/ - fun chaotic_closure(func: fun(T): set::set) { - var prev_size = 0 - while (prev_size != size()) { - prev_size = size() - var to_add.construct(size()): vec::vec - for_each(fun(i: T) { - func(i).for_each(fun(j: T) { to_add.add(j); }) - }) - to_add.for_each(fun(i:T) { add(i); }) - } - - } - fun pop(): T { - return data.pop().first - } - fun union(other: hash_set): hash_set { - for_each(fun(i: T) { - other.add(i) - }) - return other - } - fun operator-(items: ref hash_set): hash_set { - var to_ret.copy_construct(this): hash_set - items.for_each(fun(i: T) { - to_ret.remove(i) - }) - return to_ret - } -} - diff --git a/stdlib/importer.krak b/stdlib/importer.krak deleted file mode 100644 index 1cd199d..0000000 --- a/stdlib/importer.krak +++ /dev/null @@ -1,134 +0,0 @@ -import symbol:* -import tree:* -import vec:* -import stack:* -import map:* -import util:* -import str:* -import mem:* -import io:* -import ast_nodes:* -import ast_transformation:* -import parser:* - -fun import(file_name: str, parsers: ref vec, ast_pass: ref ast_transformation, import_paths: vec): map,*ast_node>> { - var name_ast_map = map,*ast_node>>() - // lambda closes over our fix-up list - var imports_to_fix = vec<*ast_node>() - var import_first_pass = fun(file_name_idx: pair) { - var file_name = file_name_idx.first - var file = str() - import_paths.for_each(fun(path: str) { - if (file_exists(path + file_name)) { - file = read_file(path + file_name) - } else { - } - }) - printerr(file_name + ", ") - var parse_tree = parsers[file_name_idx.second].parse_input(file, file_name) - trim(parse_tree) - var ast_and_imports = ast_pass.first_pass(file_name, parse_tree) - imports_to_fix += ast_and_imports.second - name_ast_map[file_name] = make_pair(parse_tree, ast_and_imports.first) - } - printlnerr("**First Pass**") - printerr("parsing: ") - import_first_pass(make_pair(file_name,0)) - for (var i = 0; i < imports_to_fix.size; i++;) { - var import_name = imports_to_fix[i]->import.name - var file_name = import_name + ".krak" - if (!name_ast_map.contains_key(file_name)) { - import_first_pass(make_pair(file_name,0)) - } - var im = imports_to_fix[i] - var file_name = import_name + ".krak" - im->import.translation_unit = name_ast_map[file_name].second - add_to_scope(import_name, im->import.translation_unit, im->import.containing_translation_unit) - } - printlnerr() - printlnerr("**Second Pass**") - name_ast_map.for_each(fun(name: str, tree_pair: pair<*tree, *ast_node>) ast_pass.second_pass(tree_pair.first, tree_pair.second);) - printlnerr("**Third Pass**") - name_ast_map.for_each(fun(name: str, tree_pair: pair<*tree, *ast_node>) ast_pass.third_pass(tree_pair.first, tree_pair.second);) - printlnerr("**Fourth Pass**") - name_ast_map.for_each(fun(name: str, tree_pair: pair<*tree, *ast_node>) ast_pass.fourth_pass(tree_pair.first, tree_pair.second);) - - return name_ast_map -} - -fun trim(parse_tree: *tree) { - remove_node(symbol("$NULL$", false), parse_tree) - remove_node(symbol("WS", false), parse_tree) - // the terminals have " around them, which we have to escape - remove_node(symbol("\"\\(\"", true), parse_tree) - remove_node(symbol("\"\\)\"", true), parse_tree) - remove_node(symbol("\"template\"", true), parse_tree) - remove_node(symbol("\"return\"", true), parse_tree) - remove_node(symbol("\"defer\"", true), parse_tree) - remove_node(symbol("\";\"", true), parse_tree) - remove_node(symbol("line_end", false), parse_tree) - remove_node(symbol("\"{\"", true), parse_tree) - remove_node(symbol("\"}\"", true), parse_tree) - remove_node(symbol("\"(\"", true), parse_tree) - remove_node(symbol("\")\"", true), parse_tree) - remove_node(symbol("\"if\"", true), parse_tree) - remove_node(symbol("\"while\"", true), parse_tree) - remove_node(symbol("\"__if_comp__\"", true), parse_tree) - remove_node(symbol("\"comp_simple_passthrough\"", true), parse_tree) - /*remove_node(symbol("obj_nonterm", false), parse_tree)*/ - remove_node(symbol("adt_nonterm", false), parse_tree) - - collapse_node(symbol("case_statement_list", false), parse_tree) - collapse_node(symbol("opt_param_assign_list", false), parse_tree) - collapse_node(symbol("param_assign_list", false), parse_tree) - collapse_node(symbol("opt_typed_parameter_list", false), parse_tree) - collapse_node(symbol("opt_parameter_list", false), parse_tree) - collapse_node(symbol("intrinsic_parameter_list", false), parse_tree) - collapse_node(symbol("identifier_list", false), parse_tree) - collapse_node(symbol("adt_option_list", false), parse_tree) - collapse_node(symbol("statement_list", false), parse_tree) - collapse_node(symbol("parameter_list", false), parse_tree) - collapse_node(symbol("typed_parameter_list", false), parse_tree) - collapse_node(symbol("unorderd_list_part", false), parse_tree) - collapse_node(symbol("if_comp_pred", false), parse_tree) - collapse_node(symbol("declaration_block", false), parse_tree) - collapse_node(symbol("type_list", false), parse_tree) - collapse_node(symbol("opt_type_list", false), parse_tree) - collapse_node(symbol("template_param_list", false), parse_tree) - collapse_node(symbol("trait_list", false), parse_tree) - collapse_node(symbol("dec_type", false), parse_tree) -} -fun remove_node(remove: symbol, parse_tree: *tree) { - var to_process = stack<*tree>() - to_process.push(parse_tree) - while(!to_process.empty()) { - var node = to_process.pop() - for (var i = 0; i < node->children.size; i++;) { - if (!node->children[i] || node->children[i]->data.equal_wo_data(remove)) { - node->children.remove(i) - i--; - } else { - to_process.push(node->children[i]) - } - } - } -} -fun collapse_node(remove: symbol, parse_tree: *tree) { - var to_process = stack<*tree>() - to_process.push(parse_tree) - while(!to_process.empty()) { - var node = to_process.pop() - for (var i = 0; i < node->children.size; i++;) { - if (node->children[i]->data.equal_wo_data(remove)) { - var add_children = node->children[i]->children; - // stick child's children between the current children divided - // on i, without including i - node->children = node->children.slice(0,i) + - add_children + node->children.slice(i+1,-1) - i--; - } else { - to_process.push(node->children[i]) - } - } - } -} diff --git a/stdlib/interpreter.krak b/stdlib/interpreter.krak deleted file mode 100644 index d0772fe..0000000 --- a/stdlib/interpreter.krak +++ /dev/null @@ -1,1067 +0,0 @@ -import mem:* -import math:* -import map:* -import stack:* -import str:* -import util:* -import tree:* -import symbol:* -import ast_nodes:* -import type:* -import os:* -// for is_dot_style_method_call -import pass_common:* - -adt value { - boolean: bool, - character: char, - ucharacter: uchar, - short_int: short, - ushort_int: ushort, - integer: int, - uinteger: uint, - long_int: long, - ulong_int: ulong, - floating: float, - double_precision: double, - void_nothing, - pointer: pair<*void,*type>, - object_like: pair<*void,*type>, - variable: pair<*void,*type>, - function: pair<*ast_node,*map<*ast_node,value>> -} -adt control_flow { - nor, - con, - bre, - ret -} - -// note that there is not object_like, variable, or pointer raw_to_value -fun raw_to_value(data:bool): value - return value::boolean(data) -fun raw_to_value(data:char): value - return value::character(data) -fun raw_to_value(data:uchar): value - return value::ucharacter(data) -fun raw_to_value(data:short): value - return value::short_int(data) -fun raw_to_value(data:ushort): value - return value::ushort_int(data) -fun raw_to_value(data:int): value - return value::integer(data) -fun raw_to_value(data:uint): value - return value::uinteger(data) -fun raw_to_value(data:long): value - return value::long_int(data) -fun raw_to_value(data:ulong): value - return value::ulong_int(data) -fun raw_to_value(data:float): value - return value::floating(data) -fun raw_to_value(data:double): value - return value::double_precision(data) - -fun wrap_value(val: *ast_node): value { - var value_str = val->value.string_value - var value_type = val->value.value_type - if (value_str[0] == '"') { // " // Comment hack for emacs now - var to_ret = str() - // triple quoted strings - if (value_str[1] == '"' && value_str.length() > 2 && value_str[2] == '"') - value_str = value_str.slice(3,-4) - else - value_str = value_str.slice(1,-2) - for (var i = 0; i < value_str.length()-1; i++;) { - if (value_str[i] == '\\' && value_str[i+1] == 'n') { - to_ret += '\n' - i++ - } else if (value_str[i] == '\\' && value_str[i+1] == 't') { - to_ret += '\t' - i++ - } else if (value_str[i] == '\\' && value_str[i+1] == '\\') { - to_ret += '\\' - i++ - } else if (i == value_str.length()-2) { - to_ret += value_str[i] - to_ret += value_str[i+1] - } else { - to_ret += value_str[i] - } - } - // if there was only one character - if (value_str.length() == 1) - to_ret = value_str - return value::pointer(make_pair((to_ret.toCharArray()) cast *void, get_ast_type(val))) - } else if (value_str[0] == '\'') //'// lol, comment hack for vim syntax highlighting (my fault, of course) - return value::character(value_str[1]) - else if (value_str == "true") - return value::boolean(true) - else if (value_str == "false") - return value::boolean(false) - else { - var contains_dot = false - for (var i = 0; i < value_str.length(); i++;) { - if (value_str[i] == '.') { - contains_dot = true - break - } - } - if (contains_dot) - if (value_str[value_str.length()-1] == 'f') - return value::floating((string_to_double(value_str.slice(0,-2))) cast float) - else - if (value_str[value_str.length()-1] == 'd') - return value::double_precision(string_to_double(value_str.slice(0,-2))) - else - return value::double_precision(string_to_double(value_str)) - else { - match(value_type->base) { - base_type::character() return value::character(string_to_num(value_str)) - base_type::ucharacter() return value::ucharacter(string_to_num(value_str)) - base_type::short_int() return value::short_int(string_to_num(value_str)) - base_type::ushort_int() return value::ushort_int(string_to_num(value_str)) - base_type::integer() return value::integer(string_to_num(value_str)) - base_type::uinteger() return value::uinteger(string_to_num(value_str)) - base_type::long_int() return value::long_int(string_to_num(value_str)) - base_type::ulong_int() return value::ulong_int(string_to_num(value_str)) - } - } - } - error("Could not wrap value") - return value::void_nothing() -} -fun unwrap_value(val: value): *ast_node { - // str, char, bool, floating - var value_string = str() - match (get_real_value(val)) { - value::boolean(data) value_string = to_string(data) - value::character(data) value_string = to_string(data) - value::ucharacter(data) value_string = to_string(data) - value::short_int(data) value_string = to_string(data) - value::ushort_int(data) value_string = to_string(data) - value::integer(data) value_string = to_string(data) - value::uinteger(data) value_string = to_string(data) - value::long_int(data) value_string = to_string(data) - value::ulong_int(data) value_string = to_string(data) - value::floating(data) value_string = to_string(data) - value::double_precision(data) value_string = to_string(data) - value::void_nothing() error("trying to unwrap a void into an _value") - value::pointer(point) { - if (point.second->base == base_type::character() && point.second->indirection == 1) - value_string = str("\"") + str((point.first) cast *char) + "\"" - else - error("trying to unwrap a pointer into an _value") - } - value::object_like(ob) error("trying to unwrap an object_like into an _value") - value::function(fn) error("trying to unwrap a function into an _value") - } - return _value(value_string, get_type_from_primitive_value(get_real_value(val))) -} - -fun is_boolean(it: value): bool { match(it) { value::boolean(var) return true; } return false; } -fun is_character(it: value): bool { match(it) { value::character(var) return true; } return false; } -fun is_ucharacter(it: value): bool { match(it) { value::ucharacter(var) return true; } return false; } -fun is_short_int(it: value): bool { match(it) { value::short_int(var) return true; } return false; } -fun is_ushort_int(it: value): bool { match(it) { value::ushort_int(var) return true; } return false; } -fun is_integer(it: value): bool { match(it) { value::integer(var) return true; } return false; } -fun is_uinteger(it: value): bool { match(it) { value::uinteger(var) return true; } return false; } -fun is_long_int(it: value): bool { match(it) { value::long_int(var) return true; } return false; } -fun is_ulong_int(it: value): bool { match(it) { value::ulong_int(var) return true; } return false; } -fun is_floating(it: value): bool { match(it) { value::floating(var) return true; } return false; } -fun is_double_precision(it: value): bool { match(it) { value::double_precision(var) return true; } return false; } -fun is_void_nothing(it: value): bool { match(it) { value::void_nothing() return true; } return false; } -fun is_pointer(it: value): bool { match(it) { value::pointer(var) return true; } return false; } -fun is_object_like(it: value): bool { match(it) { value::object_like(var) return true; } return false; } -fun is_variable(it: value): bool { match(it) { value::variable(var) return true; } return false; } -fun is_function(it: value): bool { match(it) { value::function(var) return true; } return false; } - -fun print_value(v: ref value) { - match (get_real_value(v)) { - value::boolean(data) println(data) - value::character(data) println(data) - value::ucharacter(data) println(data) - value::short_int(data) println(data) - value::ushort_int(data) println(data) - value::integer(data) println(data) - value::uinteger(data) println(data) - value::long_int(data) println(data) - value::ulong_int(data) println(data) - value::floating(data) println(data) - value::double_precision(data) println(data) - value::void_nothing() println("void") - value::pointer(var) println("pointer") - value::object_like(var) println("object_like") - value::variable(var) println("variable") - value::function(var) println("function") - } -} -fun truthy(v: ref value):bool { - match (get_real_value(v)) { - value::boolean(data) return data - value::character(data) return data != 0 - value::ucharacter(data) return data != 0 - value::short_int(data) return data != 0 - value::ushort_int(data) return data != 0 - value::integer(data) return data != 0 - value::uinteger(data) return data != 0 - value::long_int(data) return data != 0 - value::ulong_int(data) return data != 0 - value::floating(data) return data != 0 - value::double_precision(data) return data != 0 - value::pointer(data) return data.first != 0 - } - error("untruthy value") -} -fun do_basic_op(func_name: str, a: value, b: value): value { - match (get_real_value(a)) { - value::boolean(av) return do_basic_op_second_half(func_name, av, b, null()) - value::character(av) return do_basic_op_second_half(func_name, av, b, null()) - value::ucharacter(av) return do_basic_op_second_half(func_name, av, b, null()) - value::short_int(av) return do_basic_op_second_half(func_name, av, b, null()) - value::ushort_int(av) return do_basic_op_second_half(func_name, av, b, null()) - value::integer(av) return do_basic_op_second_half(func_name, av, b, null()) - value::uinteger(av) return do_basic_op_second_half(func_name, av, b, null()) - value::long_int(av) return do_basic_op_second_half(func_name, av, b, null()) - value::ulong_int(av) return do_basic_op_second_half(func_name, av, b, null()) - value::floating(av) return do_basic_floating_op_second_half(func_name, av, b, null()) - value::double_precision(av) return do_basic_floating_op_second_half(func_name, av, b, null()) - value::pointer(av) { - var real_b = get_real_value(b) - if (func_name == "==") { - if (!is_pointer(real_b)) { - print("equality between pointer and not pointer: ") - print_value(real_b) - error(":/") - } - return value::boolean(av.first == real_b.pointer.first) - } else if (func_name == "!=") { - if (!is_pointer(real_b)) { - print("inequality between pointer and not pointer: ") - print_value(real_b) - error(":/") - } - return value::boolean(av.first != real_b.pointer.first) - } - var inc_in_bytes = cast_value(b, type_ptr(base_type::ulong_int())).ulong_int * type_size(av.second->clone_with_decreased_indirection()) - var ptr = null() - if (func_name == "+") { - ptr = ((av.first) cast *char + inc_in_bytes) cast *void - } else if (func_name == "-") { - ptr = ((av.first) cast *char - inc_in_bytes) cast *void - } else { - println(str("pointer arithmatic is not +, -, ==, or !=: ") + func_name + ", b is: ") - print_value(b) - error(str("pointer arithmatic is not +, -, ==, or !=: ") + func_name) - } - return value::pointer(make_pair(ptr, av.second)) - } - value::void_nothing() error(str("basic op called with void_nothing as first param: ") + func_name) - value::object_like() error(str("basic op called with object_like as first param: ") + func_name) - } - error(str("basic op called with something wrong as first param: ") + func_name) -} -fun do_basic_op_second_half(func_name: str, av: T, b: value, ptr_type: *type): value { - // because of the trickery in do_basic_op, if either param is a pointer, it's b - match (get_real_value(b)) { - value::boolean(bv) return do_op(func_name, av, bv, ptr_type) - value::character(bv) return do_op(func_name, av, bv, ptr_type) - value::ucharacter(bv) return do_op(func_name, av, bv, ptr_type) - value::short_int(bv) return do_op(func_name, av, bv, ptr_type) - value::ushort_int(bv) return do_op(func_name, av, bv, ptr_type) - value::integer(bv) return do_op(func_name, av, bv, ptr_type) - value::uinteger(bv) return do_op(func_name, av, bv, ptr_type) - value::long_int(bv) return do_op(func_name, av, bv, ptr_type) - value::ulong_int(bv) return do_op(func_name, av, bv, ptr_type) - value::floating(bv) return do_floating_op(func_name, av, bv, ptr_type) - value::double_precision(bv) return do_floating_op(func_name, av, bv, ptr_type) - value::void_nothing() error(str("basic op called with void_nothing as second param: ") + func_name) - value::object_like() error(str("basic op called with object_like as second param: ") + func_name) - // if one is a pointer, we want it to be a - value::pointer(bv) return do_basic_op(func_name, b, raw_to_value(av)) - } - print_value(b) - error(str("basic op called with something wrong as second param: ") + func_name) -} -fun do_op(op: str, a: T, b: U, ptr_type: *type): value { - if (op == "+") return raw_to_value(a + b) - if (op == "-") return raw_to_value(a - b) - if (op == "*") return raw_to_value(a * b) - if (op == "/") return raw_to_value(a / b) - if (op == "<") return raw_to_value(a < b) - if (op == ">") return raw_to_value(a > b) - if (op == "<=") return raw_to_value(a <= b) - if (op == ">=") return raw_to_value(a >= b) - if (op == "==") return raw_to_value(a == b) - if (op == "!=") return raw_to_value(a != b) - if (op == "%") return raw_to_value(a % b) - if (op == "^") return raw_to_value(a ^ b) - if (op == "|") return raw_to_value(a | b) - if (op == "&") return raw_to_value(a & b) - error(("Invalid op: ") + op) -} -fun do_basic_floating_op_second_half(func_name: str, av: T, b: value, ptr_type: *type): value { - // because of the trickery in do_basic_op, if either param is a pointer, it's b - match (get_real_value(b)) { - value::boolean(bv) return do_floating_op(func_name, av, bv, ptr_type) - value::character(bv) return do_floating_op(func_name, av, bv, ptr_type) - value::ucharacter(bv) return do_floating_op(func_name, av, bv, ptr_type) - value::short_int(bv) return do_floating_op(func_name, av, bv, ptr_type) - value::ushort_int(bv) return do_floating_op(func_name, av, bv, ptr_type) - value::integer(bv) return do_floating_op(func_name, av, bv, ptr_type) - value::uinteger(bv) return do_floating_op(func_name, av, bv, ptr_type) - value::long_int(bv) return do_floating_op(func_name, av, bv, ptr_type) - value::ulong_int(bv) return do_floating_op(func_name, av, bv, ptr_type) - value::floating(bv) return do_floating_op(func_name, av, bv, ptr_type) - value::double_precision(bv) return do_floating_op(func_name, av, bv, ptr_type) - value::void_nothing() error(str("basic op called with void_nothing as second param: ") + func_name) - value::object_like() error(str("basic op called with object_like as second param: ") + func_name) - // if one is a pointer, we want it to be a - value::pointer(bv) return do_basic_op(func_name, b, raw_to_value(av)) - } - print_value(b) - error(str("basic op called with something wrong as second param: ") + func_name) -} -fun do_floating_op(op: str, a: T, b: U, ptr_type: *type): value { - if (op == "+") return raw_to_value(a + b) - if (op == "-") return raw_to_value(a - b) - if (op == "*") return raw_to_value(a * b) - if (op == "/") return raw_to_value(a / b) - if (op == "<") return raw_to_value(a < b) - if (op == ">") return raw_to_value(a > b) - if (op == "<=") return raw_to_value(a <= b) - if (op == ">=") return raw_to_value(a >= b) - if (op == "==") return raw_to_value(a == b) - if (op == "!=") return raw_to_value(a != b) - error(("Invalid op: ") + op) -} -// the ref special case is interesting because it also means we have to take in the value by ref -fun store_into_variable(to: ref value, from: value) { - assert(is_variable(to), "trying to store into not variable") - var variable = to.variable - // NOTE - // we have a special case here - we allow assigning to a ref from a pointer, as this is used in adt_lower - if (variable.second->is_ref && is_pointer(from) && variable.second->clone_with_increased_indirection()->equality(from.pointer.second, false)) { - to.variable.first = from.pointer.first - return; - } - // check for indirection - if (variable.second->indirection) { - assert(is_pointer(from), "mismatching assignemnt types - from is not pointer") - *(variable.first) cast **void = from.pointer.first - return; - } - // TODO - check to make sure that we don't have to cast pre assign (perhaps alwyas send through the cast?) - match (variable.second->base) { - base_type::object() { assert(is_object_like(from), "mismatching assignemnt types - from is not object"); memmove(variable.first, from.object_like.first, type_size(from.object_like.second)); } - base_type::function() { assert(is_function(from), "mismatching assignemnt types - from is not function"); *(variable.first) cast *pair<*ast_node, *map<*ast_node,value>> = from.function; } - base_type::boolean() { assert(is_boolean(from), "mismatching assignemnt types - from is not boolean"); *(variable.first) cast *bool = from.boolean; } - base_type::character() { assert(is_character(from), "mismatching assignemnt types - from is not character"); *(variable.first) cast *char = from.character; } - base_type::ucharacter() { assert(is_ucharacter(from), "mismatching assignemnt types - from is not ucharacter"); *(variable.first) cast *uchar = from.ucharacter; } - base_type::short_int() { assert(is_short_int(from), "mismatching assignemnt types - from is not short_int"); *(variable.first) cast *short = from.short_int; } - base_type::ushort_int() { assert(is_ushort_int(from), "mismatching assignemnt types - from is not ushort_int"); *(variable.first) cast *ushort = from.ushort_int; } - base_type::integer() { assert(is_integer(from), "mismatching assignemnt types - from is not integer"); *(variable.first) cast *int = from.integer; } - base_type::uinteger() { assert(is_uinteger(from), "mismatching assignemnt types - from is not uinteger"); *(variable.first) cast *uint = from.uinteger; } - base_type::long_int() { assert(is_long_int(from), "mismatching assignemnt types - from is not long_int"); *(variable.first) cast *long = from.long_int; } - base_type::ulong_int() { assert(is_ulong_int(from), "mismatching assignemnt types - from is not ulong_int"); *(variable.first) cast *ulong = from.ulong_int; } - base_type::floating() { assert(is_floating(from), "mismatching assignemnt types - from is not floating"); *(variable.first) cast *float = from.floating; } - base_type::double_precision() { assert(is_double_precision(from), "mismatching assignemnt types - from is not double"); *(variable.first) cast *double = from.double_precision; } - } -} -fun get_real_value(v: value): value { - if (!is_variable(v)) - return v - var variable = v.variable - var var_ptr = variable.first - var var_type = variable.second - // step through indirection first - if (var_type->indirection) - return value::pointer(make_pair(*(var_ptr) cast **void, var_type)) - match (var_type->base) { - base_type::object() return value::object_like(make_pair(var_ptr, var_type)) - base_type::boolean() return value::boolean(*(var_ptr) cast *bool) - base_type::character() return value::character(*(var_ptr) cast *char) - base_type::ucharacter() return value::ucharacter(*(var_ptr) cast *uchar) - base_type::short_int() return value::short_int(*(var_ptr) cast *short) - base_type::ushort_int() return value::ushort_int(*(var_ptr) cast *ushort) - base_type::integer() return value::integer(*(var_ptr) cast *int) - base_type::uinteger() return value::uinteger(*(var_ptr) cast *uint) - base_type::long_int() return value::long_int(*(var_ptr) cast *long) - base_type::ulong_int() return value::ulong_int(*(var_ptr) cast *ulong) - base_type::floating() return value::floating(*(var_ptr) cast *float) - base_type::double_precision() return value::double_precision(*(var_ptr) cast *double) - base_type::function() return value::function(*(var_ptr) cast *pair<*ast_node,*map<*ast_node,value>>) - } - error(str("Cannot get real value from variable: ") + variable.second->to_string()) -} -fun wrap_into_variable(v: value): value { - if (is_variable(v)) - return v - if (is_object_like(v)) - return value::variable(make_pair(v.object_like.first, v.object_like.second)) - var variable_type = get_type_from_primitive_value(v) - var to_ret = value::variable(make_pair(malloc(type_size(variable_type)), variable_type)) - store_into_variable(to_ret, v) - return to_ret -} -fun get_type_from_primitive_value(v: value): *type { - match (v) { - value::boolean(data) return type_ptr(base_type::boolean()) - value::character(data) return type_ptr(base_type::character()) - value::ucharacter(data) return type_ptr(base_type::ucharacter()) - value::short_int(data) return type_ptr(base_type::short_int()) - value::ushort_int(data) return type_ptr(base_type::ushort_int()) - value::integer(data) return type_ptr(base_type::integer()) - value::uinteger(data) return type_ptr(base_type::uinteger()) - value::long_int(data) return type_ptr(base_type::long_int()) - value::ulong_int(data) return type_ptr(base_type::ulong_int()) - value::floating(data) return type_ptr(base_type::floating()) - value::double_precision(data) return type_ptr(base_type::double_precision()) - value::pointer(data) return data.second - value::void_nothing() return type_ptr(base_type::void_return()) - value::function(data) return data.first->function.type - } - println("Bad get_type_from_primitive_value!") - print_value(v) - error("Called get_type_from_primitive_value with non-primitive value (maybe in a variable?)") -} -fun cast_value(v: value, to_type: *type): value { - if (to_type->indirection) { - match (get_real_value(v)) { - value::boolean(data) return value::pointer(make_pair((data) cast *void, to_type)) - value::character(data) return value::pointer(make_pair((data) cast *void, to_type)) - value::ucharacter(data) return value::pointer(make_pair((data) cast *void, to_type)) - value::short_int(data) return value::pointer(make_pair((data) cast *void, to_type)) - value::ushort_int(data) return value::pointer(make_pair((data) cast *void, to_type)) - value::integer(data) return value::pointer(make_pair((data) cast *void, to_type)) - value::uinteger(data) return value::pointer(make_pair((data) cast *void, to_type)) - value::long_int(data) return value::pointer(make_pair((data) cast *void, to_type)) - value::ulong_int(data) return value::pointer(make_pair((data) cast *void, to_type)) - // floats and anything object_like are illegal to cast from - /*value::floating(data) return value::pointer(make_pair((data) cast *void, to_type))*/ - /*value::double_precision(data) return value::pointer(make_pair((data) cast *void, to_type))*/ - value::pointer(data) return value::pointer(make_pair(data.first, to_type)) - } - error("Bad cast to pointer") - } - match (to_type->base) { - // object_like can't be casted - base_type::boolean() return cast_value_second_half(v) - base_type::character() return cast_value_second_half(v) - base_type::ucharacter() return cast_value_second_half(v) - base_type::short_int() return cast_value_second_half(v) - base_type::ushort_int() return cast_value_second_half(v) - base_type::integer() return cast_value_second_half(v) - base_type::uinteger() return cast_value_second_half(v) - base_type::long_int() return cast_value_second_half(v) - base_type::ulong_int() return cast_value_second_half(v) - // float and double need their own because it can't go from - base_type::floating() match (get_real_value(v)) { - value::boolean(data) return value::floating((data) cast float) - value::character(data) return value::floating((data) cast float) - value::ucharacter(data) return value::floating((data) cast float) - value::short_int(data) return value::floating((data) cast float) - value::ushort_int(data) return value::floating((data) cast float) - value::integer(data) return value::floating((data) cast float) - value::uinteger(data) return value::floating((data) cast float) - value::long_int(data) return value::floating((data) cast float) - value::ulong_int(data) return value::floating((data) cast float) - value::floating(data) return get_real_value(v) - value::double_precision(data) return value::floating((data) cast float) - } - base_type::double_precision() match (get_real_value(v)) { - value::boolean(data) return value::double_precision((data) cast double) - value::character(data) return value::double_precision((data) cast double) - value::ucharacter(data) return value::double_precision((data) cast double) - value::short_int(data) return value::double_precision((data) cast double) - value::ushort_int(data) return value::double_precision((data) cast double) - value::integer(data) return value::double_precision((data) cast double) - value::uinteger(data) return value::double_precision((data) cast double) - value::long_int(data) return value::double_precision((data) cast double) - value::ulong_int(data) return value::double_precision((data) cast double) - value::floating(data) return value::double_precision((data) cast double) - value::double_precision(data) return get_real_value(v) - } - } - error(str("Bad cast to ") + to_type->to_string()) -} -fun cast_value_second_half(v: value): value { - match (get_real_value(v)) { - // object_like can't be casted - value::boolean(data) return raw_to_value((data) cast T) - value::character(data) return raw_to_value((data) cast T) - value::ucharacter(data) return raw_to_value((data) cast T) - value::short_int(data) return raw_to_value((data) cast T) - value::ushort_int(data) return raw_to_value((data) cast T) - value::integer(data) return raw_to_value((data) cast T) - value::uinteger(data) return raw_to_value((data) cast T) - value::long_int(data) return raw_to_value((data) cast T) - value::ulong_int(data) return raw_to_value((data) cast T) - value::floating(data) return raw_to_value((data) cast T) - value::double_precision(data) return raw_to_value((data) cast T) - value::pointer(data) return raw_to_value((data.first) cast T) - } - error("Illegal type to cast cast from") -} -fun type_size(t: *type): ulong - return type_size_and_alignment(t).first -fun type_size_and_alignment(t: *type): pair { - if (t->indirection) - return make_pair(#sizeof<*void>, #sizeof<*void>) - match (t->base) { - base_type::object() { - var total_size: ulong = 0 - var max_size: ulong = 0 - var max_align: ulong = 0 - t->type_def->type_def.variables.for_each(fun(i: *ast_node) { - var individual = type_size_and_alignment(i->declaration_statement.identifier->identifier.type) - max_size = max(max_size, individual.first) - max_align = max(max_align, individual.second) - // increase total size by the individual size + padding to get alignment - var padding = 0 - if (individual.second != 0) - padding = (individual.second - (total_size % individual.second)) % individual.second - total_size += individual.first + padding - }) - if (t->type_def->type_def.is_union) - total_size = max_size - // pad the end so that consecutive objects in memory are aligned - if (max_align != 0) - total_size += (max_align - (total_size % max_align)) % max_align - return make_pair(total_size, max_align) - } - base_type::function() return make_pair(#sizeof>>, #sizeof<*void>) - base_type::boolean() return make_pair(#sizeof, #sizeof) - base_type::character() return make_pair(#sizeof, #sizeof) - base_type::ucharacter() return make_pair(#sizeof, #sizeof) - base_type::short_int() return make_pair(#sizeof, #sizeof) - base_type::ushort_int() return make_pair(#sizeof, #sizeof) - base_type::integer() return make_pair(#sizeof, #sizeof) - base_type::uinteger() return make_pair(#sizeof, #sizeof) - base_type::long_int() return make_pair(#sizeof, #sizeof) - base_type::ulong_int() return make_pair(#sizeof, #sizeof) - base_type::floating() return make_pair(#sizeof, #sizeof) - base_type::double_precision() return make_pair(#sizeof, #sizeof) - } - error(str("Invalid type for type_size: ") + t->to_string()) -} -fun offset_into_struct(struct_type: *type, ident: *ast_node): ulong { - var offset: ulong = 0 - if (struct_type->type_def->type_def.is_union) - return offset - for (var i = 0; i < struct_type->type_def->type_def.variables.size; i++;) { - var size_and_align = type_size_and_alignment(struct_type->type_def->type_def.variables[i]->declaration_statement.identifier->identifier.type) - var align = size_and_align.second - if (align != 0) - offset += (align - (offset % align)) % align - if (struct_type->type_def->type_def.variables[i]->declaration_statement.identifier == ident) - break - else - offset += size_and_align.first - } - return offset -} -// to dereference, we basically take the pointer's value (maybe going through a variable to get it) -// and re-wrap it up into a variable value (so it can be assigned to, etc) -fun dereference_pointer_into_variable(dereference_val: value): value - return value::variable(make_pair(get_real_value(dereference_val).pointer.first, dereference_val.pointer.second->clone_with_decreased_indirection())) -fun pop_and_free(var_stack: *stack>) { - var_stack->pop().for_each(fun(k: *ast_node, v: value) { - match(v) { - value::variable(backing) { - /*free(backing.first)*/ - } - } - }) -} - -fun call_main(name_ast_map: ref map,*ast_node>>) { - var results = vec<*ast_node>() - name_ast_map.for_each(fun(key: str, value: pair<*tree,*ast_node>) { - results += scope_lookup(str("main"), value.second) - }) - if (results.size != 1) - error(str("wrong number of mains to call: ") + results.size) - var globals = setup_globals(name_ast_map) - var result = call_function(results[0], vec(), &globals) -} -fun evaluate_constant_expression(node: *ast_node): value - return interpret(node, null>>(), value::void_nothing(), null(), null>()).first -fun evaluate_with_globals(node: *ast_node, globals: *map<*ast_node, value>): value - return interpret(node, null>>(), value::void_nothing(), null(), globals).first -fun setup_globals(name_ast_map: ref map,*ast_node>>): map<*ast_node, value> { - var globals = map<*ast_node, value>() - name_ast_map.for_each(fun(key: str, value: pair<*tree,*ast_node>) { - value.second->translation_unit.children.for_each(fun(child: *ast_node) { - if (is_declaration_statement(child)) { - var declaration = child->declaration_statement - var identifier = declaration.identifier->identifier - if (identifier.is_extern) { - if (identifier.name == "stderr") { - var stderr_type = type_ptr(base_type::void_return(), 1) - var stderr_pointer = malloc(type_size(stderr_type)) - *(stderr_pointer) cast **void = stderr; - globals[declaration.identifier] = value::variable(make_pair(stderr_pointer, stderr_type)) - } else if (identifier.name == "stdin") { - var stdin_type = type_ptr(base_type::void_return(), 1) - var stdin_pointer = malloc(type_size(stdin_type)) - *(stdin_pointer) cast **void = stdin; - globals[declaration.identifier] = value::variable(make_pair(stdin_pointer, stdin_type)) - } else { - error(str("unknown extern: ") + identifier.name) - } - } else { - globals[declaration.identifier] = value::variable(make_pair(calloc(type_size(identifier.type)), identifier.type)) - if (declaration.expression) - store_into_variable(globals[declaration.identifier], get_real_value(interpret(declaration.expression, null>>(), value::void_nothing(), null(), null>()).first)) - } - } - }) - }) - return globals -} -fun interpret_function_call(func_call: *ast_node, var_stack: *stack>, enclosing_object: value, enclosing_func: *ast_node, globals: *map<*ast_node, value>): pair { - var func_call_parameters = func_call->function_call.parameters - var func_call_func = func_call->function_call.func - var new_enclosing_object = value::void_nothing() - var dot_style_method_call = is_dot_style_method_call(func_call) - var possible_closure_map = map<*ast_node,value>() - // test for function value - if (!dot_style_method_call && (!is_function(func_call_func) || func_call_func->function.closed_variables.size())) { - var func_value = get_real_value(interpret(func_call_func, var_stack, enclosing_object, enclosing_func, globals).first) - func_call_func = func_value.function.first - possible_closure_map = *func_value.function.second - // if the closure closes over this, put it as the enclosing object inside the closure - possible_closure_map.for_each(fun(key: *ast_node, v: value) { - if (key->identifier.name == "this") { - new_enclosing_object = get_real_value(dereference_pointer_into_variable(v)) - } - }) - } - // note here also that this is likely not a foolproof method - if (dot_style_method_call) { - new_enclosing_object = get_real_value(interpret(func_call_func->function_call.parameters[0], var_stack, enclosing_object, enclosing_func, globals).first) - // do a dereference - if (is_pointer(new_enclosing_object)) - new_enclosing_object = get_real_value(value::variable(make_pair(new_enclosing_object.pointer.first, new_enclosing_object.pointer.second->clone_with_decreased_indirection()))) - func_call_func = func_call_func->function_call.parameters[1] - } else if (!is_void_nothing(enclosing_object)) { - if (method_in_object(func_call_func, enclosing_object.object_like.second->type_def)) { - // should maybe do something special for closure here - // copy over old enclosing object - new_enclosing_object = enclosing_object - } - } - var func_name = func_call_func->function.name - // some of these have to be done before parameters are evaluated (&&, ||, ., ->) - if (func_name == "&&" || func_name == "||") { - error("short circuit still in interpreter") - } else if (func_name == "." || func_name == "->") { - var left_side = get_real_value(interpret(func_call_parameters[0], var_stack, enclosing_object, enclosing_func, globals).first) - var ret_ptr = null() - if (func_name == "->") - ret_ptr = ((left_side.pointer.first) cast *char + offset_into_struct(left_side.pointer.second->clone_with_decreased_indirection(), func_call_parameters[1])) cast *void - else - ret_ptr = ((left_side.object_like.first) cast *char + offset_into_struct(left_side.object_like.second, func_call_parameters[1])) cast *void - return make_pair(value::variable(make_pair(ret_ptr, func_call_parameters[1]->identifier.type)), control_flow::nor()) - } - // so here we either do an operator, call call_func with value parameters, or call call_func with ast_expressions - // (so we can properly copy_construct if necessary) - var parameters = vec() - var parameter_sources = vec<*ast_node>() - // if we don't have to copy_construct params (is an operator, or has no object params) - if (func_name == "&" || !func_call_parameters.any_true(fun(p: *ast_node): bool return get_ast_type(p)->is_object() && get_ast_type(p)->indirection == 0;)) { - parameters = func_call_parameters.map(fun(p: *ast_node): value return interpret(p, var_stack, enclosing_object, enclosing_func, globals).first;) - if ( parameters.size == 2 && (func_name == "+" || func_name == "-" || func_name == "*" || func_name == "/" - || func_name == "<" || func_name == ">" || func_name == "<=" || func_name == ">=" - || func_name == "==" || func_name == "!=" || func_name == "%" || func_name == "^" - || func_name == "|" || func_name == "&" - )) - return make_pair(do_basic_op(func_name, parameters[0], parameters[1]), control_flow::nor()) - // do negate by subtracting from zero - if (func_name == "-") - return make_pair(do_basic_op_second_half(str("-"), 0, parameters[0], null()), control_flow::nor()) - if (func_name == "!") - return make_pair(value::boolean(!truthy(get_real_value(parameters[0]))), control_flow::nor()) - if (func_name == "++p" || func_name == "--p") { - var to_ret = get_real_value(parameters[0]) - store_into_variable(parameters[0], do_basic_op(func_name.slice(0,1), parameters[0], value::integer(1))) - return make_pair(to_ret, control_flow::nor()) - } - if (func_name == "++" || func_name == "--") { - store_into_variable(parameters[0], do_basic_op(func_name.slice(0,1), parameters[0], value::integer(1))) - return make_pair(get_real_value(parameters[0]), control_flow::nor()) - } - if (func_name == "&") { - if (is_variable(parameters[0])) - return make_pair(value::pointer(make_pair(parameters[0].variable.first, parameters[0].variable.second->clone_with_increased_indirection())), control_flow::nor()) - else if (is_object_like(parameters[0])) - return make_pair(value::pointer(make_pair(parameters[0].object_like.first, parameters[0].object_like.second->clone_with_increased_indirection())), control_flow::nor()) - else { - print("can't take address of: ") - print_value(parameters[0]) - error("Trying to take address of not a variable or object_like") - } - } - if (func_name == "*" || func_name == "[]") { - var dereference_val = parameters[0] - if (func_name == "[]") - dereference_val = do_basic_op(str("+"), parameters[0], parameters[1]) - if (!is_pointer(get_real_value(parameters[0]))) - error("Trying to take dereference not a pointer") - return make_pair(dereference_pointer_into_variable(dereference_val), control_flow::nor()) - } - // check for built-in-ish externs (everything the standard library needs) - if (func_name == "printf" || func_name == "malloc" || func_name == "free" || func_name == "memmove" || func_name == "fflush" || func_name == "snprintf" || func_name == "fopen" || func_name == "fclose" || func_name == "ftell" || func_name == "fseek" || func_name == "fread" || func_name == "fwrite" || func_name == "atan" || func_name == "atan2" || func_name == "acos" || func_name == "asin" || func_name == "tan" || func_name == "cos" || func_name == "sin" || func_name == "fgets" || func_name == "popen" || func_name == "pclose") - return make_pair(call_built_in_extern(func_name, parameters), control_flow::nor()) - if (!func_call_func->function.body_statement) - error(str("trying to call unsupported extern function: ") + func_name) - } else { - // not the operator & and at least one object like parameter - parameter_sources = func_call_parameters - } - return make_pair(call_function(func_call_func, parameters, parameter_sources, var_stack, possible_closure_map, enclosing_object, new_enclosing_object, enclosing_func, globals), control_flow::nor()) -} - -fun call_function(func: *ast_node, parameters: vec, globals: *map<*ast_node, value>): value { - var var_stack = stack>() - var_stack.push(map<*ast_node,value>()) - var result = call_function(func, parameters, vec<*ast_node>(), &var_stack, map<*ast_node,value>(), value::void_nothing(), value::void_nothing(), null(), globals) - pop_and_free(&var_stack) - return result -} -// call_function can be called with either parameter values in parameters or ast expressions in parameter_sources -// this is to allow easy function calling if we already have the values (for main, say, or to make our job if it's not -// an operator easier), but we need to be able to be called with ast_expressions too so we can properly copy_construct once -fun call_function(func: *ast_node, parameters: vec, parameter_sources: vec<*ast_node>, var_stack: *stack>, possible_closure_map: ref map<*ast_node, value>, enclosing_object: value, new_enclosing_object: value, enclosing_func: *ast_node, globals: *map<*ast_node, value>): value { - // will need adjustment - if (!is_function(func)) - error("Can't handle not function function calls (can do regular method, is this chained or something?)") - var func_name = func->function.name - // do regular function - // start out with the possible closure map as the highest scope (gloabals checked seperately) - var new_var_stack = stack(possible_closure_map) - new_var_stack.push(map<*ast_node,value>()) - // if this is a value based call, pull from parameters - if (parameter_sources.size == 0) { - /*println(func_name + " being called with parameter values")*/ - if (parameters.size != func->function.parameters.size) - error(str("calling function ") + func->function.name + " with wrong number of parameters (values)") - for (var i = 0; i < parameters.size; i++;) { - var param_type = get_ast_type(func)->parameter_types[i] - var param_ident = func->function.parameters[i] - if (param_type->is_ref) { - if (is_variable(parameters[i])) - new_var_stack.top()[param_ident] = parameters[i] - else - new_var_stack.top()[param_ident] = wrap_into_variable(parameters[i]) - } else { - new_var_stack.top()[param_ident] = value::variable(make_pair(malloc(type_size(param_type)), param_type)) - store_into_variable(new_var_stack.top()[param_ident], get_real_value(parameters[i])) - } - } - } else { - // on this side we construct temps in the old var stack, then move it over to the new one so that references resolve correctly - var_stack->push(map<*ast_node,value>()) - /*println(func_name + " being called with parameter sources")*/ - // need to pull from parameter_sources instead - if (parameter_sources.size != func->function.parameters.size) - error(str("calling function ") + func->function.name + " with wrong number of parameters (sources)") - for (var i = 0; i < parameter_sources.size; i++;) { - var param_type = get_ast_type(func)->parameter_types[i] - var param_ident = func->function.parameters[i] - if (param_type->is_ref) { - var param = interpret(parameter_sources[i], var_stack, enclosing_object, enclosing_func, globals).first - if (is_variable(param)) - new_var_stack.top()[param_ident] = param - else - new_var_stack.top()[param_ident] = wrap_into_variable(param) - } else { - new_var_stack.top()[param_ident] = value::variable(make_pair(malloc(type_size(param_type)), param_type)) - store_into_variable(new_var_stack.top()[param_ident], get_real_value(interpret(parameter_sources[i], var_stack, enclosing_object, enclosing_func, globals).first)) - } - } - } - var to_ret = interpret(func->function.body_statement, &new_var_stack, new_enclosing_object, func, globals).first - // to_ret is on the new_var_stack, likely - /*pop_and_free(&new_var_stack)*/ - if (parameter_sources.size) { - // pop off the temporaries if we needed to, but only after destructing any params we needed to - pop_and_free(var_stack) - } - return to_ret -} -fun call_built_in_extern(func_name: str, parameters: vec): value { - for (var i = 0; i < parameters.size; i++;) - parameters[i] = get_real_value(parameters[i]) - if (func_name == "printf") { - assert(parameters.size == 2 && is_pointer(parameters[0]) && is_pointer(parameters[1]), "Calling printf with wrong params") - printf((parameters[0].pointer.first) cast *char, (parameters[1].pointer.first) cast *char) - return value::integer(0) - } else if (func_name == "malloc") { - assert(parameters.size == 1 && is_ulong_int(parameters[0]), "Calling malloc with wrong params") - return value::pointer(make_pair(malloc(parameters[0].ulong_int), type_ptr(base_type::void_return())->clone_with_increased_indirection())) - } else if (func_name == "free") { - assert(parameters.size == 1 && is_pointer(parameters[0]), "Calling free with wrong params") - free(parameters[0].pointer.first) - } else if (func_name == "memmove") { - assert(parameters.size == 3 && is_pointer(parameters[0]) && is_pointer(parameters[1]) && is_ulong_int(parameters[2]), "Calling memmove with wrong params") - return value::pointer(make_pair(memmove((parameters[0].pointer.first) cast *void, (parameters[1].pointer.first) cast *void, parameters[2].ulong_int), type_ptr(base_type::void_return(), 1))) - } else if (func_name == "fflush") { - assert(parameters.size == 1 && is_integer(parameters[0]), "Calling fflush with wrong params") - fflush(parameters[0].integer) - } else if (func_name == "snprintf") { - assert(parameters.size == 4 && is_pointer(parameters[0]) && is_ulong_int(parameters[1]) && is_pointer(parameters[2]) && is_double_precision(parameters[3]), "Calling snprintf with wrong params") - return value::integer(snprintf((parameters[0].pointer.first) cast *char, parameters[1].ulong_int, (parameters[2].pointer.first) cast *char, parameters[3].double_precision)) - } else if (func_name == "fopen") { - assert(parameters.size == 2 && is_pointer(parameters[0]) && is_pointer(parameters[1]), "Calling fopen with wrong params") - return value::pointer(make_pair(fopen((parameters[0].pointer.first) cast *char, (parameters[1].pointer.first) cast *char), type_ptr(base_type::void_return(), 1))) - } else if (func_name == "fclose") { - assert(parameters.size == 1 && is_pointer(parameters[0]), "Calling fclose with wrong params") - return value::integer(fclose((parameters[0].pointer.first) cast *void)) - } else if (func_name == "ftell") { - assert(parameters.size == 1 && is_pointer(parameters[0]), "Calling ftell with wrong params") - return value::long_int(ftell((parameters[0].pointer.first) cast *void)) - } else if (func_name == "fseek") { - assert(parameters.size == 3 && is_pointer(parameters[0]) && is_long_int(parameters[1]) && is_integer(parameters[2]), "Calling fseek with wrong params") - return value::integer(fseek((parameters[0].pointer.first) cast *void, parameters[1].long_int, parameters[2].integer)) - } else if (func_name == "fread") { - assert(parameters.size == 4 && is_pointer(parameters[0]) && is_ulong_int(parameters[1]) && is_ulong_int(parameters[2]) && is_pointer(parameters[3]), "Calling fread with wrong params") - return value::ulong_int(fread((parameters[0].pointer.first) cast *void, parameters[1].ulong_int, parameters[2].ulong_int, parameters[3].pointer.first)) - } else if (func_name == "fwrite") { - assert(parameters.size == 4 && is_pointer(parameters[0]) && is_ulong_int(parameters[1]) && is_ulong_int(parameters[2]) && is_pointer(parameters[3]), "Calling fwrite with wrong params") - return value::ulong_int(fwrite((parameters[0].pointer.first) cast *void, parameters[1].ulong_int, parameters[2].ulong_int, parameters[3].pointer.first)) - } else if (func_name == "exit") { - assert(parameters.size == 1 && is_integer(parameters[0]), "Calling exit with wrong params") - exit(parameters[0].integer) - } else if (func_name == "atan") { - assert(parameters.size == 1 && is_double_precision(parameters[0]), "Calling atan with wrong params") - return value::double_precision(atan(parameters[0].double_precision)) - } else if (func_name == "atan2") { - assert(parameters.size == 2 && is_double_precision(parameters[0]) && is_double_precision(parameters[1]), "Calling atan2 with wrong params") - return value::double_precision(atan2(parameters[0].double_precision, parameters[1].double_precision)) - } else if (func_name == "acos") { - assert(parameters.size == 1 && is_double_precision(parameters[0]), "Calling acos with wrong params") - return value::double_precision(acos(parameters[0].double_precision)) - } else if (func_name == "asin") { - assert(parameters.size == 1 && is_double_precision(parameters[0]), "Calling asin with wrong params") - return value::double_precision(asin(parameters[0].double_precision)) - } else if (func_name == "tan") { - assert(parameters.size == 1 && is_double_precision(parameters[0]), "Calling tan with wrong params") - return value::double_precision(tan(parameters[0].double_precision)) - } else if (func_name == "cos") { - assert(parameters.size == 1 && is_double_precision(parameters[0]), "Calling cos with wrong params") - return value::double_precision(cos(parameters[0].double_precision)) - } else if (func_name == "sin") { - assert(parameters.size == 1 && is_double_precision(parameters[0]), "Calling sin with wrong params") - return value::double_precision(sin(parameters[0].double_precision)) - } else if (func_name == "fgets") { - assert(parameters.size == 3 && is_pointer(parameters[0]) && is_integer(parameters[1]) && is_pointer(parameters[2]), "Calling fgets with wrong params") - // first param is *char, so reuse for return - return value::pointer(make_pair((fgets((parameters[0].pointer.first) cast *char, parameters[1].integer, parameters[2].pointer.first)) cast *void, parameters[0].pointer.second)) - } else if (func_name == "popen") { - assert(parameters.size == 2 && is_pointer(parameters[0]) && is_pointer(parameters[1]), "Calling popen with wrong params") - return value::pointer( - make_pair(popen((parameters[0].pointer.first) cast *char, (parameters[1].pointer.first) cast *char), type_ptr(base_type::void_return(), 1))) - } else if (func_name == "pclose") { - assert(parameters.size == 1 && is_pointer(parameters[0]), "Calling pclose with wrong params") - return value::integer(pclose(parameters[0].pointer.first)) - } else { - error(str("trying to call invalid func: ") + func_name) - } - return value::void_nothing() -} -fun interpret_function(function: *ast_node, var_stack: *stack>, enclosing_object: value, enclosing_func: *ast_node, globals: *map<*ast_node, value>): pair { - var possible_closure_map = new>()->construct() - function->function.closed_variables.for_each(fun(v: *ast_node) { - (*possible_closure_map)[v] = interpret_identifier(v, var_stack, enclosing_object, enclosing_func, globals).first - }) - return make_pair(value::function(make_pair(function, possible_closure_map)), control_flow::nor()) -} -fun interpret_if_statement(if_stmt: *ast_node, var_stack: *stack>, enclosing_object: value, enclosing_func: *ast_node, globals: *map<*ast_node, value>): pair { - var_stack->push(map<*ast_node,value>()) - var value_from_inside = make_pair(value::void_nothing(), control_flow::nor()) - if (truthy(interpret(if_stmt->if_statement.condition, var_stack, enclosing_object, enclosing_func, globals).first)) { - value_from_inside = interpret(if_stmt->if_statement.then_part, var_stack, enclosing_object, enclosing_func, globals) - } else if (if_stmt->if_statement.else_part) { - value_from_inside = interpret(if_stmt->if_statement.else_part, var_stack, enclosing_object, enclosing_func, globals) - } - pop_and_free(var_stack) - return value_from_inside -} -fun interpret_while_loop(while_loop: *ast_node, var_stack: *stack>, enclosing_object: value, enclosing_func: *ast_node, globals: *map<*ast_node, value>): pair { - var_stack->push(map<*ast_node,value>()) - var value_from_inside = make_pair(value::void_nothing(), control_flow::nor()) - var going = true - while (going && truthy(interpret(while_loop->while_loop.condition, var_stack, enclosing_object, enclosing_func, globals).first)) { - value_from_inside = interpret(while_loop->while_loop.statement, var_stack, enclosing_object, enclosing_func, globals) - if (value_from_inside.second == control_flow::ret() || value_from_inside.second == control_flow::bre()) - going = false - if (value_from_inside.second == control_flow::bre() || value_from_inside.second == control_flow::con()) - value_from_inside = make_pair(value::void_nothing(), control_flow::nor()) - } - pop_and_free(var_stack) - return value_from_inside -} -fun interpret_for_loop(for_loop: *ast_node, var_stack: *stack>, enclosing_object: value, enclosing_func: *ast_node, globals: *map<*ast_node, value>): pair { - var_stack->push(map<*ast_node,value>()) - var value_from_inside = make_pair(value::void_nothing(), control_flow::nor()) - var going = true - if (for_loop->for_loop.init) - interpret(for_loop->for_loop.init, var_stack, enclosing_object, enclosing_func, globals) - while (going && (!for_loop->for_loop.condition || truthy(interpret(for_loop->for_loop.condition, var_stack, enclosing_object, enclosing_func, globals).first))) { - value_from_inside = interpret(for_loop->for_loop.body, var_stack, enclosing_object, enclosing_func, globals) - if (value_from_inside.second == control_flow::ret() || value_from_inside.second == control_flow::bre()) - going = false - if (value_from_inside.second == control_flow::bre() || value_from_inside.second == control_flow::con()) - value_from_inside = make_pair(value::void_nothing(), control_flow::nor()) - - // only run update if we're not breaking or continuing - if (going && for_loop->for_loop.update) - interpret(for_loop->for_loop.update, var_stack, enclosing_object, enclosing_func, globals) - } - pop_and_free(var_stack) - return value_from_inside -} -fun interpret_branching_statement(bstatement: *ast_node): pair { - match (bstatement->branching_statement.b_type) { - branching_type::break_stmt() return make_pair(value::void_nothing(), control_flow::bre()) - branching_type::continue_stmt() return make_pair(value::void_nothing(), control_flow::con()) - } - error("bad branch type") -} -fun interpret_code_block(block: *ast_node, var_stack: *stack>, enclosing_object: value, enclosing_func: *ast_node, globals: *map<*ast_node, value>): pair { - var_stack->push(map<*ast_node,value>()) - for (var i = 0; i < block->code_block.children.size; i++;) { - var statement = interpret(block->code_block.children[i], var_stack, enclosing_object, enclosing_func, globals) - match (statement.second) { - control_flow::con() { - pop_and_free(var_stack) - return make_pair(value::void_nothing(), control_flow::con()) - } - control_flow::bre() { - pop_and_free(var_stack) - return make_pair(value::void_nothing(), control_flow::bre()) - } - control_flow::ret() { - pop_and_free(var_stack) - return statement - } - } - // if nor, continue on - } - pop_and_free(var_stack) - return make_pair(value::void_nothing(), control_flow::nor()) -} -fun interpret_return_statement(stmt: *ast_node, var_stack: *stack>, enclosing_object: value, enclosing_func: *ast_node, globals: *map<*ast_node, value>): pair { - if (stmt->return_statement.return_value == null()) - return make_pair(value::void_nothing(), control_flow::ret()) - var return_expression = stmt->return_statement.return_value - var return_type = get_ast_type(return_expression) - var to_ret.construct(): value - if (get_ast_type(enclosing_func)->return_type->is_ref) { - to_ret = interpret(return_expression, var_stack, enclosing_object, enclosing_func, globals).first - if (!is_variable(to_ret)) { - print("here is: ") - print_value(to_ret) - error("interpreter returning reference is not variable") - } - } else { - to_ret = interpret(return_expression, var_stack, enclosing_object, enclosing_func, globals).first - } - return make_pair(to_ret, control_flow::ret()) -} -fun interpret_declaration_statement(stmt: *ast_node, var_stack: *stack>, enclosing_object: value, enclosing_func: *ast_node, globals: *map<*ast_node, value>): pair { - var ident = stmt->declaration_statement.identifier - var ident_type = ident->identifier.type - var_stack->top()[ident] = value::variable(make_pair(malloc(type_size(ident_type)),ident_type)) - // NOTE: store_into_variable takes to in as a ref because it might change it in the special case ref = ptr - if (stmt->declaration_statement.expression) { - store_into_variable(var_stack->top()[ident], get_real_value(interpret(stmt->declaration_statement.expression, var_stack, enclosing_object, enclosing_func, globals).first)) - } else if (stmt->declaration_statement.init_method_call) { - interpret(stmt->declaration_statement.init_method_call, var_stack, enclosing_object, enclosing_func, globals) - } - return make_pair(value::void_nothing(), control_flow::nor()) -} -fun interpret_assignment_statement(stmt: *ast_node, var_stack: *stack>, enclosing_object: value, enclosing_func: *ast_node, globals: *map<*ast_node, value>): pair { - var to = interpret(stmt->assignment_statement.to, var_stack, enclosing_object, enclosing_func, globals).first - var from = interpret(stmt->assignment_statement.from, var_stack, enclosing_object, enclosing_func, globals).first - assert(is_variable(to), "assigning into not a variable") - // always do cast now to make our best effort at assignment (assign into a double from a float, etc) - // unless it's an object - var from_real = get_real_value(from) - // NOTE: store_into_variable takes to in as a ref because it might change it in the special case ref = ptr - if (is_object_like(from_real) || is_function(from_real)) - store_into_variable(to, from_real) - else - store_into_variable(to, cast_value(from_real, to.variable.second)) - return make_pair(value::void_nothing(), control_flow::nor()) -} -fun interpret_identifier(ident: *ast_node, var_stack: *stack>, enclosing_object: value, enclosing_func: *ast_node, globals: *map<*ast_node, value>): pair { - for (var i = 0; i < var_stack->size(); i++;) - if (var_stack->from_top(i).contains_key(ident)) - return make_pair(var_stack->from_top(i)[ident], control_flow::nor()) - // check for object member / this - if (is_object_like(enclosing_object)) { - if (ident->identifier.name == "this") - return make_pair(value::pointer(make_pair(enclosing_object.object_like.first, enclosing_object.object_like.second->clone_with_increased_indirection())), control_flow::nor()) - var object_def = enclosing_object.object_like.second->type_def - for (var i = 0; i < object_def->type_def.variables.size; i++;) { - if (object_def->type_def.variables[i]->declaration_statement.identifier == ident) { - var ret_ptr = ((enclosing_object.object_like.first) cast *char + offset_into_struct(enclosing_object.object_like.second, ident)) cast *void - return make_pair(value::variable(make_pair(ret_ptr, ident->identifier.type)), control_flow::nor()) - } - } - } - // check for global - if (globals->contains_key(ident)) - return make_pair((*globals)[ident], control_flow::nor()) - println("couldn't find " + get_ast_name(ident) + " in interpret identifier, scope:") - for (var i = 0; i < var_stack->size(); i++;) { - println(str("level: ") + i) - var_stack->from_top(i).for_each(fun(key: *ast_node, v: value) print(get_ast_name(key) + " ");) - println() - } - if (is_object_like(enclosing_object)) { - println("object scope:") - var object_def = enclosing_object.object_like.second->type_def - for (var i = 0; i < object_def->type_def.variables.size; i++;) { - print(get_ast_name(object_def->type_def.variables[i]->declaration_statement.identifier) + " ") - } - } else { - print("no object scope: ") - print_value(enclosing_object) - } - error(str("Cannot find variable: ") + ident->identifier.name) -} -fun interpret_cast(node: *ast_node, var_stack: *stack>, enclosing_object: value, enclosing_func: *ast_node, globals: *map<*ast_node, value>): pair { - return make_pair(cast_value(interpret(node->cast.value, var_stack, enclosing_object, enclosing_func, globals).first, node->cast.to_type), control_flow::nor()) -} -fun interpret_compiler_intrinsic(node: *ast_node, var_stack: *stack>): pair { - var intrinsic_name = node->compiler_intrinsic.intrinsic - if (intrinsic_name == "sizeof") - return make_pair(value::ulong_int(type_size(node->compiler_intrinsic.type_parameters[0])), control_flow::nor()) - error(str("bad intrinsic: ") + intrinsic_name) -} -fun interpret_value(val: *ast_node): pair - return make_pair(wrap_value(val), control_flow::nor()) -fun interpret(node: *ast_node, var_stack: *stack>, enclosing_object: value, enclosing_func: *ast_node, globals: *map<*ast_node, value>): pair { - if (!node) error("cannot interpret null node!") - match (*node) { - ast_node::function_call(backing) return interpret_function_call(node, var_stack, enclosing_object, enclosing_func, globals) - ast_node::function(backing) return interpret_function(node, var_stack, enclosing_object, enclosing_func, globals) - ast_node::if_statement(backing) return interpret_if_statement(node, var_stack, enclosing_object, enclosing_func, globals) - ast_node::while_loop(backing) return interpret_while_loop(node, var_stack, enclosing_object, enclosing_func, globals) - ast_node::for_loop(backing) return interpret_for_loop(node, var_stack, enclosing_object, enclosing_func, globals) - ast_node::branching_statement(backing) return interpret_branching_statement(node) - ast_node::code_block(backing) return interpret_code_block(node, var_stack, enclosing_object, enclosing_func, globals) - ast_node::return_statement(backing) return interpret_return_statement(node, var_stack, enclosing_object, enclosing_func, globals) - ast_node::declaration_statement(backing) return interpret_declaration_statement(node, var_stack, enclosing_object, enclosing_func, globals) - ast_node::assignment_statement(backing) return interpret_assignment_statement(node, var_stack, enclosing_object, enclosing_func, globals) - ast_node::identifier(backing) return interpret_identifier(node, var_stack, enclosing_object, enclosing_func, globals) - ast_node::cast(backing) return interpret_cast(node, var_stack, enclosing_object, enclosing_func, globals) - ast_node::compiler_intrinsic(backing) return interpret_compiler_intrinsic(node, var_stack) - ast_node::value(backing) return interpret_value(node) - } - error(str("Cannot interpret node: ") + get_ast_name(node)) -} - diff --git a/stdlib/io.krak b/stdlib/io.krak deleted file mode 100644 index b9e6d50..0000000 --- a/stdlib/io.krak +++ /dev/null @@ -1,160 +0,0 @@ -import str; -import vec; -import mem:* - -ext fun printf(fmt_str: *char, ...): int -ext fun fprintf(file: *void, format: *char, ...): int -ext fun fflush(file: int): int -ext var stderr: *void -ext fun fgets(buff: *char, size: int, file: *void): *char -ext var stdin: *void - -// dead simple stdin -fun get_line(prompt: str::str, line_size: int): str::str { - print(prompt) - return get_line(line_size) -} -fun get_line(line_size: int): str::str - return get_line(line_size, stdin) -fun get_line(line_size: int, file: *void): str::str { - var buff = new(line_size) - if fgets(buff, line_size, file) == null() { - delete(buff) - return str::str("***EOF***") - } - var to_ret = str::str(buff) - delete(buff) - return to_ret.slice(0,-2) // remove '\n' -} -fun printlnerr(toPrint: T) : void { - printerr(toPrint) - printerr("\n") -} -fun printlnerr() - printerr("\n") -fun printerr(toPrint: str::str) : void { - var charArr = toPrint.toCharArray() - printerr(charArr) - delete(charArr) -} -fun printerr(toPrint: *char) : void { - fprintf(stderr, "%s", toPrint) - // stderr is already flushed -} - -fun println(toPrint: T) : void { - print(toPrint) - print("\n") -} -fun print(toPrint: *char) : void { - printf("%s", toPrint) - fflush(0) -} -fun println() - print("\n") - -fun print(toPrint: char) : void - print(str::str(toPrint)) - -fun print(toPrint: str::str) : void { - var charArr = toPrint.toCharArray() - print(charArr) - delete(charArr) -} -fun print(toPrint: bool) { - if (toPrint) - print("true") - else - print("false") -} -fun print(toPrint: T): void - print(str::to_string(toPrint)) - -// Ok, just some DEAD simple file io for now -ext fun fopen(path: *char, mode: *char): *void -ext fun fclose(file: *void): int -// fprintf is already used for stderr above -ext fun ftell(file: *void): long -ext fun fseek(file: *void, offset: long, whence: int): int -ext fun fread(ptr: *void, size: ulong, nmemb: ulong, file: *void): ulong -ext fun fwrite(ptr: *void, size: ulong, nmemb: ulong, file: *void): ulong -fun file_exists(path: str::str): bool { - var char_path = path.toCharArray() - defer delete(char_path) - var fp = fopen(char_path, "r") - if (fp) { - fclose(fp) - return true - } - return false -} -fun read_file(path: str::str): str::str { - if (!file_exists(path)) - return str::str() - var toRet.construct(read_file_binary(path)): str::str - return toRet -} -fun write_file(path: str::str, data: str::str) { - var char_path = path.toCharArray() - defer delete(char_path) - var char_data = data.toCharArray() - defer delete(char_data) - var fp = fopen(char_path, "w") - fprintf(fp, "%s", char_data) - fclose(fp) -} -fun read_file_binary(path: str::str): vec::vec { - var char_path = path.toCharArray() - defer delete(char_path) - var fp = fopen(char_path, "r") - fseek(fp, (0) cast long, 2)// fseek(fp, 0L, SEEK_END) - var size = ftell(fp) - fseek(fp, (0) cast long, 0)//fseek(fp, 0L, SEEK_SET) - var data = new((size+1) cast int) - var readSize = fread((data) cast *void, (1) cast ulong, (size) cast ulong, fp) - fclose(fp) - data[readSize] = 0 - var toRet.construct((size) cast int): vec::vec - for (var i = 0; i < size; i++;) - toRet.add(data[i]) - delete(data) - return toRet -} -fun write_file_binary(path: str::str, vdata: vec::vec) { - var char_path = path.toCharArray() - defer delete(char_path) - var data = vdata.getBackingMemory() - var size = vdata.size - var fp = fopen(char_path, "wb") - fwrite((data) cast *void, (1) cast ulong, (size) cast ulong, fp) - fclose(fp) -} - -fun BoldRed(): void{ - print("\033[1m\033[31m"); -} - -fun BoldGreen(): void{ - print("\033[1m\033[32m"); -} - -fun BoldYellow(): void{ - print("\033[1m\033[33m"); -} - -fun BoldBlue(): void{ - print("\033[1m\033[34m"); -} - -fun BoldMagenta(): void{ - print("\033[1m\033[35m"); -} - -fun BoldCyan(): void{ - print("\033[1m\033[36m"); -} - -fun Reset(): void{ - print("\033[0m"); -} - diff --git a/stdlib/lexer.krak b/stdlib/lexer.krak deleted file mode 100644 index be5138f..0000000 --- a/stdlib/lexer.krak +++ /dev/null @@ -1,89 +0,0 @@ -import regex -import symbol -import str -import vec -import util - -fun lexer(regs: vec::vec): lexer { - /*var toRet:lexer*/ - var toRet.construct() :lexer - regs.for_each( fun(reg: regex::regex) { - toRet.add_regex(util::make_pair(reg.regexString, reg)); - }) - return toRet -} - -fun lexer(regs: vec::vec>): lexer { - /*var toRet:lexer*/ - var toRet.construct() :lexer - regs.for_each( fun(reg: util::pair) - toRet.add_regex(util::make_pair(reg.first.name, reg.second)); - ) - return toRet -} - -obj lexer (Object) { - var regs: vec::vec> - var input: str::str - var position: int - var line_number: int - fun construct(): *lexer { - regs.construct() - input.construct() - position = 0 - line_number = 1 - return this - } - fun destruct() { - regs.destruct() - input.destruct() - } - fun copy_construct(old: *lexer) { - regs.copy_construct(&old->regs) - input.copy_construct(&old->input) - position = old->position - line_number = old->line_number - } - fun operator=(old: lexer) { - destruct() - copy_construct(&old) - } - fun add_regex(name: str::str, newOne: regex::regex) { - regs.add(util::make_pair(name,newOne)) - } - fun add_regex(newOne: util::pair) { - regs.add(newOne) - } - fun add_regex(newOne: regex::regex) { - regs.add(util::make_pair(newOne.regexString, newOne)) - } - fun add_regex(newOne: *char) { - regs.add(util::make_pair(str::str(newOne), regex::regex(newOne))) - } - fun set_input(in: ref str::str) { - position = 0 - line_number = 1 - input = in - } - fun next(): symbol::symbol { - if (position >= input.length()) - return symbol::eof_symbol() - var max = -1 - var max_length = -1 - for (var i = 0; i < regs.size; i++;) { - var new_length = regs[i].second.long_match(input.getBackingMemory(), position, input.length()) - if (new_length > max_length) { - max = i - max_length = new_length - } - } - if (max < 0) - return symbol::invalid_symbol() - for (var i = position; i < position+max_length; i++;) - if (input[i] == '\n') - line_number++ - position += max_length - return symbol::symbol(regs[max].first, true, input.slice(position-max_length, position), line_number) - } -} - diff --git a/stdlib/map.krak b/stdlib/map.krak deleted file mode 100644 index 1c06c74..0000000 --- a/stdlib/map.krak +++ /dev/null @@ -1,130 +0,0 @@ -import vec -import mem -import io -import serialize -import util - -fun map(): map { - var toRet.construct(): map - return toRet -} -fun map(key: ref T, value: ref U): map { - var toRet.construct(): map - toRet.set(key, value) - return toRet -} - -obj map (Object, Serializable) { - var keys: vec::vec - var values: vec::vec - - fun construct(): *map { - keys.construct() - values.construct() - return this - } - fun copy_construct(old: *map) { - keys.copy_construct(&old->keys) - values.copy_construct(&old->values) - } - fun operator=(rhs: ref map) { - keys = rhs.keys - values = rhs.values - } - fun destruct() { - keys.destruct() - values.destruct() - } - fun serialize(): vec::vec { - return serialize::serialize(keys) + serialize::serialize(values) - } - fun unserialize(it: ref vec::vec, pos: int): int { - pos = keys.unserialize(it, pos) - pos = values.unserialize(it, pos) - return pos - } - fun size(): int { - return keys.size - } - // the old unnecessary template to prevent generation - // if not used trick (in this case, changing out U with V) - fun operator==(other: ref map): bool { - return keys == other.keys && values == other.values - } - fun operator[]=(key: ref T, value: ref U) { - set(key,value) - } - fun set(key: ref T, value: ref U) { - var keyIdx = keys.find(key) - if (keyIdx >= 0) { - values.set(keyIdx, value) - return; - } - keys.add(key) - values.add(value) - } - fun contains_key(key: ref T): bool { - return keys.contains(key) - } - fun contains_value(value: ref V): bool { - return values.contains(value) - } - fun get(key: ref T): ref U { - var key_loc = keys.find(key) - if (key_loc == -1) - util::error("trying to access nonexistant key-value!") - return values.get(key_loc) - } - fun get_ptr_or_null(key: ref T): *U { - var key_loc = keys.find(key) - if (key_loc == -1) - return mem::null() - return &values.get(key_loc) - } - fun get_with_default(key: ref T, default_val: ref U): ref U { - if (contains_key(key)) - return get(key) - return default_val - } - fun reverse_get(value: ref V): ref T { - /*return values.get(keys.find(key))*/ - var value_loc = values.find(value) - if (value_loc == -1) - util::error("trying to access nonexistant value-key!") - return keys.get(value_loc) - } - fun remove(key: ref T) { - var idx = keys.find(key) - if (idx < 0) - return; - keys.remove(idx) - values.remove(idx) - } - fun clear() { - keys.clear() - values.clear() - } - fun operator[](key: ref T): ref U { - return get(key) - } - fun for_each(func: fun(T, U):void) { - for (var i = 0; i < keys.size; i++;) - func(keys[i], values[i]) - } - fun for_each(func: fun(ref T, ref U):void) { - for (var i = 0; i < keys.size; i++;) - func(keys[i], values[i]) - } - fun associate(func: fun(T,U): util::pair): map { - var to_ret = map() - for (var i = 0; i < keys.size; i++;) { - var nkv = func(keys[i], values[i]) - to_ret[nkv.first] = nkv.second - } - return to_ret - } - fun pop(): util::pair { - return util::make_pair(keys.pop(), values.pop()) - } -} - diff --git a/stdlib/math.krak b/stdlib/math.krak deleted file mode 100644 index 452d59a..0000000 --- a/stdlib/math.krak +++ /dev/null @@ -1,29 +0,0 @@ -#link("m") - -fun fibanacci(num: int): int { - var l1 = 1 - var l2 = 1 - for (var i = 0; i < num; i++;) { - var next = l1 + l2 - l2 = l1 - l1 = next - } - return l1 -} - -/********************* - * Trig Functions - ********************/ - -ext fun atan(arg: double): double -ext fun atan2(x: double, y: double): double -ext fun acos(arg: double): double -ext fun asin(arg: double): double -ext fun tan(arg: double): double -ext fun cos(arg: double): double -ext fun sin(arg: double): double -fun mod(x: double, y: double): double -{ - var intAns = x / y; - return x - intAns*y; -} diff --git a/stdlib/matrix.krak b/stdlib/matrix.krak deleted file mode 100644 index 80235c3..0000000 --- a/stdlib/matrix.krak +++ /dev/null @@ -1,146 +0,0 @@ -import vec:*; -import io:*; - -obj matrix (Object) { - var data: vec; - var rows: int; - var cols: int; - - ///****************************** - // Constructors - ///*****************************/ - - //Constructor with no arguments - //No matrix is made - fun construct(): *matrix { - rows = 0; - cols = 0; - data.construct(); - return this; - } - - //Constructor with single argument - //Creates an N x N matrix - fun construct(size: int): *matrix { - rows = size; - cols = size; - data.construct(rows*cols); - return this; - } - - //Constructor with two arguments - //Creates an N x M matrix - fun construct(r: int, c: int): *matrix { - rows = r; - cols = c; - data.construct(rows*cols); - return this; - } - - ///**************************** - // Utility Functions - ///***************************/ - - //Test using indexing at 0 - fun test0(i: int, j: int): bool { - - var index = i*rows + j; - - if(index > (rows * cols - 1) ) { - print("Index ("); - print(i); - print(", "); - print(j); - println(") is out of bounds."); - print("Max index = ("); - print(rows-1); - print(", "); - print(cols-1); - println(")."); - return false; - } - - return true; - } - - //Test using indexing at 1 - fun test1(i: int, j: int): bool { - - var index = (i-1)*rows + (j-1); - - if(index > (rows * cols - 1) ) { - print("Index ("); - print(i); - print(", "); - print(j); - println(") is out of bounds."); - print("Max index = ("); - print(rows); - print(", "); - print(cols); - println(")."); - return false; - } - - return true; - } - - //Access matrix element - fun at(i: int, j: int): double { - - var index = i*rows + j; - - if(test0(i,j)) - return data.at(index); - - return 0; - } - - //Set matrix element - fun set(i: int, j: int, num: double): void { - - var index = i*rows + j; - - if(test0(i,j)) - data.set(index,num); - - return; - } - - fun printMatrix(): void { - - for(var i: int = 0; i < rows; i++;) - { - for(var j: int = 0; j < cols; j++;) - { - print(at(i,j)); - print(" "); - } - println(" "); - } - - return; - } - - ///************************** - // Linear Algebra Functions - //**************************/ - - fun transpose(): void { - var val1: double; - var val2: double; - - for(var n: int = 0; n <= rows - 2; n++;) - for(var m: int = n+1; m <= rows - 1; m++;){ - val1 = at(n, m); - val2 = at(m, n); - - set(n, m, val2); - set(m, n, val1); - } - - return; - } - -};//end Matrix class - diff --git a/stdlib/mem.krak b/stdlib/mem.krak deleted file mode 100644 index a44e994..0000000 --- a/stdlib/mem.krak +++ /dev/null @@ -1,126 +0,0 @@ - -ext fun malloc(size: ulong): *void -ext fun free(size: *void) -ext fun memmove(dest: *void, src: *void, size: ulong): *void - -fun calloc(size: ulong): *void { - var to_ret = malloc(size) - for (var i = 0; i < size; i++;) - *((to_ret) cast *char + i) = 0 - return to_ret -} - -fun null(): *T - return (0) cast *T - -fun new(count: int): *T - return (malloc( (#sizeof * count ) cast ulong )) cast *T - -fun new(): *T - return new(1) - -/* We specilize on the trait Object to decide on whether or not the destructor should be called */ -fun delete(toDelete: *T, itemCount: int) - delete(toDelete) - -/* Calling this with itemCount = 0 allows you to delete destructable objects without calling their destructors. */ -fun delete(toDelete: *T, itemCount: int): void { - // start at one because the actual delete will call the destructor of the first one as it - // finishes the pointer - for (var i: int = 0; i < itemCount; i++;) - toDelete[i].destruct(); - free((toDelete) cast *void); -} - -/* We specilize on the trait Object to decide on whether or not the destructor should be called */ -fun delete(toDelete: *T) - free((toDelete) cast *void) - -fun delete(toDelete: *T): void { - toDelete->destruct(); - free((toDelete) cast *void); -} - -// a wrapper for construct if it has the Object trait -fun maybe_construct(it:*T):*T - return it - -fun maybe_construct(it:*T):*T - return it->construct() - -// a wrapper for copy constructing if it has the Object trait -fun maybe_copy_construct(to:*T, from:*T) - *to = *from - - -fun maybe_copy_construct(to:*T, from:*T) - to->copy_construct(from) - -// a wrapper for destruct if it has the Object trait -fun maybe_destruct(it:*T) {} - -fun maybe_destruct(it:*T) - it->destruct() - -obj shared_ptr (Object){ - var data: *T; - var refCount: int; - - fun construct(): *shared_ptr { - data = 0; - refCount = 1; - return this; - } - - fun construct(newPtr: *T): *shared_ptr { - data = newPtr; - refCount = 1; - return this; - } - - fun construct(newPtr: ref shared_ptr): *shared_ptr { - data = newPtr.data; - refCount = newPtr.refCount; - refCount++; - return this; - } - - fun destruct(): void { - if(refCount == 1){ - delete(data,1); - refCount--; - } - - } - - fun operator*(): ref T { - return *data; - } - - fun operator->(): *T { - return data; - } - - fun operator=(newPtr: ref shared_ptr): ref shared_ptr { - if(this != &newPtr){ - if(refCount == 1){ - delete(data,1); - refCount--; - } - //use copy constructor here??? - data = newPtr.data; - refCount = newPtr.refCount; - refCount++; - }//end self-assignment check - return *this; - } - - fun operator=(newPtr: ref *T): ref shared_ptr { - data = newPtr; - refCount = 1; - delete(newPtr,1); - return *this; - } - -}; //end shared_ptr class - diff --git a/stdlib/node_counter.krak b/stdlib/node_counter.krak deleted file mode 100644 index b774eeb..0000000 --- a/stdlib/node_counter.krak +++ /dev/null @@ -1,35 +0,0 @@ -import symbol:* -import tree:* -import vec:* -import map:* -import util:* -import str:* -import mem:* -import io:* -import ast_nodes:* -import ast_transformation:* - -import pass_common:* - -fun node_counter(name_ast_map: *map,*ast_node>>, ast_to_syntax: *map<*ast_node, *tree>) { - var counter = node_counter_helper(name_ast_map, ast_to_syntax) - println(str("Number of nodes touched: ") + counter) -} -fun node_counter_test(name_ast_map: *map,*ast_node>>, ast_to_syntax: *map<*ast_node, *tree>) { - var counter = node_counter_helper(name_ast_map, ast_to_syntax) - if (counter > 10000) - println("more than 10000 nodes!") -} -fun node_counter_helper(name_ast_map: *map,*ast_node>>, ast_to_syntax: *map<*ast_node, *tree>): int { - var counter = 0 - var visited = hash_set<*ast_node>() - name_ast_map->for_each(fun(name: str, syntax_ast_pair: pair<*tree,*ast_node>) { - var helper = fun(node: *ast_node, parent_chain: *stack<*ast_node>) { - counter++ - } - run_on_tree(helper, empty_pass_second_half(), syntax_ast_pair.second, &visited) - }) - return counter -} - - diff --git a/stdlib/obj_lower.krak b/stdlib/obj_lower.krak deleted file mode 100644 index e7be82d..0000000 --- a/stdlib/obj_lower.krak +++ /dev/null @@ -1,384 +0,0 @@ -import symbol:* -import tree:* -import vec:* -import map:* -import util:* -import str:* -import mem:* -import io:* -import ast_nodes:* -import ast_transformation:* -import pass_common:* -import hash_set:* -/* - Here's how we lower objects - PASS ONE THROUGH name_ast_map - 1 first, we make sure that all functions, if statments, while loops and for loops have code blocks - as children, not just statements. - 1 during the same pass, we "uglify" for loops and while loops so that functions that need pre and post statements always - have a code block to insert them into that makes sure that they get run. - 1 we also make a set of all type_defs for pass 4 - - PASS TWO THROUGH name_ast_map - 2 in another pass (more complicated because different children have different parent scopes) - we transform the short circuit operators - - 3 then on the pass up the chain, at function calls we add in they copy_construct in and defer destruct out - temporaries. Also, pull out init method calls. - 3 this is also when we add in defer destructs for function parameters (inside the function) and declaration statements - - PASS THREE THROUGH name_ast_map - 4 change all methods to take in self, change all method calls to pass in self, change all in method references to be explicit -*/ -fun obj_lower(name_ast_map: *map,*ast_node>>, ast_to_syntax: *map<*ast_node, *tree>) { - var visited1 = hash_set<*ast_node>() - var visited2 = hash_set<*ast_node>() - var visited3 = hash_set<*ast_node>() - var functions_visited_for_construct_in_destruct_out = hash_set<*ast_node>() - var all_type_defs = set<*ast_node>() - name_ast_map->for_each(fun(name: str, syntax_ast_pair: pair<*tree,*ast_node>) { - // Pass 1 - var ensure_block_and_munge: fun(*ast_node,*stack<*ast_node>,*hash_set<*ast_node>):bool = fun(node: *ast_node, parent_chain: *stack<*ast_node>, visited: *hash_set<*ast_node>):bool { - match(*node) { - ast_node::type_def(backing) all_type_defs.add(node) - ast_node::function(backing) if (backing.body_statement && !is_code_block(backing.body_statement)) { - backing.body_statement = _code_block(backing.body_statement) - add_to_scope("~enclosing_scope", node, backing.body_statement) - if (!is_code_block(backing.body_statement)) - error("BUT EXTRA WHY") - if (!is_code_block(node->function.body_statement)) - error("BUT EXTRA WHY - now with more") - } - ast_node::if_statement(backing) { - if (!is_code_block(backing.then_part)) { - backing.then_part = _code_block(backing.then_part) - add_to_scope("~enclosing_scope", node, backing.then_part) - } - if (backing.else_part && !is_code_block(backing.else_part)) { - backing.else_part = _code_block(backing.else_part) - add_to_scope("~enclosing_scope", node, backing.else_part) - } - } - // no need for case because it's already been lowered - ast_node::while_loop(backing) { - if (!is_code_block(backing.statement)) { - backing.statement = _code_block(backing.statement) - add_to_scope("~enclosing_scope", node, backing.statement) - } - var condition = backing.condition - backing.condition = _value(str("true"), type_ptr(base_type::boolean())) - // objects do not coerce to booleans, so it should be ok for this not to be a ref - var condition_ident = _ident("condition_temp", get_ast_type(condition), backing.statement) - backing.statement->code_block.children.add(0, _declaration(condition_ident, condition)) - var condition_if = _if(make_operator_call("!", vec(condition_ident))) - condition_if->if_statement.then_part = _branch(branching_type::break_stmt()) - backing.statement->code_block.children.add(1, condition_if) - } - ast_node::for_loop(backing) { - if (!is_code_block(backing.body)) { - backing.body = _code_block(backing.body) - add_to_scope("~enclosing_scope", node, backing.body) - } - add_before_in(backing.init, node, parent_chain->top()) - backing.init = null() - // the do_update goes in the block above the for - var update_ident = _ident("do_update", type_ptr(base_type::boolean()), parent_chain->top()) - add_before_in(_declaration(update_ident, _value(str("false"), type_ptr(base_type::boolean()))), - node, parent_chain->top()) - var update_if = _if(update_ident) - add_to_scope("~enclosing_scope", backing.body, update_if) - update_if->if_statement.then_part = _code_block(backing.update) - add_to_scope("~enclosing_scope", update_if, update_if->if_statement.then_part) - backing.update = null() - backing.body->code_block.children.add(0, update_if) - backing.body->code_block.children.add(1, _assign(update_ident, _value(str("true"), type_ptr(base_type::boolean())))) - - var condition = backing.condition - backing.condition = _value(str("true"), type_ptr(base_type::boolean())) - // objects do not coerce to booleans, so it should be ok for this not to be a ref - var condition_ident = _ident("condition_temp", get_ast_type(condition), backing.body) - backing.body->code_block.children.add(2, _declaration(condition_ident, condition)) - var condition_if = _if(make_operator_call("!", vec(condition_ident))) - condition_if->if_statement.then_part = _branch(branching_type::break_stmt()) - backing.body->code_block.children.add(3, condition_if) - } - } - return true - } - run_on_tree(ensure_block_and_munge, empty_pass_second_half(), syntax_ast_pair.second, &visited1) - }) - - // make sure all blockes munged before we move ahead - name_ast_map->for_each(fun(name: str, syntax_ast_pair: pair<*tree,*ast_node>) { - var visit = hash_set<*ast_node>() - var short_check: fun(*ast_node,*stack<*ast_node>,*hash_set<*ast_node>): bool = fun(node: *ast_node, parent_chain: *stack<*ast_node>, visited: *hash_set<*ast_node>): bool { - match(*node) { - ast_node::function(backing) { - if (backing.body_statement && !is_code_block(backing.body_statement)) - error("Bad in short chec") - } - } - return true - } - run_on_tree(short_check, empty_pass_second_half(), syntax_ast_pair.second, &visit) - - // Pass 2 - var short_circut_op: fun(*ast_node,*stack<*ast_node>,*hash_set<*ast_node>): bool = fun(node: *ast_node, parent_chain: *stack<*ast_node>, visited: *hash_set<*ast_node>): bool { - match(*node) { - ast_node::function(backing) { - if (backing.body_statement && !is_code_block(backing.body_statement)) - error("Bad in 2") - } - ast_node::function_call(backing) { - var func_name = str() - if (is_function(backing.func)) { - func_name = backing.func->function.name - if (func_name == "+" || func_name == "-" || func_name == "*" || func_name == "/" - || func_name == "<" || func_name == ">" || func_name == "<=" || func_name == ">=" - || func_name == "==" || func_name == "!=" || func_name == "%" || func_name == "^" - || func_name == "|" || func_name == "&" || func_name == "." || func_name == "->" - || func_name == "." || func_name == "->" || func_name == "[]" || func_name == "++p" || func_name == "--p" - || func_name == "*" || func_name == "&" - ) - return true - } - if (func_name == "||" || func_name == "&&") { - var enclosing_block_idx = parent_chain->index_from_top_satisfying(fun(i: *ast_node): bool return is_code_block(i);) - var short_circuit_result = _ident("short_circut_result", type_ptr(base_type::boolean()), parent_chain->from_top(enclosing_block_idx)) - var short_circuit_declaration = _declaration(short_circuit_result, backing.parameters[0]) - var condition = short_circuit_result - if (func_name == "||") - condition = make_operator_call("!", vec(condition)) - var short_circuit_if = _if(condition) - add_to_scope("~enclosing_scope", parent_chain->from_top(enclosing_block_idx), short_circuit_if) - // how to get proper parent scoping working for this part - short_circuit_if->if_statement.then_part = _code_block(_assign(short_circuit_result, backing.parameters[1])) - add_to_scope("~enclosing_scope", short_circuit_if, short_circuit_if->if_statement.then_part) - add_before_in(short_circuit_declaration, parent_chain->from_top(enclosing_block_idx-1), parent_chain->from_top(enclosing_block_idx)) - add_before_in(short_circuit_if, parent_chain->from_top(enclosing_block_idx-1), parent_chain->from_top(enclosing_block_idx)) - replace_with_in(node, short_circuit_result, parent_chain) - var shorter_tree = stack_from_vector( parent_chain->data.slice(0, parent_chain->size()-enclosing_block_idx)) - run_on_tree_helper(short_circut_op, empty_pass_second_half(), short_circuit_declaration, &shorter_tree, visited) - run_on_tree_helper(short_circut_op, empty_pass_second_half(), short_circuit_if, &shorter_tree, visited) - return false - } - } - } - return true - } - run_on_tree(short_circut_op, empty_pass_second_half(), syntax_ast_pair.second, &visited2) - // Pass 3 - var construct_in_destruct_out = fun(node: *ast_node, parent_chain: *stack<*ast_node>) { - match(*node) { - ast_node::function_call(backing) { - if (is_function(backing.func)) { - var func_name = backing.func->function.name - if (func_name == "+" || func_name == "-" || func_name == "*" || func_name == "/" - || func_name == "<" || func_name == ">" || func_name == "<=" || func_name == ">=" - || func_name == "==" || func_name == "!=" || func_name == "%" || func_name == "^" - || func_name == "|" || func_name == "&" || func_name == "." || func_name == "->" - || func_name == "." || func_name == "->" || func_name == "[]" || func_name == "++p" || func_name == "--p" - || func_name == "*" || func_name == "&" || func_name == "||" || func_name == "&&" - || func_name == "!" - ) - return - } - var enclosing_block_idx = parent_chain->index_from_top_satisfying(is_code_block) - var replace_before: *ast_node - if (enclosing_block_idx > 0) - replace_before = parent_chain->from_top(enclosing_block_idx-1) - else if (enclosing_block_idx == 0) - replace_before = node - else - error("gonna corrupt") - var replace_in = parent_chain->from_top(enclosing_block_idx) - var func_type = get_ast_type(backing.func) - for (var i = 0; i < backing.parameters.size; i++;) { - var param = backing.parameters[i] - var in_function_param_type = null() - // grab type from param itself if we're out of param types (because variadic function) - if (i < func_type->parameter_types.size) - in_function_param_type = func_type->parameter_types[i] - else - in_function_param_type = get_ast_type(param)->clone_without_ref() - var param_type = get_ast_type(param) - if (!in_function_param_type->is_ref && param_type->indirection == 0 && (param_type->is_object() && has_method(param_type->type_def, "copy_construct", vec(param_type->clone_with_indirection(1))))) { - var temp_ident = _ident("temporary_param_boom", param_type->clone_without_ref(), replace_in) - add_to_scope("temporary_param_boom", temp_ident, replace_in) - add_to_scope("~enclosing_scope", replace_in, temp_ident) - var declaration = _declaration(temp_ident, null()) - var copy_in = make_method_call(temp_ident, "copy_construct", vec(make_operator_call("&", vec(param)))) - add_before_in(declaration, replace_before, replace_in) - add_before_in(copy_in, replace_before, replace_in) - backing.parameters[i] = temp_ident - } - } - var func_return_type = func_type->return_type - if (!func_return_type->is_ref && func_return_type->indirection == 0 && func_return_type->is_object()) { - var temp_return = _ident("temporary_return_boomchaka", func_return_type, replace_in) - add_to_scope("temporary_return_boomchaka", temp_return, replace_in) - add_to_scope("~enclosing_scope", replace_in, temp_return) - var declaration = _declaration(temp_return, node) - add_before_in(declaration, replace_before, replace_in) - if (has_method(func_return_type->type_def, "destruct", vec<*type>())) { - add_before_in(_defer(make_method_call(temp_return, "destruct", vec<*ast_node>())), - replace_before, replace_in) - } - replace_with_in(node, temp_return, parent_chain) - } - } - ast_node::function(backing) { - // Because of how iteration is done now, we might touch functions multiple times (binding-like iteration in a DFS) - // To deal with this, we keep a visited set. - if (functions_visited_for_construct_in_destruct_out.contains(node)) - return; - functions_visited_for_construct_in_destruct_out.add(node) - - var order = 0; - backing.parameters.for_each(fun(param: *ast_node) { - var param_type = get_ast_type(param) - if (!param_type->is_ref && param_type->indirection == 0 && (param_type->is_object() && has_method(param_type->type_def, "destruct", vec<*type>()))) { - // the first pass ensures a code_block child - if (!is_code_block(backing.body_statement)) - error("BUT WHY") - backing.body_statement->code_block.children.add(order++, - _defer(make_method_call(param, "destruct", vec<*ast_node>()))) - } - }) - } - ast_node::declaration_statement(backing) { - var ident_type = get_ast_type(backing.identifier) - if (is_translation_unit(parent_chain->top()) || is_type_def(parent_chain->top())) - return; - if (!ident_type->is_ref && ident_type->indirection == 0 && ident_type->is_object()) { - if (backing.expression && has_method(ident_type->type_def, "copy_construct", vec(get_ast_type(backing.expression)->clone_with_increased_indirection()))) { - var temp_cpy_ctst = _ident("temp_declaration_copy_construct", get_ast_type(backing.expression)->clone_without_ref(), parent_chain->top()) - add_to_scope("temp_declaration_copy_construct", temp_cpy_ctst, parent_chain->top()) - add_to_scope("~enclosing_scope", parent_chain->top(), temp_cpy_ctst) - var declaration = _declaration(temp_cpy_ctst, backing.expression) - add_after_in(make_method_call(backing.identifier, "copy_construct", vec(make_operator_call("&", vec(temp_cpy_ctst)))), - node, parent_chain->top()) - // do second so the order's right - add_after_in(declaration, - node, parent_chain->top()) - backing.expression = null() - } - if (has_method(ident_type->type_def, "destruct", vec<*type>())) { - add_after_in(_defer(make_method_call(backing.identifier, "destruct", vec<*ast_node>())), - node, parent_chain->top()) - } - } - if (backing.init_method_call) { - add_after_in(backing.init_method_call, node, parent_chain) - backing.init_method_call = null() - } - } - ast_node::return_statement(backing) { - var block = parent_chain->top() - if (!is_code_block(block)) - error("Isn't block in return statement obj munging") - var return_value = backing.return_value - var enclosing_function = parent_chain->item_from_top_satisfying(is_function) - if (!is_code_block(enclosing_function->function.body_statement)) - error("this would by unusual") - if (return_value) { - if (get_ast_type(enclosing_function)->return_type->is_ref) - return_value = make_operator_call("&", vec(return_value)) - var temp_return = _ident("temp_boom_return", get_ast_type(return_value)->clone_without_ref(), block) - add_to_scope("temp_boom_return", temp_return, block) - add_to_scope("~enclosing_scope", block, temp_return) - var declaration_statement = _declaration(temp_return, null()) - var assign_statement = assign_or_copy_construct_statement(temp_return, return_value) - add_before_in(declaration_statement, node, block) - add_before_in(assign_statement, node, block) - - // dereference so that the real ref can take it back - if (get_ast_type(enclosing_function)->return_type->is_ref) - temp_return = make_operator_call("*", vec(temp_return)) - backing.return_value = temp_return - } - } - } - } - run_on_tree(empty_pass_first_half(), construct_in_destruct_out, syntax_ast_pair.second, &visited3) - }) - var visited4 = hash_set<*ast_node>() - var var_to_obj = map<*ast_node, *ast_node>() - var fun_to_obj = map<*ast_node, *ast_node>() - all_type_defs.for_each(fun(t: *ast_node) { - t->type_def.variables.for_each(fun(v: *ast_node) { - if (is_declaration_statement(v)) { - var_to_obj[v->declaration_statement.identifier] = t - } else { - // is template - v->template.instantiated.for_each(fun(tv: *ast_node) { - var_to_obj[v->declaration_statement.identifier] = t - }) - } - }) - t->type_def.methods.for_each(fun(m: *ast_node) { - if (is_function(m)) { - fun_to_obj[m] = t - } else { - // is template - m->template.instantiated.for_each(fun(tm: *ast_node) { - fun_to_obj[tm] = t - }) - } - }) - }) - fun_to_obj.for_each(fun(method: *ast_node, object: *ast_node) { - var this_type = object->type_def.self_type->clone_with_increased_indirection() - var this_ident = method->function.this_param - method->function.parameters.add(0, this_ident) - add_to_scope("this", this_ident, method) - add_to_scope("~enclosing_scope", method, this_ident) - method->function.type->parameter_types.add(0, this_type) - }) - name_ast_map->for_each(fun(name: str, syntax_ast_pair: pair<*tree,*ast_node>) { - // Pass 4 - var unmethod: fun(*ast_node,*stack<*ast_node>,*hash_set<*ast_node>): bool = fun(node: *ast_node, parent_chain: *stack<*ast_node>, visited: *hash_set<*ast_node>): bool { - match(*node) { - ast_node::function_call(backing) { - // add this to call (including if it's implicit) - if (is_dot_style_method_call(node)) { - var this_ident = backing.func->function_call.parameters[0] - if (backing.func->function_call.func->function.name == ".") - this_ident = make_operator_call("&", vec(this_ident)) - backing.func = backing.func->function_call.parameters[1] - backing.parameters.add(0, this_ident) - } else { - // add this - // don't need to check to see if is implicit because a non implicit one wouldn't be in the map - var enclosing_obj = fun_to_obj.get_with_default(backing.func, null()) - if (enclosing_obj) { - var this_ident = parent_chain->item_from_top_satisfying(fun(i: *ast_node): bool { - return is_function(i) && fun_to_obj.get_with_default(i, null()) == enclosing_obj - })->function.parameters[0] - backing.parameters.add(0, this_ident) - } - } - } - ast_node::identifier(backing) { - // not if this is the declaration - if (!is_declaration_statement(parent_chain->top()) || parent_chain->top()->declaration_statement.identifier != node) { - // needs to make sure this is actually implicit - var enclosing_obj = var_to_obj.get_with_default(node, null()) - if (enclosing_obj && !(is_function_call(parent_chain->top()) && - is_function(parent_chain->top()->function_call.func) && - (parent_chain->top()->function_call.func->function.name == "." || - parent_chain->top()->function_call.func->function.name == "->") && - parent_chain->top()->function_call.parameters[1] == node)) { - var this_ident = parent_chain->item_from_top_satisfying(fun(i: *ast_node): bool { - return is_function(i) && fun_to_obj.get_with_default(i, null()) == enclosing_obj - })->function.parameters[0] - replace_with_in(node, make_operator_call("->", vec(this_ident, node)), parent_chain) - } - } - } - } - return true - } - run_on_tree(unmethod, empty_pass_second_half(), syntax_ast_pair.second, &visited4) - }) -} diff --git a/stdlib/os.krak b/stdlib/os.krak deleted file mode 100644 index aaa5a10..0000000 --- a/stdlib/os.krak +++ /dev/null @@ -1,32 +0,0 @@ -import str:* -import mem:* -import io:* - -fun system(call_string: str):int { - var c_call_string = call_string.toCharArray() - var result = system(c_call_string) - delete(c_call_string) - return result -} -ext fun system(call_string: *char): int -ext fun exit(code: int):void -fun exit() exit(0) - -ext fun popen(command: *char, mode: *char): *void -ext fun pclose(file: *void): int -fun from_system_command(command: str, line_size: int): str { - var command_string = command.toCharArray() - defer delete(command_string) - var p = popen(command_string, "r") - var to_ret = get_line(line_size, p) - pclose(p) - return to_ret -} -fun get_time(): long { return string_to_num(from_system_command(str("date +%s"), 50)); } -fun split(time: long, split_label: *char): long { - var new_time = get_time() - print(str(split_label) + ": ") - println(new_time - time) - return new_time -} - diff --git a/stdlib/parser.krak b/stdlib/parser.krak deleted file mode 100644 index e8b0dcb..0000000 --- a/stdlib/parser.krak +++ /dev/null @@ -1,488 +0,0 @@ -import grammer:* -import symbol:* -import lexer:* -import tree:* -import vec:* -import stack:* -import map:* -import hash_map:* -import util:* -import str:* -import mem:* -import io:* - -obj parser (Object) { - var input: vec - var gram: *grammer - var lex: *lexer - var gss: gss - var to_reduce: stack - var to_shift: stack< pair<*tree, int> > - var SPPFStepNodes: vec< pair<*tree, int> > - var packed_map: map<*tree, bool> - var reduces_to_null_map: map, bool> - - fun construct(grammerIn: *grammer, lexIn: *lexer): *parser { - input.construct() - gram = grammerIn - lex = lexIn - gss.construct() - to_reduce.construct() - to_shift.construct() - SPPFStepNodes.construct() - packed_map.construct() - reduces_to_null_map.construct() - return this - } - // for maybe_construct for containers - fun construct(): *parser { - return construct(null(), null()) - } - fun copy_construct(old: *parser) { - input.copy_construct(&old->input) - gram = old->gram - lex = old->lex - gss.copy_construct(&old->gss) - to_reduce.copy_construct(&old->to_reduce) - to_shift.copy_construct(&old->to_shift) - SPPFStepNodes.copy_construct(&old->SPPFStepNodes) - packed_map.copy_construct(&old->packed_map) - reduces_to_null_map.copy_construct(&old->reduces_to_null_map) - } - fun operator=(old: ref parser) { - destruct() - copy_construct(&old) - } - fun destruct() { - input.destruct() - gss.destruct() - to_reduce.destruct() - to_shift.destruct() - SPPFStepNodes.destruct() - packed_map.destruct() - reduces_to_null_map.destruct() - } - - fun parse_input(inputStr: str, name: str): *tree { - input.clear() - gss.clear() - to_reduce.clear() - to_shift.clear() - SPPFStepNodes.clear() - packed_map.clear() - - // if the zero state contains any reductions for state 0 and eof, then - // it must be reducing to the goal state - if (inputStr == "" && gram->parse_table.get(0, eof_symbol()).contains(action(action_type::reduce(), 0))) { - println("Accept on no input for ") - println(name) - return new>()->construct(null_symbol()) - } - - lex->set_input(inputStr) - var current_symbol.construct(): symbol - for (current_symbol = lex->next(); current_symbol != eof_symbol() && current_symbol != invalid_symbol(); current_symbol = lex->next();) { - if (current_symbol != eof_symbol() && current_symbol != invalid_symbol()) - current_symbol.source = name - input.addEnd(current_symbol) - } - input.addEnd(current_symbol) - if (current_symbol == invalid_symbol()) { - println("**PARSE ERROR**") - println("lexing failed for ") - println(name) - return null>() - } - - var v0 = gss.new_node(0) - gss.add_to_frontier(0, v0) - - var null_symbol_tree = null>() - - gram->parse_table.get(0, input[0]).for_each(fun(act: action) { - if (act.act == action_type::push()) - to_shift.push(make_pair(v0, act.state_or_rule)) - else if (act.act == action_type::reduce() && act.rule_position == 0) { - to_reduce.push(reduction(v0, gram->rules[act.state_or_rule].lhs, 0, null_symbol_tree, null_symbol_tree)) - } - }) - - for (var i = 0; i < input.size; i++;) { - if (gss.frontier_is_empty(i)) { - println("**PARSE ERROR**") - print(i) - print("th frontier is empty in file '") - print(name) - print("' with txt ") - print(input[i].to_string()) - print(" line number: ") - print(find_line(i)) - println() - return null>() - } - SPPFStepNodes.clear() - while (to_reduce.size()) - reducer(i) - shifter(i) - } - var acc_state = gss.frontier_get_acc_state(input.size-1) - if (acc_state) { - return gss.get_edge(acc_state, v0) - } - - println("**PARSE ERROR**") - println("REJECTED") - println("parsing (not lexing) failed AT THE END for ") - println(name) - print(" line number: ") - print(find_line(input.size)) - println("(minus 2?)") - print("' with txt ") - println(input.last().to_string()) - return null>() - } - fun reducer(i: int) { - var curr_reduction = to_reduce.pop() - gss.get_reachable_paths(curr_reduction.from, max(0, curr_reduction.length-1)). - for_each(fun(path: ref vec<*tree>) { - var path_edges = range(path.size-1).map(fun(indx: int): *tree { return gss.get_edge(path[indx], path[indx+1]);}).reverse() - if (curr_reduction.length != 0) { - path_edges.addEnd(curr_reduction.label) - } - var curr_reached = path.last() - // if this is the Goal = a type reduction, then skip the actual reduction part. - // the shift lookup will fail, and likely other things, and this is our accept - // criteria anyway - /*if (curr_reached->data == 0 && curr_reduction.sym == gram.rules[0].lhs)*/ - if (curr_reduction.sym == gram->rules[0].lhs) { - /*println("would accept here")*/ - return; - } - var shift_to = gram->parse_table.get_shift(curr_reached->data, curr_reduction.sym).state_or_rule - var new_label = null>() - if (curr_reduction.length == 0) { - new_label = curr_reduction.nullable_parts - } else { - var reached_frontier = gss.get_containing_frontier(curr_reached) - for (var j = 0; j < SPPFStepNodes.size; j++;) { - if (SPPFStepNodes[j].second == reached_frontier - && SPPFStepNodes[j].first->data == curr_reduction.sym) { - new_label = SPPFStepNodes[j].first - break - } - } - if (!new_label) { - new_label = new>()->construct(curr_reduction.sym) - SPPFStepNodes.addEnd(make_pair(new_label, reached_frontier)) - } - } - var shift_to_node = gss.in_frontier(i, shift_to) - if (shift_to_node) { - if (!gss.has_edge(shift_to_node, curr_reached)) { - gss.add_edge(shift_to_node, curr_reached, new_label) - // do non-null reductions - if (curr_reduction.length) { - gram->parse_table.get(shift_to, input[i]).for_each(fun(act: action) { - if (act.act == action_type::reduce() && act.rule_position != 0) { - var reduce_rule = gram->rules[act.state_or_rule] - to_reduce.push(reduction(curr_reached, reduce_rule.lhs, - act.rule_position, - get_nullable_parts(reduce_rule), - new_label)) - } - }) - } - } - } else { - shift_to_node = gss.new_node(shift_to) - gss.add_to_frontier(i, shift_to_node) - gss.add_edge(shift_to_node, curr_reached, new_label) - gram->parse_table.get(shift_to, input[i]).for_each(fun(act: action) { - if (act.act == action_type::push()) { - to_shift.push(make_pair(shift_to_node, act.state_or_rule)) - } else { - var action_rule = gram->rules[act.state_or_rule] - // tricky tricky tricky. Fully reduces to null is not the same as act.rule_position being 0 - /*if (fully_reduces_to_null(action_rule)) {*/ - if (act.rule_position == 0) { - to_reduce.push(reduction(shift_to_node, action_rule.lhs, 0, - get_nullable_parts(action_rule), - null>() )) - } else if (curr_reduction.length != 0) { - to_reduce.push(reduction(curr_reached, action_rule.lhs, act.rule_position, - get_nullable_parts(action_rule), - new_label )) - } - } - }) - } - if (curr_reduction.length) - add_children(new_label, path_edges, curr_reduction.nullable_parts) - }) - } - fun shifter(i: int) { - if (i >= input.size-1) - return; // darn ambiguity - var next_shifts = stack< pair<*tree, int> >() - var new_label = new>()->construct(input[i]) - while (!to_shift.empty()) { - var shift = to_shift.pop() - var shift_to_node = gss.in_frontier(i+1, shift.second) - if (shift_to_node) { - gss.add_edge(shift_to_node, shift.first, new_label) - gram->parse_table.get_reduces(shift.second, input[i+1]).for_each(fun(action: action) { - var reduce_rule = gram->rules[action.state_or_rule] - if (action.rule_position != 0) { - to_reduce.push(reduction(shift.first, reduce_rule.lhs, action.rule_position, - get_nullable_parts(reduce_rule), - new_label )) - } - }) - } else { - shift_to_node = gss.new_node(shift.second) - gss.add_to_frontier(i+1, shift_to_node) - gss.add_edge(shift_to_node, shift.first, new_label) - gram->parse_table.get(shift.second, input[i+1]).for_each(fun(action: action) { - if (action.act == action_type::push()) { - next_shifts.push(make_pair(shift_to_node, action.state_or_rule)) - } else { - var action_rule = gram->rules[action.state_or_rule] - if (action.rule_position != 0) { - to_reduce.push(reduction(shift.first, action_rule.lhs, action.rule_position, - get_nullable_parts(action_rule), - new_label )) - } else { - to_reduce.push(reduction(shift_to_node, action_rule.lhs, 0, - get_nullable_parts(action_rule), - null>() )) - } - } - }) - } - } - to_shift = next_shifts - } - fun add_children(parent: *tree, children: vec<*tree>, nullable_parts: *tree) { - if (nullable_parts) - children.add(nullable_parts) - if (!belongs_to_family(parent, children)) { - if (parent->children.size == 0) { - parent->children.add_all(children) - } else { - if (!are_packed(parent->children)) { - // ambiguity inner - var sub_parent = new>()->construct(symbol("AmbiguityInner", true)) - set_packed(sub_parent, true) - sub_parent->children.add_all(parent->children) - parent->children.clear() - parent->children.add(sub_parent) - } - // ambiguity outer - var next_sub_parent = new>()->construct(symbol("AmbiguityOuter", true)) - set_packed(next_sub_parent, true) - parent->children.add(next_sub_parent) - next_sub_parent->children.add_all(children) - } - } - } - fun belongs_to_family(node: *tree, nodes: vec<*tree>): bool { - for (var i = 0; i < nodes.size; i++;) { - var contains_one = false - for (var j = 0; j < node->children.size; j++;) { - var child = node->children[j] - if (nodes[i] == child || (nodes[i] && child && *nodes[i] == *child)) { - contains_one = true - break - } - } - if (!contains_one) - return false - } - return true - } - fun are_packed(nodes: vec<*tree>): bool { - return nodes.any_true(fun(it: *tree):bool { return packed_map.contains_key(it) && packed_map[it]; }) - } - fun set_packed(node: *tree, packed: bool) { - packed_map.set(node, packed) - } - fun fully_reduces_to_null(r: ref rule): bool { - return r.position == 0 && reduces_to_null(r) - } - fun reduces_to_null(r: ref rule): bool { - if (!reduces_to_null_map.contains_key(r.rhs)) - reduces_to_null_map[r.rhs] = gram->first_vector(r.rhs).contains(null_symbol()) - return reduces_to_null_map[r.rhs] - } - fun get_nullable_parts(r: ref rule): *tree { - if (reduces_to_null(r)) - return new>()->construct(null_symbol()) - return null>() - } - fun find_line(token_no: int): int { - var line_no = 1 - for (var i = 0; i < token_no; i++;) - for (var j = 0; j < input[i].data.length(); j++;) - if (input[i].data[j] == '\n') - line_no++ - return line_no - } -} - -obj gss (Object) { - var data: vec>> - var edges: hash_map< pair<*tree, *tree>, *tree > - - fun construct(): *gss { - data.construct() - edges.construct() - } - fun copy_construct(old: *gss) { - data.copy_construct(&old->data) - edges.copy_construct(&old->edges) - } - fun destruct() { - clear() - data.destruct() - edges.destruct() - } - fun clear() { - data.for_each(fun(second: ref vec<*tree>) second.for_each(fun(node: *tree) delete(node););) - data.clear() - edges.clear() - } - fun new_node(state: int): *tree { - return new>()->construct(state) - } - fun add_to_frontier(frontier: int, node: *tree) { - while(data.size <= frontier) - data.addEnd(vec<*tree>()) - data[frontier].addEnd(node) - } - fun frontier_is_empty(frontier: int): bool { - return frontier >= data.size || data[frontier].size == 0 - } - fun frontier_get_acc_state(frontier: int): *tree { - // the accepting state is always state 1, for now - return in_frontier(frontier, 1) - } - fun in_frontier(frontier: int, state: int): *tree { - if (frontier >= data.size) - return null>() - for (var i = 0; i < data[frontier].size; i++;) - if (data[frontier][i]->data == state) - return data[frontier][i] - return null>() - } - fun get_edge(start: *tree, end: *tree): *tree { - return edges[make_pair(start, end)] - } - fun has_edge(start: *tree, end: *tree): bool { - // could also look in map, but this is faster... - return start->children.find(end) != -1 - } - fun add_edge(start: *tree, end: *tree, edge: *tree) { - start->children.add(end) - edges.set(make_pair(start,end), edge) - } - fun get_containing_frontier(node: *tree): int { - for (var i = data.size-1; i >= 0; i--;) - if (data[i].contains(node)) - return i - return -1 - } - fun get_reachable_paths(start: *tree, length: int): vec>> { - var paths = vec>>() - var recursive_path_find: fun(*tree, int, vec<*tree>):void = fun(start: *tree, length: int, current_path: vec<*tree>) { - current_path.addEnd(start) - if (!length) { - paths.addEnd(current_path) - return - } - start->children.for_each(fun(child: *tree) { - recursive_path_find(child, length-1, current_path) - }) - } - recursive_path_find(start, length, vec<*tree>()) - return paths - } -} - -fun reduction(f: *tree, s: symbol, l: int, n: *tree, label:*tree): reduction { - var toRet.construct(f,s,l,n,label): reduction - return toRet -} - -obj reduction (Object) { - var from: *tree - var sym: symbol - var length: int - var nullable_parts: *tree - var label: *tree - - fun construct(): *reduction { - from = null>() - sym = invalid_symbol() - length = -1 - nullable_parts = null>() - label = null>() - return this - } - - fun construct(f: *tree, s: symbol, l: int, n: *tree, labelIn:*tree): *reduction { - from = f - sym.copy_construct(&s) - length = l - nullable_parts = n - label = labelIn - return this - } - fun copy_construct(old: *reduction) { - from = old->from - sym.copy_construct(&old->sym) - length = old->length - nullable_parts = old->nullable_parts - label = old->label - } - fun operator=(other: reduction):void { - destruct() - copy_construct(&other) - } - fun destruct() { - sym.destruct() - } -} - -fun syntax_tree_to_dot(root: *tree): str { - var ret = str("digraph Kaken {\n") - var counter = 0 - var node_name_map = map<*tree, str>() - var get_name = fun(node: *tree): str { - if (node_name_map.contains_key(node)) - return node_name_map[node] - var escaped = str("") - node->data.to_string().data.for_each(fun(c: char) { - if (c != '"' && c != '\\') - escaped += c - else if (c == '"') - escaped += "\\\"" - else if (c == '\\') - escaped += "\\\\" - - }) - escaped += to_string(counter++) - node_name_map.set(node, escaped) - return escaped - } - var helper: fun(*tree):void = fun(node: *tree) { - node->children.for_each(fun(child: *tree) { - if (!child) - return; // where on earth does the null come from - ret += str("\"") + get_name(node) + "\" -> \"" + get_name(child) + "\"\n"; - helper(child) - }) - } - if (root) - helper(root) - return ret + "}" -} diff --git a/stdlib/pass_common.krak b/stdlib/pass_common.krak deleted file mode 100644 index bcd6938..0000000 --- a/stdlib/pass_common.krak +++ /dev/null @@ -1,515 +0,0 @@ -import ast_nodes:* -import mem:* -import util:* -import vec:* -import stack:* -import str:* -import hash_set:* - -fun get_first_terminal(source: *tree): *tree { - if (!source) - return null>() - if (source->data.terminal) - return source - if (source->children.size == 0) - return null>() - return get_first_terminal(source->children.first()) -} -fun error(source: *tree, message: *char) error(source, str(message)); -fun error(source: *tree, message: str) { - var first = get_first_terminal(source) - if (first) - error("***error |" + concat_symbol_tree(source) + "| *** " + first->data.source + ": " + first->data.position + " " + message) - error(message) -} -fun method_in_object(method: *ast_node, enclosing_object: *ast_node): bool { - var methods = enclosing_object->type_def.methods - for (var i = 0; i < methods.size; i++;) { - if (methods[i] == method || (is_template(methods[i]) && methods[i]->template.instantiated.contains(method))) { - return true - } - } - return false -} -fun is_dot_style_method_call(node: *ast_node): bool { - return is_function_call(node->function_call.func) && - is_function(node->function_call.func->function_call.func) && - (node->function_call.func->function_call.func->function.name == "->" || node->function_call.func->function_call.func->function.name == ".") && - is_function(node->function_call.func->function_call.parameters[1]) && - (is_type_def(get_ast_scope(node->function_call.func->function_call.parameters[1])->get(str("~enclosing_scope"))[0]) || - // or if it's a templated method (yes, this has gotten uuuuugly) - is_type_def(get_ast_scope(get_ast_scope(node->function_call.func->function_call.parameters[1])->get(str("~enclosing_scope"))[0])->get(str("~enclosing_scope"))[0]) || - // or it's in an adt - is_adt_def(get_ast_scope(node->function_call.func->function_call.parameters[1])->get(str("~enclosing_scope"))[0])) - // should get uglier when we have to figure out if it's just an inside lambda -} -fun function_satisfies_params(node: *ast_node, param_types: vec<*type>): bool { - var func_type = get_ast_type(node) - var func_param_types = func_type->parameter_types - if (!func_type->is_variadic && func_param_types.size != param_types.size) { - var param_string = str() - param_types.for_each(fun(t: *type) param_string += t->to_string() + ", ";) - /*println(str("type sizes don't match ") + param_types.size + " with needed " + param_string)*/ - return false - } else if (param_types.size < func_param_types.size) { - return false - } - // note we iterate over the func_param_types which will stop short if function is variadic - // just like we want - for (var j = 0; j < func_param_types.size; j++;) { - // don't care about references - if (!func_param_types[j]->equality(param_types[j], false)) { - /*println(str("types don't match ") + func_param_types[j]->to_string() + " with needed " + param_types[j]->to_string())*/ - if (func_param_types[j]->to_string() == param_types[j]->to_string()) - error(str("types aren't equal, but their str rep is (and ref doesn't even matter): ") + func_param_types[j]->to_string() + " vs " + param_types[j]->to_string() ) - return false - } - } - return true -} -fun access_expression(left: *ast_node, right: *char): *ast_node return access_expression(left, str(right)) -fun access_expression(left: *ast_node, right: ref str): *ast_node { - var ltype = get_ast_type(left) - if (!ltype->is_object()) - error("Trying to generate an access expression and the left side is not an object") - var ident = identifier_lookup(right, ltype->type_def) - if (!ident) - error("Trying to generate an access expression, can't find right: " + right) - - if (ltype->indirection) - return make_operator_call("->", vec(left, ident)) - return make_operator_call(".", vec(left, ident)) -} -fun function_lookup(name: str, scope: *ast_node, param_types: vec<*type>): *ast_node { - var results = scope_lookup(name, scope) - for (var i = 0; i < results.size; i++;) { - if ((is_function(results[i]) || (is_identifier(results[i]) && get_ast_type(results[i])->is_function())) && function_satisfies_params(results[i], param_types)) { - return results[i] - } - } - return null() -} -fun identifier_lookup(name: ref str, scope: *ast_node): *ast_node { - /*println(str("doing identifier lookup for: ") + name)*/ - var results = scope_lookup(name, scope) - if (!results.size) { - /*println(str("identifier lookup failed for ") + name)*/ - return null() - } - return results[0] -} -fun scope_lookup(name: ref str, scope: *ast_node): vec<*ast_node> { - // println("*****Doing a name lookup for*****") - // println(name) - var results = vec(scope) - name.split("::").for_each(fun(i: str) { - // println(str("based on split, looking up: ") + i) - var next_results = vec<*ast_node>() - results.for_each(fun(s: *ast_node) { - // print("looking in scope: ") - // println(s) - scope_lookup_helper(i, s, set<*ast_node>()).for_each(fun (result: *ast_node) { - if (!next_results.contains(result)) - next_results.add(result) - }) - }) - results = next_results - }) - return results -} -fun scope_lookup_helper(name: ref str, scope: *ast_node, visited: set<*ast_node>): vec<*ast_node> { - // need to do properly scopded lookups - // print("scope is: ") - // get_ast_scope(scope)->for_each(fun(key: str, value: vec<*ast_node>) print(key + " ");) - // println() - var results = vec<*ast_node>() - // prevent re-checking the same one... - if (visited.contains(scope)) - return results - visited.add(scope) - if (get_ast_scope(scope)->contains_key(name)) { - // println(name + " is in scope, adding to results") - results += get_ast_scope(scope)->get(name) - } - if (get_ast_scope(scope)->contains_key(str("~enclosing_scope"))) - results += scope_lookup_helper(name, get_ast_scope(scope)->get(str("~enclosing_scope"))[0], visited) - if (is_translation_unit(scope)) { - scope->translation_unit.children.for_each(fun(child: *ast_node) { - if (is_import(child)) { - if (child->import.imported.contains(name)) { - // println(name + " is indeed imported") - results += scope_lookup_helper(name, child->import.translation_unit, visited) - } else if (child->import.starred) { - // println("import has an import *, checking along it") - results += scope_lookup_helper(name, child->import.translation_unit, visited) - } else { - // println(name + " is not imported (this time)") - // print("import imports") - // child->import.imported.for_each(fun(it: str) print(it + " ");) - } - } - }) - } - return results -} -fun has_method(object: *ast_node, name: *char, parameter_types: vec<*type>): bool return has_method(object, str(name), parameter_types); -fun has_method(object: *ast_node, name: str, parameter_types: vec<*type>): bool { - var to_ret = function_lookup(name, object, parameter_types) || false - return to_ret -} -fun get_from_scope(node: *ast_node, member: *char): *ast_node - return get_from_scope(node, str(member)) -fun get_from_scope(node: *ast_node, member: str): *ast_node { - /*if (get_ast_scope(node)->contains(member))*/ - return get_ast_scope(node)->get(member).first() - /*return null()*/ -} -fun make_method_call(object_ident: *ast_node, name: *char, parameters: vec<*ast_node>): *ast_node return make_method_call(object_ident, str(name), parameters); -fun make_method_call(object_ident: *ast_node, name: str, parameters: vec<*ast_node>): *ast_node { - // note that this type_def is the adt_def if this is an adt type - var method = function_lookup(name, get_ast_type(object_ident)->type_def, parameters.map(fun(param: *ast_node): *type return get_ast_type(param);)) - return make_method_call(object_ident, method, parameters) -} -fun make_method_call(object_ident: *ast_node, method: *ast_node, parameters: vec<*ast_node>): *ast_node { - var access_op = "." - if (get_ast_type(object_ident)->indirection) - access_op = "->" - var method_access = _func_call(get_builtin_function(str(access_op), vec(get_ast_type(object_ident), get_ast_type(method))), vec(object_ident, method)) - return _func_call(method_access, parameters) -} -fun make_operator_call(func: *char, params: vec<*ast_node>): *ast_node return make_operator_call(str(func), params); -fun make_operator_call(func: str, params: vec<*ast_node>): *ast_node { - return _func_call(get_builtin_function(func, params.map(fun(p:*ast_node): *type return get_ast_type(p);)), params) -} -fun get_builtin_function(name: *char, param_types: vec<*type>): *ast_node - return get_builtin_function(str(name), param_types, null>()) -fun get_builtin_function(name: str, param_types: vec<*type>): *ast_node - return get_builtin_function(name, param_types, null>()) -fun get_builtin_function(name: str, param_types: vec<*type>, syntax: *tree): *ast_node { - // none of the builtin functions should take in references - param_types = param_types.map(fun(t: *type): *type return t->clone_without_ref();) - if (name == "==" || name == "!=" || name == ">" || name == "<" || name == "<=" || name == ">" || name == ">=" || name == "&&" || name == "||" || name == "!") - return _function(name, type_ptr(param_types, type_ptr(base_type::boolean()), 0, false, false, true), vec<*ast_node>(), false) - if (name == "." || name == "->") { - if (name == "->" && param_types[0]->indirection == 0) - error(syntax, str("drereferencing not a pointer: ") + name) - else if (name == "." && param_types[0]->indirection != 0) - error(syntax, str("dot operator on a pointer: ") + name) - else - return _function(name, type_ptr(param_types, param_types[1], 0, false, false, true), vec<*ast_node>(), false) - } - if (name == "[]") { - if (param_types[0]->indirection == 0) - error(syntax, str("drereferencing not a pointer: ") + name) - else - return _function(name, type_ptr(param_types, param_types[0]->clone_with_decreased_indirection(), 0, false, false, true), vec<*ast_node>(), false) - } - if (name == "&" && param_types.size == 1) - return _function(name, type_ptr(param_types, param_types[0]->clone_with_increased_indirection(), 0, false, false, true), vec<*ast_node>(), false) - if (name == "*" && param_types.size == 1) { - if (param_types[0]->indirection == 0) - error(syntax, str("drereferencing not a pointer: ") + name) - else - return _function(name, type_ptr(param_types, param_types[0]->clone_with_decreased_indirection(), 0, false, false, true), vec<*ast_node>(), false) - } - if (param_types.size > 1 && param_types[1]->rank() > param_types[0]->rank()) - return _function(name, type_ptr(param_types, param_types[1], 0, false, false, true), vec<*ast_node>(), false) - return _function(name, type_ptr(param_types, param_types[0], 0, false, false, true), vec<*ast_node>(), false) -} -fun possible_object_equality(lvalue: *ast_node, rvalue: *ast_node): *ast_node { - var ltype = get_ast_type(lvalue) - var rtype = get_ast_type(rvalue) - if (ltype->indirection == 0 && (ltype->is_object() && has_method(ltype->type_def, "operator==", vec(rtype)))) { - return make_method_call(lvalue, "operator==", vec(rvalue)) - } else if (ltype->is_object()) - // return false if object but no operator== (right now don't try for templated) - return _value(str("false"), type_ptr(base_type::boolean())) - return make_operator_call("==", vec(lvalue, rvalue)) -} -fun concat_symbol_tree(node: *tree): str { - var str.construct(): str - if (node->data.data != "no_value") - str += node->data.data - node->children.for_each(fun(child: *tree) str += concat_symbol_tree(child);) - return str -} -fun get_node(lookup: *char, parent: *tree): *tree { - return get_node(str(lookup), parent) -} -fun get_node(lookup: str, parent: *tree): *tree { - var results = get_nodes(lookup, parent) - if (results.size > 1) - error(parent, "get node too many results!") - if (results.size) - return results[0] - return null>() -} -fun get_nodes(lookup: *char, parent: *tree): vec<*tree> { - return get_nodes(str(lookup), parent) -} -fun get_nodes(lookup: str, parent: *tree): vec<*tree> { - return parent->children.filter(fun(node: *tree):bool return node->data.name == lookup;) -} -fun add_to_scope(name: *char, to_add: *ast_node, add_to: *ast_node) { - add_to_scope(str(name), to_add, add_to) -} -fun add_to_scope(name: str, to_add: *ast_node, add_to: *ast_node) { - var add_to_map = get_ast_scope(add_to) - if (add_to_map->contains_key(name)) - (*add_to_map)[name].add(to_add) - else - add_to_map->set(name, vec(to_add)) -} -// for now, needs source to already be in a variable for copy_constructing -fun assign_or_copy_construct_statement(lvalue: *ast_node, rvalue: *ast_node): *ast_node { - var ltype = get_ast_type(lvalue) - if (ltype->indirection == 0 && (ltype->is_object() && has_method(ltype->type_def, "copy_construct", vec(ltype->clone_with_increased_indirection())))) - return make_method_call(lvalue, "copy_construct", vec(make_operator_call("&", vec(rvalue)))) - return _assign(lvalue, rvalue) -} - -fun get_children_pointer(node: *ast_node): *vec<*ast_node> { - var bc = null>() - match(*node) { - ast_node::translation_unit(backing) bc = &node->translation_unit.children - ast_node::code_block(backing) bc = &node->code_block.children - } - return bc -} -fun remove(orig: *ast_node, in: *stack<*ast_node>): *ast_node - return remove(orig, in->top()) -fun remove(orig: *ast_node, in: *ast_node): *ast_node { - var bc = get_children_pointer(in) - if (bc) { - var i = bc->find(orig) - if (i >= 0) { - var temp = bc->at(i) - bc->remove(i) - return temp - } - } - error(str("cannot remove inside ") + get_ast_name(in)) -} -fun replace_with_in(orig: *ast_node, new: *ast_node, in: *stack<*ast_node>) - replace_with_in(orig, new, in->top()) -fun replace_with_in(orig: *ast_node, new: *ast_node, in: *ast_node) { - match (*in) { - ast_node::return_statement(backing) { backing.return_value = new; return; } - ast_node::cast(backing) { if (backing.value == orig) { backing.value = new; return; } } - ast_node::assignment_statement(backing) { - if (backing.to == orig) { - backing.to = new - return - } - if (backing.from == orig) { - backing.from = new - return - } - } - ast_node::declaration_statement(backing) { - if (backing.identifier == orig) { - backing.identifier = new - return - } - if (backing.expression == orig) { - backing.expression = new - return - } - } - ast_node::if_statement(backing) { - if (backing.condition == orig) { - backing.condition = new - return - } - if (backing.then_part == orig) { - backing.then_part = new - return - } - if (backing.else_part == orig) { - backing.else_part = new - return - } - } - ast_node::for_loop(backing) { - if (backing.init == orig) { - backing.init = new - return - } - if (backing.condition == orig) { - backing.condition = new - return - } - if (backing.update == orig) { - backing.update = new - return - } - if (backing.body == orig) { - backing.body = new - return - } - } - ast_node::while_loop(backing) { - if (backing.condition == orig) { - backing.condition = new - return - } - if (backing.statement == orig) { - backing.statement = new - return - } - } - ast_node::function(backing) { - if (backing.body_statement == orig) - backing.body_statement = new - return - } - ast_node::function_call(backing) { - if (backing.func == orig) { - backing.func = new - return - } - for (var i = 0; i < backing.parameters.size; i++;) { - if (backing.parameters[i] == orig) { - backing.parameters[i] = new - return - } - } - } - } - - var bc = get_children_pointer(in) - if (bc) { - var i = bc->find(orig) - if (i >= 0) { - bc->set(i, new) - return - } - } - error(str("cannot replace_with_in inside ") + get_ast_name(in)) -} - -fun add_before_in(to_add: ref vec<*ast_node>, before: *ast_node, in: *stack<*ast_node>) - to_add.for_each(fun(n: *ast_node) add_before_in(n, before, in);) -fun add_before_in(to_add: vec<*ast_node>, before: *ast_node, in: *ast_node) - to_add.for_each(fun(n: *ast_node) add_before_in(n, before, in);) - -fun add_before_in(to_add: *ast_node, before: *ast_node, in: *stack<*ast_node>) - add_before_in(to_add, before, in->top()) -fun add_before_in(to_add: *ast_node, before: *ast_node, in: *ast_node) { - var bc = get_children_pointer(in) - if (bc) { - var i = bc->find(before) - if (i >= 0) { - bc->add(i, to_add) - return - } - } - error(str("cannot add_before_in to ") + get_ast_name(in)) -} -fun add_after_in(to_add: *ast_node, before: *ast_node, in: *stack<*ast_node>) - add_after_in(to_add, before, in->top()) -fun add_after_in(to_add: *ast_node, before: *ast_node, in: *ast_node) { - var bc = get_children_pointer(in) - if (bc) { - var i = bc->find(before) - if (i >= 0) { - bc->add(i+1, to_add) - return - } - } - error(str("cannot add_after_in to ") + get_ast_name(in)) -} - -fun empty_pass_first_half(): fun(*ast_node, *stack<*ast_node>, *hash_set<*ast_node>): bool { - return fun(node: *ast_node, parent_chain: *stack<*ast_node>, visited: *hash_set<*ast_node>): bool { return true; } -} -fun empty_pass_second_half(): fun(*ast_node, *stack<*ast_node>): void { - return fun(node: *ast_node, parent_chain: *stack<*ast_node>) {} -} -fun run_on_tree(func_before: fun(*ast_node,*stack<*ast_node>):void, func_after: fun(*ast_node,*stack<*ast_node>):void, tree: *ast_node, visited: *hash_set<*ast_node>) - run_on_tree(fun(n: *ast_node, s: *stack<*ast_node>, v: *hash_set<*ast_node>): bool {func_before(n, s);return true;}, func_after, tree, visited) - -fun run_on_tree(func_before: fun(*ast_node,*stack<*ast_node>,*hash_set<*ast_node>):bool, func_after: fun(*ast_node,*stack<*ast_node>):void, tree: *ast_node, visited: *hash_set<*ast_node>) { - var parent_stack = stack<*ast_node>() - run_on_tree_helper(func_before, func_after, tree, &parent_stack, visited) -} -fun run_on_tree_helper(func_before: fun(*ast_node,*stack<*ast_node>,*hash_set<*ast_node>):bool, - func_after: fun(*ast_node,*stack<*ast_node>):void, - node: *ast_node, parent_chain: *stack<*ast_node>, visited: *hash_set<*ast_node>) { - // So some nodes should be done regardless of weather or not we've visited them - these are the places where a more reasonable AST might use bindings, i.e. variables and functions. - if (!node || (!is_function(node) && !is_identifier(node) && visited->contains(node))) return; - visited->add(node) - var do_children = func_before(node, parent_chain, visited) - parent_chain->push(node) - if (do_children) { - match(*node) { - ast_node::translation_unit(backing) get_ast_children(node).for_each(fun(n: *ast_node) run_on_tree_helper(func_before, func_after, n, parent_chain, visited);) - ast_node::type_def(backing) get_ast_children(node).for_each(fun(n: *ast_node) run_on_tree_helper(func_before, func_after, n, parent_chain, visited);) - ast_node::adt_def(backing) get_ast_children(node).for_each(fun(n: *ast_node) run_on_tree_helper(func_before, func_after, n, parent_chain, visited);) - ast_node::function(backing) get_ast_children(node).for_each(fun(n: *ast_node) run_on_tree_helper(func_before, func_after, n, parent_chain, visited);) - ast_node::template(backing) get_ast_children(node).for_each(fun(n: *ast_node) run_on_tree_helper(func_before, func_after, n, parent_chain, visited);) - ast_node::code_block(backing) get_ast_children(node).for_each(fun(n: *ast_node) run_on_tree_helper(func_before, func_after, n, parent_chain, visited);) - ast_node::if_statement(backing) get_ast_children(node).for_each(fun(n: *ast_node) run_on_tree_helper(func_before, func_after, n, parent_chain, visited);) - ast_node::match_statement(backing) get_ast_children(node).for_each(fun(n: *ast_node) run_on_tree_helper(func_before, func_after, n, parent_chain, visited);) - ast_node::case_statement(backing) get_ast_children(node).for_each(fun(n: *ast_node) run_on_tree_helper(func_before, func_after, n, parent_chain, visited);) - ast_node::while_loop(backing) get_ast_children(node).for_each(fun(n: *ast_node) run_on_tree_helper(func_before, func_after, n, parent_chain, visited);) - ast_node::for_loop(backing) get_ast_children(node).for_each(fun(n: *ast_node) run_on_tree_helper(func_before, func_after, n, parent_chain, visited);) - ast_node::return_statement(backing) get_ast_children(node).for_each(fun(n: *ast_node) run_on_tree_helper(func_before, func_after, n, parent_chain, visited);) - ast_node::defer_statement(backing) get_ast_children(node).for_each(fun(n: *ast_node) run_on_tree_helper(func_before, func_after, n, parent_chain, visited);) - ast_node::assignment_statement(backing) get_ast_children(node).for_each(fun(n: *ast_node) run_on_tree_helper(func_before, func_after, n, parent_chain, visited);) - ast_node::declaration_statement(backing) get_ast_children(node).for_each(fun(n: *ast_node) run_on_tree_helper(func_before, func_after, n, parent_chain, visited);) - ast_node::if_comp(backing) get_ast_children(node).for_each(fun(n: *ast_node) run_on_tree_helper(func_before, func_after, n, parent_chain, visited);) - ast_node::compiler_intrinsic(backing) get_ast_children(node).for_each(fun(n: *ast_node) run_on_tree_helper(func_before, func_after, n, parent_chain, visited);) - ast_node::function_call(backing) { - run_on_tree_helper(func_before, func_after, backing.func, parent_chain, visited) - node->function_call.parameters.for_each(fun(n: *ast_node) run_on_tree_helper(func_before, func_after, n, parent_chain, visited);) - } - ast_node::cast(backing) get_ast_children(node).for_each(fun(n: *ast_node) run_on_tree_helper(func_before, func_after, n, parent_chain, visited);) - } - } - // function may have messed with the parent chain - if (parent_chain->data.contains(node)) - while(parent_chain->pop() != node){} - func_after(node, parent_chain) -} - -fun is_legal_parameter_node_type(n: *ast_node): bool { - match(*n) { - ast_node::translation_unit() return false; - ast_node::import() return false; - ast_node::identifier() return true; - ast_node::type_def() return false; - ast_node::adt_def() return false; - ast_node::function() return true; - ast_node::template() return false; - ast_node::code_block() return false; - ast_node::if_statement() return false; - ast_node::match_statement() return false; - ast_node::case_statement() return false; - ast_node::while_loop() return false; - ast_node::for_loop() return false; - ast_node::return_statement() return false; - ast_node::branching_statement() return false; - ast_node::defer_statement() return false; - ast_node::assignment_statement() return false; - ast_node::declaration_statement() return false; - ast_node::if_comp() return false; - ast_node::simple_passthrough() return false; - ast_node::function_call() return true; - ast_node::compiler_intrinsic() return true; - ast_node::cast() return true; - ast_node::value() return true; - } - error("is_legal_parameter_node_type with no type") -} - -fun get_fully_scoped_name(n: *ast_node): str { - if (!n) - return str("NULL") - var above = str() - var scope_map = get_ast_scope(n); - if (scope_map && scope_map->contains_key(str("~enclosing_scope"))) - above = get_fully_scoped_name(scope_map->get(str("~enclosing_scope"))[0]) - return above + "::" + get_ast_name(n) -} - diff --git a/stdlib/poset.krak b/stdlib/poset.krak deleted file mode 100644 index cc90a1b..0000000 --- a/stdlib/poset.krak +++ /dev/null @@ -1,96 +0,0 @@ -import vec:* -import queue:* -import map:* -import set:* -import util:* - -fun poset(): poset { - var to_ret.construct(): poset - return to_ret -} - -obj poset (Object) { - var open_deps: map> - var close_deps: map> - var done: set - fun construct(): *poset { - open_deps.construct() - close_deps.construct() - done.construct() - return this - } - fun copy_construct(old: *poset) { - open_deps.copy_construct(&old->open_deps) - close_deps.copy_construct(&old->close_deps) - done.copy_construct(&old->done) - } - fun operator=(other: ref poset) { - destruct() - copy_construct(&other) - } - fun destruct() { - open_deps.destruct() - close_deps.destruct() - done.destruct() - } - fun size(): int { - return open_deps.size() - } - fun add_open_dep(first: T, second: T) { - add_job(first) - add_job(second) - open_deps[first].add(second) - // also add all of the closed deps of what we depend on - close_deps[second].for_each(fun(cd: T) { - add_open_dep(first, cd) - }) - } - fun add_close_dep(first: T, second: T) { - add_job(first) - add_job(second) - close_deps[first].add(second) - // patch this one in to everything that currently depends on first - open_deps.for_each(fun(v: T, ods: set) { - if ods.contains(first) { - add_open_dep(v, second) - } - }) - } - fun add_job(vertex: T) { - if (open_deps.contains_key(vertex)) - return; - open_deps.set(vertex, set()) - close_deps.set(vertex, set()) - } - fun done(job: T): bool { - return done.contains(job) - } - fun run(f: fun(T): void) { - done = set() - while done.size() != size() { - var changed = false - // intentionally not refs, as it can change out from under us - open_deps.for_each(fun(v: T, ods: set) { - if !done.contains(v) && done.contains(ods) { - changed = true - f(v) - if done.contains(open_deps[v]) { - done.add(v) - } - } - }) - if (changed == false) { - error("Poset has not changed!") - } - } - } - fun get_sorted(): vec { - var to_ret = vec() - run(fun(i: T) { - to_ret.add(i) - }) - return to_ret - } -} - - diff --git a/stdlib/queue.krak b/stdlib/queue.krak deleted file mode 100644 index 0cc51d3..0000000 --- a/stdlib/queue.krak +++ /dev/null @@ -1,70 +0,0 @@ -import stack -import serialize -import vec - -fun queue() : queue { - var out.construct() : queue - return out -} - -obj queue (Object, Serializable) { - var stack1 : stack::stack - var stack2 : stack::stack - - fun construct(): *queue { - stack1.construct() - stack2.construct() - return this - } - - fun copy_construct(other : *queue) { - stack1.copy_construct(&other->stack1) - stack2.copy_construct(&other->stack2) - } - - fun destruct() { - stack1.destruct() - stack2.destruct() - } - - fun operator=(other : ref queue) { - stack1 = other.stack1 - stack2 = other.stack2 - } - - fun serialize() : vec::vec { - return serialize::serialize(stack1)+serialize::serialize(stack2) - } - - fun unserialize(it : ref vec::vec, pos : int) : int { - pos = stack1.unserialize(it,pos) - pos = stack2.unserialize(it,pos) - return pos - } - - fun push(it : ref T) { - stack1.push(it) - } - - fun pop() : T { - if(stack2.empty()) { - while(!stack1.empty()) { - stack2.push(stack1.pop()) - } - } - return stack2.pop() - } - - fun clear() { - stack1.clear() - stack2.clear() - } - - fun size() : int { - return stack1.size()+stack2.size() - } - - fun empty() : bool { - return ((stack1.size()+stack2.size()) == 0) - } -} diff --git a/stdlib/rc.krak b/stdlib/rc.krak deleted file mode 100644 index 8fb4c19..0000000 --- a/stdlib/rc.krak +++ /dev/null @@ -1,44 +0,0 @@ -import mem:* - -fun rc(in:T):rc { - var to_ret.construct(in): rc - return to_ret -} - -obj rc (Object) { - var inner: *rc_inner - fun construct(): *rc { - inner = null>() - return this - } - fun construct(data: ref T): *rc { - inner = new>() - inner->data.copy_construct(&data) - inner->count = 1 - } - fun copy_construct(old: *rc): void { - inner = old->inner - inner->count++; - } - fun operator=(other: ref rc): void { - if other.inner != inner { - destruct() - copy_construct(&other) - } - } - fun destruct(): void { - inner->count--; - if inner->count == 0 { - inner->data.destruct() - delete(inner) - } - } - fun get(): ref T { - return inner->data - } -} - -obj rc_inner { - var count: int - var data: T -} diff --git a/stdlib/ref_lower.krak b/stdlib/ref_lower.krak deleted file mode 100644 index d584a5b..0000000 --- a/stdlib/ref_lower.krak +++ /dev/null @@ -1,97 +0,0 @@ -import symbol:* -import tree:* -import map:* -import vec:* -import set:* -import hash_set:* -import util:* -import str:* -import mem:* -import io:* -import ast_nodes:* -import ast_transformation:* - -import pass_common:* - -fun has_ref_inside(t: *type): bool { - if (t->is_ref) - return true - if (t->is_function()) { - for (var i = 0; i < t->parameter_types.size; i++;) - if (has_ref_inside(t->parameter_types[i])) - return true - if (has_ref_inside(t->return_type)) - return true - } - return false -} -fun remove_ref(t: *type) { - if (t->is_ref) { - t->is_ref = false - t->indirection++ - } - if (t->is_function()) { - for (var i = 0; i < t->parameter_types.size; i++;) - remove_ref(t->parameter_types[i]) - remove_ref(t->return_type) - } -} - -fun ref_lower(name_ast_map: *map,*ast_node>>, ast_to_syntax: *map<*ast_node, *tree>) { - var remove_ref_type_set = set>() - var modify_reference_use_set = set>() - var modify_return_set = set<*ast_node>() - var visited = hash_set<*ast_node>() - name_ast_map->for_each(fun(name: str, syntax_ast_pair: pair<*tree,*ast_node>) { - var helper_before = fun(node: *ast_node, parent_chain: *stack<*ast_node>) { - match(*node) { - ast_node::identifier(backing) { - if (backing.type->is_ref) - modify_reference_use_set.add(make_pair(node, parent_chain->top())) - if (has_ref_inside(backing.type)) { - remove_ref_type_set.add(make_pair("identifier: " + backing.name, backing.type)) - } - } - ast_node::function(backing) { - var full_name = get_fully_scoped_name(node) + " - (" + backing.name + ")" - if (has_ref_inside(backing.type)) - remove_ref_type_set.add(make_pair(full_name, backing.type)) - } - ast_node::function_call(backing) { - // check to see if it's taking a ref, if so add in the & - var func_type_params = get_ast_type(backing.func)->parameter_types - for (var i = 0; i < func_type_params.size; i++;) - if (func_type_params[i]->is_ref) - backing.parameters[i] = make_operator_call("&", vec(backing.parameters[i])) - // add the function call to the modify_reference_use set if the function returns a ref - if (get_ast_type(backing.func)->return_type->is_ref) - modify_reference_use_set.add(make_pair(node, parent_chain->top())) - } - ast_node::return_statement(backing) { - // check to see if it's returning a ref, if so add in the & - if (parent_chain->item_from_top_satisfying(is_function)->function.type->return_type->is_ref) - modify_return_set.add(node) - } - } - } - run_on_tree(helper_before, empty_pass_second_half(), syntax_ast_pair.second, &visited) - }) - remove_ref_type_set.for_each(fun(p: pair) { - var t = p.second - remove_ref(t) - }) - modify_reference_use_set.for_each(fun(p: pair<*ast_node, *ast_node>) { - // if we haven't modified it's indirection yet - if (is_identifier(p.first) && p.first->identifier.type->is_ref) { - // remove ref, add 1 to indirection - p.first->identifier.type = p.first->identifier.type->clone_with_increased_indirection(1, false); - } - // note that we definitly want to replace the type for unused parameters, but we don't want to add the * for paramters - // in function declarations or the new identifier in declaration statements (but we do for expressions in declaration statements) - if (!is_identifier(p.first) || (!is_function(p.second) && (!is_declaration_statement(p.second) || p.second->declaration_statement.identifier != p.first))) - replace_with_in(p.first, make_operator_call("*", vec(p.first)), p.second); - }) - modify_return_set.for_each(fun(r: *ast_node) { - r->return_statement.return_value = make_operator_call("&", vec(r->return_statement.return_value)); - }) -} diff --git a/stdlib/regex.krak b/stdlib/regex.krak deleted file mode 100644 index 22e0ed9..0000000 --- a/stdlib/regex.krak +++ /dev/null @@ -1,269 +0,0 @@ -import io -import str -import util -import vec -import str -import mem -import set -import util -import serialize - -fun regex(in: *char):regex { - return regex(str::str(in)) -} -fun regex(in: str::str):regex { - var out.construct(in):regex - return out -} -fun regexState(): regexState { - var to_ret.construct(): regexState - return to_ret -} -fun regexState(charIn: char): regexState { - var to_ret.construct(charIn): regexState - return to_ret -} -fun regexState(first: char, last: char): regexState { - var to_ret.construct(first, last): regexState - return to_ret -} -obj regexState (Object) { - // if only one character, both are the same - var characterBegin: char - var characterEnd: char - var next_states: set::set - fun construct(charIn:char): *regexState { - return construct(charIn, charIn) - } - fun construct(charFirst:char, charSecond:char): *regexState { - characterBegin = charFirst - characterEnd = charSecond - next_states.construct() - return this - } - fun construct(): *regexState { - return construct((0) cast char) - } - fun copy_construct(old:*regexState): void { - characterBegin = old->characterBegin - characterEnd = old->characterEnd - next_states.copy_construct(&old->next_states) - } - fun destruct():void { - next_states.destruct() - } - fun match_char(input: char, states: ref vec::vec, flags: *vec::vec, num_states: *int) { - next_states.for_each(fun(it:int) { - if (states[it].characterBegin <= input && input <= states[it].characterEnd) { - (*flags)[it] = true - (*num_states)++ - } - }) - } - fun is_end(states: ref vec::vec):bool { - return next_states.any_true(fun(state: int):bool { return states[state].characterBegin == 1; }) - } -} - -obj regex (Object, Serializable) { - var regexString: str::str - var states: vec::vec - var flagsA: vec::vec - var flagsB: vec::vec - var is_straight_string: bool - - fun construct(): *regex { - regexString.construct() - states.construct() - flagsA.construct() - flagsB.construct() - is_straight_string = false - return this - } - fun construct(regexStringIn: str::str): *regex { - regexString.copy_construct(®exStringIn) - states.construct() - is_straight_string = true - for (var i = 0; i < regexString.length(); i++;) { - // simple implementation doesn't count escaped characters as straight str - if (regexString[i] == '\\' || regexString[i] == '(' || regexString[i] == ')' || regexString[i] == '[' || regexString[i] == '*' || regexString[i] == '+' || regexString[i] == '?' || regexString[i] == '|') { - is_straight_string = false - break - } - } - if (!is_straight_string) { - var beginningAndEnd = compile(regexStringIn) - // init our begin, and the end state as the next state of each end - var end = states.size - states.add(regexState((1) cast char)) - beginningAndEnd.second.for_each(fun(it: int): void { states[it].next_states.add(end); }) - } - flagsA.construct(states.size); flagsA.size = states.size - flagsB.construct(states.size); flagsB.size = states.size - return this - } - - fun copy_construct(old:*regex):void { - regexString.copy_construct(&old->regexString) - is_straight_string = old->is_straight_string - states.copy_construct(&old->states) - flagsA.construct(states.size); flagsA.size = states.size - flagsB.construct(states.size); flagsB.size = states.size - } - - fun destruct():void { - regexString.destruct() - states.destruct() - flagsA.destruct() - flagsB.destruct() - } - fun serialize(): vec::vec { - return serialize::serialize(regexString) - } - fun unserialize(it: ref vec::vec, pos: int): int { - pos = regexString.unserialize(it, pos) - states.construct() - construct(regexString) - flagsA.construct(states.size); flagsA.size = states.size - flagsB.construct(states.size); flagsB.size = states.size - return pos - } - - fun operator==(other: regex):bool { - return regexString == other.regexString - } - - fun operator=(other: regex):void { - destruct() - copy_construct(&other) - } - - fun compile(regex_string: str::str): util::pair> { - /*io::println(regex_string)*/ - var first = states.size; states.add(regexState()) - var previous_begin = set::set() - var previous_end = set::set() - var current_begin = set::set(first) - var current_end = set::set(first) - var alternating = false - var escapeing = false - - for (var i = 0; i < regex_string.length(); i++;) { - if (regex_string[i] == '*' && !escapeing) { - current_end.for_each(fun(item: int) states[item].next_states.add_all(current_begin);) - current_begin.add_all(previous_begin) - current_end.add_all(previous_end) - - } else if (regex_string[i] == '+' && !escapeing) { - current_end.for_each(fun(item: int) states[item].next_states.add_all(current_begin);) - - } else if (regex_string[i] == '?' && !escapeing) { - current_begin.add_all(previous_begin) - current_end.add_all(previous_end) - - } else if (regex_string[i] == '|' && !escapeing) { - alternating = true - } else if (regex_string[i] == '(' && !escapeing) { - // note that we don't have a ')' case, as we skip past it with our indicies - var perenEnd = i + 1 - for (var depth = 1; depth > 0; perenEnd++;) { - if (perenEnd >= regex_string.length()) - util::error(str::str("can't find matching peren in: ") + regex_string) - // be careful, this isn't quite right yet - /*var not_non_special = perenEnd == 0 || (regex_string[perenEnd-1] != '\\' && regex_string[perenEnd-1] != '[' && (perenEnd+1 >= regex_string.length() || regex_string[perenEnd+1] != ']'))*/ - var not_non_special = perenEnd == 0 || (regex_string[perenEnd-1] != '[' && (perenEnd+1 >= regex_string.length() || regex_string[perenEnd+1] != ']')) - if (regex_string[perenEnd] == '(' && not_non_special) - depth++ - else if (regex_string[perenEnd] == ')' && not_non_special) - depth-- - } - var innerBeginEnd = compile(regex_string.slice(i+1, perenEnd-1)) - // NOTE: perenEnd is one past the close peren - i = perenEnd-1 - - if (alternating) { - previous_end.for_each(fun(it: int):void { states[it].next_states.add_all(states[innerBeginEnd.first].next_states); } ) - current_begin.add_all(states[innerBeginEnd.first].next_states) - current_end.add_all(innerBeginEnd.second) - } else { - current_end.for_each(fun(it: int):void { states[it].next_states.add_all(states[innerBeginEnd.first].next_states); } ) - previous_begin = current_begin - previous_end = current_end - current_begin = states[innerBeginEnd.first].next_states - current_end = innerBeginEnd.second - } - alternating = false - - } else if (regex_string[i] == '\\' && !escapeing) { - escapeing = true - } else { - var next: int - if (regex_string[i] == '[' && !escapeing) { - next = states.size; states.add(regexState(regex_string[i+1], regex_string[i+3])) - i += 4 // [a-b] is 5, i++ adds one - } else { - next = states.size; states.add(regexState(regex_string[i])) - } - if (alternating) { - previous_end.for_each(fun(it: int):void { states[it].next_states.add(next); }) - current_begin.add(next) - current_end.add(next) - } else { - current_end.for_each(fun(it: int):void { states[it].next_states.add(next); }) - previous_begin = current_begin - previous_end = current_end - current_begin = set::set(next) - current_end = set::set(next) - } - escapeing = false - alternating = false - } - } - var beginAndEnd = util::make_pair(first, current_end) - return beginAndEnd - } - - fun long_match(to_match: *char): int { return long_match(str::str(to_match)); } - fun long_match(to_match: str::str): int return long_match(to_match.getBackingMemory(), 0, to_match.length()) - fun long_match(to_match: *char, position: int, end: int): int { - if (is_straight_string) { - if (regexString.length() > end-position) - return -1 - for (var i = 0; i < regexString.length(); i++;) - if (regexString[i] != to_match[position+i]) - return -1 - return regexString.length(); - } - for (var i = 1; i < flagsA.size; i++;) - flagsA[i] = false; - flagsA[0] = true - var num_active = 1 - var longest = -1 - var flags = &flagsA - var next_flags = &flagsB - for (var i = 0; i < end-position; i++;) { - if (num_active == 0) - return longest - num_active = 0 - for (var state = 0; state < flags->size; state++;) { - if ((*flags)[state] && states[state].is_end(states)) { - longest = i - break - } - } - for (var j = 0; j < next_flags->size; j++;) - (*next_flags)[j] = false; - for (var state = 0; state < flags->size; state++;) - if ((*flags)[state]) - states[state].match_char(to_match[position+i], states, next_flags, &num_active) - var tmp = flags - flags = next_flags - next_flags = tmp - } - for (var state = 0; state < flags->size; state++;) - if ((*flags)[state] && states[state].is_end(states)) - return end-position - return longest - } -} - diff --git a/stdlib/serialize.krak b/stdlib/serialize.krak deleted file mode 100644 index 58d7708..0000000 --- a/stdlib/serialize.krak +++ /dev/null @@ -1,30 +0,0 @@ -import vec -import mem -import util - -fun serialize(it: T): vec::vec { - return it.serialize() -} - -fun serialize(it: T): vec::vec { - var char_data = (&it) cast *char - var toRet = vec::vec() - for (var i = 0; i < #sizeof; i++;) - toRet.add(char_data[i]) - return toRet -} - -// dead simple wrapper for ease of use -fun unserialize(it: ref vec::vec): T { - return unserialize(it, 0).first -} -fun unserialize(it: ref vec::vec, pos: int): util::pair { - return util::make_pair(*(it.getBackingMemory()+pos) cast *T, pos + (#sizeof) cast int) -} -fun unserialize(it: ref vec::vec, pos: int): util::pair { - var toRet: T - pos = toRet.unserialize(it, pos) - return util::make_pair(toRet, pos) -} - - diff --git a/stdlib/set.krak b/stdlib/set.krak deleted file mode 100644 index f28dea5..0000000 --- a/stdlib/set.krak +++ /dev/null @@ -1,160 +0,0 @@ -import vec -import io -import serialize -import util - -fun set(): set { - var toRet.construct() : set - return toRet -} - -fun set(item: T): set { - var toRet.construct() : set - toRet.add(item) - return toRet -} - -fun from_vector(items: vec::vec): set { - var toRet.construct() : set - items.for_each( fun(item: T) toRet.add(item); ) - return toRet -} - -obj set (Object, Serializable) { - var data: vec::vec - fun construct(): *set { - data.construct() - return this - } - fun construct(ammt: int): *set { - data.construct(ammt) - return this - } - fun copy_construct(old: *set) { - data.copy_construct(&old->data) - } - fun operator=(rhs: ref set) { - data = rhs.data - } - fun serialize(): vec::vec { - return serialize::serialize(data) - } - fun unserialize(it: ref vec::vec, pos: int): int { - return data.unserialize(it, pos) - } - fun operator==(rhs: ref set): bool { - if (size() != rhs.size()) - return false - return !data.any_true( fun(item: T): bool return !rhs.contains(item); ) - } - fun operator!=(rhs: ref set): bool { - return ! (*this == rhs) - } - fun destruct() { - data.destruct() - } - fun size():int { - return data.size - } - fun single(): T { - if (size() != 1) - util::error("trying to single with size != 1") - return data[0] - } - fun contains(items: ref set): bool { - return items.size() == 0 || !items.any_true( fun(item: T): bool return !contains(item); ) - } - fun contains(item: ref T): bool { - return data.find(item) != -1 - } - fun operator+=(item: ref T) { - add(item) - } - fun operator+=(items: ref set) { - add(items) - } - fun operator+(item: ref T): set { - var to_ret.copy_construct(this): set - to_ret.add(item) - return to_ret - } - fun operator+(items: ref set): set { - var to_ret.copy_construct(this): set - to_ret.add(items) - return to_ret - } - fun operator-(items: ref set): set { - var to_ret.copy_construct(this): set - for (var i = 0; i < items.data.size; i++;) - to_ret.remove(items.data[i]) - return to_ret - } - fun add(item: ref T) { - if (!contains(item)) - data.add(item) - } - fun add_all(items: ref set) { - add(items) - } - fun add(items: ref set) { - items.for_each( fun(item: ref T) add(item); ) - } - fun add(items: ref vec::vec) { - items.for_each( fun(item: ref T) add(item); ) - } - fun remove(item: ref T) { - var idx = data.find(item) - if (idx == -1) { - /*io::println("CANNOT FIND ITEM TO REMOVE")*/ - return - } - data.remove(idx) - } - fun for_each(func: fun(ref T):void) { - data.for_each(func) - } - fun for_each(func: fun(T):void) { - data.for_each(func) - } - fun any_true(func: fun(T):bool):bool { - return data.any_true(func) - } - fun reduce(func: fun(T,U): U, initial: U): U { - return data.reduce(func, initial) - } - fun map(func: fun(T):U):set { - var newSet.construct(size()): set - for (var i = 0; i < size(); i++;) - newSet.add(func(data[i])) - return newSet - } - fun flatten_map(func: fun(T):set):set { - var newSet.construct(size()): set - for (var i = 0; i < size(); i++;) - func(data[i]).for_each(fun(item: ref U) newSet.add(item);) - return newSet - } - fun filter(func: fun(T):bool):set { - var newSet.construct(): set - newSet.data = data.filter(func) - return newSet - } - fun chaotic_closure(func: fun(T): set) { - var prev_size = 0 - while (prev_size != data.size) { - prev_size = data.size - for (var i = 0; i < data.size; i++;) - add(func(data[i])) - } - - } - fun pop(): T { - return data.pop() - } - fun union(other: set): set { - for (var i = 0; i < data.size; i++;) - other.add(data[i]) - return other - } -} - diff --git a/stdlib/stack.krak b/stdlib/stack.krak deleted file mode 100644 index 9928639..0000000 --- a/stdlib/stack.krak +++ /dev/null @@ -1,109 +0,0 @@ -import vec -import serialize -import util - -fun stack_from_vector(i: vec::vec): stack { - var to_ret.construct(): stack - to_ret.data = i - return to_ret -} - -fun stack():stack { - var out.construct():stack - return out -} -fun stack(in:T):stack { - var out.construct():stack - out.push(in) - return out -} - -obj stack (Object, Serializable) { - var data: vec::vec - fun construct(): *stack { - data.construct() - return this - } - fun construct(ammt: int): *stack { - data.construct(ammt) - return this - } - fun copy_construct(other: *stack) { - data.copy_construct(&other->data) - } - fun destruct() { - data.destruct() - } - fun operator=(other: ref stack) { - data = other.data - } - fun serialize(): vec::vec { - return serialize::serialize(data) - } - fun unserialize(it: ref vec::vec, pos: int): int { - return data.unserialize(it, pos) - } - fun push(it: ref T) { - data.addEnd(it) - } - fun pop(): T { - var toRet = data[data.size-1] - data.remove(data.size-1) - return toRet - } - fun clear() { - data.clear() - } - fun top(): ref T { - return data[data.size-1] - } - fun from_top(num: int): ref T { - return data[(data.size-1)-num] - } - fun size(): int { - return data.size - } - fun available(): int { - return data.available - } - fun empty():bool { - return data.size == 0 - } - fun for_each(func: fun(ref T):void) { - data.for_each(func) - } - fun for_each(func: fun(T):void) { - data.for_each(func) - } - fun for_each_reverse(func: fun(ref T):void) { - data.for_each_reverse(func) - } - fun for_each_reverse(func: fun(T):void) { - data.for_each_reverse(func) - } - fun reverse_vector(): vec::vec - return data.reverse() - fun index_from_top_satisfying(func_raw: run(T):bool): int { - var temp_lambda = fun(i: T):bool { return func_raw(i); } - return index_from_top_satisfying(temp_lambda); - } - fun index_from_top_satisfying(func: fun(T):bool): int { - for (var i = 0; i < data.size; i++;) - if (func(from_top(i))) - return i - return -1 - } - fun item_from_top_satisfying(func_raw: run(T):bool): T { - var temp_lambda = fun(i: T):bool { return func_raw(i); } - return item_from_top_satisfying(temp_lambda); - } - fun item_from_top_satisfying(func: fun(T):bool): T { - return from_top(index_from_top_satisfying(func)) - } - fun item_from_top_satisfying_or(func: fun(T):bool, other: T): T { - var idx = index_from_top_satisfying(func) - if (idx != -1) - return from_top(idx) - return other - } -} diff --git a/stdlib/str.krak b/stdlib/str.krak deleted file mode 100644 index 5805a18..0000000 --- a/stdlib/str.krak +++ /dev/null @@ -1,337 +0,0 @@ -import vec -import util -import mem -import serialize -import io - -ext fun snprintf(to_str: *char, num: ulong, format: *char, ...): int -fun to_string(in: float): str - return to_string((in) cast double) -fun to_string(in: double): str { - var how_much = snprintf(mem::null(), (0) cast ulong, "%f", in) - var int_str = mem::new(how_much+2) - snprintf(int_str, (how_much+1) cast ulong, "%f", in) - var to_ret = str(int_str) - mem::delete(int_str) - return to_ret -} -fun to_string(in: bool): str - if (in) return str("true") - else return str("false") -fun to_string(in: char): str - return str(in) -fun to_string(in: uchar): str - return to_string_num(in) -fun to_string(in: short): str - return to_string_num(in) -fun to_string(in: ushort): str - return to_string_num(in) -fun to_string(in: int): str - return to_string_num(in) -fun to_string(in: uint): str - return to_string_num(in) -fun to_string(in: long): str - return to_string_num(in) -fun to_string(in: ulong): str - return to_string_num(in) -fun to_string(in: *T): str - return str("ptr:<") + to_string_num((in) cast ulong) + ">" - -/*fun deref_to_string(in: *T): str*/ - /*if (in == mem::null())*/ - /*return str("null")*/ - /*else*/ - /*return to_string(in)*/ - /*return in->to_string()*/ - -fun string_to_num(it: str): T { - var is_negative = false - if (it[0] == '-') { - is_negative = true - it = it.slice(1,-1) - } - var result:T = 0 - var power:T = 1 - while (it.length()) { - result += power * (it.last() - '0') - it = it.slice(0,-2) - power *= 10 - } - if (is_negative) - return -result - return result -} -fun string_to_double(it: str): double { - var parts = it.split('.') - var divisor = 1 - for (var i = 0; i < parts[1].length(); i++;) divisor *= 10 - return string_to_num(parts[0]) + (string_to_num(parts[1])) cast double / divisor -} - -fun to_string_num(in: T): str { - if (in == 0) - return str("0") - var ret = str() - var pos = 0 - var is_neg = false - if (in > 0) { - pos = in - } else { - pos = -in - is_neg = true - } - while (pos) { - ret = str((pos%10 + '0') cast char) + ret - pos = pos / 10 - } - if (is_neg) - return str("-") + ret - return ret -} - -fun operator+(first: *char, second: ref str): str { - return str(first) + second -} -fun operator+(first: int, second: ref str): str { - return to_string(first) + second -} -fun operator*(first: *char, second: int): str { - return str(first) * second -} -fun operator*(first: int, second: *char): str { - return str(second) * first -} -fun operator*(first: int, second: ref str): str { - return second * first -} - -fun str(in:*char):str { - var out.construct(in):str - return out -} -fun str(in:char):str { - var out.construct():str - out += in - return out -} -fun str():str { - return str("") -} - -obj str (Object, Serializable, Hashable) { - var data: vec::vec; - fun construct(): *str { - data.construct(); - return this; - } - fun construct(ammt: int): *str { - data.construct(ammt); - return this; - } - fun construct(str: *char): *str { - var len = 0 - while (str[len] != 0) len++ - data.construct(len); - data.set_size(len); - mem::memmove((data.getBackingMemory()) cast *void, (str) cast *void, (len) cast ulong) - // no null terminator - return this; - } - fun construct(vec: ref vec::vec): *str { - data.copy_construct(&vec); - return this; - } - fun construct(str: ref str): *str { - return construct(str.data); - } - - fun copy_construct(old: *str): void { - data.copy_construct(&old->data) - } - - fun copy_construct(old: **char): void { - construct(*old) - } - - fun hash(): ulong { - var hash: ulong = 7 - for (var i = 0; i < data.size; i++;) - hash = hash*31 + data[i] - return hash - } - - fun operator=(str: *char): void { - destruct(); - construct(str) - } - - fun operator=(str: ref str): void { - data = str.data - } - - fun destruct():void { - data.destruct() - } - - fun serialize(): vec::vec { - return serialize::serialize(data) - } - fun unserialize(it: ref vec::vec, pos: int): int { - return data.unserialize(it, pos) - } - - fun operator[](index: int): ref char { return data[index]; } - fun slice(first: int, second: int): str { - var new.construct(data.slice(first,second)): str - return new - } - fun set(index: int, toSet: char) { - data.set(index, toSet) - } - fun length():int { return data.size; } - - fun operator!=(other: ref str): bool return !(*this ==other) - fun operator!=(other: *char): bool return !(*this==other) - fun operator==(other: ref str): bool { - // you were too good for this world - //return length() == other.length() && !util::range(length()).any_true(fun(i: int):bool { return data[i] != other[i]; } ) - if (data.size != other.data.size) - return false - for (var i = 0; i < data.size; i++;) - if (data.data[i] != other.data.data[i]) - return false - return true - } - fun operator==(other: *char): bool { - var str.construct(other) : str - return *this == str - } - fun operator<=(other: ref str): bool { - var l = 0 - var r = 0 - while (l < length() || r < other.length()) { - if l == length() { - return true - } else if r == other.length() { - return false - } else if (*this)[l] < other[r] { - return true - } else if (*this)[l] > other[r] { - return false - } - l++ - r++ - } - } - fun operator<(other: ref str): bool { - return *this <= other && *this != other - } - - fun operator*(n: int): str { - var to_ret.construct(): str - while (n-- > 0) - to_ret += *this - return to_ret - } - - fun operator+(c: char): str { - var to_ret = *this - to_ret += c - return to_ret - } - fun operator+(integer: int): str return *this + to_string(integer); - fun operator+(integer: long): str return *this + to_string(integer); - fun operator+(integer: ulong): str return *this + to_string(integer); - /*fun operator+(b: bool): str return *this + to_string(b);*/ - - fun operator+(str: *char): str { - var newStr.construct(str):str - var ret.construct(data + newStr.data):str - return ret - } - - fun operator+(str: ref str): str { - var ret.construct(data + str.data):str - return ret - } - - fun operator+=(integer: int) *this += to_string(integer); - fun operator+=(integer: ulong) *this += to_string(integer); - /*fun operator+=(b: bool) *this += to_string(b);*/ - - fun operator+=(character: char): void { - data += character - } - - fun operator+=(str: *char): void { - var newStr.construct(str):str - data += newStr.data - } - - fun operator+=(str: ref str): void { - //var newStr.construct(str):str - //data += newStr.data - data += str.data - } - - fun toCharArray(): *char { - var out: *char = mem::new(data.size+1); - for (var i: int = 0; i < data.size; i++;) - out[i] = data.get(i); - // null terminator - out[data.size] = 0 - return out; - } - fun getBackingMemory(): *char return data.getBackingMemory(); - - fun split(delim: *char): vec::vec return split(str(delim)) - fun split(delim: str): vec::vec { - var out.construct(): vec::vec - var current = str("") - for (var i = 0; i < data.size; i++;) { - if (i < data.size-delim.length() && slice(i, i+delim.length()) == delim) { - out.add(current) - current = str("") - i += delim.length()-1 - } else { - current += data[i] - } - } - out.add(current) - return out - } - fun first(): char return data.first() - fun last(): char return data.last() - fun lines(): vec::vec return split('\n') - fun split(delim: char): vec::vec { - var out.construct(): vec::vec - var current = str("") - for (var i = 0; i < data.size; i++;) { - if (data[i] == delim) { - out.add(current) - current = str("") - } else { - current += data[i] - } - } - out.add(current) - return out - } - fun join(to_join: ref vec::vec): str { - if (to_join.size != 0) { - var to_ret = to_join.first() - for (var i = 1; i < to_join.size; i++;) - to_ret += *this + to_join[i] - return to_ret - } else { - return str("") - } - } - fun for_each(func: fun(char):void) { - data.for_each(func) - } - fun contains(c: char): bool { - return data.contains(c) - } -}; - diff --git a/stdlib/symbol.krak b/stdlib/symbol.krak deleted file mode 100644 index 246a0b1..0000000 --- a/stdlib/symbol.krak +++ /dev/null @@ -1,117 +0,0 @@ -import str -import serialize -import vec -import util - -fun null_symbol(): symbol { - var toRet.construct(str::str("$NULL$"), false, str::str("$NULL$")): symbol - return toRet -} -fun eof_symbol(): symbol { - var toRet.construct(str::str("$EOF$"), false, str::str("$EOF$")): symbol - return toRet -} -fun invalid_symbol(): symbol { - var toRet.construct(str::str("$INVALID$"), false, str::str("$INVALID$")): symbol - return toRet -} - -fun symbol(nameIn: *char, terminalIn: bool): symbol { - var toRet.construct(str::str(nameIn), terminalIn, str::str("no_value")): symbol - return toRet -} - -fun symbol(nameIn: ref str::str, terminalIn: bool): symbol { - var toRet.construct(nameIn, terminalIn, str::str("no_value")): symbol - return toRet -} - -fun symbol(nameIn: *char, terminalIn: bool, dataIn: *char): symbol { - var toRet.construct(str::str(nameIn), terminalIn, str::str(dataIn)): symbol - return toRet -} - -fun symbol(nameIn: ref str::str, terminalIn: bool, dataIn: ref str::str): symbol return symbol(nameIn, terminalIn, dataIn, 0) - -fun symbol(nameIn: ref str::str, terminalIn: bool, dataIn: ref str::str, position: int): symbol { - var toRet.construct(nameIn, terminalIn, dataIn): symbol - toRet.position = position - return toRet -} - -fun to_string(s: ref symbol): str::str { - return s.to_string() -} -obj symbol (Object, Serializable) { - var data: str::str - var name: str::str - var terminal: bool - - var source: str::str - var position: int - - fun construct(): *symbol { - data.construct() - name.construct() - terminal = false - source.construct() - position = 0 - return this - } - fun construct(nameIn: ref str::str, terminalIn: bool, dataIn: ref str::str): *symbol { - name.construct(nameIn) - terminal = terminalIn - data.construct(dataIn) - source.construct() - position = 0 - return this - } - fun destruct() { - data.destruct() - name.destruct() - source.destruct() - } - fun copy_construct(old: *symbol) { - data.copy_construct(&old->data) - name.copy_construct(&old->name) - terminal = old->terminal - source.copy_construct(&old->source) - position = old->position - } - fun operator=(old: ref symbol) { - destruct() - copy_construct(&old) - } - fun serialize(): vec::vec { - return serialize::serialize(data) + serialize::serialize(name) + serialize::serialize(terminal) + serialize::serialize(source) + serialize::serialize(position) - } - fun unserialize(it: ref vec::vec, pos: int): int { - /*construct()*/ - /*util::unpack(data, pos) = serialize::unserialize(it, pos)*/ - /*util::unpack(name, pos) = serialize::unserialize(it, pos)*/ - pos = data.unserialize(it, pos) - pos = name.unserialize(it, pos) - util::unpack(terminal, pos) = serialize::unserialize(it, pos) - pos = source.unserialize(it, pos) - util::unpack(position, pos) = serialize::unserialize(it, pos) - return pos - } - fun equal_wo_data(other: ref symbol): bool { - return name == other.name && terminal == other.terminal; - } - fun operator==(other: ref symbol): bool { - return data == other.data && name == other.name && terminal == other.terminal && source == other.source && position == other.position - } - fun operator!=(other: ref symbol): bool { - return !(*this == other); - } - fun to_string(): str::str { - var terminalString: *char - if (terminal) - terminalString = "true" - else - terminalString = "false" - return name + ": " + data + " " + terminalString + "[" + source + ":" + position + "]" - } -} - diff --git a/stdlib/thread.krak b/stdlib/thread.krak deleted file mode 100644 index 0c81353..0000000 --- a/stdlib/thread.krak +++ /dev/null @@ -1,51 +0,0 @@ -import io:* -import os:* -import mem:* -import util:* - -#link("pthread") -ext fun pthread_attr_init(attr_ptr: *void): int -ext fun pthread_create(thread: *ulong, attr_ptr: *void, func: *void, param: *void): int -ext fun pthread_attr_destroy(attr_ptr: *void): int -ext fun pthread_join(thread: ulong, ret: **void): int - -obj dual_ptrs { var data: *void; var func: *void; } -fun extract_func_ptr(func: T): *void { - return (&func) cast *dual_ptrs -> func -} -fun run(func :fun(T): void, data: T) : *ulong { - var thread = new() - var data_copy = new() - // TODO: figure out why the func type structs aren't the same - // to avoid extra copy etc - var func_copy = new() - var func_and_data = new>()->construct() - maybe_copy_construct(data_copy, &data) - memmove((func_copy) cast *void, (&func) cast *void, #sizeof) - *func_and_data = make_pair((func_copy) cast *void, data_copy) - var wrapper = fun(func_and_data: *void): *void { - var fnd_pair = (func_and_data) cast *pair<*fun(T):void, *T> - (*fnd_pair->first)(*fnd_pair->second) - delete(fnd_pair->first) - delete(fnd_pair->second) - delete(fnd_pair) - return null() - } - // I counted 18 or so word-sized or smaller members (recursively) in the attr struct - var attr = malloc(20*#sizeof<*void>) - pthread_attr_init(attr) - // joinable is default - var ret = pthread_create(thread, attr, extract_func_ptr(wrapper), (func_and_data) cast *void) - // error check ret? - pthread_attr_destroy(attr) - free(attr) - return thread -} - -fun join(thrd : *ulong) : void { - // yep **void null - pthread_join(*thrd, null<*void>()) - // error check join - delete(thrd) -} - diff --git a/stdlib/tree.krak b/stdlib/tree.krak deleted file mode 100644 index e33a289..0000000 --- a/stdlib/tree.krak +++ /dev/null @@ -1,72 +0,0 @@ -import mem -import vec -import io:* -import str:* - -obj tree (Object) { - var data: T - var parent: *tree - var children: vec::vec<*tree> - fun construct(dataIn: ref T): *tree { - mem::maybe_copy_construct(&data, &dataIn) - parent = mem::null>() - children.construct() - return this - } - fun construct(dataIn: ref T, c: ref vec::vec<*tree>): *tree { - mem::maybe_copy_construct(&data, &dataIn) - parent = mem::null>() - children.copy_construct(&c) - children.for_each(fun(i: *tree) { - i->parent = this - }) - return this - } - // Some of these don't really make much sense considering this tree is all about - // heap allocated pointers. Best to have it for saftey, though - fun copy_construct(old: *tree) { - mem::maybe_copy_construct(&data, &old->data) - parent = old->parent - children.copy_construct(&old->children) - } - // ditto - fun operator=(other: tree):void { - destruct() - copy_construct(&other) - } - fun operator==(other: ref tree):bool { - return data == other.data - } - fun destruct() { - mem::maybe_destruct(&data) - children.destruct() - } - fun add_child(c: *tree) { - children.add(c) - c->parent = this - } - fun add_children(c: vec::vec<*tree>) { - for (var i = 0; i < c.size; i++;) { - children.add(c[i]) - c[i]->parent = this - } - } - fun set_child(i: int, c: *tree) { - children[i] = c - c->parent = this - } - fun replace_child(old_c: *tree, new_c: *tree) { - children[children.find(old_c)] = new_c - new_c->parent = this - } - fun remove_child(old_c: *tree) { - children.remove(children.find(old_c)) - } - fun clone(): *tree { - return mem::new>()->construct(data, children.map(fun(c: *tree): *tree return c->clone();)) - } - fun clone(f: fun(ref T): T): *tree { - return mem::new>()->construct(f(data), children.map(fun(c: *tree): *tree return c->clone(f);)) - } -} - diff --git a/stdlib/type.krak b/stdlib/type.krak deleted file mode 100644 index 5ba07c4..0000000 --- a/stdlib/type.krak +++ /dev/null @@ -1,285 +0,0 @@ -import mem:* -import str:* -import vec:* -import set:* -import ast_nodes:* -import io:* - -// hmm, like the ast_node, this is another candadate for being fully an ADT -// one issue is that there are properties shared between most of the options (indirection, say) -adt base_type { - none, - object, - no_type_adt_option, - function, - template, - template_type, - void_return, - boolean, - character, - ucharacter, - short_int, - ushort_int, - integer, - uinteger, - long_int, - ulong_int, - floating, - double_precision -} - -fun type_ptr(): *type { - return new()->construct() -} -fun type_ptr(definition: *ast_node): *type return type_ptr(definition, set()); -fun type_ptr(definition: *ast_node, traits: set): *type { - return new()->construct(definition, traits) -} -fun type_ptr(base: base_type): *type return type_ptr(base, 0, false); -fun type_ptr(base: base_type, indirection: int): *type return type_ptr(base, indirection, false) -fun type_ptr(base: base_type, indirection: int, is_ref: bool): *type { - return new()->construct(base, indirection, is_ref) -} -fun type_ptr(parameters: vec<*type>, return_type: *type, indirection: int, is_ref: bool, is_variadic: bool, is_raw: bool): *type - return new()->construct(parameters, return_type, indirection, is_ref, is_variadic, is_raw) - -fun type_ptr(traits: set): *type { - return new()->construct(traits) -} - -obj type (Object) { - var base: base_type - var parameter_types: vec<*type> - var is_variadic: bool - var is_raw: bool - var return_type: *type - var indirection: int - var type_def: *ast_node - var traits: set - var is_ref: bool - fun construct(): *type { - base.copy_construct(&base_type::none()) - parameter_types.construct() - indirection = 0 - return_type = null() - type_def = null() - traits.construct() - is_ref = false - is_variadic = false - is_raw = false - return this - } - fun construct(traits_in: set): *type { - base.copy_construct(&base_type::template_type()) - parameter_types.construct() - indirection = 0 - return_type = null() - type_def = null() - traits.copy_construct(&traits_in) - is_ref = false - is_variadic = false - is_raw = false - return this - } - fun construct(base_in: base_type, indirection_in: int, is_ref_in: bool): *type { - base.copy_construct(&base_in) - parameter_types.construct() - indirection = indirection_in - return_type = null() - type_def = null() - traits.construct() - is_ref = is_ref_in - is_variadic = false - is_raw = false - return this - } - fun construct(type_def_in: *ast_node, traits_in: set): *type { - base.copy_construct(&base_type::object()) - parameter_types.construct() - indirection = 0 - return_type = null() - type_def = type_def_in - traits.copy_construct(&traits_in) - is_ref = false - is_variadic = false - is_raw = false - return this - } - fun construct(parameter_types_in: vec<*type>, return_type_in: *type, indirection_in: int, is_ref_in: bool, is_variadic_in: bool, is_raw_in: bool): *type { - base.copy_construct(&base_type::function()) - parameter_types.copy_construct(¶meter_types_in) - return_type = return_type_in - indirection = indirection_in - type_def = null() - traits.construct() - is_ref = is_ref_in - is_variadic = is_variadic_in - is_raw = is_raw_in - return this - } - fun copy_construct(old: *type) { - base.copy_construct(&old->base) - parameter_types.copy_construct(&old->parameter_types) - return_type = old->return_type - indirection = old->indirection - type_def = old->type_def - traits.copy_construct(&old->traits) - is_ref = old->is_ref - is_variadic = old->is_variadic - is_raw = old->is_raw - } - fun operator=(other: ref type) { - destruct() - copy_construct(&other) - } - fun destruct() { - base.destruct() - parameter_types.destruct() - traits.destruct() - } - fun operator!=(other: ref type):bool return !equality(other, true); - fun operator==(other: ref type):bool return equality(other, true); - fun equality(other: *type, care_about_ref: bool):bool return equality(*other, care_about_ref); - fun equality(other: ref type, care_about_ref: bool):bool { - if (parameter_types.size != other.parameter_types.size || is_variadic != other.is_variadic || is_raw != other.is_raw) - return false - for (var i = 0; i < parameter_types.size; i++;) - if (!deref_equality(parameter_types[i], other.parameter_types[i])) - return false - if (care_about_ref && (is_ref != other.is_ref)) - return false - return base == other.base && deref_equality(return_type, other.return_type) && - indirection == other.indirection && deref_equality(type_def, other.type_def) && traits == other.traits - } - fun to_string(): str return to_string(true); - fun to_string(include_traits: bool): str { - var trait_string = str() - if (include_traits) { - trait_string = str(":[") - traits.for_each(fun(t: str) trait_string += t;) - trait_string += "] " - } - - var indr_string = str("") - if (is_ref) - indr_string += " ref " - if (is_variadic) - indr_string += " variadic " - if (is_raw) - indr_string += " raw " - for (var i = 0; i < indirection; i++;) indr_string += "*" - match (base) { - base_type::none() return indr_string + str("none") + trait_string - base_type::object() return indr_string + get_ast_name(type_def) + trait_string - base_type::no_type_adt_option() return indr_string + "no_type_adt_option" + trait_string - base_type::template() return indr_string + str("template") + trait_string - base_type::template_type() return indr_string + str("template_type") + trait_string - base_type::void_return() return indr_string + str("void_return") + trait_string - base_type::boolean() return indr_string + str("boolean") + trait_string - base_type::character() return indr_string + str("character") + trait_string - base_type::short_int() return indr_string + str("short") + trait_string - base_type::integer() return indr_string + str("integer") + trait_string - base_type::long_int() return indr_string + str("long") + trait_string - base_type::ucharacter() return indr_string + str("ucharacter") + trait_string - base_type::ushort_int() return indr_string + str("ushort") + trait_string - base_type::uinteger() return indr_string + str("uinteger") + trait_string - base_type::ulong_int() return indr_string + str("ulong") + trait_string - base_type::floating() return indr_string + str("floating") + trait_string - base_type::double_precision() return indr_string + str("double_precision") + trait_string - base_type::function() { - var temp = indr_string + str("fun(") - parameter_types.for_each(fun(parameter_type: *type) temp += parameter_type->to_string() + ", ";) - return temp + ")" + return_type->to_string() + trait_string - } - } - return str("impossible type, indirection:") + indirection - } - fun rank(): int { - if (indirection > 0) - return 5 - match (base) { - base_type::character() return 1 - base_type::ucharacter() return 1 - base_type::short_int() return 2 - base_type::ushort_int() return 2 - base_type::integer() return 3 - base_type::uinteger() return 3 - base_type::long_int() return 4 - base_type::ulong_int() return 4 - base_type::floating() return 5 - base_type::double_precision() return 6 - } - return 0 - } - fun clone(): *type return clone_with_indirection(indirection, is_ref); - fun clone_without_ref(): *type return clone_with_indirection(indirection, false); - fun clone_with_ref(): *type return clone_with_indirection(indirection, true); - fun clone_with_increased_indirection(): *type return clone_with_indirection(indirection+1); - fun clone_with_increased_indirection(more: int, is_ref_in: bool): *type return clone_with_indirection(indirection+more, is_ref_in); - fun clone_with_decreased_indirection(): *type return clone_with_indirection(indirection-1); - fun clone_with_indirection(ind: int): *type return clone_with_indirection(ind, false) - fun clone_with_indirection(ind: int, is_ref_in: bool): *type { - var to_ret = new() - to_ret->copy_construct(this) - to_ret->indirection = ind - to_ret->is_ref = is_ref_in - return to_ret - } - fun is_object(): bool { - match (base) { - base_type::object() return true - } - return false - } - fun is_bool(): bool { - match (base) { - base_type::boolean() return true - } - return false - } - fun is_function(): bool { - match (base) { - base_type::function() return true - } - return false - } - fun is_void(): bool { - match (base) { - base_type::void_return() return true - } - return false - } - fun is_empty_adt_option(): bool { - match (base) { - base_type::no_type_adt_option() return true - } - return false - } - fun is_none(): bool { - match (base) { - base_type::none() return true - } - return false - } - fun is_template_type(): bool { - match (base) { - base_type::template_type() return true - } - return false - } - fun is_signed_type(): bool { - match (base) { - base_type::character() return true - base_type::short_int() return true - base_type::integer() return true - base_type::long_int() return true - - base_type::ucharacter() return false - base_type::ushort_int() return false - base_type::uinteger() return false - base_type::ulong_int() return false - } - return false - } -} - diff --git a/stdlib/type2.krak b/stdlib/type2.krak deleted file mode 100644 index e9e2b99..0000000 --- a/stdlib/type2.krak +++ /dev/null @@ -1,335 +0,0 @@ -import mem:* -import str:* -import vec:* -import util:* -import tree:* -import ast:* -import binding:* - -adt ref_type { - _unknown, - _ref, - _notref -} -fun to_string(r: ref_type): str { - match (r) { - ref_type::_unknown() return str("_ref/unknown") - ref_type::_ref() return str("_ref/ref") - ref_type::_notref() return str("_ref/notref") - } -} - -adt type { - _unknown, - _void, - _template_placeholder, - _ptr: *binding, - _obj: *tree, - // triple>, pair>, is_variadic, is raw> - _fun: triple>>, pair>>, bool, bool>, - _bool, - _char, - _uchar, - _short, - _ushort, - _int, - _uint, - _long, - _ulong, - _float, - _double -} - -fun has_unknown(t: *binding, epoch: binding_epoch): bool { - match (*t->get_bound_to(epoch)) { - type::_unknown() return true - type::_ptr(p) return has_unknown(p, epoch) - type::_obj(o) return o->data._binding.second.any_true(fun(inner_t: *binding): bool return has_unknown(inner_t, epoch);) - type::_fun(f) return has_unknown(f.first.second.second, epoch) || f.first.first.any_true(fun(p: pair>): bool return has_unknown(p.second, epoch);) - } - return false -} - -fun unify(t1: *binding, t2: *binding, epoch: binding_epoch) { - println("attempting to unify " + to_string(t1->get_bound_to(epoch)) + " and " + to_string(t2->get_bound_to(epoch))) - if (is_unknown(t1->get_bound_to(epoch))) { - t1->set(t2->get_bound_to(epoch), epoch) - } else if (is_unknown(t2->get_bound_to(epoch))) { - t2->set(t1->get_bound_to(epoch), epoch) - } else { - if (shallow_equality(t1->get_bound_to(epoch), t2->get_bound_to(epoch), epoch)) { - if (is_fun(t1->get_bound_to(epoch))) { - unify(t1->get_bound_to(epoch)->_fun.first.second.second, t2->get_bound_to(epoch)->_fun.first.second.second, epoch) - // unify ref_types - if (t1->get_bound_to(epoch)->_fun.first.second.first == ref_type::_unknown()) - t1->get_bound_to(epoch)->_fun.first.second.first = t2->get_bound_to(epoch)->_fun.first.second.first - if (t2->get_bound_to(epoch)->_fun.first.second.first == ref_type::_unknown()) - t2->get_bound_to(epoch)->_fun.first.second.first = t1->get_bound_to(epoch)->_fun.first.second.first - // might be veradic... - for (var i = 0; i < t1->get_bound_to(epoch)->_fun.first.first.size && i < t2->get_bound_to(epoch)->_fun.first.first.size; i++;) { - unify(t1->get_bound_to(epoch)->_fun.first.first[i].second, t2->get_bound_to(epoch)->_fun.first.first[i].second, epoch) - if (t1->get_bound_to(epoch)->_fun.first.first[i].first == ref_type::_unknown()) - t1->get_bound_to(epoch)->_fun.first.first[i].first = t2->get_bound_to(epoch)->_fun.first.first[i].first - if (t2->get_bound_to(epoch)->_fun.first.first[i].first == ref_type::_unknown()) - t2->get_bound_to(epoch)->_fun.first.first[i].first = t1->get_bound_to(epoch)->_fun.first.first[i].first - } - } else if (is_ptr(t1->get_bound_to(epoch))) { - unify(t1->get_bound_to(epoch)->_ptr, t2->get_bound_to(epoch)->_ptr, epoch) - } else if (is_obj(t1->get_bound_to(epoch))) { - for (var i = 0; i < t1->get_bound_to(epoch)->_obj->data._binding.second.size; i++;) { - unify(t1->get_bound_to(epoch)->_obj->data._binding.second[i], t2->get_bound_to(epoch)->_obj->data._binding.second[i], epoch) - } - } - } else { - error("Doesn't typecheck! Attempted to unify " + to_string(t1->get_bound_to(epoch)) + " and " + to_string(t2->get_bound_to(epoch))) - } - } -} -fun shallow_equality(a: *type, b: *type, epoch: binding_epoch):bool { - if (is_ptr(a) != is_ptr(b)) - return false - if (is_ptr(a) && is_ptr(b)) - return true - match(*a) { - type::_fun(x) { - return is_fun(b) && a->_fun.third == b->_fun.third - } - type::_obj(x) { - return is_obj(b) && (get_ast_binding(x, epoch) == get_ast_binding(b->_obj, epoch) || ((!ast_bound(x) || !ast_bound(b->_obj)) - && x->data._binding.second.size == b->_obj->data._binding.second.size - && x->data._binding.first == b->_obj->data._binding.first)) - } - } - return *a == *b -} - -fun inst_temp_type(t: *binding, replacements: ref map<*binding, *binding>, read_epoch: binding_epoch, write_epoch: binding_epoch): *binding { - match (*t->get_bound_to(read_epoch)) { - type::_unknown() error("Unknown in temp type") - type::_obj(o) { - var binding_types = o->data._binding.second.map(fun(b: *binding): *binding return inst_temp_type(b, replacements, read_epoch, write_epoch);) - for (var i = 0; i < o->data._binding.second.size; i++;) { - if (o->data._binding.second[i] != binding_types[i]) - return binding_p(type::_obj(_binding(o->data._binding.first, binding_types, o->data._binding.third)), write_epoch) - } - } - type::_ptr(p) { - var cp = inst_temp_type(p, replacements, read_epoch, write_epoch) - if (cp == p) - return t - else - return binding_p(type::_ptr(cp), write_epoch) - } - type::_fun(b) { - // triple, is_variadic, is raw> - var rt = make_pair(b.first.second.first, inst_temp_type(b.first.second.second, replacements, read_epoch, write_epoch)) - var pts = b.first.first.map(fun(pt: pair>): pair> return make_pair(pt.first, inst_temp_type(pt.second, replacements, read_epoch, write_epoch));) - if (rt.second != b.first.second.second) - return binding_p(type::_fun(make_triple(make_pair(pts, rt), b.second, b.third)), write_epoch) - for (var i = 0; i < pts.size; i++;) - if (pts[i].second != b.first.first[i].second) - return binding_p(type::_fun(make_triple(make_pair(pts, rt), b.second, b.third)), write_epoch) - return t - } - type::_template_placeholder() return replacements[t] - } - return t -} - -fun equality(a: *type, b: *type, count_unknown_as_equal: bool, epoch: binding_epoch): bool { - /*println("equality of " + to_string(a) + " and " + to_string(b))*/ - if (count_unknown_as_equal && (is_unknown(a) || is_unknown(b))) - return true - match(*a) { - type::_obj(x) { - if (!is_obj(b)) - return false - if (get_ast_binding(x, epoch) == get_ast_binding(b->_obj, epoch)) - return true - if (!count_unknown_as_equal || (ast_bound(x) && ast_bound(b->_obj)) || x->data._binding.first != b->_obj->data._binding.first || x->data._binding.second.size != b->_obj->data._binding.second.size) - return false - for (var i = 0; i < x->data._binding.second.size; i++;) { - if (!equality(x->data._binding.second[i]->get_bound_to(epoch), b->_obj->data._binding.second[i]->get_bound_to(epoch), count_unknown_as_equal, epoch)) - return false - } - return true - } - type::_ptr(p) { - if (!is_ptr(b)) - return false - return equality(p->get_bound_to(epoch), b->_ptr->get_bound_to(epoch), count_unknown_as_equal, epoch) - } - type::_fun(i) { - if ( !(is_fun(b) && a->_fun.second == b->_fun.second && a->_fun.third == b->_fun.third) ) - return false - if ( !equality(a->_fun.first.second.second->get_bound_to(epoch), b->_fun.first.second.second->get_bound_to(epoch), count_unknown_as_equal, epoch) ) - return false - if ( !(a->_fun.first.first.size == b->_fun.first.first.size) ) - return false - for (var i = 0; i < a->_fun.first.first.size; i++;) - if ( !equality(a->_fun.first.first[i].second->get_bound_to(epoch), b->_fun.first.first[i].second->get_bound_to(epoch), count_unknown_as_equal, epoch) ) - return false - return true - } - } - return *a == *b -} -fun deref_to_string(in: *T): str - if (in == mem::null()) - return str("null") - else - return to_string(in) -fun to_string(it: *type): str { - match (*it) { - type::_unknown() return str("_unknown") - type::_void() return str("_void") - type::_ptr(p) return "*(pre_ref:" + deref_to_string(p->get_bound_to(binding_epoch::pre_ref())) + "/post_ref" + deref_to_string(p->get_bound_to(binding_epoch::post_ref())) + ")" - type::_obj(b) { - return "_obj(" + to_string(b->data) + ")" - } - type::_fun(b) { - // triple, is_variadic, is raw> - var to_ret = str() - if (b.second) - to_ret += "_run(" - else - to_ret += "_fun(" - to_ret += str(", ").join(b.first.first.map(fun(pt: pair>): str return to_string(pt.first) + "(pre_ref:" + deref_to_string(pt.second->get_bound_to(binding_epoch::pre_ref())) + "/post_ref" + deref_to_string(pt.second->get_bound_to(binding_epoch::post_ref())) + ")";)) - if (b.third) - to_ret += " ..." - return to_ret + "): " + to_string(b.first.second.first) + ": (pre_ref:" + deref_to_string(b.first.second.second->get_bound_to(binding_epoch::pre_ref())) + "/post_ref:" + deref_to_string(b.first.second.second->get_bound_to(binding_epoch::post_ref())) + ")" - } - type::_template_placeholder() return str("_template_placeholder") - type::_bool() return str("_bool") - type::_char() return str("_char") - type::_uchar() return str("_uchar") - type::_short() return str("_short") - type::_ushort() return str("_ushort") - type::_int() return str("_int") - type::_uint() return str("_uint") - type::_long() return str("_long") - type::_ulong() return str("_ulong") - type::_float() return str("_float") - type::_double() return str("_double") - } - return str("impossible type") -} -fun is_unknown(x: *type): bool { - match (*x) { - type::_unknown() return true - } - return false -} -fun is_void(x: *type): bool { - match (*x) { - type::_void() return true - } - return false -} -fun is_ptr(x: *type): bool { - match (*x) { - type::_ptr(p) return true - } - return false -} -fun is_obj(x: *type): bool { - match (*x) { - type::_obj() return true - } - return false -} -fun is_fun(x: *type): bool { - match (*x) { - type::_fun(b) return true - } - return false -} -fun is_template_placeholder(x: *type): bool { - match (*x) { - type::_template_placeholder() return true - } - return false -} -fun is_bool(x: *type): bool { - match (*x) { - type::_bool() return true - } - return false -} -fun is_char(x: *type): bool { - match (*x) { - type::_char() return true - } - return false -} -fun is_uchar(x: *type): bool { - match (*x) { - type::_uchar() return true - } - return false -} -fun is_short(x: *type): bool { - match (*x) { - type::_short() return true - } - return false -} -fun is_ushort(x: *type): bool { - match (*x) { - type::_ushort() return true - } - return false -} -fun is_int(x: *type): bool { - match (*x) { - type::_int() return true - } - return false -} -fun is_uint(x: *type): bool { - match (*x) { - type::_uint() return true - } - return false -} -fun is_long(x: *type): bool { - match (*x) { - type::_long() return true - } - return false -} -fun is_ulong(x: *type): bool { - match (*x) { - type::_ulong() return true - } - return false -} -fun is_float(x: *type): bool { - match (*x) { - type::_float() return true - } - return false -} -fun is_double(x: *type): bool { - match (*x) { - type::_double() return true - } - return false -} -fun is_signed(x: *type): bool { - match (*x) { - type::_char() return true - type::_int() return true - type::_long() return true - type::_short() return true - type::_float() return true - type::_double() return true - - type::_uchar() return false - type::_ushort() return false - type::_uint() return false - type::_ulong() return false - } - return false -} - diff --git a/stdlib/util.krak b/stdlib/util.krak deleted file mode 100644 index 2933f97..0000000 --- a/stdlib/util.krak +++ /dev/null @@ -1,276 +0,0 @@ -import mem -import io -import os -import str -import set -import map -import vec -import serialize - - -// maybe my favorite function -fun do_nothing() {} - -fun is_object(): bool return false -fun is_object(): bool return true - -fun error(message: *char) error(str::str(message)); -fun error(message: str::str) { - io::printlnerr("****ERROR****") - io::printlnerr(message) - os::exit(-1) -} -fun assert(works: bool, message: *char) { - if (!works) - error(message) -} -fun assert(works: bool, message: str::str) { - if (!works) - error(message) -} - -fun deref_equality(a: *T, b: *T): bool { - if ( (a && b && !(*a == *b)) || (a && !b) || (!a && b) ) - return false - return true -} - -fun max(a: T, b: T): T { - if (a > b) - return a; - return b; -} - -fun min(a: T, b: T): T { - if (a > b) - return b; - return a; -} - -fun hash(item: T): ulong return item.hash() -fun hash(item: *T): ulong return (item) cast ulong -fun hash(item: char): ulong return (item) cast ulong -fun hash(item: uchar): ulong return (item) cast ulong -fun hash(item: short): ulong return (item) cast ulong -fun hash(item: ushort): ulong return (item) cast ulong -fun hash(item: int): ulong return (item) cast ulong -fun hash(item: uint): ulong return (item) cast ulong -fun hash(item: long): ulong return (item) cast ulong -fun hash(item: ulong): ulong return (item) cast ulong - -// default hash -fun hash(item: T): ulong { - io::println("using empty hash - please do not do!") - return (0) cast ulong -} - -fun make_pair(first: T, second: U): pair { - var it.construct(first, second): pair - return it -} - -// little ugly, but it works -fun unpack(first: ref T, second: ref U): unpack_dummy_pair { - var toRet: unpack_dummy_pair - toRet.first = &first - toRet.second = &second - return toRet -} -obj unpack_dummy_pair { - var first: *T - var second: *U - fun operator=(p: ref pair) { - *first = p.first - *second = p.second - } -} - -obj pair (Object, Serializable, Hashable) { - var first: T - var second: U - - fun construct(firstIn: ref T, secondIn: ref U): *pair { - mem::maybe_copy_construct(&first, &firstIn) - mem::maybe_copy_construct(&second, &secondIn) - return this - } - - fun construct(): *pair { - mem::maybe_construct(&first) - mem::maybe_construct(&second) - return this - } - - fun copy_construct(old: *pair):void { - mem::maybe_copy_construct(&first, &old->first) - mem::maybe_copy_construct(&second, &old->second) - } - - fun destruct():void { - mem::maybe_destruct(&first) - mem::maybe_destruct(&second) - } - fun serialize(): vec::vec { - return serialize::serialize(first) + serialize::serialize(second) - } - fun unserialize(it: ref vec::vec, pos: int): int { - // can't use unpack :( (b/c we can't make an already constructed empty one) - var first_pair = serialize::unserialize(it, pos) - var second_pair = serialize::unserialize(it, first_pair.second) - mem::maybe_copy_construct(&first, &first_pair.first) - mem::maybe_copy_construct(&second, &second_pair.first) - return second_pair.second - } - - fun hash():ulong return hash(first) ^ hash(second) - - // the old unnecessary template to prevent generation - // if not used trick (in this case, changing out U with V) - fun operator==(other: ref pair): bool { - return first == other.first && second == other.second - } -} - -fun make_triple(first: T, second: U, third: V): triple { - var it.construct(first, second, third): triple - return it -} - -// little ugly, but it works -fun unpack(first: ref T, second: ref U, third: ref V): unpack_dummy_triple { - var toRet: unpack_dummy_triple - toRet.first = &first - toRet.second = &second - toRet.third = &third - return toRet -} -obj unpack_dummy_triple { - var first: *T - var second: *U - var third: *V - fun operator=(p: ref triple) { - *first = p.first - *second = p.second - *third = p.third - } -} - -obj triple (Object, Serializable, Hashable) { - var first: T - var second: U - var third: V - - fun construct(firstIn: ref T, secondIn: ref U, thirdIn: ref V): *triple { - mem::maybe_copy_construct(&first, &firstIn) - mem::maybe_copy_construct(&second, &secondIn) - mem::maybe_copy_construct(&third, &thirdIn) - return this - } - - fun construct(): *triple { - mem::maybe_construct(&first) - mem::maybe_construct(&second) - mem::maybe_construct(&third) - return this - } - - fun copy_construct(old: *triple):void { - mem::maybe_copy_construct(&first, &old->first) - mem::maybe_copy_construct(&second, &old->second) - mem::maybe_copy_construct(&third, &old->third) - } - - fun destruct():void { - mem::maybe_destruct(&first) - mem::maybe_destruct(&second) - mem::maybe_destruct(&third) - } - fun serialize(): vec::vec { - return serialize::serialize(first) + serialize::serialize(second) + serialize::serialize(third) - } - fun unserialize(it: ref vec::vec, pos: int): int { - // can't use unpack :( (b/c we can't make an already constructed empty one) - var first_pair = serialize::unserialize(it, pos) - var second_pair = serialize::unserialize(it, first_pair.second) - var third_pair = serialize::unserialize(it, second_pair.second) - mem::maybe_copy_construct(&first, &first_pair.first) - mem::maybe_copy_construct(&second, &second_pair.first) - mem::maybe_copy_construct(&third, &third_pair.first) - return third_pair.second - } - - fun hash():ulong return hash(first) ^ hash(second) ^ hash(third) - - // the old unnecessary template to prevent generation - // if not used trick (in this case, changing out V with X) - fun operator==(other: ref triple): bool { - return first == other.first && second == other.second && third == other.third - } -} - -fun range(end:int): range { - var toRet.construct(0, end, 1): range - return toRet -} - -fun range(begin: int, end:int): range { - var toRet.construct(begin, end, 1): range - return toRet -} -fun range(begin: int, end:int, step: int): range { - var toRet.construct(begin, end, step): range - return toRet -} - -obj range { - var begin: int - var end: int - var step: int - fun construct(beginIn: int, endIn: int, stepIn: int) : *range { - begin = beginIn - end = endIn - step = stepIn - } - fun for_each(func: fun(int):void):void { - for (var i = begin; i < end; i+= step;) - func(i) - } - fun map(func: fun(int): T): vec::vec { - var ret.construct( (end-begin)/step + 1 ) : vec::vec - for (var i = begin; i < end; i+= step;) - ret.addEnd(func(i)) - return ret - } - fun any_true(func: fun(int):bool):bool { - for (var i = begin; i < end; i+= step;) - if (func(i)) - return true - return false - } -} - -// a function that allows the safe deletion of recursive and complicated data structures -fun safe_recursive_delete(first: *T, addingFunc: fun(*T): set::set<*T>) { - var toDelete = set::set<*T>() - var next = set::set(first) - while (toDelete != next) { - toDelete = next - toDelete.for_each( fun(it: *T) next.add(addingFunc(it)); ) - } - toDelete.for_each( fun(it: *T) mem::delete(it); ) -} - -// a function that allows the safe cloning of recursive and complicated data structures -// cloneing func is the func that does the cloning, it takes in a recursive clone function and -// a register clone function -fun safe_recursive_clone(first: *T, cloningFunc: fun(*T, fun(*T):*T, fun(*T):void): void): *T { - var rec_map = map::map<*T,*T>() - // can't do type infrence if you need the type inside the expression... - var rec_it: fun(*T):*T = fun(it: *T): *T { - if (!rec_map.contains_key(it)) - cloningFunc(it, rec_it, fun(cloned: *T) { rec_map[it] = cloned; }) - return rec_map[it] - } - return rec_it(first) -} - diff --git a/stdlib/vec.krak b/stdlib/vec.krak deleted file mode 100644 index a14e866..0000000 --- a/stdlib/vec.krak +++ /dev/null @@ -1,403 +0,0 @@ -import mem:*; -import util:*; -import io:*; -import serialize:*; -import util:*; -import map:*; - -fun vec():vec { - var out.construct():vec - return out -} - -fun vec(in:T):vec { - var out.construct():vec - out.add(in) - return out -} - -obj vec (Object, Serializable) { - var data: *T; - var size: int; - var available: int; - - fun construct(): *vec { - size = 0; - available = 8; - data = new(8); - return this; - } - fun construct(ammt: int): *vec { - size = 0; - available = ammt; - data = new(ammt); - return this; - } - - fun copy_construct(old: *vec): void { - construct(old->available) - size = old->size - if (is_object()) { - for (var i = 0; i < old->size; i++;) - maybe_copy_construct(&data[i], &old->data[i]); - } else { - memmove((data) cast *void, (old->data) cast *void, size * #sizeof) - } - } - fun swap(other: ref vec) { - var temp_data = data - var temp_size = size - var temp_available = available - data = other.data - size = other.size - available = other.available - other.data = temp_data - other.size = temp_size - other.available = temp_available - } - fun serialize(): vec { - var toRet = serialize(size) - for (var i = 0; i < size; i++;) - toRet += serialize(data[i]) - return toRet - } - fun unserialize(it: ref vec, pos: int): int { - unpack(size, pos) = unserialize(it, pos) - data = new(size) - available = size - for (var i = 0; i < size; i++;) { - var curr = unserialize(it, pos) - pos = curr.second - maybe_copy_construct(&data[i], &curr.first); - } - return pos - } - - fun destruct(): void { - if (data) - delete(data, size); - //data = 1337 - data = 0 - } - - fun set_size(s: int) { - size = s - } - - fun operator=(other:ref vec):void { - if (size < other.size) { - destruct() - copy_construct(&other) - } else { - clear() - if (is_object()) { - for (var i = 0; i < other.size; i++;) - addEnd(other.get(i)) - } else { - size = other.size - memmove((data) cast *void, (other.data) cast *void, size * #sizeof) - } - } - } - - fun operator+(other: ref vec):vec { - var newVec.construct(size+other.size):vec - for (var i = 0; i < size; i++;) - newVec.addEnd(get(i)) - for (var i = 0; i < other.size; i++;) - newVec.addEnd(other.get(i)) - return newVec - } - fun operator+(other: ref T):vec { - var newVec.copy_construct(this):vec - newVec.addEnd(other) - return newVec - } - - fun operator+=(other: ref T):void { - addEnd(other) - } - - fun operator+=(other: ref vec):void { - for (var i = 0; i < other.size; i++;) - addEnd(other.get(i)) - } - - fun clone(): vec { - var newVec.construct(size): vec - for (var i = 0; i < size; i++;) - newVec.addEnd(data[i]) - return newVec - } - fun reverse(): vec { - var newVec.construct(size): vec - for (var i = 0; i < size; i++;) - newVec.addEnd(data[(size-i)-1]) - return newVec - } - - fun resize(newSize: int): bool { - var newData: *T = new(newSize); - if (!newData) - return false; - for (var i: int = 0; i < min(size, newSize); i++;) - maybe_copy_construct(&newData[i], &data[i]); - delete(data, size); - data = newData; - available = newSize; - size = min(size, newSize) - return true; - } - - fun slice(start: int, end: int): vec { - if (start < 0) - start += size + 1 - if (end < 0) - end += size + 1 - var new.construct(end-start): vec - for (var i = start; i < end; i++;) - new.add(data[i]) - return new - } - - fun at(index: int): ref T { return get(index); } - fun operator[](index: int): ref T { return get(index); } - fun first(): ref T { - return get(0) - } - fun last(): ref T { - return get(size-1) - } - fun get(index: int): ref T { - if (index < 0 || index >= size) { - print("Vector tried to access element: "); - println(index); - print("Max Index of vec: "); - println(size-1); - while(true) {} - return data[0]; - } - return data[index]; - } - - fun getBackingMemory(): *T { return data; } - - // This is a template for the interesting reason that structs - // can not be compared for equality in C, and maybe we haven't defined equality - // on an object that we want to put in a vec. In this way we avoid the problem - // by not generating this function unless it's called - we also get the ability to - // do a find index using a different type, which could be fun. - fun find(value: ref U): int { - for (var i = 0; i < size; i++;) - if (data[i] == value) - return i; - return -1; - } - // ditto - fun contains(item: ref U): bool { - return find(item) != -1 - } - - // yep - fun operator==(other: ref vec):bool { - if (size != other.size) - return false - for (var i = 0; i < size; i++;) - if (!(data[i] == other.data[i])) // it's !(==) because we want equality if our members are equal, and overloading etc - return false - return true - } - fun operator< (other: ref vec):bool { - if (size < other.size) - return true - if (size > other.size) - return false - for (var i = 0; i < size; i++;) - if (data[i] < other.data[i]) // it's !(==) because we want equality if our members are equal, and overloading etc - return true - return false - } - - fun set(index: int, dataIn: ref T): void { - if (index < 0 || index >= size) - return; - data[index] = dataIn; - } - fun add_all(dataIn: ref vec): void { - for (var i = 0; i < dataIn.size; i++;) - addEnd(dataIn[i]); - } - fun add_all_unique(dataIn: ref vec): void { - for (var i = 0; i < dataIn.size; i++;) - add_unique(dataIn[i]); - } - // same darn trick - fun add_unique(dataIn: ref U): void { - if (!contains(dataIn)) - addEnd(dataIn) - } - fun add(dataIn: ref T): void { addEnd(dataIn); } - fun addEnd(dataIn: ref T): void { - // if we resize, we need to be careful as the dataIn reference - // may come from this itself - if (size+1 > available) { - var temp = dataIn - resize((size+1)*2); - maybe_copy_construct(&data[size], &temp); - } else { - maybe_copy_construct(&data[size], &dataIn); - } - size++; - } - - fun add(index: int, dataIn: ref T) { - if (size == 0) { - add(dataIn) - return - } - add(last()) - for (var i = size-2; i > index; i--;) { - data[i] = data[i-1] - } - data[index] = dataIn - } - - fun remove(index: int) { - maybe_destruct(&data[index]) - for (var i = index+1; i < size; i++;) { - maybe_copy_construct(&data[i-1], &data[i]) - maybe_destruct(&data[i]) - } - size-- - } - - fun clear() { - for (var i = 0; i < size; i++;) - maybe_destruct(&data[i]) - size = 0 - } - - fun for_each(func: fun(ref T):void):void { - for (var i = 0; i < size; i++;) - func(data[i]) - } - fun for_each(func: fun(T):void):void { - for (var i = 0; i < size; i++;) - func(data[i]) - } - fun for_each_reverse(func: fun(ref T):void):void { - for (var i = size-1; i >= 0; i--;) - func(data[i]) - } - fun for_each_reverse(func: fun(T):void):void { - for (var i = size-1; i >= 0; i--;) - func(data[i]) - } - fun in_place(func: fun(T):T):void { - for (var i = 0; i < size; i++;) - data[i] = func(data[i]) - } - fun map(func: fun(ref T):U):vec { - var newVec.construct(size): vec - for (var i = 0; i < size; i++;) - newVec.addEnd(func(data[i])) - return newVec - } - fun map(func: run(ref T):U):vec { - var newVec.construct(size): vec - for (var i = 0; i < size; i++;) - newVec.addEnd(func(data[i])) - return newVec - } - fun map(func: fun(T):U):vec { - var newVec.construct(size): vec - for (var i = 0; i < size; i++;) - newVec.addEnd(func(data[i])) - return newVec - } - fun map(func: run(T):U):vec { - var newVec.construct(size): vec - for (var i = 0; i < size; i++;) - newVec.addEnd(func(data[i])) - return newVec - } - fun flatten_map(func: fun(T):vec):vec { - var newVec.construct(size): vec - for (var i = 0; i < size; i++;) { - var to_add = func(data[i]) - for (var j = 0; j < to_add.size; j++;) - newVec.addEnd(to_add.get(j)) - } - return newVec - } - fun associate(func: fun(T):pair): map { - var to_ret = map() - for (var i = 0; i < size; i++;) { - var kv = func(data[i]) - to_ret[kv.first] = kv.second - } - return to_ret - } - fun find_first_satisfying(func: fun(T):bool): T return filter(func)[0] - fun filter(func: fun(T):bool):vec { - var newVec.construct(): vec - for (var i = 0; i < size; i++;) - if (func(data[i])) - newVec.addEnd(data[i]) - return newVec - } - fun any_true(func: fun(T):bool):bool { - for (var i = 0; i < size; i++;) - if (func(data[i])) - return true - return false - } - fun max(func: fun(ref T, ref T):bool): T { - var maxIdx = 0 - for (var i = 1; i < size; i++;) - if (func(data[maxIdx], data[i])) - maxIdx = i - return data[maxIdx] - } - fun max(func: fun(T,T):bool): T { - var maxIdx = 0 - for (var i = 1; i < size; i++;) - if (func(data[maxIdx], data[i])) - maxIdx = i - return data[maxIdx] - } - fun reduce(func: fun(T,U): U, initial: U): U { - for (var i = 0; i < size; i++;) - initial = func(data[i], initial) - return initial - } - fun sorted(less_than: run(ref U, ref U): bool): vec { - if size < 2 { - return *this - } else { - var left = slice(0, size/2).sorted(less_than) - var right = slice(size/2, -1).sorted(less_than) - var to_ret.construct(size): vec - var l = 0 - var r = 0 - while (l < left.size || r < right.size) { - if l == left.size { - to_ret.add(right[r++]) - } else if r == right.size { - to_ret.add(left[l++]) - } else if less_than(left[l], right[r]) { - to_ret.add(left[l++]) - } else { - to_ret.add(right[r++]) - } - } - return to_ret - } - } - fun pop(): T { - var to_ret = data[size-1] - remove(size-1) - return to_ret - } -}; - diff --git a/stdlib/vec_literals.krak b/stdlib/vec_literals.krak deleted file mode 100644 index ce42940..0000000 --- a/stdlib/vec_literals.krak +++ /dev/null @@ -1,134 +0,0 @@ -import vec - -fun vec(first:T, second:T):vec::vec { - var out.construct():vec::vec - out.add(first) - out.add(second) - return out -} - -fun vec(first:T, second:T, third:T):vec::vec { - var out.construct():vec::vec - out.add(first) - out.add(second) - out.add(third) - return out -} - -fun vec(first:T, second:T, third:T, fourth:T):vec::vec { - var out.construct():vec::vec - out.add(first) - out.add(second) - out.add(third) - out.add(fourth) - return out -} - -fun vec(first:T, second:T, third:T, fourth:T, fifth:T):vec::vec { - var out.construct():vec::vec - out.add(first) - out.add(second) - out.add(third) - out.add(fourth) - out.add(fifth) - return out -} - -fun vec(first:T, second:T, third:T, fourth:T, fifth:T, sixth:T):vec::vec { - var out.construct():vec::vec - out.add(first) - out.add(second) - out.add(third) - out.add(fourth) - out.add(fifth) - out.add(sixth) - return out -} - -fun vec(first:T, second:T, third:T, fourth:T, fifth:T, sixth:T, seventh:T):vec::vec { - var out.construct():vec::vec - out.add(first) - out.add(second) - out.add(third) - out.add(fourth) - out.add(fifth) - out.add(sixth) - out.add(seventh) - return out -} - -fun vec(first:T, second:T, third:T, fourth:T, fifth:T, sixth:T, seventh:T, eighth:T):vec::vec { - var out.construct():vec::vec - out.add(first) - out.add(second) - out.add(third) - out.add(fourth) - out.add(fifth) - out.add(sixth) - out.add(seventh) - out.add(eighth) - return out -} - -fun vec(first:T, second:T, third:T, fourth:T, fifth:T, sixth:T, seventh:T, eighth:T, ninth:T):vec::vec { - var out.construct():vec::vec - out.add(first) - out.add(second) - out.add(third) - out.add(fourth) - out.add(fifth) - out.add(sixth) - out.add(seventh) - out.add(eighth) - out.add(ninth) - return out -} - -fun vec(first:T, second:T, third:T, fourth:T, fifth:T, sixth:T, seventh:T, eighth:T, ninth:T, tenth:T):vec::vec { - var out.construct():vec::vec - out.add(first) - out.add(second) - out.add(third) - out.add(fourth) - out.add(fifth) - out.add(sixth) - out.add(seventh) - out.add(eighth) - out.add(ninth) - out.add(tenth) - return out -} - -fun vec(first:T, second:T, third:T, fourth:T, fifth:T, sixth:T, seventh:T, eighth:T, ninth:T, tenth:T, eleventh:T):vec::vec { - var out.construct():vec::vec - out.add(first) - out.add(second) - out.add(third) - out.add(fourth) - out.add(fifth) - out.add(sixth) - out.add(seventh) - out.add(eighth) - out.add(ninth) - out.add(tenth) - out.add(eleventh) - return out -} - -fun vec(first:T, second:T, third:T, fourth:T, fifth:T, sixth:T, seventh:T, eighth:T, ninth:T, tenth:T, eleventh:T, twelveth:T):vec::vec { - var out.construct():vec::vec - out.add(first) - out.add(second) - out.add(third) - out.add(fourth) - out.add(fifth) - out.add(sixth) - out.add(seventh) - out.add(eighth) - out.add(ninth) - out.add(tenth) - out.add(eleventh) - out.add(twelveth) - return out -} - diff --git a/stress_generator.py b/stress_generator.py deleted file mode 100644 index 776c81f..0000000 --- a/stress_generator.py +++ /dev/null @@ -1,21 +0,0 @@ - -func_base = "main" -var_base = "var" - -numlines = 20 -numfuncs = 5 - -def genFunc(): - stress_test = open("stress_test.krak",'w') - for i in range(numfuncs): - stress_test.write('fun '+func_base+(str(i) if i != 0 else "")+'() : int {\n') - for j in range(numlines): - stress_test.write("var " + var_base+str(j)+' : int = (5*4+3-2)+1; \n') - stress_test.write("return 0;\n") - stress_test.write('}') - stress_test.write("\n\n") - - stress_test.close() - - -genFunc() diff --git a/syntax.gp b/syntax.gp deleted file mode 100644 index 5c37694..0000000 --- a/syntax.gp +++ /dev/null @@ -1,29 +0,0 @@ - -; LISP style -(do - (println (+ 2 3)) - (println (- 2 3)) - (println (* 2 3)) - (println (/ 2 3)) - (println "howdy") -) - -; let's add some stuff to our grammer... -(add_grammer_rule :semi_forms [:form ";"] (fn* (xs) (list (first xs)))) -(add_grammer_rule :semi_forms [:form ";" :optional_WS :semi_forms ] (fn* (xs) (cons (first xs) (nth xs 3)))) -(add_grammer_rule :form ["{" :optional_WS :semi_forms :optional_WS "}"] (fn* (xs) `(do ,(nth xs 2)))) -(add_grammer_rule :form [:atom :form ] (fn* (xs) `(~(first xs) ,(nth xs 1)))) -(add_grammer_rule :form [:form :optional_WS "$" :atom :optional_WS :form] (fn* (xs) `(~(nth xs 3) ~(nth xs 0) ~(nth xs 5)))) - -; C style -{ - println( 2 $+ 3 ); - println( 2 $- 3 ); - println( 2 $* 3 ); - println( 2 $/ 3 ); - println("howdy"); -} - -; combo -(println (list 1 2 4 $+ 5)) -{ println( (+ 2 3) ); } diff --git a/tests/.gitignore b/tests/.gitignore deleted file mode 100644 index 734aac7..0000000 --- a/tests/.gitignore +++ /dev/null @@ -1,13 +0,0 @@ -tester -test_compiler -*.results -*.c -test_chainedIndirectTemplates -test_functionsValues -test_future -test_grammer -test_set -test_templateFuncInfr -test_util -test_close_over_members -test_string diff --git a/tests/.test_trigTest.krak.un~ b/tests/.test_trigTest.krak.un~ deleted file mode 100644 index c0d6c7701d37a5e2ab8681d861a45470a6377191..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1379 zcmWH`%$*;a=aT=Ffys2D4`Y`uuhk#3SEog)d~2Vk9do%A@uJ)LR(&kPf#tjm3=EnK z3=B*P3JeSkY9JN^0|O%i0|PSy1b}E5W(d`+>Sh7SGBU(pfXFj2L1_>Lk^&jR0^
~+X z07V-pszBllqfrG57FyAvnpLgnQ3Z-75C%m7lY#;?qCgRY>36 VsAg3cIHDL)^AxC*gh$l#RRF)?GVA~V diff --git a/tests/SupressOut.sh b/tests/SupressOut.sh deleted file mode 100755 index eee017e..0000000 --- a/tests/SupressOut.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -rm *krakout* diff --git a/tests/c_passthrough_diff.krak b/tests/c_passthrough_diff.krak deleted file mode 100644 index 2b78e6b..0000000 --- a/tests/c_passthrough_diff.krak +++ /dev/null @@ -1,17 +0,0 @@ - -__if_comp__ __C__ simple_passthrough """ - #include - int diff = 7; -""" - -fun print_it(): void { - __if_comp__ __C__ simple_passthrough """ - printf("diff_file: %d\n", diff); - """ -} - -fun print_it(i: int): void { - __if_comp__ __C__ simple_passthrough(i = i::) """ - printf("diff_file: %d\n", i); - """ -} diff --git a/tests/disabled_test_ctce_pass.expected_results b/tests/disabled_test_ctce_pass.expected_results deleted file mode 100644 index 32cf98b..0000000 --- a/tests/disabled_test_ctce_pass.expected_results +++ /dev/null @@ -1 +0,0 @@ -more than 10000 nodes! diff --git a/tests/disabled_test_ctce_pass.krak b/tests/disabled_test_ctce_pass.krak deleted file mode 100644 index fb6ce2d..0000000 --- a/tests/disabled_test_ctce_pass.krak +++ /dev/null @@ -1,12 +0,0 @@ -import node_counter: * - -#ctce_pass(node_counter::node_counter_test) - -fun small_func() { - println("hello") -} - -fun main(): int { - return 0 -} - diff --git a/tests/error_test.krak b/tests/error_test.krak deleted file mode 100644 index 94ab785..0000000 --- a/tests/error_test.krak +++ /dev/null @@ -1,13 +0,0 @@ -import mem:* -import vector:* - - -fun main():int { - var a = null>() - /*doesnt_exist(2)*/ - /*var b: doesnt_exist*/ - return -1 -} - - - diff --git a/tests/new_runner.sh b/tests/new_runner.sh deleted file mode 100755 index a21c3b5..0000000 --- a/tests/new_runner.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env bash - -runner_path="./tester" -#testDir=${1:-"../tests"} -testDir="." -ext=${2:-"krak"} - -fileList="" -for dir in `find ${testDir} -type f -name "test_*.${ext}"`; do - filename=$(basename ${dir}) - filename="${filename%.*}" - fileList+=\ $testDir\/$filename -done - -${runner_path} ${fileList} diff --git a/tests/sameNameOne.krak b/tests/sameNameOne.krak deleted file mode 100644 index 0fe8e06..0000000 --- a/tests/sameNameOne.krak +++ /dev/null @@ -1,7 +0,0 @@ - -var sameVar: int; -fun sameFun(): int { return 5; } -obj classTester { - fun method(): int { return 8; } -} - diff --git a/tests/sameNameTwo.krak b/tests/sameNameTwo.krak deleted file mode 100644 index 43a0435..0000000 --- a/tests/sameNameTwo.krak +++ /dev/null @@ -1,6 +0,0 @@ - -var sameVar: int; -fun sameFun(): int { return 6; } -obj classTester { - fun method(): int { return 9; } -} diff --git a/tests/scopeQualified.krak b/tests/scopeQualified.krak deleted file mode 100644 index cb5cd7e..0000000 --- a/tests/scopeQualified.krak +++ /dev/null @@ -1,27 +0,0 @@ -var qualified_variable: int = 7; -fun qualified_func(): int { return 9; } - -obj qualified_class { - var number: int; - fun construct(num: int): *qualified_class { - number = num; - return this; - } - fun get(): int { - return number; - } -}; - -obj qualified_container { - var data: T; - fun construct(dataIn: T): *qualified_container { - data = dataIn; - } - fun get(): T { - return data; - } -}; - -fun qualified_id(it: T): T { - return it; -} diff --git a/tests/scopeUnqualified.krak b/tests/scopeUnqualified.krak deleted file mode 100644 index a55546b..0000000 --- a/tests/scopeUnqualified.krak +++ /dev/null @@ -1,27 +0,0 @@ -var unqualifed_variable: int = 8; -fun unqualified_func(): int { return 10; } - -obj unqualified_class { - var number: int; - fun construct(num: int): *unqualified_class { - number = num; - return this; - } - fun get(): int { - return number; - } -}; - -obj unqualified_container { - var data: T; - fun construct(dataIn: T): *unqualified_container { - data = dataIn; - } - fun get(): T { - return data; - } -}; - -fun unqualified_id(it: T): T { - return it; -} diff --git a/tests/syntax_error.krak b/tests/syntax_error.krak deleted file mode 100644 index 5a67538..0000000 --- a/tests/syntax_error.krak +++ /dev/null @@ -1,34 +0,0 @@ -import io: something - -//comments - -fun first(): cutomTye { -} -fun another(): cutomTye* { - -} - -fun main():int { - if (true) { - thing; - } - if ( 3 < 300) { - } - if ( 3 > 300) { - } - var hastype: type = 20 - thingy.other; - if ( 3 < 300) { - } - io::print("hi") - wanna.callit(internal, to ,it) - var a = 2 + 7; - var b = 2 + 7 / 3 - 2 * 7 && 9 || 2 + !g - return 0 - return 11820 - return 1.1 - return 1.1f - return "hi" -} - - diff --git a/tests/test_OperatorOverloadTest.expected_results b/tests/test_OperatorOverloadTest.expected_results deleted file mode 100644 index 78b0a52..0000000 --- a/tests/test_OperatorOverloadTest.expected_results +++ /dev/null @@ -1,5 +0,0 @@ -3 9 -6 18 -Subtraction -3 9 --97 -61 diff --git a/tests/test_OperatorOverloadTest.krak b/tests/test_OperatorOverloadTest.krak deleted file mode 100644 index d3c5e71..0000000 --- a/tests/test_OperatorOverloadTest.krak +++ /dev/null @@ -1,64 +0,0 @@ -import io:*; - -obj Vec2 { - var x: int; - var y: int; - - fun print(): void { - print(x); - print(" "); - print(y); - } - - fun add(other: Vec2): Vec2 { - var toReturn: Vec2; - toReturn.x = x + other.x; - toReturn.y = y + other.y; - print(); - return toReturn; - } - - fun subtract(other: Vec2): Vec2 { - var toReturn: Vec2; - toReturn.x = x - other.x; - toReturn.y = y - other.y; - print(); - return toReturn; - } - - fun operator+(other: Vec2): Vec2 { - return add(other); - } - -}; - -fun operator-(lhs: Vec2, rhs: Vec2): Vec2 { - return lhs.subtract(rhs); -} - -fun main(): int { - var vector1: Vec2; - var vector2: Vec2; - vector1.x = 3; - vector1.y = 9; - vector2 = vector1; - /* NOTE COMMENT - |Vec2| vector3; - vector3.x = vector1.x + vector2.x; - vector3.y = vector1.y + vector2.y; - vector2.print(); - */ - var addition: Vec2 = vector1 + vector2; - print("\n"); - addition.print(); - print("\nSubtraction\n"); - vector2.x = 100; - vector2.y = 70; - var subtraction: Vec2 = vector1 - vector2; - print("\n"); - print(subtraction.x); print(" "); print(subtraction.y); - - print("\n"); - - return 0; -} diff --git a/tests/test_RecursiveTest.expected_results b/tests/test_RecursiveTest.expected_results deleted file mode 100644 index 7ed6ff8..0000000 --- a/tests/test_RecursiveTest.expected_results +++ /dev/null @@ -1 +0,0 @@ -5 diff --git a/tests/test_RecursiveTest.krak b/tests/test_RecursiveTest.krak deleted file mode 100644 index 04fbe40..0000000 --- a/tests/test_RecursiveTest.krak +++ /dev/null @@ -1,14 +0,0 @@ -import io:*; - -fun fibanacci(num: int): int { - if (num < 2) - return 1; - return fibanacci(num-1) + fibanacci(num-2); -} - -fun main(): int { - print(fibanacci(4)); - print("\n"); - return 0; -} - diff --git a/tests/test_access_expression.expected_results b/tests/test_access_expression.expected_results deleted file mode 100644 index d00491f..0000000 --- a/tests/test_access_expression.expected_results +++ /dev/null @@ -1 +0,0 @@ -1 diff --git a/tests/test_access_expression.krak b/tests/test_access_expression.krak deleted file mode 100644 index 7a03fd7..0000000 --- a/tests/test_access_expression.krak +++ /dev/null @@ -1,23 +0,0 @@ -import io:* -import vector:* - -obj container { - var v1: vector - var v2: vector - fun construct(): *container { - v1.construct() - v2.construct() - } - fun destruct() { - v1.destruct() - v2.destruct() - } -} - -fun main():int { - var c.construct() : container - c.v1 = vector(1); // need this ; otherwise this could ambigiously be one or two lines - (c.v1).for_each(fun(i: int) { - println(i) - }) -} diff --git a/tests/test_adt.expected_results b/tests/test_adt.expected_results deleted file mode 100644 index 5661c1e..0000000 --- a/tests/test_adt.expected_results +++ /dev/null @@ -1,55 +0,0 @@ -option1 -no int -an int: 7 -equality true works! -equality false works! -matched an int:11 correctly! -matched no int correctly! -matched no_obj correctly -assignment to old variable -gonna make object in function 100 -constructed object 100 : 100 -copy constructed object 100 : 200 from 100 : 100 -destructed object 100 : 100 -copy constructed object 100 : 300 from 100 : 200 -copy constructed object 100 : 400 from 100 : 300 -copy constructed object 100 : 500 from 100 : 400 -destructed object 100 : 400 -destructed object 100 : 300 -copy constructed object 100 : 600 from 100 : 500 -done assignment to old variable -matched an_obj correctly 100 : 600 -int assignment to old var -destructed object 100 : 600 -done int assignment to old var -matched an_int correctly 1337 -test copy_construct for non ref equality -gonna make object in function 110 -constructed object 110 : 110 -copy constructed object 110 : 210 from 110 : 110 -destructed object 110 : 110 -copy constructed object 110 : 310 from 110 : 210 -copy constructed object 110 : 410 from 110 : 310 -copy constructed object 110 : 510 from 110 : 410 -destructed object 110 : 410 -destructed object 110 : 310 -gonna make object in function 110 -constructed object 110 : 110 -copy constructed object 110 : 210 from 110 : 110 -destructed object 110 : 110 -copy constructed object 110 : 310 from 110 : 210 -copy constructed object 110 : 410 from 110 : 310 -copy constructed object 110 : 510 from 110 : 410 -destructed object 110 : 410 -destructed object 110 : 310 -copy constructed object 110 : 610 from 110 : 510 -destructed object 110 : 610 -equality an_obj correctly -done test copy_construct for non ref equality -10 -destructed object 110 : 510 -destructed object 110 : 210 -destructed object 110 : 510 -destructed object 110 : 210 -destructed object 100 : 500 -destructed object 100 : 200 diff --git a/tests/test_adt.krak b/tests/test_adt.krak deleted file mode 100644 index e988075..0000000 --- a/tests/test_adt.krak +++ /dev/null @@ -1,163 +0,0 @@ -import io:* - -adt options { - option0, - option1 -} - -adt maybe_int { - no_int, - an_int: int -} - -fun TestObj(num: int): TestObj { - print("gonna make object in function ") - println(num) - var toRet.construct(num): TestObj - return toRet -} -obj TestObj (Object) { - var obj_num: int - var ref_num: int - fun construct(num:int): *TestObj { - obj_num = num - ref_num = num - print("constructed object ") - print(obj_num);print(" : ");println(ref_num) - } - fun copy_construct(old: *TestObj) { - obj_num = old->obj_num - ref_num = old->ref_num + 100 - print("copy constructed object ") - print(obj_num);print(" : ");print(ref_num) - print(" from ") - print(old->obj_num);print(" : ");println(old->ref_num) - } - fun destruct() { - print("destructed object ") - print(obj_num);print(" : ");println(ref_num) - } - /*fun operator==(other: ref TestObj): bool {*/ - fun operator==(other: TestObj): bool { - return obj_num == other.obj_num; - } -} - -adt maybe_object { - no_obj, - an_obj: TestObj, - an_int: int -} - -fun handle_possibility(it: maybe_int) { - if (it == maybe_int::no_int()) { - println("no int") - } else { - print("an int: ") - println(it.an_int) - } -} - -fun give_maybe(give_it: bool): maybe_int { - if (give_it) - return maybe_int::an_int(7) - return maybe_int::no_int() -} - -fun can_pass(it: options): options { - return it -} - -fun main():int { - var it: options = can_pass(options::option1()) - if (it == options::option0()) { - println("nope") - } - if (it == options::option1()) { - println("option1") - } - - var possibility = give_maybe(false) - handle_possibility(possibility) - possibility = give_maybe(true) - handle_possibility(possibility) - if ( maybe_int::an_int(7) == maybe_int::an_int(7) ) - println("equality true works!") - else - println("equality true fails!") - - if ( maybe_int::an_int(7) != maybe_int::an_int(8) ) - println("equality false works!") - else - println("equality false fails!") - - match (maybe_int::an_int(11)) { - maybe_int::an_int(the_int) { - print("matched an int:") - print(the_int) - println(" correctly!") - } - maybe_int::no_int() { - println("matched no int incorrectly!") - } - } - match (maybe_int::no_int()) { - maybe_int::an_int(the_int) println("matched an int incorrectly!") - maybe_int::no_int() println("matched no int correctly!") - } - var obj_item = maybe_object::no_obj() - match (obj_item) { - maybe_object::no_obj() println("matched no_obj correctly") - maybe_object::an_obj(obj_instance) { - print("matched an_obj incorrectly ") - println(obj_instance.obj_num) - } - maybe_object::an_int(int_thiny) { - print("matched an_intj incorrectly ") - println(int_thiny) - } - } - println("assignment to old variable") - obj_item = maybe_object::an_obj(TestObj(100)) - println("done assignment to old variable") - match (obj_item) { - maybe_object::no_obj() println("matched no_obj incorrectly") - maybe_object::an_obj(obj_instance) { - print("matched an_obj correctly ") - print(obj_instance.obj_num);print(" : ");println(obj_instance.ref_num) - } - maybe_object::an_int(int_thiny) { - print("matched an_intj incorrectly ") - println(int_thiny) - } - } - println("int assignment to old var") - obj_item = maybe_object::an_int(1337) - println("done int assignment to old var") - /*println("test copying thing");*/ - /*var obj_item_new = maybe_object::an_obj(TestObj(1000))*/ - /*println("new object assingment")*/ - /*var obj_item_new_copy = obj_item_new;*/ - /*println("done new object assingment")*/ - /*println("done test copying thing");*/ - match (obj_item) { - maybe_object::no_obj() println("matched no_obj incorrectly") - maybe_object::an_obj(obj_instance) { - print("matched an_obj incorrectly ") - print(obj_instance.obj_num);print(" : ");println(obj_instance.ref_num) - } - maybe_object::an_int(int_thiny) { - print("matched an_int correctly ") - println(int_thiny) - } - } - println("test copy_construct for non ref equality"); - if (maybe_object::an_obj(TestObj(110)) == maybe_object::an_obj(TestObj(110))) - println("equality an_obj correctly ") - else - println("equality an_obj incorrectly ") - println("done test copy_construct for non ref equality"); - println(maybe_object::an_int(10).an_int) - return 0 -} - diff --git a/tests/test_auto_void.expected_results b/tests/test_auto_void.expected_results deleted file mode 100644 index ad12014..0000000 --- a/tests/test_auto_void.expected_results +++ /dev/null @@ -1,3 +0,0 @@ -Woooo -7 -uh huh diff --git a/tests/test_auto_void.krak b/tests/test_auto_void.krak deleted file mode 100644 index 2114782..0000000 --- a/tests/test_auto_void.krak +++ /dev/null @@ -1,16 +0,0 @@ -import io:* - -fun retVoid() { - println("Woooo") -} - -fun withParams(a:int, b:*char) { - println(a) - println(b) -} - -fun main():int { - retVoid() - withParams(7, "uh huh") - return 0 -} diff --git a/tests/test_badMath.expected_results b/tests/test_badMath.expected_results deleted file mode 100644 index 20381cc..0000000 --- a/tests/test_badMath.expected_results +++ /dev/null @@ -1,11 +0,0 @@ -Spam -12 -14 -28 -We'll find out. -34 -woo not -false -7 -6 -1 diff --git a/tests/test_badMath.krak b/tests/test_badMath.krak deleted file mode 100644 index 808d3e6..0000000 --- a/tests/test_badMath.krak +++ /dev/null @@ -1,26 +0,0 @@ -import io:* - -fun main(): int { - io::println("Spam"); - var x: int = 4; - x += 3; - x++; - var y :int = 6; - var z :int = x + y; - var q :int = z+z; - var q2:int = z*3; - var q3:int = y + y; - io::println(q3); - io::println(z); - io::println(q); - for (var i:int = 0; i < 20; i++;) z++; - if (z > 20) io::println("We'll find out."); - io::println(z); - var boolean = false - if ( z > 20 && !boolean) - io::println("woo not") - io::println('b' == 'a') - println(3|5) - println(3^5) - println(3&5) -} diff --git a/tests/test_bracket_assign.expected_results b/tests/test_bracket_assign.expected_results deleted file mode 100644 index 36b192e..0000000 --- a/tests/test_bracket_assign.expected_results +++ /dev/null @@ -1,3 +0,0 @@ -bracket assign: index: 4, rhs: 9 -just bracket: index: 5 -just =: index: 6 diff --git a/tests/test_bracket_assign.krak b/tests/test_bracket_assign.krak deleted file mode 100644 index 669289b..0000000 --- a/tests/test_bracket_assign.krak +++ /dev/null @@ -1,26 +0,0 @@ -import io:* - -obj BracketAssign { - fun operator[]=(index:int, rhs:int) { - print("bracket assign: index: ") - print(index) - print(", rhs: ") - println(rhs) - } - fun operator[](index:int) { - print("just bracket: index: ") - println(index) - } - fun operator=(index:int) { - print("just =: index: ") - println(index) - } -} - -fun main():int { - var test:BracketAssign - test[4] = 9 - test[5] - test = 6 - return 0 -} diff --git a/tests/test_break_continue_defer.expected_results b/tests/test_break_continue_defer.expected_results deleted file mode 100644 index 25d3ff5..0000000 --- a/tests/test_break_continue_defer.expected_results +++ /dev/null @@ -1,17 +0,0 @@ -1 -happens every time, even when breaking or continueing -happens every time, even when breaking or continueing -3 -happens every time, even when breaking or continueing -happens every time, even when breaking or continueing -5 -happens every time, even when breaking or continueing -happens every time, even when breaking or continueing -only happens once before breaking 7 -happens every time, even when breaking or continueing -happens every time, even when breaking or continueing -happens every time, even when breaking or continueing -block outside for -first -last -deferred diff --git a/tests/test_break_continue_defer.krak b/tests/test_break_continue_defer.krak deleted file mode 100644 index 237e71e..0000000 --- a/tests/test_break_continue_defer.krak +++ /dev/null @@ -1,27 +0,0 @@ -import io:* - -fun main():int { - { - defer println("block outside for") - for (var i = 1; i < 10; i++;) { - { - defer println("happens every time, even when breaking or continueing") - if (i % 2 == 0) - continue - if (i == 9) - break - if (i == 7) { - defer println("only happens once before breaking 7") - continue - } - println(i) - } - } - } - { - println("first") - defer println("deferred") - println("last") - } - return 0 -} diff --git a/tests/test_c_comments.expected_results b/tests/test_c_comments.expected_results deleted file mode 100644 index d00491f..0000000 --- a/tests/test_c_comments.expected_results +++ /dev/null @@ -1 +0,0 @@ -1 diff --git a/tests/test_c_comments.krak b/tests/test_c_comments.krak deleted file mode 100644 index 7537f65..0000000 --- a/tests/test_c_comments.krak +++ /dev/null @@ -1,11 +0,0 @@ -/*here*/ -/*here*/import /*here*/io/*here*/:/*here*/*/*here*/ -/*here*/ -/*here*/fun/*here*/ main/*here*/(/*here*/)/*here*/:/*here*/ int/*here*/ {/*here*/ - /*here*/ println/*here*/( /*here*/1 /*here*/ )/*here*/ - - /*/1337*/ - - /*here*/ return /*here*/0/*here*/ - /*here*/}/*here*/ -/*here*/ diff --git a/tests/test_cgen_bug.expected_results b/tests/test_cgen_bug.expected_results deleted file mode 100644 index b261da1..0000000 --- a/tests/test_cgen_bug.expected_results +++ /dev/null @@ -1,2 +0,0 @@ -1 -0 diff --git a/tests/test_cgen_bug.krak b/tests/test_cgen_bug.krak deleted file mode 100644 index e8ad0d2..0000000 --- a/tests/test_cgen_bug.krak +++ /dev/null @@ -1,14 +0,0 @@ -import io:* -import vector:* - -fun onlyMatch(vec: vector, matchWith: int): vector { - return vec.filter(fun(it:int):bool { return it == matchWith; }) -} - -fun main():int { - var vec = vector(7) - println(onlyMatch(vec,7).size) - println(onlyMatch(vec,9).size) - - return 0 -} diff --git a/tests/test_chainedIndirectTemplates.expected_results b/tests/test_chainedIndirectTemplates.expected_results deleted file mode 100644 index 0cfbf08..0000000 --- a/tests/test_chainedIndirectTemplates.expected_results +++ /dev/null @@ -1 +0,0 @@ -2 diff --git a/tests/test_chainedIndirectTemplates.krak b/tests/test_chainedIndirectTemplates.krak deleted file mode 100644 index ebe5e57..0000000 --- a/tests/test_chainedIndirectTemplates.krak +++ /dev/null @@ -1,15 +0,0 @@ -import vector:*; -import io:*; - -fun test(a: vector): T { - return a.at(0); -} - -fun main(): int { - var a.construct(): vector; - a.addEnd(2); - println(test(a)); - return 0; -} - - diff --git a/tests/test_close_over_members.expected_results b/tests/test_close_over_members.expected_results deleted file mode 100644 index 192bcdc..0000000 --- a/tests/test_close_over_members.expected_results +++ /dev/null @@ -1,5 +0,0 @@ -4 -7 -129 -222 -129 diff --git a/tests/test_close_over_members.krak b/tests/test_close_over_members.krak deleted file mode 100644 index 85a6100..0000000 --- a/tests/test_close_over_members.krak +++ /dev/null @@ -1,55 +0,0 @@ -import io:* -import set -import util - -fun runFunc(func: fun():void) { - func() -} - -obj ToClose { - var data: int - fun print4() { - println(4) - } - fun testMethod() { - runFunc(fun() { print4(); } ) - } - fun testVariable() { - data = 7 - runFunc(fun() { println(data); } ) - } -} - -obj One (Object) { - fun construct(): *One { - return this - } - fun destruct() { - var a:One - util::safe_recursive_delete(&a, fun(it: *One): set::set<*One> { return set::set(it); } ) - } -} - - -fun main():int { - var it: ToClose - it.testMethod() - it.testVariable() - - var a = 129 - var b = 222 - fun() { - fun() { - println(a) - }() - }() - var c = fun() { - println(b) - fun() { - println(a) - }() - } - c() - return 0 -} - diff --git a/tests/test_close_over_references.expected_results b/tests/test_close_over_references.expected_results deleted file mode 100644 index b629232..0000000 --- a/tests/test_close_over_references.expected_results +++ /dev/null @@ -1,2 +0,0 @@ -9 -9 diff --git a/tests/test_close_over_references.krak b/tests/test_close_over_references.krak deleted file mode 100644 index 8091983..0000000 --- a/tests/test_close_over_references.krak +++ /dev/null @@ -1,17 +0,0 @@ -import io:* - -fun func(it: ref int) { - it++ - fun() { - it++ - println(it) - }() -} - -fun main(): int { - var it = 7 - func(it) - println(it) - - return 0 -} diff --git a/tests/test_commentFirstTest.expected_results b/tests/test_commentFirstTest.expected_results deleted file mode 100644 index 3239433..0000000 --- a/tests/test_commentFirstTest.expected_results +++ /dev/null @@ -1,2 +0,0 @@ -1337 -42 diff --git a/tests/test_commentFirstTest.krak b/tests/test_commentFirstTest.krak deleted file mode 100644 index bbe6b4c..0000000 --- a/tests/test_commentFirstTest.krak +++ /dev/null @@ -1,9 +0,0 @@ -/* Comment first! */ -import io:*; - -fun main(): int { - println(1337) /*how bout now*/ - println(42) //or now - return 0; - //hmm -} diff --git a/tests/test_comparison_overload.expected_results b/tests/test_comparison_overload.expected_results deleted file mode 100644 index c508d53..0000000 --- a/tests/test_comparison_overload.expected_results +++ /dev/null @@ -1 +0,0 @@ -false diff --git a/tests/test_comparison_overload.krak b/tests/test_comparison_overload.krak deleted file mode 100644 index 885fc8b..0000000 --- a/tests/test_comparison_overload.krak +++ /dev/null @@ -1,25 +0,0 @@ -import io:* - -fun Comparable(): Comparable { - var toRet : Comparable - return toRet -} - -fun Comparable(item: T): Comparable { - var toRet : Comparable - return toRet -} - -obj Comparable { - fun operator==(other: Comparable):bool { - return false - } -} - -fun main():int { - var first: Comparable - var second: Comparable - println(first == second) - return 0 -} - diff --git a/tests/test_compiler_intrinsic.expected_results b/tests/test_compiler_intrinsic.expected_results deleted file mode 100644 index ddddcb1..0000000 --- a/tests/test_compiler_intrinsic.expected_results +++ /dev/null @@ -1,5 +0,0 @@ -1 -4 -4 -8 -8 diff --git a/tests/test_compiler_intrinsic.krak b/tests/test_compiler_intrinsic.krak deleted file mode 100644 index d45105d..0000000 --- a/tests/test_compiler_intrinsic.krak +++ /dev/null @@ -1,12 +0,0 @@ -import io:* - -fun main(): int { - println(#sizeof) - println(#sizeof) - println(#sizeof) - println(#sizeof) - println(#sizeof<*void>) - return 0 -} - - diff --git a/tests/test_conversions.expected_results b/tests/test_conversions.expected_results deleted file mode 100644 index 63e1ab9..0000000 --- a/tests/test_conversions.expected_results +++ /dev/null @@ -1,11 +0,0 @@ -A -66 -57 -5 -0 -0 - -57 -5 -0 -0 diff --git a/tests/test_conversions.krak b/tests/test_conversions.krak deleted file mode 100644 index 5d856aa..0000000 --- a/tests/test_conversions.krak +++ /dev/null @@ -1,25 +0,0 @@ -import io:* - -fun main():int { - println((65) cast char) - println(('B') cast int) - - var a = 1337 - var b = &a; - var c = (b) cast *char - - //var d = c + 1 - //var e = 1 + c - println((*(c+0)) cast int) - println((*(c+1)) cast int) - println((*(c+2)) cast int) - println((*(c+3)) cast int) - - println() - - println((c[0]) cast int) - println((c[1]) cast int) - println((c[2]) cast int) - println((c[3]) cast int) - return 0 -} diff --git a/tests/test_ctce.expected_results b/tests/test_ctce.expected_results deleted file mode 100644 index 0979046..0000000 --- a/tests/test_ctce.expected_results +++ /dev/null @@ -1,53 +0,0 @@ - - -=====During CTCE!===== - - -3 -hello, world -From Shell -From Shell -From Shell -From Shell -From Shell -From Shell -From Shell -From Shell -From Shell -From Shell -true -true -true -true -true -true -true -true -true -true -true -true -true -true -true -true -true -true -true -true -true -true -true -true -true -true -true -true -true -true -true -true -true -true -true -true diff --git a/tests/test_ctce.krak b/tests/test_ctce.krak deleted file mode 100644 index 42af371..0000000 --- a/tests/test_ctce.krak +++ /dev/null @@ -1,110 +0,0 @@ -import io: * -import os: * -import string: * -import ast_nodes: * - -obj first { - var p1: *char - var p2: char - var p3: int -} -obj second { - var p1: *char - var p2: char - var p3: short -} -obj third { - var p1: *char - var p2: long - var p3: char -} -obj fourth { - var p1: char - var p2: *char - var p3: long -} -obj fifth { - var p1: *char - var p2: char -} -obj sixth { - var p1: *char - var p2: char - var p3: long -} -obj seventh { - var p1: char - var p2: *char - var p3: long -} -obj eigth { - var p1: short - var p2: char -} -obj ninth { - var p1: *char - var p2: short -} -obj tenth { - var p1: char - var p2: ninth -} - -fun compare_sizes() { - var a = #sizeof - var b = #ctce(#sizeof) - println(a == b) - if (a != b) - println(string() + a + " is not the same size as " + b) -} - -fun main(): int { - var a = #ctce(1+2) - println(a) - println(#ctce("junkhello, world"+4)) - for (var i = 0; i < 10; i++;) { - println(#ctce(fun(): *char { - println("\n\n=====During CTCE!=====\n\n") - var it = from_system_command(string("echo From Shell"), 100) - return it.toCharArray() - }())) - } - compare_sizes() - compare_sizes() - compare_sizes() - compare_sizes() - compare_sizes() - compare_sizes() - compare_sizes() - compare_sizes() - compare_sizes() - compare_sizes() - - compare_sizes() - compare_sizes() - compare_sizes() - compare_sizes() - compare_sizes() - compare_sizes() - compare_sizes() - compare_sizes() - compare_sizes